// ==UserScript==
// @name Opera Browser Rocker+Mouse Gestures + Search HighLight
// @namespace OperaBrowserGestures
// @description This script works on any browser and simulates the Opera Browser Mouse and Rocker Gestures, along with the Search HighLight Opera Browser Features, but with this script you can modify or disable them as you want.
// @version 0.0.14
// @author hacker09
// @include *
// @icon https://www.google.com/s2/favicons?domain=www.opera.com
// @require https://code.jquery.com/jquery-3.5.1.min.js
// @grant GM_registerMenuCommand
// @grant GM_openInTab
// @grant window.close
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-end
// ==/UserScript==
// *** Mouse Gesture Settings Below *****************************************************************************************************************************************
GM_registerMenuCommand("Enable/Disable Mouse Gestures", MouseGestures); //Adds an option to the tampermonkey menu
if (GM_getValue("MouseGestures") !== true && GM_getValue("MouseGestures") !== false) { //If the value doesn't exist define as true
GM_setValue("MouseGestures", true); //Defines the variable as true
} //Finishes the if condition
function MouseGestures() //Function to enable or disable the MouseGestures
{ //Starts the function MouseGestures
if (GM_getValue("MouseGestures") === true) { //If the last config was true, set as false
GM_setValue("MouseGestures", false); //Defines the variable as false
} //Finishes the if condition
else { //If the last config was false, set as true
GM_setValue("MouseGestures", true); //Defines the variable as true
location.reload(); //Reloads the page
} //Finishes the else condition
} //Finishes the function MouseGestures
if (GM_getValue("MouseGestures") === true) //If the MouseGestures is enabled
{ //Starts the if condition
const SENSITIVITY = 3; // Adjust the script mouse senvity here between 1 ~ 5
const TOLERANCE = 3; // Adjust the script mouse tolerance here between 1 ~ 5
const funcs = { //Variable to store the functions
'L': function() { //Function that will run when the mouse movement Left is performed
window.history.back(); //Go Back
}, //Finishes the mouse movement Left
'R': function() { //Function that will run when the mouse movement Right is performed
window.history.forward(); //Go Foward
}, //Finishes the mouse movement Right
'D': function() { //Function that will run when the mouse movement Down is performed
if (IsShiftNotPressed) { //If the shift key isn't being pressed
GM_openInTab(link, { //Open the link on a new tab
active: true, //Focus on the new tab
insert: true, //Insert the new tab after the actual tab
setParent: true //Return to the tab the user was in
}); //Open the link that was hovered
setTimeout(function() { //Starts the settimeout function
link = 'about:newtab'; //Make the script open a new browser tab if no links were hovered
}, 100); //Finishes the settimeout function
} //Finishes the if condition
IsShiftNotPressed = true; //Variable to hold the shift key status
}, //Finishes the mouse movement Down
'UD': function() { //Function that will run when the mouse movement Up+Down is performed
window.location.reload(); //Reload the Tab
}, //Finishes the mouse movement Up+Down
'DR': function(e) { //Function that will run when the mouse movement Down+Right is performed
window.top.close(); //Close the tab
e.preventDefault(); //Prevent the default context menu from being opened
e.stopPropagation(); //Prevent the default context menu from being opened
}, //Finishes the mouse movement Down+Right
'DU': function() { //Function that will run when the mouse movement Down+Up is performed
GM_openInTab(link, { //Open the link that was hovered
active: false, //Don't focus on the new tab
insert: true, //Insert the new tab after the actual tab
setParent: true //Return to the tab the user was in
}); //Open the link that was hovered on a new background tab
setTimeout(function() { //Starts the setimeout function
link = 'about:newtab'; //Make the script open a browser tab if no links were hovered
}, 100); //Finishes the setimeout function
} //Finishes the mouse movement Down+Up
}; //Finishes the variable to store the functions
// *** Below this line is the math codes that track the mouse movement gestures *******************************************************************************************
const s = 1 << ((7 - SENSITIVITY) << 1);
const t1 = Math.tan(0.15708 * TOLERANCE),
t2 = 1 / t1;
let x, y, path;
const tracer = function(e) {
let cx = e.clientX,
cy = e.clientY,
deltaX = cx - x,
deltaY = cy - y,
distance = deltaX * deltaX + deltaY * deltaY;
if (distance > s) {
let slope = Math.abs(deltaY / deltaX),
direction = '';
if (slope > t1) {
direction = deltaY > 0 ? 'D' : 'U';
} else if (slope <= t2) {
direction = deltaX > 0 ? 'R' : 'L';
}
if (path.charAt(path.length - 1) !== direction) {
path += direction;
}
x = cx;
y = cy;
}
};
window.addEventListener('mousedown', function(e) { //Add an advent listener to the page to detect when the mouse is clicked
if (e.which === 3) { //Starts the if condition
x = e.clientX;
y = e.clientY;
path = "";
window.addEventListener('mousemove', tracer, false); //Add an advent listener to the page to detect the mouse position
} //Finishes the if condition
}, false); //Finishes the advent listener
window.addEventListener('contextmenu', function(e) { //When the right click button is released
window.removeEventListener('mousemove', tracer, false); //Stop tracking the mouse movements
if (path !== "") { //Starts the if condition
e.preventDefault(); //Prevent the default context menu from being opened
if (funcs.hasOwnProperty(path)) { //Starts the if condition
funcs[path]();
} //Finishes the if condition
} //Finishes the if condition
}, false); //Finishes the advent listener
var link; //Make the variable global
Array.from(document.querySelectorAll('a')).forEach(Element => Element.onmouseover = function() { //Get all the a link elements and add an advent listener to the link element
link = this.href; //Store the actual hovered link to a variable
}); //Finishes the forEach
var IsShiftNotPressed = true; //Variable to hold the shift key status
window.addEventListener("contextmenu", function(e) { //Adds an advent listener to the page to know when the shift key is pressed or not
if (e.shiftKey) { //If the shift key was pressed
window.open(link, '_blank', 'height=' + window.screen.height + ',width=' + window.screen.width); //Open the link on a new window
IsShiftNotPressed = false; //Variable to hold the shift key status
} //Finishes the if condition
if (LeftClicked) { //If Right was Clicked and then Left Click was released
e.preventDefault(); //Prevent the default context menu from being opened
e.stopPropagation(); //Prevent the default context menu from being opened
} //Finishes the if condition
}, false); //Finishes the advent listener
} //Finishes the if condition
// *** Rocker Mouse Gesture Settings Below ***************************************************************************************************************************
GM_registerMenuCommand("Enable/Disable Rocker Mouse Gestures", RockerMouseGestures); //Adds an option to the tampermonkey menu
if (GM_getValue("RockerMouseGestures") !== true && GM_getValue("RockerMouseGestures") !== false) { //If the value doesn't exist define as false
GM_setValue("RockerMouseGestures", false); //Defines the variable as false
} //Finishes the if condition
function RockerMouseGestures() //Function to enable or disable the RockerMouseGestures
{ //Starts the function RockerMouseGestures
if (GM_getValue("RockerMouseGestures") === true) { //If the last config was true, set as false
GM_setValue("RockerMouseGestures", false); //Defines the variable as false
} //Finishes the if condition
else { //If the last config was false, set as true
GM_setValue("RockerMouseGestures", true); //Defines the variable as true
location.reload(); //Reloads the page
} //Finishes the else condition
} //Finishes the function RockerMouseGestures
if (GM_getValue("RockerMouseGestures") === true) //If the RockerMouseGestures is enabled
{ //Starts the if condition
var LeftClicked, RightClicked; //Make these variables global
window.addEventListener("mousedown", function(e) { //Detect the right and left mouse clicks presses on the page
switch (e.button) { //Start the switch condition
case 0: //If Left Click was Pressed
LeftClicked = true; //Set the variable LeftClicked as true
break; //Don't execute the lines below if the Left Key was Pressed
case 2: //If Right Click was Pressed
RightClicked = true; //Set the variable RightClicked as true
break; //Don't execute the lines below if the Right Key was Pressed
} //Finishes the switch condition
}, false); //Finishes the adventlistener mousedown
window.addEventListener("mouseup", function(e) { //Detect the right and left mouse clicks releases on the page
switch (e.button) { //Start the switch condition
case 0: //If Left Click was released
LeftClicked = false; //Set the variable LeftClicked as false
break; //Don't execute the lines below if the Left Key was Pressed
case 2: //If Right Click was released
RightClicked = false; //Set the variable RightClicked as false
break; //Don't execute the lines below if the Left Key was Pressed
} //Finishes the switch condition
if (LeftClicked && RightClicked === false) { //If Left was Clicked and then Right Click was released
window.history.back(); //Go Back
} //Finishes the if condition
if (RightClicked && LeftClicked === false) { //If Right was Clicked and then Left Click was released
window.history.forward(); //Go Foward
} //Finishes the if condition
}, false); //Finishes the adventlistener mouseup
} //Finishes the if condition
// *** SearchHighLight Settings Below ***************************************************************************************************************************
GM_registerMenuCommand("Enable/Disable SearchHiLight", SearchHiLight); //Adds an option to the tampermonkey menu
if (GM_getValue("SearchHiLight") !== true && GM_getValue("SearchHiLight") !== false) { //If the value doesn't exist define as true
GM_setValue("SearchHiLight", true); //Defines the variable as true
} //Finishes the if condition
if (GM_getValue("CurrenciesConverter") !== true && GM_getValue("CurrenciesConverter") !== false) { //If the value doesn't exist define as true
GM_setValue("CurrenciesConverter", true); //Defines the variable as true
} //Finishes the if condition
function SearchHiLight() //Function to enable or disable the SearchHiLight
{ //Starts the function SearchHiLight
if (GM_getValue("SearchHiLight") === true) { //If the last config was true, set as false
GM_setValue("SearchHiLight", false); //Defines the variable as false
GM_setValue("CurrenciesConverter", false); //Defines the variable as false
} //Finishes the if condition
else { //If the last config was false, set as true
GM_setValue("SearchHiLight", true); //Defines the variable as true
if (confirm('If you want to enable the Currency Converter press OK.')) //Show the confimation alert box text
{ //Starts the if condition
GM_setValue("CurrenciesConverter", true); //Defines the variable as true
} //Finishes the if condition
else //If the user pressed cancel
{ //Starts the else condition
GM_setValue("CurrenciesConverter", false); //Defines the variable as false
} //Finishes the else condition
location.reload(); //Reloads the page
} //Finishes the else condition
} //Finishes the function SearchHiLight
if (GM_getValue("SearchHiLight") === true) //If the SearchHiLight is enabled
{ //Starts the if condition
var $ = window.jQuery; //Defines That The Symbol $ Is A jQuery
var SelectedTextIsLink; //Creates a new global variable
var Links = new RegExp(/\.org|\.ly|\.net|\.co|\.tv|\.me|\.biz|\.club|\.site|\.br|\.gov|\.io|\.jp|\.edu|\.au|\.in|\.it|\.ca|\.mx|\.fr|\.tw|\.il|\.uk/); //Creates a global variable to check if a link is matched
var Currencies; //Creates a global variable
var FinalCurrency = ''; //Creates a global variable
$(function() { //Starts the function
var menu = $("#highlight_menu", $("#highlight_menu_div")[0].shadowRoot); //Creates a variable to hold the menu element
$(document.body).on('mouseup', function() { //When the user releases the mouse click after selecting something
if (GM_getValue("CurrenciesConverter") === true) { //If the Currencies Converter option is activated
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#ShowCurrency").innerText = ''; //Remove the previous Currency text
//Currency regexes https://regex101.com/r/6vTbtv/8 Davidebyzero
//Good exchange APIs https://pastebin.com/Rfaup8SQ
Currencies = new RegExp(/^.*(\d+(?:\.\d+)?)(?<=(?= ?(\$|Dólares|dolares|dólares|dollars|BRL|AUD|BCH|BTC|BYN|CAD|CHF|CNY|CZK|DKK|EGP|ETH|EUR|GBP|GEL|HK|HKD|HRK|IDR|ILS|INR|JPY|KRW|KZT|Kč|LTC|MXN|MYR|NOK|NZD|PHP|PLN|RM|RON|RUB|SEK|SGD|THB|TRY|UAH|USD|YTL|ZAR|\$|¥|€|Rp|kn|kr|R\$|zł|£|฿|₩) ?(?:(?! )\3 ?)?$)(?:(?<=^\1)|^.*(\1)(?= ?$))).*$/); //Adds an regex expression to the Currencies variable
if (window.getSelection().toString().match(Currencies) !== null) //If the selected text is a currency
{ //Starts the if condition
if (GM_getValue("YouLocalCurrency") === undefined) { //If the value is undefined
var UserInput = prompt('This is the first time that you selected a currency.\nThis is the first and last time this popup will appear, so please write your local currency so that the script will always use your local currency to make exchange rate conversions.\n*Example of what you should write: BRL\nCAD\nUSD\netc...\n*Press OK'); //Gets the user input
GM_setValue("YouLocalCurrency", UserInput); //Defines the variable as the UserInput
} //Finishes the if condition
(async () => { //Creates a function to get the final value
const responsehtml = await (await fetch(`https://api.allorigins.win/raw?url=${encodeURIComponent('https://www.google.com/search?q=' + window.getSelection().toString().match(Currencies)[0] + '%20in%20' + GM_getValue("YouLocalCurrency"))}`)).text(); //Fetch
const newDocument = new DOMParser().parseFromString(responsehtml, 'text/html'); //Parses the fetch response
FinalCurrency = parseFloat(newDocument.querySelector("div.BNeawe.iBp4i.AP7Wnd").innerText.match(/\d+\.\d+/)[0]); //Gets the final amount of money
var CurrencySymbols = new RegExp(/Kč|\$|¥|€|Rp|kn|kr|R\$|zł|£|฿|₩/);
if (window.getSelection().toString().match(CurrencySymbols) !== null) //If the selected currency contains a symbol
{ //Starts the if condition
switch (window.getSelection().toString().match(CurrencySymbols)[0]) { //If the selected currency constains a symbol
case '$': //Get the actual selected currency symbol
var CurrencySymbol = 'USD'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case "¥": //Get the actual selected currency symbol
var CurrencySymbol = 'JPY'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case '€': //Get the actual selected currency symbol
var CurrencySymbol = 'EUR'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case 'R$': //Get the actual selected currency symbol
var CurrencySymbol = 'BRL'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case 'Kč': //Get the actual selected currency symbol
var CurrencySymbol = 'CZK'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case 'Rp': //Get the actual selec //"Convert" the symbol to the Currency Lettersted currency symbol
var CurrencySymbol = 'IDR'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case 'kn': //Get the actual selected currency symbol
var CurrencySymbol = 'HRK'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case 'kr': //Get the actual selected currency symbol
var CurrencySymbol = 'DKK'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case 'zł': //Get the actual selected currency symbol
var CurrencySymbol = 'PLN'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case '£': //Get the actual selected currency symbol
var CurrencySymbol = 'GBP'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case '฿': //Get the actual selected currency symbol
var CurrencySymbol = 'THB'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
case '₩': //Get the actual selected currency symbol
var CurrencySymbol = 'KRW'; //"Convert" the symbol to the Currency Letters
break; //Stop trying to get the correct Currency Letters
} //Finishes the switch condition
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#ShowCurrency").innerText = CurrencySymbol + ' 🠂 ' + Intl.NumberFormat(navigator.language, {
style: 'currency',
currency: GM_getValue("YouLocalCurrency")
}).format(FinalCurrency) + ' | '; //Show the FinalCurrency on the menu
} //Finishes the if condition
else //If the selected currency contains no symbol
{ //Starts the else condition
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#ShowCurrency").innerText = Intl.NumberFormat(navigator.language, {
style: 'currency',
currency: GM_getValue("YouLocalCurrency")
}).format(FinalCurrency) + ' | '; //Show the FinalCurrency on the menu
} //Finishes the else condition
var text = document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#ShowCurrency").innerText; //Save the actual currency text
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#ShowCurrency").onmousemove = function() { //When the mouse is hovering the currency
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#ShowCurrency").innerText = "Copy | "; //Change the element text to copy
}; //Finishes the onmousemove advent listener
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#ShowCurrency").onmouseout = function() { //When the mouse leaves the button
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#ShowCurrency").innerText = text; //Return the previous text
}; //Finishes the onmouseout advent listener
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#ShowCurrency").onclick = function() { //When the user clicks on the currency
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#ShowCurrency").innerText = "Done | "; //Change the element text to copy
navigator.clipboard.writeText(FinalCurrency); //Copy the Final Currency
}; //Finishes the onclick advent listener
})(); //Finishes the async function
} //Finishes the if condition
} //Finishes the if condition
if (document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#SearchBTN").innerText === 'Open') //If the Search butotn text is 'Open'
{ //Starts the if condition
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#highlight_menu > ul").style.paddingLeft = '7px'; //Change the ul menu element padding left css style
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#SearchBTN").innerText = 'Search'; //The next time that the menu is shown display the button text as Search again
SelectedTextIsLink = false; //Add the value false to the variable to make common words searchable again
} //Finishes the if condition
if (window.getSelection().toString().match(Links) !== null) //If the selected text is a link
{ //Starts the if condition
SelectedTextIsLink = true; //Add the value true to the variable
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#highlight_menu > ul").style.paddingLeft = '15px'; //Change the ul menu element padding left css style
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#SearchBTN").innerText = 'Open'; //Change the button text to Done
} //Finishes the if condition
if (document.getSelection().toString().trim() !== '') { //If the user selected something
var p = document.getSelection().getRangeAt(0).getBoundingClientRect(); //Create a new variable to get the positions later
menu.css({ //Set the menu css
left: (p.left + (p.width / 2)) - (menu.width() / 2), //Make the menu show on the correct left position
top: (p.top - menu.height() - 10), //Make the menu show on the correct top position
display: '' //Show the menu on the page
}).animate({ //Creates the animation animation
opacity: 1 //Set the animation opacity
}, 0); //Add an animation to the menu
menu.addClass('highlight_menu_animate'); //Add the class to animate the menu
//$('head').append('<style>.highlight_menu_animate .popuptext::after { content: ""; height: 35px !important; top: 100%; left: 50%; margin-left: -10px !important; border-width: 10px !important; position: absolute; border-style: solid; border-color: #292929 transparent transparent transparent; }</style>'); //Create a class to animate the menu
return; //Keep displaying the menu box
} //Finishes the if condition
menu.animate({ //Creates the animation animation
opacity: 0 //Set the animation opacity
}); //Hide the menu If the user clicked on any of the options
}); //Finishes the mouseup advent listener
}); //Finishes the function
var HtmlMenu = document.createElement('div'); //Creates a variable
HtmlMenu.setAttribute("id", "highlight_menu_div"); //Set the div id to the HtmlMenu variable
HtmlMenu.attachShadow({
mode: 'open'
}).innerHTML = '<style>.highlight_menu_animate .popuptext::after { content: ""; height: 35px !important; top: 100%; left: 50%; margin-left: -10px !important; border-width: 10px !important; position: absolute; border-style: solid; border-color: #292929 transparent transparent transparent; }</style><div id="highlight_menu" style="display:none; color: #fff; position: fixed; background-color: #292929; font-size: 13.4px; font-family: monospace;z-index: 999;"> <ul style="margin-block-end: 10px; padding-left: 7px; padding-right: 7px; margin-top:10px;"><li class="popuptext" id="ShowCurrency" style="cursor: pointer; display: inline;">' + FinalCurrency + '</li><li class="popuptext" id="SearchBTN" style="cursor: pointer; display: inline;">Search</li><li class="popuptext" id="CopyBTN" style="cursor: pointer; display: inline;"> | Copy</li></ul></div>'; //Set the HtmlMenu div html
document.body.appendChild(HtmlMenu); //Append the HtmlMenu div to the page
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#SearchBTN").onmousedown = function() { //When the user clicks on the Search button
var LinkfyOrSearch = 'https://www.google.com/search?q='; //Creates a variable to open google
if (SelectedTextIsLink === true) //If the selected text is a link
{ //Starts the if condition
var LinkfyOrSearch = 'https://'; //Make the non http and non https links able to be opened
} //Finishes the if condition
if (window.getSelection().toString().match(/http:|https:/) !== null) //If the selected text is a link that already has http or https
{ //Starts the if condition
var LinkfyOrSearch = ''; //Remove the https:// that was previsouly added to this variable
} //Finishes the if condition
window.open(LinkfyOrSearch + window.getSelection().toString()); //Open google and search for the selected word(s)
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#highlight_menu").style.display = 'none'; //Hide the menu
}; //Finishes the onmousedown advent listener
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#CopyBTN").onmousedown = function() { //When the user clicks on the copy button
navigator.clipboard.writeText(window.getSelection().toString()); //Copy the selected word(s)
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#CopyBTN").innerText = ' | Done'; //Change the button text to Done
setTimeout(function() { //Starts the setTimeout function
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#CopyBTN").innerText = ' | Copy'; //The next time that the menu is shown display the button text as Copy again, instead of Done
}, 400); //Finishes the setTimeout function
}; //Finishes the onmousedown advent listener
document.onclick = function() { //When the user clicks anywhwere on the page
if (document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#highlight_menu").style.display !== '') { //If the menu is being displayed
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#highlight_menu").style.display = 'none'; //Hide the menu
} //Finishes the if condition
}; //Finishes the onclick advent listener
setTimeout(function() { //Starts the setTimeout function
var AllIframes = document.querySelectorAll("iframe"); //Get all iframes on the page
for (var i = AllIframes.length; i--;) { //Starts the for condition
if (AllIframes[i].allow.match('clipboard-write;') === null && AllIframes[i].src.match(Links) !== null) //If the iframe doesn't have the clipboard-write attribute yet and the iframed source attribute has a link
{ //Starts the if condition
AllIframes[i].allow = AllIframes[i].allow + 'clipboard-write;'; //Add he permission to copy the iframe text
AllIframes[i].src = AllIframes[i].src; //Reload the iframe to make the iframe have the new permission
} //Finishes the if condition
} //Finishes the for condition
}, 2000); //Finishes the setTimeout function
window.onscroll = async function() { //When the page is scrolled
document.querySelector("#highlight_menu_div").shadowRoot.querySelector("#highlight_menu").style.display = 'none'; //Hide the menu
}; //Finishes the onscroll advent listener
} //Finishes the if condition