// ==UserScript==
// @name AutoClick
// @namespace https://github.com/AutoClick
// @version 0.1.11
// @description 基于大佬(ywzhaiqi)的AutoClick(火狐版)改造而来
// @author AutoClick
// @license MIT
// @match https://*/*
// @match http://*/*
// @match file:///*
// @grant GM_setClipboard
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addValueChangeListener
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// ==/UserScript==
(function() {
// 'use strict';
// 请不要在这里更改,更改在图标右键打开的设置里。
var
BUTTON_TYPE = 1, // 0:地址栏按钮,1:可移动按钮,2:菜单
ENABLE = true,
hovering_time = 500, // 悬停的时间(毫秒)
clicked_elem = 'a, input, button, li',
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='
;
try {
class AutoClick {
constructor() {
this.clicked_elems = [];
this.clicked_parent_elems = [];
}
get enable() {
return ENABLE;
}
set enable(bool) {
bool = !!bool;
console.log('setEnabel', bool, ENABLE)
if (!this.isFirstRun && ENABLE === bool) return;
this.prefs.setPrefVal('enable', ENABLE = bool);
this.updateState(bool);
}
get BUTTON_TYPE() {
return BUTTON_TYPE;
}
set BUTTON_TYPE(num) {
if (!this.isFirstRun && BUTTON_TYPE === num) return;
BUTTON_TYPE = num;
this.prefs.setPrefVal('BUTTON_TYPE', BUTTON_TYPE);
this.rebuildButton();
this.updateState(ENABLE);
}
get hovering_time() {
return hovering_time;
}
set hovering_time(num) {
if (hovering_time == num) return;
hovering_time = num;
this.prefs.setPrefVal('hovering_time', hovering_time);
}
get default_prefs() {
return {
clicked_elem: clicked_elem,
clicked_parent_elem: clicked_parent_elem
};
}
get clicked_elem () {
return this.clicked_elems;
}
set clicked_elem(str) {
this.clicked_elems = str.split(',').map((x) => x.trim());
}
set clicked_parent_elem(str) {
this.clicked_parent_elems = str.split(',').map((x) => x.trim());
}
init () {
this. prefs = {
hasPrefVal: (key) => {
return GM_getValue(key) !== undefined;
},
getPrefVal: (key, def) => {
return GM_getValue(key, def);
},
setPrefVal: (key, val) => {
return GM_setValue(key, val);
},
addObserver: (a, context, bool) => {
GM_addValueChangeListener(name, function(name, old_value, new_value, remote) {
});
}
};
this.isFirstRun = true;
this.loadSetting();
window.document.addEventListener('mouseover', this.handleEvent.bind(this), false);
window.document.addEventListener('mouseout', this.handleEvent.bind(this), false);
window.document.addEventListener('keydown', this.handleEvent.bind(this), false);
window.document.addEventListener('keyup', this.handleEvent.bind(this), false);
// this.prefs.addObserver('', this, false);
GM_registerMenuCommand('配置管理', () => {
this.openPref()
});
this.isFirstRun = false;
}
uninit() {
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(type) { // 载入设置并执行相应的任务
if (!type || type === 'BUTTON_TYPE') {
this.BUTTON_TYPE = this.prefs.hasPrefVal('BUTTON_TYPE') ?
this.prefs.getPrefVal('BUTTON_TYPE') :
this.BUTTON_TYPE;
}
if (!type || type === 'enable') {
this.enable = this.prefs.hasPrefVal('enable') ?
this.prefs.getPrefVal('enable') :
this.enable;
}
if (!type || type === 'hovering_time') {
this.hovering_time = this.prefs.hasPrefVal('hovering_time') ?
this.prefs.getPrefVal('hovering_time') :
this.hovering_time;
}
if (!type || type === 'clicked_elem') {
if (this.prefs.hasPrefVal('clicked_elem')) {
this.clicked_elem = this.prefs.getPrefVal('clicked_elem');
} else {
this.prefs.setPrefVal('clicked_elem', this.clicked_elem = clicked_elem);
}
}
if (!type || type === 'clicked_parent_elem') {
if (this.prefs.hasPrefVal('clicked_parent_elem')) {
this.clicked_parent_elem = this.prefs.getPrefVal('clicked_parent_elem');
} else {
this.prefs.setPrefVal('clicked_parent_elem', this.clicked_parent_elem = clicked_parent_elem);
}
}
}
removeButton() {
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() {
this.removeButton();
if (BUTTON_TYPE === 2) {
let menuitem = $C('button', {
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('button', {
id: "AutoClick-icon",
class: 'toolbarbutton-1 chromeclass-toolbar-additional',
title: "自动点击开/关",
click: this.iconClick.bind(this),
// context: "AutoClick-popup",
});
if (BUTTON_TYPE === 1) {
ToolbarManager.addWidget(window, button, true);
} else {
$('urlbar-icons').appendChild(button);
}
this.button = button;
// background: transparent !important;\
// background-image: none !important;\
let css = '\
#AutoClick-icon {\
-moz-appearance: none !important;\
border-style: none !important;\
border-radius: 0 !important;\
padding: 0 0 !important;\
margin: 0 3px !important;\
box-shadow: none !important;\
-moz-box-align: center !important;\
-moz-box-pack: center !important;\
min-width: 18px !important;\
min-height: 18px !important;\
width: 18px;\
z-index: 100000;\
}\
#AutoClick-icon > .toolbarbutton-icon {\
max-width: 18px !important;\
padding: 0 !important;\
margin: 0 !important;\
border: 0 !important;\
background-color: transparent !important;\
box-shadow: none !important;\
-moz-transition: none !important;\
}\
#AutoClick-icon dropmarker { display:none; }\
';
this.style = addStyle(css);
}
}
updateState(enable, isTmpDisable) {
let preLabel = isTmpDisable ? '临时' : '',
label = 'AutoClick 已' + preLabel + (enable ? '启用' : '停用');
if (this.button) {
console.log('label', label);
this.button.style.background = 'url(' + (enable ? ON_IMG : OFF_IMG) + ') no-repeat #fff';
this.button.title = label;
} else if (this.menuitem) {
this.menuitem.setAttribute('checked', enable);
this.menuitem.setAttribute('label', label);
}
}
handleEvent(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(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(event){
const elem = this.findLink(event.target);
if (elem && String(elem.id).indexOf('AutoClick') === -1) {
console.log('mouseover.elem: ->', elem);
this.timeoutID = setTimeout(() => {
this.click(elem, event.view);
}, this.hovering_time);
}
}
mouseout(event) {
if (this.timeoutID) {
clearTimeout(this.timeoutID);
this.timeoutID = null;
}
}
findLink(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(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(element, win) {
console.log('click--->', element, win, '创建点击事件');
let doc = win.document,
e = doc.createEvent('MouseEvents');
e.initEvent('click', true, true, win, 0,
0, 0, 0, 0, this.ctrlKey, false, false, false, 0, element);
return !element.dispatchEvent(e);
}
iconClick(event) {
console.log('event', event.button, this.enable);
if (event.button === 0) {
this.enable = !this.enable;
} else {
this.openPref();
event.preventDefault();
event.stopPropagation();
}
}
openPref() {
alert('待添加,请直接修改代码顶部配置。')
/*let xul = '<?xml version="1.0"?>\
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>\
\
<prefwindow\
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"\
id="AutoClick"\
windowtype="AutoClick:Preferences">\
<prefpane id="main" flex="1">\
\
<preferences>\
<preference id="hovering_time" type="int" name="userChromeJS.AutoClick.hovering_time"/>\
<preference id="BUTTON_TYPE" type="int" name="userChromeJS.AutoClick.BUTTON_TYPE"/>\
<preference id="clicked_elem" type="string" name="userChromeJS.AutoClick.clicked_elem"/>\
<preference id="clicked_parent_elem" type="string" name="userChromeJS.AutoClick.clicked_parent_elem"/>\
</preferences>\
\
<hbox>\
<label value="悬停的时间:" />\
<textbox size="10" preference="hovering_time" />\
<label value="毫秒" />\
</hbox>\
<hbox>\
<label value="按钮的类型:" />\
<menulist preference="BUTTON_TYPE">\
<menupopup>\
<menuitem label="地址栏按钮" value="0"/>\
<menuitem label="可移动按钮" value="1"/>\
<menuitem label="菜单" value="2"/>\
</menupopup>\
</menulist>\
</hbox>\
<label value="点击的节点名:" />\
<textbox id="clicked_elem" flex="1" preference="clicked_elem" multiline="true" rows="3" />\
<label value="需要查找父元素的节点名:" />\
<textbox flex="1" id="clicked_parent_elem" preference="clicked_parent_elem" \
multiline="true" rows="3" />\
<button label="重置" tooltiptext="重置上面2个设置为默认值" />\
\
</prefpane>\
<script>\
function reset() {\
$("clicked_elem").value = opener.AutoClick.default_prefs.clicked_elem;\
$("clicked_parent_elem").value = opener.AutoClick.default_prefs.clicked_parent_elem;\
}\
function $(id) document.getElementById(id); \
</script>\
</prefwindow>\
';
window.openDialog(
"data:application/vnd.mozilla.xul+xml;charset=UTF-8," + encodeURIComponent(xul), '',
'chrome,titlebar,toolbar,centerscreen,dialog=no');*/
}
};
const ToolbarManager = (function() {
let layoutWidget = function(document, button, isFirstRun) {
// Add to the customization palette
let toolbox = document.getElementById('navigator-toolbox');
console.log('toolbox--->', toolbox, button);
toolbox.appendChild(button);
};
let addWidget = function(window, widget, isFirstRun) {
try {
layoutWidget(window.document, widget, isFirstRun);
} catch(error) {
console.log(error);
}
};
let removeWidget = function(window, widgetId) {
try {
let widget = window.document.getElementById(widgetId);
widget.parentNode.removeChild(widget);
} catch(error) {
console.log(error);
}
};
const initLoayoutContainer = () => {
const div = document.createElement('div');
div.id = 'navigator-toolbox';
div.style.height = '24px';
div.style.width = '24px';
//div.style.border = 'solid 2px #a94442';
div.style.position = 'fixed';
div.style.right = '10px';
div.style.top = '10px';
div.style.zIndex = '100000';
// div.style.backgroundColor = '#777';
div.innerHTML = '';
document.body.appendChild(div);
};
initLoayoutContainer();
let exports = {
addWidget: addWidget,
removeWidget: removeWidget,
};
return exports;
})();
function $(id, doc) {
return (doc || document).getElementById(id);
};
function $C(name, attr) {
var el = document.createElement(name);
if (attr) {
Object.keys(attr).forEach(function(n) {
if (typeof attr[n] === 'function') {
el.addEventListener(n, attr[n], false);
} else {
el.setAttribute(n, attr[n]);
}
});
}
return el;
}
function addStyle(css) {
return GM_addStyle(css);
}
(new AutoClick()).init();
} catch(e) {
console.error('AutoClick. Error', e)
}
})();