NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Selext // @namespace http://nirelbaz.com/ // @version 1.12 // @description Do something useful after text selection // @author Nir Elbaz // @require https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser-polyfill.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js // @include * // @grant GM_addStyle // @grant GM_setClipboard // @exclude https://openuserjs.org/* // @exclude https://translate.google.com/* // @exclude http://feditor.io/* // @exclude https://github.com/* // ==/UserScript== /* jshint ignore:start */ var inline_src = (<><![CDATA[ /* jshint ignore:end */ /* jshint esnext:true */ let selext, blnMouseMove = false, arrMenu = [ { command: 'search', class: 'ion-search', title: 'Search it on Google', action: function () { window.open('https://www.google.co.il/#q=' + selext.text); } }, { command: 'email', class: 'ion-email', title: 'Email it to a friend', action: function () { document.location.href = 'mailto:?body=' + selext.text; } }, { command: 'twitter', class: 'ion-social-twitter', title: 'Share it on Twitter', action: function () { window.open('https://twitter.com/intent/tweet?text=' + selext.text); } }, { command: 'copy', class: 'ion-clipboard', title: 'Copy it to your clipboard', action: function () { GM_setClipboard(selext.text); } }, { command: 'speak', class: 'ion-speakerphone', title: 'Speak it load and clear', action: function () { let ssu = new SpeechSynthesisUtterance(); ssu.text = selext.text; ssu.lang = document.getElementsByTagName('html')[0].getAttribute('lang') || 'en-US'; ssu.volume = 1; speechSynthesis.speak(ssu); } }, { command: 'translate', class: 'ion-earth', title: 'Translate it to browser\'s language', action: function () { window.open('https://translate.google.com/#auto/' + navigator.language + '/' + selext.text); } }, { command: 'dismiss', class: 'ion-power', title: 'Dismiss Selext for current website during current session', action: function () { sessionStorage.setItem('selext-dismiss', '1'); document.removeEventListener('mouseup', onDocumentMouseup); } } ]; class Selext { constructor (arrMenu) { this.element = document.createElement('div'); this.element.id = 'selext-menu'; this.text = ''; this.draw(arrMenu); this.element.style.display = 'block'; // Listen to transition-end event on menu: this.element.addEventListener('click', (e) => { if (e.target.dataset && e.target.dataset.action) { arrMenu.filter(function (item) { return item.command === e.target.dataset.command; })[0].action(); } }); // Listen to transition-end event on menu: this.element.addEventListener('transitionend', () => { if (this.element.style.opacity === '0') { this.element.style.zIndex = -1; } }); } draw (arrMenu) { let arrMenuMarkup = arrMenu.map(item => `<li class="${item.class}" data-command="${item.command}" data-action="${eval(item.action)};" title="${item.title}"></li>`); let elmLink = document.createElement('LINK'); let strStyle = ` #selext-menu { font-family: arial; position: absolute; display: none; top: -500; -webkit-filter: drop-shadow(4px 4px 4px rgba(0,0,0,0.5)); filter: drop-shadow(4px 4px 4px rgba(0,0,0,0.5)); left: -500; z-index: -1; opacity: 0; width: 150px; -webkit-user-select: none; user-select: none; transition: opacity 500ms ease-out; } #selext-menu header { background-color: #333; border-radius: 5px 5px 0 0; color: #fff; font-size: 12px; font-weight: bold; height: auto; padding: 2px; text-transform: uppercase; } #selext-menu ul { list-style: none; display: flex; flex-flow: wrap; margin: 0; padding: 0; text-align: center; } #selext-menu li { color: #ddd; cursor: pointer; flex: 1 1 33%; font-size: 25px; line-height: 40px; transition: color 300ms ease-out, font-size 300ms ease-out; } #selext-menu li:hover { color: #fff; font-size: 30px; } #selext-menu li:nth-child(1) { background-color: #F44336; } #selext-menu li:nth-child(2) { background-color: #8BC34A; } #selext-menu li:nth-child(3) { background-color: #03A9F4; } #selext-menu li:nth-child(4) { background-color: #FF9800; } #selext-menu li:nth-child(5) { background-color: #9C27B0; } #selext-menu li:nth-child(6) { background-color: #009688; } #selext-menu li:last-child { background-color: #616161; border-radius: 0 0 5px 5px; color: #FF7777; flex: 1 1 100%; font-size: 15px; line-height: 25px; } `; // Style: GM_addStyle(strStyle); elmLink.setAttribute('rel', 'stylesheet'); elmLink.setAttribute('href', 'https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css'); document.head.appendChild(elmLink); // Menu: this.element.innerHTML = '<header> Selext</header><ul>' + arrMenuMarkup.join('') + '</ul>'; document.body.appendChild(this.element); } show (strText, intLeft, intTop) { this.text = strText; this.element.style.left = intLeft + 10 + 'px'; this.element.style.top = intTop + 10 + 'px'; this.element.style.opacity = 1; this.element.style.zIndex = 9999; } hide () { this.element.style.opacity = 0; } } /** * Listens to mouse up events and detect text selection * @param {object} e Mouse event */ function onDocumentMouseup (e) { if (blnMouseMove) { let strText = window.getSelection().toString(); if (strText !== '') { selext.show(strText, e.pageX, e.pageY); } } } /** * Listens to mousemove events on document to show Selext menu right after * @param {object} e Event */ function onDocumentMousemove (e) { if (e.which === 1) { blnMouseMove = true; } } /** * Listens to click events on document to hide Selext menu * @param {object} e Event */ function onDocumentClick (e) { if (blnMouseMove === true) { blnMouseMove = false; return; } selext.hide(); } // Create menu only if user hasn't dismissed Selext: if (sessionStorage.hasOwnProperty('selext-dismiss') === false) { selext = new Selext(arrMenu); // Listen to mouseup event on document: document.addEventListener('mouseup', onDocumentMouseup); // Listen to mousemove event on document: document.addEventListener('mousemove', onDocumentMousemove); // Listen to click event on document: document.addEventListener('click', onDocumentClick); } /* jshint ignore:start */ ]]></>).toString(); var c = babel.transform(inline_src); eval(c.code); /* jshint ignore:end */