-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathAutoCopySelectionText.uc.js
278 lines (269 loc) · 12.4 KB
/
AutoCopySelectionText.uc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
// ==UserScript==
// @name AutoCopySelectionText.uc.js
// @description 自动复制选中文本(ScrLk 亮起时不复制)
// @author Ryan
// @version 2023.05.14
// @compatibility Firefox 70
// @charset UTF-8
// @system windows
// @license MIT License
// @include main
// @homepageURL https://github.com/benzBrake/FirefoxCustomize/tree/master/userChromeJS
// @version 2023.05.14 修复内置页面无法复制,增加长按时间达到后不释放按键就复制
// @version 2023.02.02 修复部分复制失败的情况
// @version 2023.02.01 framescript 更换为 JSActor,增加复制成功通知
// @version 2022.11.13 修复移动鼠标即复制
// @version 2022.10.11 增加文本框开关
// @version 2022.07.28 网页支持文本框
// @version 2022.07.18 支持长按延时
// @version 2022.07.16 重写代码,支持热插拔,采用 异步消息,支持 Firefox 内置页面
// @version 2022.07.13 初始化版本
// ==/UserScript==
// Configurations, implement read from about:config preferences in future
const ACST_COPY_SUCCESS_NOTICE = "Auto Copied!";
const ACST_WAIT_TIME = 0; // Change it to any number as you want
const ACST_BLACK_LIST = ["input", "textarea"]; // disable auto copy when focus on textboxes
const ACST_SHOW_SUCCESS_NOTICE = true; // show notice on webpace when copyed successful
const ACST_COPY_WITHOUT_RELEASE_KEY = false; // when the popup appears you can release the mouse button (work is not perfect, need to set ACST_WAIT_TIME as a reasonable number)
const ACST_COPY_AS_PLAIN_TEXT = false; // copy as plain text
// =================================================================
if (typeof window === "undefined" || globalThis !== window) {
let BrowserOrSelectionUtils = Cu.import("resource://gre/modules/BrowserUtils.jsm").BrowserUtils
try {
if (!BrowserOrSelectionUtils.hasOwnProperty("getSelectionDetails")) {
BrowserOrSelectionUtils = Cu.import("resource://gre/modules/SelectionUtils.jsm").SelectionUtils;
}
} catch (e) { }
if (!Services.appinfo.remoteType) {
this.EXPORTED_SYMBOLS = ["ACSTParent"];
try {
const actorParams = {
parent: {
moduleURI: __URI__,
},
child: {
moduleURI: __URI__,
events: {},
},
allFrames: true,
messageManagerGroups: ["browsers"],
matches: ["*://*/*", "file:///*", "about:*", "view-source:*"],
};
ChromeUtils.registerWindowActor("ACST", actorParams);
} catch (e) { console.error(e); }
this.ACSTParent = class extends JSWindowActorParent {
receiveMessage({ name, data }) {
// https://searchfox.org/mozilla-central/rev/43ee5e789b079e94837a21336e9ce2420658fd19/browser/actors/ContextMenuParent.sys.mjs#60-63
let windowGlobal = this.manager.browsingContext.currentWindowGlobal;
let browser = windowGlobal.rootFrameLoader.ownerElement;
let win = browser.ownerGlobal;
switch (name) {
case "ACST:setSelectedText":
win.AutoCopySelectionText.setSelectedText(data.text, data.tag || "");
break;
}
}
}
} else {
this.EXPORTED_SYMBOLS = ["ACSTChild"];
this.ACSTChild = class extends JSWindowActorChild {
receiveMessage({ name, data }) {
let win = this.contentWindow;
let actor = this.contentWindow.windowGlobalChild.getActor("ACST");
switch (name) {
case "ACST:getSelectedText":
if (win.document.activeElement) {
if (ACST_ifItemTagInBackList(win.document.activeElement)) return;
}
let obj = {
text: BrowserOrSelectionUtils.getSelectionDetails(win).fullText
}
if (obj.text && obj.text.length) {
actor.sendAsyncMessage("ACST:setSelectedText", obj);
if (data.ACST_SHOW_SUCCESS_NOTICE)
ACST_showSuccessInfo(this.contentWindow);
}
break;
}
}
}
}
} else {
try {
if (parseInt(Services.appinfo.version) < 101) {
ChromeUtils.import(Components.stack.filename);
} else {
let fileHandler = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler);
let scriptPath = Components.stack.filename;
if (scriptPath.startsWith("chrome")) {
scriptPath = resolveChromeURL(scriptPath);
function resolveChromeURL(str) {
const registry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
try {
return registry.convertChromeURL(Services.io.newURI(str.replace(/\\/g, "/"))).spec
} catch (e) {
console.error(e);
return ""
}
}
}
let scriptFile = fileHandler.getFileFromURLSpec(scriptPath);
let resourceHandler = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
if (!resourceHandler.hasSubstitution("acst-ucjs")) {
resourceHandler.setSubstitution("acst-ucjs", Services.io.newFileURI(scriptFile.parent));
}
ChromeUtils.import(`resource://acst-ucjs/${encodeURIComponent(scriptFile.leafName)}?${scriptFile.lastModifiedTime}`);
}
} catch (e) { console.error(e); }
(function () {
Cu.import("resource://gre/modules/ctypes.jsm");
if (window.AutoCopySelectionText) {
return;
}
// =========================================
let user32 = ctypes.open("user32.dll");
let getKeyState = user32.declare('GetKeyState', ctypes.winapi_abi, ctypes.bool, ctypes.int);
let BrowserOrSelectionUtils = Cu.import("resource://gre/modules/BrowserUtils.jsm").BrowserUtils
try {
if (!BrowserOrSelectionUtils.hasOwnProperty("getSelectionDetails")) {
BrowserOrSelectionUtils = Cu.import("resource://gre/modules/SelectionUtils.jsm").SelectionUtils;
}
} catch (e) { }
var LONG_PRESS = false;
var TIMEOUT_ID = null;
var START_COPY = false;
var DBL_NOTICE = false;
window.AutoCopySelectionText = {
init: function () {
["mousedown", "mousemove", "dblclick", "mouseup"].forEach(type => {
(gBrowser.mPanelContainer || gBrowser.tabpanels).addEventListener(type, this, false);
});
},
handleEvent: function (event) {
if (getKeyState(0x91)) return;
let that = this;
const { clearTimeout, setTimeout } = event.target.ownerGlobal;
switch (event.type) {
case 'mousedown':
START_COPY = true;
if (DBL_NOTICE) {
// 双击判定
setTimeout(function () {
LONG_PRESS = true;
}, ACST_WAIT_TIME);
}
break;
case 'mousemove':
if (LONG_PRESS) return;
if (TIMEOUT_ID) clearTimeout(TIMEOUT_ID);
TIMEOUT_ID = setTimeout(function () {
// 长按判定
LONG_PRESS = true;
if (ACST_COPY_WITHOUT_RELEASE_KEY) {
// 无需释放左键就复制
copyText(content);
}
}, ACST_WAIT_TIME);
break;
case 'dblclick':
case 'mouseup':
if (!START_COPY) return;
// 不响应左键事件
if (event.button !== 0) return;
// copy text on mouse button up
if (LONG_PRESS && !ACST_COPY_WITHOUT_RELEASE_KEY) {
copyText(content);
}
START_COPY = false;
DBL_CLICK = false;
// 限定时间内判定双击
DBL_NOTICE = true;
setTimeout(() => {
DBL_NOTICE = false;
}, 150);
break;
}
LONG_PRESS = false;
function copyText(content) {
if (content) {
// 内置页面
let info = content.getSelection();
// 黑名单不获取选中文本
if (info && info.anchorNode && info.anchorNode.activeElement && ACST_ifItemTagInBackList(info.anchorNode.activeElement)) return;
let text = BrowserOrSelectionUtils.getSelectionDetails(content).fullText;
if (text && text.length) {
that.setSelectedText(text);
if (ACST_SHOW_SUCCESS_NOTICE)
ACST_showSuccessInfo(content);
}
} else {
// 网页
let actor = gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.getActor("ACST");
actor.sendAsyncMessage("ACST:getSelectedText", { ACST_SHOW_SUCCESS_NOTICE: ACST_SHOW_SUCCESS_NOTICE });
}
}
},
setSelectedText: function (text, tag) {
if (tag && ACST_BLACK_LIST.includes(tag)) return;
if (typeof text !== undefined) {
if (ACST_COPY_AS_PLAIN_TEXT)
this.copyText(text);
else
goDoCommand('cmd_copy');
}
},
copyText: function (text) {
Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper).copyString(text);
}
}
window.AutoCopySelectionText.init();
})()
}
/**
* 检查是否在黑名单内选中文本
* @param {HTMLElement} item
* @returns
*/
function ACST_ifItemTagInBackList(item) {
if (ACST_BLACK_LIST.includes(item.tagName.toLowerCase())) return true;
ACST_BLACK_LIST.forEach(tag => {
if (item.closest(tag)) return true;
});
return false;
}
/**
* 显示复制成功通知
* @param {*} win
*/
function ACST_showSuccessInfo(win) {
let { document } = win;
let main = document.querySelector("body") || document.documentElement;
let wrapper = document.querySelector("#acst-success-info-wrapper");
if (!wrapper) {
let wEl = document.createElement("div");
wEl.setAttribute("id", "acst-success-info-wrapper");
wEl.setAttribute("style", "z-index: 9999999; position: fixed; top: 20px; right: 20px; display: none; pointer-events:none; transition:all .2s")
wrapper = main.appendChild(wEl);
wrapper.addEventListener("DOMSubtreeModified", function (event) {
let target = event.target
if (target.childNodes.length) {
target.style.display = "block";
} else {
target.style.display = "none";
}
});
}
let div = document.createElement("div");
div.innerText = ACST_COPY_SUCCESS_NOTICE;
div.setAttribute("style", "pointer-events: initial; cursor: pointer; position: relative; opacity: 1; transition:all .2s; margin-top: 10px; padding: 10px 20px; color: white; background-color: #4ade80; border-radius: 5px;");
div = wrapper.appendChild(div);
div.addEventListener("click", (event) => {
event.target.parentNode.removeChild(event.target);
});
win.setTimeout(() => {
div.style.opacity = 0;
win.setTimeout(() => {
div.parentNode.removeChild(div);
}, 200);
}, 2000);
}