// ==UserScript==
// @name Mouse Gestures like Opera
// @namespace https://gf.qytechs.cn/users/37096/
// @supportURL https://gf.qytechs.cn/scripts/30726/feedback
// @version 1.0.0
// @description A Mouse Gestures script same as in Opera(old)
// @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: absolute; overflow: hidden; border: 1px solid #CCC; white-space: nowrap; font-family: sans-serif; background: url(https://png.icons8.com/mouse-right-click/ultraviolet/40) rgba(0, 0, 0, 0.7) no-repeat center; color: #333; border-radius: 50%; width: 400px; height: 400px; }',
'.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-up > .mouse-gestures-label, .mouse-gestures .mouse-gestures-down > .mouse-gestures-label, .mouse-gestures .mouse-gestures-left > .mouse-gestures-label, .mouse-gestures .mouse-gestures-right > .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; }',
'.mouse-gestures .mouse-gestures-up { top: 0; left: 200px; margin-left: -80px; background: url(https://png.icons8.com/up/ultraviolet/40) no-repeat center bottom; }',
'.mouse-gestures .mouse-gestures-down { bottom: 0; left: 200px; margin-left: -80px; background: url(https://png.icons8.com/down-arrow/ultraviolet/40) no-repeat center top; }',
'.mouse-gestures .mouse-gestures-left { top: 200px; left: 0; margin-top: -80px; background: url(https://png.icons8.com/left/ultraviolet/40) no-repeat right center; }',
'.mouse-gestures .mouse-gestures-right { top: 200px; right: 0; margin-top: -80px; background: url(https://png.icons8.com/right/ultraviolet/40) no-repeat left center; }',
'.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 .active { background: none }',
'.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 .hide { display: none }',
].join('\n'));
const SENSITIVITY = 20;
var startX;
var startY;
var gesture = '';
var preventContextMenu = false;
var mouseDownTriggered = false;
const defaultFn = {
close: function() {
window.top.close();
},
newTab: function() {
GM_openInTab('about:newtab', false);
window.open('about:blank');
},
scrollToTop: function() {
window.scrollTo(0, 0);
},
scrollToBottom: function() {
window.scrollTo(0, 1073741824);
},
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 to top',
fn: defaultFn.scrollToTop,
},
d: {
label: 'Scroll to bottom',
fn: defaultFn.scrollToBottom,
},
l: {
label: 'Back',
fn: defaultFn.back,
},
r: {
label: 'Forward',
fn: defaultFn.forward,
},
ud: {
label: 'Reload',
fn: defaultFn.reload,
},
dr: {
label: 'Close tab',
fn: defaultFn.close,
},
ru: {
label: 'New tab',
fn: defaultFn.newTab,
},
udu: {
label: 'Reload without cache',
fn: defaultFn.reloadWithoutCache,
},
};
var $mouseGestures = $('<div/>', {
class: 'mouse-gestures'
}).appendTo($('body'));
var $up = $('<div/>', {
class: 'mouse-gestures-up'
}).appendTo($mouseGestures);
var $upLabel = $('<div/>', {
class: 'mouse-gestures-label'
}).text(gestures[gesture+'u'].label).appendTo($up);
var $down = $('<div/>', {
class: 'mouse-gestures-down'
}).appendTo($mouseGestures);
var $downLabel = $('<div/>', {
class: 'mouse-gestures-label'
}).text(gestures[gesture+'d'].label).appendTo($down);
var $left = $('<div/>', {
class: 'mouse-gestures-left'
}).appendTo($mouseGestures);
var $leftLabel = $('<div/>', {
class: 'mouse-gestures-label'
}).text(gestures[gesture+'l'].label).appendTo($left);
var $right = $('<div/>', {
class: 'mouse-gestures-right'
}).appendTo($mouseGestures);
var $rightLabel = $('<div/>', {
class: 'mouse-gestures-label'
}).text(gestures[gesture+'r'].label).appendTo($right);
var timeoutDelay;
$(window).mousedown(function(e) {
preventContextMenu = false;
if(e.which == 3) {
mouseDownTriggered = true;
startX = e.pageX;
startY = e.pageY;
gesture = '';
loadMG();
timeoutDelay = setTimeout(function() {
showMG(e);
}, 500);
$(this).mousemove(function(e) {
preventContextMenu = false;
if(mouseDownTriggered) {
mouseDownTriggered = false;
} else {
clearTimeout(timeoutDelay);
showMG(e);
checkMG(e);
}
});
}
}).mouseup(function(e) {
clearTimeout(timeoutDelay);
$(this).unbind('mousemove');
$mouseGestures.hide();
if (gestures[gesture]) {
gestures[gesture].fn();
gesture = '';
}
}).contextmenu(function(e) {
if(preventContextMenu) e.preventDefault();
});
function showMG(e) {
preventContextMenu = true;
$mouseGestures.css({
top: (e.pageY - $mouseGestures.height()/2) + "px",
left: (e.pageX - $mouseGestures.width()/2) + "px"
}).show();
}
function checkMG(e) {
checkMove(startY - e.pageY, 'u', e);
checkMove(e.pageY - startY, 'd', e);
checkMove(startX - e.pageX, 'l', e);
checkMove(e.pageX - startX, 'r', e);
}
function checkMove(p, t, e) {
if(p >= SENSITIVITY) {
startX = e.pageX;
startY = e.pageY;
if(gesture[gesture.length-1] != t) {
gesture += t;
loadMG();
}
}
}
function loadMG() {
if(gestures[gesture+'u']) {
$up.removeClass('active hide');
$upLabel.text(gestures[gesture+'u'].label);
} else {
$up.addClass('hide');
}
if(gestures[gesture+'d']) {
$down.removeClass('active hide');
$downLabel.text(gestures[gesture+'d'].label);
} else {
$down.addClass('hide');
}
if(gestures[gesture+'l']) {
$left.removeClass('active hide');
$leftLabel.text(gestures[gesture+'l'].label);
} else {
$left.addClass('hide');
}
if(gestures[gesture+'r']) {
$right.removeClass('active hide');
$rightLabel.text(gestures[gesture+'r'].label);
} else {
$right.addClass('hide');
}
if(gestures[gesture]) {
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;
}
}
}
})();