//==UserScript== // @name AutoClickModY.uc.js // @description 鼠标悬停打开链接(站外链接除外),工具菜单开启或鼠标手势调用 // @author ywzhaiqi // @include main // @charset utf-8 // @version 1.2 // @downloadURL https://raw.github.com/ywzhaiqi/userChromeJS/master/AutoClickModY/AutoClickModY.uc.js // @homepageURL https://github.com/ywzhaiqi/userChromeJS/tree/master/AutoClickModY // @note 第一次需要从定制面板中拖出 // @note 当按着 Ctrl 键时,后台打开 //==/UserScript== (function(){ // 请不要在这里更改,更改在图标右键打开的设置里。 var BUTTON_TYPE = 1, // 0:地址栏按钮,1:可移动按钮,2:菜单 ENABLE = true, hovering_time = 500, // 悬停的时间(毫秒) clicked_elem = 'a, input, button', clicked_parent_elem = 'b, i, img, span, small, strong, em, big, sub, sup, s, font', ON_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABSUlEQVQ4jY3TvUvXURTH8Rf5lE0i6KCCEIiJiyS0uEViGLqE+Ngk6CCC/4EPOPhAgu1JQWtQLeIDLuoqrppDihC02JQ/QdTh3uDL9Wt24MPl3nvO+55z7z3QiFeoxja6BGtAHyYwjKcok2OdOIzOb9GNSRyhgEscx/kHPEkB1ehFE2rxFVe4jiqgHy+xhX20ZgE7WMZDLGUCs4D26FuFz9hE5V9AF56hBT/vAUAzvmMgLWU0JzgP8ACf8D4FzP4nAKawKnmVuTsAFxhCHerjuIgN4d5uAQqJznGCg4zOsJYCFrGLjphyVh0ZvcBHrKeA6UgtTS8nx+aF/1KSXeyJ6T2+J/iRUP9culGDPcwIT3WXvcYPtOVtvsEpxiT1oUj4zodYQHEeoATj8YRvGBGabRArQlO9Q8U/MlSE5/iCX/iD30KrD6I863wDIuZiYI4xbYAAAAAASUVORK5CYII=', OFF_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABHElEQVQ4jYXTuy6EURiF4SfMxKESiU6ilegotSYmWpVD5wZcgtLQTU9ItAqVGBONG9A6FLgBKodEobCKPb9hVrKzstf37pXs/0B/jWAeW9iOzycfqFkc4QFP+Io/JJ/97/ACbnCFJtbwEW8mvwn3S5Po4hRTyRopaGQ/lXk3fI/WcY+5IqsWyPw+fI8OcIKhAQVD4Q6qBefYqWT9CoQ7V7yVUVxiH9OYiW/iM17m++FHy4ILvOC2WM94j5f5S/iegg6OsYTlYjUq+6VwnbKgjjO0qg/mD7XC18twN/caH3B4PNxudbCIR6wOKFgNt1gd1LCHOz+f7XBlPpz8LlytX/sE2n5+nkNsYCV+mLwd7k+N5cA1XvEWv04+VsLfWidJd1JzB90AAAAASUVORK5CYII=' ; if (window.AutoClick) { window.AutoClick.uninit(); delete window.AutoClick; } window.AutoClick = { get prefs() { delete this.prefs; return this.prefs = Services.prefs.getBranch("userChromeJS.AutoClick.") }, get BUTTON_TYPE() BUTTON_TYPE, set BUTTON_TYPE(num) { if (!this.isFirstRun && BUTTON_TYPE === num) return; BUTTON_TYPE = num; this.prefs.setIntPref('BUTTON_TYPE', BUTTON_TYPE); this.rebuildButton(); this.updateState(ENABLE); }, get enable() ENABLE, set enable(bool) { bool = !!bool; if (!this.isFirstRun && ENABLE === bool) return; this.prefs.setBoolPref('enable', ENABLE = bool); this.updateState(bool); }, get hovering_time() hovering_time, set hovering_time(num) { if (hovering_time == num) return; hovering_time = num; this.prefs.setIntPref('hovering_time', hovering_time); }, get default_prefs() { return { clicked_elem: clicked_elem, clicked_parent_elem: clicked_parent_elem } }, set clicked_elem(str) { this.clicked_elems = str.split(',').map(function(x) x.trim() ) }, set clicked_parent_elem(str) { this.clicked_parent_elems = str.split(',').map(function(x) x.trim() ) }, init: function() { this.isFirstRun = true; this.loadSetting(); gBrowser.mPanelContainer.addEventListener('mouseover', this, false); gBrowser.mPanelContainer.addEventListener('mouseout', this, false); gBrowser.mPanelContainer.addEventListener('keydown', this, false); gBrowser.mPanelContainer.addEventListener('keyup', this, false); this.prefs.addObserver('', this, false); this.isFirstRun = false; }, uninit: function() { this.removeButton(); gBrowser.mPanelContainer.removeEventListener('mouseover', this, false); gBrowser.mPanelContainer.removeEventListener('mouseout', this, false); gBrowser.mPanelContainer.removeEventListener('keydown', this, false); gBrowser.mPanelContainer.removeEventListener('keyup', this, false); this.prefs.removeObserver('', this, false); }, loadSetting: function(type) { // 载入设置并执行相应的任务 if (!type || type === 'BUTTON_TYPE') { this.BUTTON_TYPE = this.prefs.prefHasUserValue('BUTTON_TYPE') ? this.prefs.getIntPref('BUTTON_TYPE') : this.BUTTON_TYPE; } if (!type || type === 'enable') { this.enable = this.prefs.prefHasUserValue('enable') ? this.prefs.getBoolPref('enable') : this.enable; } if (!type || type === 'hovering_time') { this.hovering_time = this.prefs.prefHasUserValue('hovering_time') ? this.prefs.getIntPref('hovering_time') : this.hovering_time; } if (!type || type === 'clicked_elem') { if (this.prefs.prefHasUserValue('clicked_elem')) { this.clicked_elem = this.prefs.getCharPref('clicked_elem'); } else { this.prefs.setCharPref('clicked_elem', this.clicked_elem = clicked_elem); } } if (!type || type === 'clicked_parent_elem') { if (this.prefs.prefHasUserValue('clicked_parent_elem')) { this.clicked_parent_elem = this.prefs.getCharPref('clicked_parent_elem'); } else { this.prefs.setCharPref('clicked_parent_elem', this.clicked_parent_elem = clicked_parent_elem); } } }, removeButton: function() { if (this.menuitem) { this.menuitem.parentNode.removeChild(this.menuitem); this.menuitem = null; } if (this.button) { this.button.parentNode.removeChild(this.button); this.button = null; } if (this.style) { this.style.parentNode.removeChild(this.style); this.style = null; } }, rebuildButton: function() { this.removeButton(); if (BUTTON_TYPE === 2) { let menuitem = $C('menuitem', { id: 'AutoClick-enable-menuitem', class: 'menuitem-iconic', type: 'checkbox', autocheck: "false", checked: AutoClick.enable, tooltiptext: '自动点击开/关', onclick: 'AutoClick.iconClick(event);', }); let insPos = $('devToolsSeparator'); insPos.parentNode.insertBefore(menuitem, insPos); this.menuitem = menuitem; } else { let button = $C('toolbarbutton', { id: "AutoClick-icon", class: 'toolbarbutton-1 chromeclass-toolbar-additional', tooltiptext: "自动点击开/关", onclick: "AutoClick.iconClick(event);", // context: "AutoClick-popup", }); if (BUTTON_TYPE === 1) { ToolbarManager.addWidget(window, button, true); } else { $('urlbar-icons').appendChild(button); } this.button = button; let css = '\ #AutoClick-icon {\ -moz-appearance: none !important;\ border-style: none !important;\ border-radius: 0 !important;\ padding: 0 0 !important;\ margin: 0 3px !important;\ background: transparent !important;\ box-shadow: none !important;\ -moz-box-align: center !important;\ -moz-box-pack: center !important;\ min-width: 18px !important;\ min-height: 18px !important;\ width: 24px;\ }\ #AutoClick-icon > .toolbarbutton-icon {\ max-width: 18px !important;\ padding: 0 !important;\ margin: 0 !important;\ border: 0 !important;\ background-image: none !important;\ background-color: transparent !important;\ box-shadow: none !important;\ -moz-transition: none !important;\ }\ #AutoClick-icon dropmarker { display:none; }\ '; this.style = addStyle(css); } }, updateState: function(enable, isTmpDisable) { let preLabel = isTmpDisable ? '临时' : '', label = 'AutoClick 已' + preLabel + (enable ? '启用' : '停用'); if (this.button) { this.button.style.listStyleImage = 'url(' + (enable ? ON_IMG : OFF_IMG) + ')'; this.button.setAttribute('tooltiptext', label); } else if (this.menuitem) { this.menuitem.setAttribute('checked', enable); this.menuitem.setAttribute('label', label); } XULBrowserWindow.statusTextField.label = label; }, handleEvent: function(event) { if (!this.enable) return; switch(event.type) { case 'mouseover': if (!this.tmpDisable) this.mouseover(event); break; case 'mouseout': if (!this.tmpDisable) this.mouseout(event); break; case 'keydown': if (event.keyCode === 17) { // Ctrl_L this.ctrlKey = true; } break; case 'keyup': if (event.keyCode === 17) { this.ctrlKey = false; } break; // case 'keypress': // if (event.keyCode === 18) { // Alt_L // this.tmpDisable = !this.tmpDisable; // this.updateState(!this.tmpDisable, this.tmpDisable); // } break; } }, observe: function(aSubject, aTopic, aData){ if (aTopic == 'nsPref:changed') { switch(aData) { case 'BUTTON_TYPE': case 'enable': case 'hovering_time': case 'clicked_elem': case 'clicked_parent_elem': this.loadSetting(aData); break; } } }, mouseover: function(event) { var elem = this.findLink(event.target); if (elem) { this.timeoutID = setTimeout(function() { AutoClick.click(elem, event.view); }, this.hovering_time); } }, mouseout: function(event) { if (this.timeoutID) { clearTimeout(this.timeoutID); this.timeoutID = null; } }, findLink: function(node) { var selector = node.nodeName.toLowerCase(); // if (node.id) { // selector += '#' + node.id; // } // var classNames = node.getAttribute('class'); // if (classNames) { // selector += '.' + classNames.trim().replace(/\s+/ig, '.'); // } var match = function(list) { return list.some(function(x) selector === x ); }; if (match(this.clicked_elems)) { return node; } else if (match(this.clicked_parent_elems)) { var parent = node.parentNode; return parent && this.findLink(parent); } return null; }, click: function(element, win) { let doc = win.document, e = doc.createEvent('MouseEvents'); e.initMouseEvent('click', true, true, win, 0, 0, 0, 0, 0, this.ctrlKey, false, false, false, 0, element); return !element.dispatchEvent(e); }, iconClick: function(event) { if (event.button === 0) { this.enable = !this.enable; } else { this.openPref(); event.preventDefault(); event.stopPropagation(); } }, openPref: function() { let xul = '\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \