Mouse Gestures like Opera

A Mouse Gestures script is the same as in the old Opera

2017-10-05 일자. 최신 버전을 확인하세요.

질문, 리뷰하거나, 이 스크립트를 신고하세요.
// ==UserScript==
// @name         Mouse Gestures like Opera
// @namespace    https://greasyfork.org/users/37096/
// @homepage     https://greasyfork.org/scripts/33398/
// @supportURL   https://greasyfork.org/scripts/33398/feedback
// @version      1.0.7
// @description  A Mouse Gestures script is the same as in the old Opera
// @author       Hồng Minh Tâm
// @require      https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js
// @icon         https://png.icons8.com/mouse-right-click/ultraviolet/40
// @include      *
// @compatible   chrome
// @license      GNU GPLv3
// @grant        GM_addStyle
// @grant        GM_openInTab
// @grant        window.close
// ==/UserScript==

(function () {
	'use strict';

	GM_addStyle([
		'.mouse-gestures { display: none; z-index: 9999999999; position: fixed; overflow: hidden; border: 1px solid #CCC; white-space: nowrap; font-family: sans-serif; background-color: rgba(0, 0, 0, 0.7); color: #333; border-radius: 50%; width: 400px; height: 400px; }',

		'.mouse-gestures .mouse-gestures-middle, .mouse-gestures .mouse-gestures-up, .mouse-gestures .mouse-gestures-down, .mouse-gestures .mouse-gestures-left, .mouse-gestures .mouse-gestures-right { display: table; position: absolute; height: 160px; width: 160px; padding: 0; margin: 0; }',
		'.mouse-gestures .mouse-gestures-middle { top: 50%; left: 50%; margin-top: -20px; margin-left: -80px; width: 160px; height: 160px; text-align: center; }',
		'.mouse-gestures .mouse-gestures-up { top: 0; left: 50%; margin-left: -80px; }',
		'.mouse-gestures .mouse-gestures-down { bottom: 0; left: 50%; margin-left: -80px; }',
		'.mouse-gestures .mouse-gestures-left { top: 50%; left: 0; margin-top: -80px; }',
		'.mouse-gestures .mouse-gestures-right { top: 50%; right: 0; margin-top: -80px; }',

		'.mouse-gestures .mouse-gestures-label { color: #fff; font-family: Arial,"Helvetica Neue",Helvetica,sans-serif; font-weight: 700; font-size: 16px; text-transform: none; letter-spacing: normal; white-space: pre-wrap; padding: 0; margin: 0; -webkit-transition: all .2s; -moz-transition: all .2s; transition: all .2s; line-height: 22px; }',
		'.mouse-gestures .mouse-gestures-up > .mouse-gestures-label { display: table-cell; vertical-align: bottom; text-align: center; padding-bottom: 50px; }',
		'.mouse-gestures .mouse-gestures-down > .mouse-gestures-label { display: table-cell; vertical-align: top; text-align: center; padding-top: 50px; }',
		'.mouse-gestures .mouse-gestures-left > .mouse-gestures-label { display: table-cell; vertical-align: middle; text-align: right; padding-right: 50px; }',
		'.mouse-gestures .mouse-gestures-right > .mouse-gestures-label { display: table-cell; vertical-align: middle; text-align: left; padding-left: 50px; }',

		'.mouse-gestures .mouse-gestures-icon { position: absolute; width: initial; }',
		'.mouse-gestures .mouse-gestures-middle > .mouse-gestures-icon { position: initial; }',
		'.mouse-gestures .mouse-gestures-up > .mouse-gestures-icon { bottom: 0; left: 50%; margin-left: -20px; }',
		'.mouse-gestures .mouse-gestures-down > .mouse-gestures-icon { top: 0; left: 50%; margin-left: -20px; }',
		'.mouse-gestures .mouse-gestures-left > .mouse-gestures-icon { top: 50%; right: 0; margin-top: -20px; }',
		'.mouse-gestures .mouse-gestures-right > .mouse-gestures-icon { top: 50%; left: 0; margin-top: -20px; }',

		'.mouse-gestures .active > .mouse-gestures-label { color: #ffff00; }',
		'.mouse-gestures .mouse-gestures-up.active > .mouse-gestures-label { padding-bottom: 10px; }',
		'.mouse-gestures .mouse-gestures-down.active > .mouse-gestures-label { padding-top: 10px; }',
		'.mouse-gestures .mouse-gestures-left.active > .mouse-gestures-label { padding-right: 10px; }',
		'.mouse-gestures .mouse-gestures-right.active > .mouse-gestures-label { padding-left: 10px; }',
		'.mouse-gestures .active > .mouse-gestures-icon { display: none; }',

		'.mouse-gestures .hide { display: none; }',
	].join('\n'));

	const SENSITIVITY = 20;
	var startX;
	var startY;
	var gesture = '';
	var preventContextMenu = false;
	var mouseDownTriggered = false;
	var link;
	const defaultFn = {
		close: function () {
			window.top.close();
		},
		newTab: function () {
			defaultFn.openInNewTab();
		},
		duplicateTab: function () {
			defaultFn.openInNewTab(window.location.href);
		},
		openInNewTab: function (link) {
			GM_openInTab(link, false);
		},
		openInNewBackgroundTab: function (link) {
			GM_openInTab(link, true);
		},
		scrollUp: function () {
			$('html, body').animate({
				scrollTop: '-=700'
			}, 'slow');
		},
		scrollDown: function () {
			$('html, body').animate({
				scrollTop: '+=700'
			}, 'slow');
		},
		scrollToTop: function () {
			$('html, body').animate({
				scrollTop: 0
			}, 'slow');
		},
		scrollToBottom: function () {
			$('html, body').animate({
				scrollTop: $(document).height()
			}, 'slow');
		},
		back: function () {
			window.history.back();
		},
		forward: function () {
			window.history.forward();
		},
		reload: function () {
			window.location.reload();
		},
		reloadWithoutCache: function () {
			window.location.reload(true);
		}
	};
	const gestures = {
		u: {
			label: 'Scroll up',
			fn: defaultFn.scrollUp,
		},
		d: {
			label: 'Scroll down',
			fn: defaultFn.scrollDown,
		},
		l: {
			label: 'Back',
			fn: defaultFn.back,
		},
		r: {
			label: 'Forward',
			fn: defaultFn.forward,
		},
		ud: {
			label: 'Reload',
			fn: defaultFn.reload,
		},
		ur: {
			label: 'New tab',
			fn: defaultFn.newTab,
		},
		du: {
			label: 'Duplicate tab',
			fn: defaultFn.duplicateTab,
		},
		dl: {
			label: 'Open link in new tab',
			fn: defaultFn.openInNewTab,
			onLink: true
		},
		dr: {
			label: 'Close tab',
			fn: defaultFn.close,
		},
		ru: {
			label: 'Scroll to top',
			fn: defaultFn.scrollToTop,
		},
		rd: {
			label: 'Scroll to bottom',
			fn: defaultFn.scrollToBottom,
		},
		udu: {
			label: 'Reload without cache',
			fn: defaultFn.reloadWithoutCache,
		},
		dld: {
			label: 'Open link in new background tab',
			fn: defaultFn.openInNewBackgroundTab,
			onLink: true
		},
	};

	var $mouseGestures = $('<div/>', {
		class: 'mouse-gestures'
	}).appendTo($('body'));

	var $up = $('<div/>', {
		class: 'mouse-gestures-up'
	}).appendTo($mouseGestures);
	var $upIcon = $('<img/>', {
		class: 'mouse-gestures-icon',
		src: 'https://png.icons8.com/up/ultraviolet/40'
	}).appendTo($up);
	var $upLabel = $('<div/>', {
		class: 'mouse-gestures-label'
	}).text(gestures[gesture + 'u'].label).appendTo($up);

	var $down = $('<div/>', {
		class: 'mouse-gestures-down'
	}).appendTo($mouseGestures);
	var $downIcon = $('<img/>', {
		class: 'mouse-gestures-icon',
		src: 'https://png.icons8.com/down-arrow/ultraviolet/40'
	}).appendTo($down);
	var $downLabel = $('<div/>', {
		class: 'mouse-gestures-label'
	}).text(gestures[gesture + 'd'].label).appendTo($down);

	var $left = $('<div/>', {
		class: 'mouse-gestures-left'
	}).appendTo($mouseGestures);
	var $leftIcon = $('<img/>', {
		class: 'mouse-gestures-icon',
		src: 'https://png.icons8.com/left/ultraviolet/40'
	}).appendTo($left);
	var $leftLabel = $('<div/>', {
		class: 'mouse-gestures-label'
	}).text(gestures[gesture + 'l'].label).appendTo($left);

	var $right = $('<div/>', {
		class: 'mouse-gestures-right'
	}).appendTo($mouseGestures);
	var $rightIcon = $('<img/>', {
		class: 'mouse-gestures-icon',
		src: 'https://png.icons8.com/right/ultraviolet/40'
	}).appendTo($right);
	var $rightLabel = $('<div/>', {
		class: 'mouse-gestures-label'
	}).text(gestures[gesture + 'r'].label).appendTo($right);

	var $middle = $('<div/>', {
		class: 'mouse-gestures-middle'
	}).appendTo($mouseGestures);
	var $middleIcon = $('<img/>', {
		class: 'mouse-gestures-icon',
		src: 'https://png.icons8.com/mouse-right-click/ultraviolet/40'
	}).appendTo($middle);
	var $middleLabel = $('<div/>', {
		class: 'mouse-gestures-label'
	}).appendTo($middle);

	var timeoutDelay;
	$(document).mousedown(function (e) {
		if (e.which == 3) {
			var $target = $(e.target);
			if ($target.closest('a').length) {
				link = $target.closest('a').prop('href');
			} else {
				link = undefined;
			}
			preventContextMenu = false;
			mouseDownTriggered = true;
			startX = e.clientX;
			startY = e.clientY;
			gesture = '';
			loadMG();
			timeoutDelay = setTimeout(function () {
				showMG(e);
			}, 500);
			$(this).mousemove(function (e) {
				if (startY - e.clientY > 10 || e.clientY - startY > 10 || startX - e.clientX > 10 || e.clientX - startX > 10) {
					preventContextMenu = false;
					if (mouseDownTriggered) {
						mouseDownTriggered = false;
					} else {
						clearTimeout(timeoutDelay);
						showMG(e);
						checkMG(e);
					}
				}
			});
		}
	}).mouseup(function (e) {
		clearTimeout(timeoutDelay);
		$(this).unbind('mousemove');
		if (gestures[gesture]) {
			if (gestures[gesture].onLink === true) {
				if (typeof link !== 'undefined') {
					gestures[gesture].fn(link);
				} else {
					$mouseGestures.hide();
				}
			} else {
				gestures[gesture].fn();
			}
			switch (gesture.slice(-1)) {
				case 'u':
					$down.addClass('hide');
					$left.addClass('hide');
					$right.addClass('hide');
					break;
				case 'd':
					$up.addClass('hide');
					$left.addClass('hide');
					$right.addClass('hide');
					break;
				case 'l':
					$up.addClass('hide');
					$down.addClass('hide');
					$right.addClass('hide');
					break;
				case 'r':
					$up.addClass('hide');
					$down.addClass('hide');
					$left.addClass('hide');
					break;
			}
			$mouseGestures.delay(300).hide(0);
			gesture = '';
		} else {
			$mouseGestures.hide();
		}
	}).contextmenu(function (e) {
		if (preventContextMenu) e.preventDefault();
	});

	function showMG(e) {
		preventContextMenu = true;
		$mouseGestures.css({
			left: (e.clientX - $mouseGestures.width() / 2) + "px",
			top: (e.clientY - $mouseGestures.height() / 2) + "px"
		}).stop(true, true).show();
	}

	function checkMG(e) {
		checkMove(startY - e.clientY, 'u', e);
		checkMove(e.clientY - startY, 'd', e);
		checkMove(startX - e.clientX, 'l', e);
		checkMove(e.clientX - startX, 'r', e);
	}

	function checkMove(p, t, e) {
		if (p >= SENSITIVITY) {
			startX = e.clientX;
			startY = e.clientY;
			if (gesture[gesture.length - 1] != t) {
				gesture += t;
				loadMG();
			}
		}
	}

	function loadMG() {
		if (gestures[gesture + 'u'] ? (gestures[gesture + 'u'].onLink === true ? typeof link !== 'undefined' : true) : false) {
			$up.removeClass('active hide');
			$upLabel.text(gestures[gesture + 'u'].label);
		} else {
			$up.addClass('hide');
		}
		if (gestures[gesture + 'd'] ? (gestures[gesture + 'd'].onLink === true ? typeof link !== 'undefined' : true) : false) {
			$down.removeClass('active hide');
			$downLabel.text(gestures[gesture + 'd'].label);
		} else {
			$down.addClass('hide');
		}
		if (gestures[gesture + 'l'] ? (gestures[gesture + 'l'].onLink === true ? typeof link !== 'undefined' : true) : false) {
			$left.removeClass('active hide');
			$leftLabel.text(gestures[gesture + 'l'].label);
		} else {
			$left.addClass('hide');
		}
		if (gestures[gesture + 'r'] ? (gestures[gesture + 'r'].onLink === true ? typeof link !== 'undefined' : true) : false) {
			$right.removeClass('active hide');
			$rightLabel.text(gestures[gesture + 'r'].label);
		} else {
			$right.addClass('hide');
		}

		if (gestures[gesture] ? (gestures[gesture].onLink === true ? typeof link !== 'undefined' : true) : false) {
			switch (gesture.slice(-1)) {
				case 'u':
					$up.removeClass('hide').addClass('active');
					break;
				case 'd':
					$down.removeClass('hide').addClass('active');
					break;
				case 'l':
					$left.removeClass('hide').addClass('active');
					break;
				case 'r':
					$right.removeClass('hide').addClass('active');
					break;
			}
		}
	}
})();