Firefox 142.0.1
I tested Firefox 142 without problems, replace makeURI with Services.io.newURI may be work
Firefox 142.0.1
I tested Firefox 142 without problems, replace makeURI with Services.io.newURI may be work
In den Zeilen 46 und 47 werden jsm-Dateien eingelesen. JSM-Dateien gibt es nicht mehr, nur noch sys.mjs-Dateien, Die Datei Services.jsm wurde aber nie konvertiert, sondern sofort abgeschafft. Zeile 46 kann also raus. CustomizableUI.jsm muss CustomizableUI.sys.mjs heißen. die ist aber nicht unbedingt mehr notwendig. Außerdem ist das Pfadprotokoll resource: veraltet, neu ist moz-src.
Lines 46 and 47 are used to fallback to older versions of Firefox. You can ignore them. The lines after will not be executed.
Es gibt eine ganze Reihe Zeilen, die mit oncommand: anfangen. Das sieht stark nach Inline-Eventhandler aus. Diese Zeilen müssen mit addEventListener umgebaut werden.
Line 981 handles these events starting with on
e.addEventListener(k.slice(2).toLocaleLowerCase(), v, false);
Also your last Version 0.0.6r3 not works.
Same issue.Error console says:
CodeUncaught (in promise) ReferenceError: makeURI is not defined get STYLE file:///C:/Users/xxxx/AppData/Roaming/Mozilla/Firefox/Profiles/9l0hyy5o.test/chrome/UserCSSLoader.uc.js:115 init file:///C:/Users/xxx/AppData/Roaming/Mozilla/Firefox/Profiles/9l0hyy5o.test/chrome/UserCSSLoader.uc.js:198 <anonymous> file:///C:/Users/xxx/AppData/Roaming/Mozilla/Firefox/Profiles/9l0hyy5o.test/chrome/UserCSSLoader.uc.js:1014 <anonymous> file:///C:/Users/xxx/AppData/Roaming/Mozilla/Firefox/Profiles/9l0hyy5o.test/chrome/UserCSSLoader.uc.js:1015 loadScript file:///C:/Program Files/Mozilla Firefox/userChromeJS/utilities.js:114 UserCSSLoader.uc.js:115:9
What version of Firefox do you have? I'll install your Loader later to see why
Hi jizz
Yes i Know.
Your version not supports Links like this to graphics:only full Links.
Codefile:///C:/Users/xxxx/AppData/Roaming/Mozilla/Firefox/Profiles/9l0hyy5o.test/chrome/icons/Bild120.png
But i like your version.
It may be caused by resource uri, I've updated the script to use file uri for default
I have a different version of UserCSSLoader:
jizz Please complete your idea in a whole script.
Because I can't really do much with the code snippet.
// ==UserScript==
// @include chrome://mozapps/content/downloads/unknownContentType.xhtml
// @charset UTF-8
// @sandbox true
// @version Fx139+
// ==/UserScript==
(function () {
const { FileUtils } = ChromeUtils.importESModule('resource://gre/modules/FileUtils.sys.mjs');
const { setTimeout } = ChromeUtils.importESModule('resource://gre/modules/Timer.sys.mjs');
setTimeout(function () {
saveTo()
}, 200);
function saveTo () {
// config
const dirArray = [
['C:\\', 'System'],
['D:\\', 'DATA'],
['D:\\Software', 'Software'],
['D:\\Downloads', 'herunterladen'],
['D:\\Video', 'Video'],
['' + FileUtils.getDir('UChrm', []).path + '', 'chrome'],
//['' + FileUtils.getDir('UChrm', ['SubScript']).path + '', 'SubScript'],
['F:\\', 'F:'],
['G:\\', 'G:'],
['H:\\', 'H:'],
];
const button = document.getElementById('unknownContentType').getButton('cancel');
const saveTo = button.parentNode.insertBefore(createEl('button', {
label: 'Speichern nach',
class: 'dialog-button',
type: 'menu'
}), button);
const saveToMenu = saveTo.appendChild(createEl('menupopup'));
saveToMenu.appendChild(createEl("html:link", {
rel: "stylesheet",
href: "chrome://global/skin/global.css"
}));
saveToMenu.appendChild(createEl("html:link", {
rel: "stylesheet",
href: "chrome://global/content/elements/menupopup.css"
}));
dirArray.forEach(function (a) {
const [dir, name] = [a[0], a[1]];
saveToMenu.appendChild(createEl('menuitem', {
label: (name || (dir.match(/[^\\/]+$/) || [dir])[0]),
image: 'moz-icon:file:///' + dir + '\\',
class: 'menuitem-iconic',
dir: dir,
onclick: function () {
const locationtext = document.getElementById('locationtext');
const file = new FileUtils.File(this.getAttribute('dir') + '\\' + (locationtext ? locationtext.value : document.getElementById('location').value));
dialog.mLauncher.saveDestinationAvailable(file);
dialog.onCancel = function () { };
close();
}
}));
});
}
function createEl (type, attrs = {}, doc = document) {
let el = type.startsWith('html:')
? doc.createElementNS('http://www.w3.org/1999/xhtml', type)
: doc.createXULElement(type);
for (let key of Object.keys(attrs)) {
key.startsWith('on')
? el.addEventListener(key.slice(2).toLocaleLowerCase(), attrs[key])
: el.setAttribute(key, attrs[key]);
}
return el;
}
}());
Alles anzeigen
Hallo zusammen.
Für das Script saveto.uc.js gibt es eine neue Version für Firefox 139
Denkt daran eure Anpassungen - Änderungen zu übertragen.JavaScript Alles anzeigen// ==UserScript== // @include chrome://mozapps/content/downloads/unknownContentType.xhtml // @charset UTF-8 // @sandbox true // @version Fx139+ // ==/UserScript== (function() { const {FileUtils} = ChromeUtils.importESModule('resource://gre/modules/FileUtils.sys.mjs'); const {setTimeout} = ChromeUtils.importESModule('resource://gre/modules/Timer.sys.mjs'); const css = ` hbox.dialog-button-box button.dialog-button menupopup { background: #F0F0F0 !important; border: 1px solid #CCCCCC !important; padding: 2px !important; } hbox.dialog-button-box button.dialog-button menupopup menuitem.menuitem-iconic:hover { background: #91C9F7 !important; } hbox.dialog-button-box button.dialog-button menupopup menuitem.menuitem-iconic hbox.menu-iconic { padding: 3px !important; } hbox.dialog-button-box button.dialog-button menupopup menuitem.menuitem-iconic label.menu-iconic-text{ padding: 3px !important; padding-left: 5px !important; padding-right: 12px !important; }`; const sss = Cc['@mozilla.org/content/style-sheet-service;1'].getService(Ci.nsIStyleSheetService); try { const uri = Services.io.newURI('data:text/css,' + encodeURIComponent(css)); if(!sss.sheetRegistered(uri, sss.AGENT_SHEET)) sss.loadAndRegisterSheet(uri, sss.AGENT_SHEET); } catch (ex) {} setTimeout(function() { saveTo() }, 200); function saveTo() { // config const dirArray = [ ['C:\\', 'System'], ['D:\\', 'DATA'], ['D:\\Software', 'Software'], ['D:\\Downloads', 'herunterladen'], ['D:\\Video', 'Video'], ['' + FileUtils.getDir('UChrm', []).path + '', 'chrome'], //['' + FileUtils.getDir('UChrm', ['SubScript']).path + '', 'SubScript'], ['F:\\', 'F:'], ['G:\\', 'G:'], ['H:\\', 'H:'], ]; const button = document.getElementById('unknownContentType').getButton('cancel'); const saveTo = button.parentNode.insertBefore(document.createXULElement('button'), button); const saveToMenu = saveTo.appendChild(document.createXULElement('menupopup')); saveTo.classList.toggle('dialog-button'); saveTo.label = 'Speichern nach'; saveTo.type = 'menu'; dirArray.forEach(function(dir) { const name = dir[1]; dir = dir[0]; const mi = document.createXULElement('menuitem'); const item = saveToMenu.appendChild(mi); item.setAttribute('label', (name || (dir.match(/[^\\/]+$/) || [dir])[0])); item.setAttribute('image', 'moz-icon:file:///' + dir + '\\'); item.setAttribute('class', 'menuitem-iconic'); item.addEventListener('click', function() { const locationtext = document.getElementById('locationtext'); const file = new FileUtils.File(dir + '\\' + (locationtext ? locationtext.value : document.getElementById('location').value)); dialog.mLauncher.saveDestinationAvailable(file); dialog.onCancel = function() {}; close(); }); }); } }());
Diese Version ist nun auch bei Github zu finden:
https://github.com/Endor8/userChr…39/saveto.uc.js
Mfg.
Endor
👍Super, danke.
Hast du eine Idee, warum auch das alte Skript plötzlich dieses Verhalten zeigt?
It is more appropriate to use the CSS built into Firefox.
const saveToMenu = saveTo.appendChild(document.createXULElement('menupopup'));
const link1 = document.createElementNS("http://www.w3.org/1999/xhtml", "html:link");
link1.rel = "stylesheet";
link1.href = "chrome://global/skin/global.css";
saveToMenu.appendChild(link1);
const link2 = document.createElementNS("http://www.w3.org/1999/xhtml", "html:link");
link2.rel = "stylesheet";
link2.href = "chrome://global/content/elements/menupopup.css";
saveToMenu.appendChild(link2);
Thanks jizz .
Here's the original script.But with which loader should it work?
userchrome.jsのインストール方法 方法 その1:
// ==UserScript==
// @name Add Bookmark Here
// @namespace about:userchromejs/addbookmarkhere
// @description add "Add Bookmark Here" contextmenu in places menu
// @include chrome://browser/content/browser.xhtml
// @include chrome://browser/content/places/places.xhtml
// @shutdown window.AddBookmarkHere.uninit()
// @author Ryan, zbinlin
// @homepage http://mozcp.com
// @version 0.0.3
// ==/UserScript==
/**
* ******************************** Changelog ********************************
* version: 0.0.3
* * Kompatibilitäts - Probleme mit neueren Firefox-Versionen behoben.
* * Achtung: nur in Firefox 100 getestet!
* version: 0.0.2
* * Kompatibel mit Firefox 21+
*
* version: 0.0.1
* * Initialisierung
* ***************************************************************************
*/
"use strict";
(function () {
if (window.AddBookmarkHere) return;
var AddBookmarkHere = {
PARENT_NODE: "placesContext",
REF_NODE: "",
init: function () {
var parentNode = document.getElementById(this.PARENT_NODE);
if (!parentNode) return;
var self = this;
window.addEventListener("unload", function _ (e) {
window.removeEventListener("unload", _, false);
self.uninit();
}, false);
var refNode;
if (this.REF_NODE !== "") {
var refNode = document.getElementById(this.REF_NODE);
}
this.addContextMenu(parentNode, refNode);
/*
var node = document.getElementById("placesContext_createBookmark");
if (!node) return;
node.removeAttribute("forcehideselection");
node.setAttribute("selection", "any");
node.removeAttribute("command");
node.setAttribute("oncommand", "AddBookmarkHere.addBookmark(event);");
*/
},
addContextMenu: function (parentNode, afterNode) {
var menuitem = document.createXULElement("menuitem");
menuitem.id = "placesContext_add:bookmark";
menuitem.setAttribute("label", Services.locale.appLocaleAsBCP47.includes("de") ? "Lesezeichen hier hinzufügen" : "Add Bookmark Here");
menuitem.setAttribute("accesskey", "h");
menuitem.setAttribute("selection", "any");
menuitem.setAttribute("class", "menuitem-iconic");
menuitem.setAttribute("style", "list-style-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0iY29udGV4dC1maWxsIiBmaWxsLW9wYWNpdHk9ImNvbnRleHQtZmlsbC1vcGFjaXR5IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNOC44MDgwMiAyLjEwMTc5QzguNDc3ODkgMS40MzI4NyA3LjUyNDAzIDEuNDMyODcgNy4xOTM5IDIuMTAxNzlMNS42NzI4MSA1LjE4Mzg0TDIuMjcxNTYgNS42NzgwN0MxLjUzMzM2IDUuNzg1MzQgMS4yMzg2MSA2LjY5MjUxIDEuNzcyNzcgNy4yMTMyTDQuMjMzOTQgOS42MTIyNEwzLjY1Mjk0IDEyLjk5OTdDMy41MjY4NCAxMy43MzUgNC4yOTg1MyAxNC4yOTU2IDQuOTU4NzkgMTMuOTQ4NUw4LjAwMDk2IDEyLjM0OTFMOC40ODI5IDEyLjYwMjVDOC4xODU5NyAxMi4zMjg0IDggMTEuOTM1OSA4IDExLjVDOCAxMS40NDQ2IDguMDAzIDExLjM5IDguMDA4ODQgMTEuMzM2MkM3Ljg2MjM2IDExLjMzNDkgNy43MTU2NCAxMS4zNjk0IDcuNTgyMTUgMTEuNDM5NUw0LjY3MjggMTIuOTY5MUw1LjIyODQzIDkuNzI5NDdDNS4yNzg1MSA5LjQzNzUxIDUuMTgxNzEgOS4xMzk2MSA0Ljk2OTYgOC45MzI4NUwyLjYxNTg4IDYuNjM4NTRMNS44Njg2NCA2LjE2NTg5QzYuMTYxNzggNi4xMjMyOSA2LjQxNTE5IDUuOTM5MTggNi41NDYyOCA1LjY3MzU1TDguMDAwOTYgMi43MjYwNUw4LjczMzUxIDQuMjEwMzZDOC45NTc4MiA0LjA3Njc1IDkuMjE5OTUgNCA5LjUgNEg5Ljc0NDg1TDguODA4MDIgMi4xMDE3OVpNOS41IDVDOS4yMjM4NiA1IDkgNS4yMjM4NiA5IDUuNUM5IDUuNzc2MTQgOS4yMjM4NiA2IDkuNSA2SDE0LjVDMTQuNzc2MSA2IDE1IDUuNzc2MTQgMTUgNS41QzE1IDUuMjIzODYgMTQuNzc2MSA1IDE0LjUgNUg5LjVaTTkuNSA4QzkuMjIzODYgOCA5IDguMjIzODYgOSA4LjVDOSA4Ljc3NjE0IDkuMjIzODYgOSA5LjUgOUgxNC41QzE0Ljc3NjEgOSAxNSA4Ljc3NjE0IDE1IDguNUMxNSA4LjIyMzg2IDE0Ljc3NjEgOCAxNC41IDhIOS41Wk05LjUgMTFDOS4yMjM4NiAxMSA5IDExLjIyMzkgOSAxMS41QzkgMTEuNzc2MSA5LjIyMzg2IDEyIDkuNSAxMkgxNC41QzE0Ljc3NjEgMTIgMTUgMTEuNzc2MSAxNSAxMS41QzE1IDExLjIyMzkgMTQuNzc2MSAxMSAxNC41IDExSDkuNVoiLz4KPC9zdmc+Cg==)");
menuitem.addEventListener("command", this, false);
if (typeof refNode !== "undefined") {
parentNode.insertBefore(menuitem, afterNode);
} else {
parentNode.appendChild(menuitem);
}
},
handleEvent: function (e) {
var popupNode = e.currentTarget.parentNode.triggerNode;
if (!popupNode) return;
var view = PlacesUIUtils.getViewForNode(popupNode);
if (!view) return;
var bookmarks = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].getService(Ci.nsINavBookmarksService);
var selectedNode = view.selectedNode;
var iid, aid;
if (selectedNode) {
if (PlacesUtils.nodeIsFolderOrShortcut(selectedNode)/* Bug 1904909 PlacesUtils.nodeIsFolder(selectedNode) /* Firefox 21+ inkompatibel && !PlacesUtils.nodeIsLivemarkContainer(selectedNode) && !PlacesUtils.isReadonlyFolder(selectedNode) */) {
iid = selectedNode.itemId;
aid = e.shiftKey ? 0 : bookmarks.DEFAULT_INDEX;
} else {
iid = bookmarks.getFolderIdForItem(selectedNode.itemId);
var id = bookmarks.getItemIndex(selectedNode.itemId);
aid = e.shiftKey ? id : id + 1;
}
} else {
iid = view.result.root.folderItemId;
aid = e.shiftKey ? 0 : bookmarks.DEFAULT_INDEX;
};
var uri = Services.io.newURI(gBrowser.currentURI.spec, null, null);
var title = gBrowser.contentTitle
bookmarks.insertBookmark(iid, uri, aid, title);
},
uninit: function () {
var self = this;
try {
var menuitem = document.getElementById("placesContext_add:bookmark");
menuitem.removeEventListener("command", self, false);
menuitem.remove();
delete window.AddBookmarkHere;
} catch (ex) {
}
}
};
AddBookmarkHere.init();
window.AddBookmarkHere = AddBookmarkHere;
})();
Alles anzeigen
This script is not maintained for a long time, but it is recommended for use https://github.com/benzBrake/Fire…okmarkOpt.uc.js
Vielleicht hilft uns ja jizz .
Please jizz can you help us fixing this Script? BeitragAutomatischer Screenshot
Hallo zusammen,
ich verwende folgendes Script, um Screenshots mit einem Klick zu erstellen:
(Quelltext, 55 Zeilen)
Leider funktioniert die Automatik seit heute mit FF 127 nicht mehr. Vielleicht kann mir wieder geholfen werden.
Im Voraus schon vielen Dank.
geldhuegel12. Juni 2024 um 02:11 Thank You.
Mfg.
Endor
Maybe it needs to be modified, you know, I use alice0775's loader
Alles anzeigenfirefox126hint: TypeError : reloadTab.getAttribute(...) is null
Please help me fix it
location.href.startsWith('chrome://browser/content/browser.x') && (() => {
const reloadTab = document.getElementById('context_reloadTab');
if(!reloadTab) return;
const menuitem = document.createXULElement('menuitem');
menuitem.setAttribute('accesskey', 'A');
menuitem.setAttribute('label', reloadTab.getAttribute('label')
.startsWith('Reload') ? 'Reload All Tabs' : '刷新所有标签页'
);
menuitem.addEventListener('command', () => {
gBrowser.visibleTabs.forEach(tab => {
try {
gBrowser.getBrowserForTab(tab).reload();
} catch (e) {}
});
});
reloadTab.after(menuitem);
})();
location.href.startsWith('chrome://browser/content/browser.x') && (() => {
document.getElementById('tabContextMenu').addEventListener('popupshowing', function () {
const reloadTab = document.getElementById('context_reloadTab');
if (!reloadTab) return;
const menuitem = document.createXULElement('menuitem');
menuitem.setAttribute('accesskey', 'A');
menuitem.setAttribute('label', reloadTab.getAttribute('label')
.startsWith('Reload') ? 'Reload All Tabs' : '刷新所有标签页'
);
menuitem.addEventListener('command', () => {
gBrowser.visibleTabs.forEach(tab => {
try {
gBrowser.getBrowserForTab(tab).reload();
} catch (e) { }
});
});
reloadTab.after(menuitem);
}, { once: true })
})();
Alles anzeigen
It was my fault. Using gBrowser.reload() / gBrower.stop() / gBrowser.reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE) to be compatible with firefox57+
Alles anzeigenHallo zusammen.
Habe hier ein Script, welches die Neuladen Schaltfläche in die Adressleiste verschiebt.
Bei Linksklick wird der Tab neu geladen, bei Rechtsklick wird der Tab neu geladen ohne
den Cache zu berücksichtigen. Habe einige Anpassungen wie weiter oben erwähnt gemacht,
aber bei klick tut sich nichts. Habt Ihr eine Idee?
Hier das Script:JavaScript Alles anzeigen// ==UserScript== // @name moveReloadIntoUrl.uc.js // @description Neuladen Schaltfläche in Adressleiste verschieben // @compatibility Firefox 103+ // @author Ryan, GOLF-AT // @include main // @shutdown window.moveReloadIntoURL.unload(); // @homepageURL https://github.com/benzBrake/FirefoxCustomize // @version 1.2.3 // @note 1.2.3 Änderung wird in neuen Fenstern nicht wirksam und kann // @note nicht verwendet werden, wenn Hot-Swapping stattfindet. // @note 1.2.2 Kompatibilität angepasst für Firefox 103 // @note 1.2.0 Hot-Swap-fähig, kompatibel mit Nachtmodus // @note und Bilder wurden ins Script integriert // @note 1.1 20220424 Fehler behoben, und Firefox 100 Kompatibel // @note 1.0 20171104 // ==/UserScript== (function () { let { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; const CustomizableUI = globalThis.CustomizableUI || Cu.import("resource:///modules/CustomizableUI.jsm").CustomizableUI; const Services = globalThis.Services || Cu.import("resource://gre/modules/Services.jsm").Services; if (window.moveReloadIntoURL) { window.moveReloadIntoURL.unload(); delete window.moveReloadIntoURL; } window.moveReloadIntoURL = { handleEvent: function (aEvent) { if (aEvent.type === "MoveReloadIntoUrlUnload") { let win = aEvent.originalTarget, doc = win.document; let RELOADBTN = CustomizableUI.getWidget("reload-button").forWindow(win).node; if (RELOADBTN) RELOADBTN.removeEventListener('DOMAttrModified', this.reloadBtnAttr); let BTN = doc.getElementById("new-stop-reload-button"); if (BTN) BTN.parentNode.removeChild(BTN); if (this.STYLE) { this.sss.unregisterSheet(this.STYLE.url, this.STYLE.type); } win.removeEventListener('MoveReloadIntoUrlUnload', this); if (win.moveReloadIntoURL) delete win.moveReloadIntoURL; } }, init: function (doc, win) { if (win.moveReloadIntoURL) { this.sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); this.STYLE = { url: Services.io.newURI('data:text/css;charset=UTF-8,' + encodeURIComponent(` @-moz-document url('chrome://browser/content/browser.xhtml') { #stop-reload-button { display: none !important; } #new-stop-reload-button { order: 999; } } `)), type: this.sss.AGENT_SHEET }; this.sss.loadAndRegisterSheet(this.STYLE.url, this.STYLE.type); } let PABTN = CustomizableUI.getWidget("pageActionButton").forWindow(win).node; let RELOADBTN = CustomizableUI.getWidget("reload-button").forWindow(win).node; let BTN = $C(doc, 'hbox', { id: "new-stop-reload-button", class: "urlbar-page-action urlbar-addon-page-action", "tooltiptext": Services.locale.appLocaleAsBCP47.includes("de") ? 'Linksklick: Seite neuladen\r\nRechtsklick: Neu laden erzwingen' : 'Left click: refresh page\nRight click: force refresh page', style: "list-style-image: url('data:image/svg+xml;base64,PCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDE2IDE2IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9ImNvbnRleHQtZmlsbCIgZmlsbC1vcGFjaXR5PSJjb250ZXh0LWZpbGwtb3BhY2l0eSI+CiAgPHBhdGggZD0iTTEwLjcwNyA2IDE0LjcgNmwuMy0uMyAwLTMuOTkzYS41LjUgMCAwIDAtLjg1NC0uMzU0bC0xLjQ1OSAxLjQ1OUE2Ljk1IDYuOTUgMCAwIDAgOCAxQzQuMTQxIDEgMSA0LjE0MSAxIDhzMy4xNDEgNyA3IDdhNi45NyA2Ljk3IDAgMCAwIDYuOTY4LTYuMzIyLjYyNi42MjYgMCAwIDAtLjU2Mi0uNjgyLjYzNS42MzUgMCAwIDAtLjY4Mi41NjJBNS43MjYgNS43MjYgMCAwIDEgOCAxMy43NWMtMy4xNzEgMC01Ljc1LTIuNTc5LTUuNzUtNS43NVM0LjgyOSAyLjI1IDggMi4yNWE1LjcxIDUuNzEgMCAwIDEgMy44MDUgMS40NDVsLTEuNDUxIDEuNDUxYS41LjUgMCAwIDAgLjM1My44NTR6Ii8+Cjwvc3ZnPgo=", onclick: function (e) { let r = CustomizableUI.getWidget("reload-button").forWindow(window).node; if (r && r.getAttribute('displaystop')) e.target.ownerGlobal.BrowserCommands.Stop(); else if (e.button == 2) { e.target.ownerGlobal.BrowserCommands.ReloadSkipCache(); } else { if (gBrowser.selectedBrowser._userTypedValue) { e.target.ownerGlobal.openTrustedLinkIn(gBrowser.selectedBrowser._userTypedValue, 'current', { postData: null, triggeringPrincipal: gBrowser.selectedBrowser.contentPrincipal }); } else { e.target.ownerGlobal.BrowserCommands.Reload(); } } } }) BTN.appendChild($C(doc, 'image', { class: 'urlbar-icon', })); PABTN.after(BTN); RELOADBTN.addEventListener('DOMAttrModified', this.reloadBtnAttr); this.reloadBtnAttr(); win.addEventListener('MoveReloadIntoUrlUnload', this) }, unload: function () { let windows = Services.wm.getEnumerator('navigator:browser'); while (windows.hasMoreElements()) { let win = windows.getNext(); win.dispatchEvent(new CustomEvent("MoveReloadIntoUrlUnload")); } }, reloadBtnAttr: function (e) { let doc = e ? e.target.ownerDocument : document; btn = doc.getElementById('new-stop-reload-button'); if (btn && (!e || e.attrName == 'displaystop')) { var newVal = e ? e.newValue : doc.getElementById( "reload-button").getAttribute('displaystop'); if (newVal) btn.style.listStyleImage = "url('data:image/svg+xml;base64,PCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDE2IDE2IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9ImNvbnRleHQtZmlsbCIgZmlsbC1vcGFjaXR5PSJjb250ZXh0LWZpbGwtb3BhY2l0eSI+CiAgPHBhdGggZD0ibTkuMTA4IDcuNzc2IDQuNzA5LTQuNzA5YS42MjYuNjI2IDAgMCAwLS44ODQtLjg4NUw4LjI0NCA2Ljg3MWwtLjQ4OCAwLTQuNjg5LTQuNjg4YS42MjUuNjI1IDAgMSAwLS44ODQuODg1TDYuODcgNy43NTRsMCAuNDkxLTQuNjg3IDQuNjg3YS42MjYuNjI2IDAgMCAwIC44ODQuODg1TDcuNzU0IDkuMTNsLjQ5MSAwIDQuNjg3IDQuNjg3YS42MjcuNjI3IDAgMCAwIC44ODUgMCAuNjI2LjYyNiAwIDAgMCAwLS44ODVMOS4xMDggOC4yMjNsMC0uNDQ3eiIvPgo8L3N2Zz4K')"; else btn.style.listStyleImage = "url('data:image/svg+xml;base64,PCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDE2IDE2IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9ImNvbnRleHQtZmlsbCIgZmlsbC1vcGFjaXR5PSJjb250ZXh0LWZpbGwtb3BhY2l0eSI+CiAgPHBhdGggZD0iTTEwLjcwNyA2IDE0LjcgNmwuMy0uMyAwLTMuOTkzYS41LjUgMCAwIDAtLjg1NC0uMzU0bC0xLjQ1OSAxLjQ1OUE2Ljk1IDYuOTUgMCAwIDAgOCAxQzQuMTQxIDEgMSA0LjE0MSAxIDhzMy4xNDEgNyA3IDdhNi45NyA2Ljk3IDAgMCAwIDYuOTY4LTYuMzIyLjYyNi42MjYgMCAwIDAtLjU2Mi0uNjgyLjYzNS42MzUgMCAwIDAtLjY4Mi41NjJBNS43MjYgNS43MjYgMCAwIDEgOCAxMy43NWMtMy4xNzEgMC01Ljc1LTIuNTc5LTUuNzUtNS43NVM0LjgyOSAyLjI1IDggMi4yNWE1LjcxIDUuNzEgMCAwIDEgMy44MDUgMS40NDVsLTEuNDUxIDEuNDUxYS41LjUgMCAwIDAgLjM1My44NTR6Ii8+Cjwvc3ZnPgo=')"; } }, } function $C(aDoc, tag, attrs, skipAttrs) { attrs = attrs || {}; skipAttrs = skipAttrs || []; var el = (aDoc || document).createXULElement(tag); return $A(el, attrs, skipAttrs); } function $A(el, obj, skipAttrs) { skipAttrs = skipAttrs || []; if (obj) Object.keys(obj).forEach(function (key) { if (!skipAttrs.includes(key)) { if (typeof obj[key] === 'function') { el.setAttribute(key, "(" + obj[key].toString() + ").call(this, event);"); } else { el.setAttribute(key, obj[key]); } } }); return el; } if (gBrowserInit.delayedStartupFinished) window.moveReloadIntoURL.init(document, window) else { let delayedListener = (subject, topic) => { if (topic == "browser-delayed-startup-finished" && subject == window) { Services.obs.removeObserver(delayedListener, topic); window.moveReloadIntoURL.init(subject.document, subject); } }; Services.obs.addObserver(delayedListener, "browser-delayed-startup-finished"); } })();
Konsole sagt folgendes:
CodeUncaught ReferenceError: gBrowserInit is not defined <anonymous> file:///C:/Users/xxxx/AppData/Roaming/Mozilla/Firefox/Profiles/6ha62y8g/chrome/move_reload_into_url.uc.js:142 <anonymous> file:///C:/Users/xxxx/AppData/Roaming/Mozilla/Firefox/Profiles/6ha62y8g/chrome/move_reload_into_url.uc.js:152 loadScript file:///C:/Program Files/Mozilla Firefox/userChromeJS/utilities.js:114 move_reload_into_url.uc.js:142:9 <anonym> file:///C:/Users/xxxx/AppData/Roaming/Mozilla/Firefox/Profiles/6ha62y8g/chrome/move_reload_into_url.uc.js:142 <anonym> file:///C:/Users/xxxx/AppData/Roaming/Mozilla/Firefox/Profiles/6ha62y8g/chrome/move_reload_into_url.uc.js:152 loadScript file:///C:/Program Files/Mozilla Firefox/userChromeJS/utilities.js:114
Zeile 142:
if (gBrowserInit.delayedStartupFinished) window.moveReloadIntoURL.init(document, window)
Zeile 152:
})();Mfg.
Endor
I updated the script, but my script was only tested using alice0775's uc loader. If not work, you have to import PlacesUIUtils yourself
Try this fake portable loader: https://github.com/benzBrake/RunFirefox
那是启动时,第一次点击:
JavaScript Alles anzeigen(function () { if (location.href !== 'chrome://browser/content/browser.xhtml') return; setTimeout(() => { const orig = document.getElementById('saveforreadlater_gmail_com-menuitem-_saveIt'); const ref = document.getElementById('context-take-screenshot'); contentAreaContextMenu.insertBefore(orig, ref.nextSibling); }, 20000); } ) ();
其子菜单中-Original后两个Element个的或要求的功能的Dropdowns的项目出现了位移。
那是基本菜单的因素是延期还是存在,但是更多。
因此,我的简单的因素就移。这个还不够。"难道(还有的部件clonen,它的功能形象,没有不和谐)(那是极度长的时间,然后超过)
因此我首先感谢就在帮忙。
(function () {
if (location.href !== 'chrome://browser/content/browser.xhtml')
return;
const ref = document.getElementById('context-take-screenshot');
if (ref) {
ref.after($C('menuitem', {
label: "Save all pages for read them later",
oncommand: 'event.target.parentNode.querySelector("#saveforreadlater_gmail_com-menuitem - _saveItAll").click(event);'
}));
ref.after($C('menuitem', {
label: "Save this page for Read Later",
oncommand: 'event.target.parentNode.querySelector("#saveforreadlater_gmail_com-menuitem-_saveIt").click(event);'
}));
}
var style = "data:text/css;charset=utf-8," + encodeURIComponent(`
#contentAreaContextMenu [id^="saveforreadlater_gmail_com-menuitem"] {
display: none;
}
`);
windowUtils.loadSheetUsingURIString(style, windowUtils.AUTHOR_SHEET);
function $C(tag, attrs) {
var el;
if (!tag) return el;
attrs = attrs || {};
el = document.createXULElement(tag);
if (attrs) Object.keys(attrs).forEach(function (key) {
el.setAttribute(key, attrs[key]);
});
return el;
}
})()
Alles anzeigen
Alles anzeigenDieses JavaScript ist ja sehr nett, aber um eine kostenlosen "API key" zu bekommen
müssen die Bankdaten angegeben werden!
Das ist nicht wirklich prickelnd und ich bekomme da "Bauchweh"!Geht es auch irgendwie ohne?
Und wer diese Japanische Schriftzeichen ändern möchte,
Zeile 83
menuItem.label = "Auswahl mit DeepL übersetzen";
und
Zeile 192
logo.textContent = "DeepL Übersetzer";
Wie ein Icon vor den Text des Menüs "gezaubert" wird, muss ich erst noch testen.
Macht nur im Moment keinen Sinn, da ohne API-Key das Script nicht funktioniert.
Und hier noch ein Mal der Code des JavaScripts im Original,
da bei mir die Seite schon einige Male nicht geladen wurde
JavaScript Alles anzeigen// ==UserScript== // @name DeepL Translator // @include main // @compatibility Firefox 78+ // @description コンテクストメニューに選択テキストをDeepLで翻訳する機能を追加する // @note DeepLのAPIキー (無料版で可) が必要 // @charset UTF-8 // ==/UserScript== "use strict"; if (typeof window === "undefined" || globalThis !== window) { /* --- 設定ここから --- */ const apiKey = "Enter your API key here!"; const apiEndpoint = "https://api-free.deepl.com/v2"; const hotkey = { enabled: false, code: "ControlLeft", repeat: 2, timeout: 500, }; const defaultLang = "JA"; const supportedLangs = { //"BG": "Bulgarian", //"CS": "Czech", //"DA": "Danish", "DE": "German", //"EL": "Greek", //"EN-GB": "English (British)", "EN-US": "English (American)", "ES": "Spanish", //"ET": "Estonian", //"FI": "Finnish", "FR": "French", //"HU": "Hungarian", "IT": "Italian", "JA": "Japanese", //"LT": "Lithuanian", //"LV": "Latvian", //"NL": "Dutch", //"PL": "Polish", //"PT-PT": "Portuguese", //"PT-BR": "Portuguese (Brazilian)", //"RO": "Romanian", //"RU": "Russian", //"SK": "Slovak", //"SL": "Slovenian", //"SV": "Swedish", //"ZH": "Chinese", }; /* --- 設定ここまで --- */ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); ChromeUtils.defineModuleGetter(this, "ContentDOMReference", "resource://gre/modules/ContentDOMReference.jsm"); ChromeUtils.defineModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); if (!Services.appinfo.remoteType) { this.EXPORTED_SYMBOLS = ["DLTranslator", "DLTranslatorParent"]; try { const actorParams = { parent: { moduleURI: __URI__, }, child: { moduleURI: __URI__, events: {}, }, allFrames: true, messageManagerGroups: ["browsers"], matches: [`*://*/*`], }; if (hotkey.enabled) { if (hotkey.repeat <= 0) hotkey.repeat = 2; if (hotkey.timeout <= 0) hotkey.timeout = 500; actorParams.child.events.keyup = {}; } ChromeUtils.registerWindowActor("DLTranslator", actorParams); } catch(e) {Cu.reportError(e);} this.DLTranslator = new class { attachToWindow(win) { let menuPopup = win.document.getElementById("contentAreaContextMenu"); let menuItem = win.document.createXULElement("menuitem"); menuItem.label = "選択テキストを DeepL で翻訳"; menuItem.id = "menu-deepl-translate"; menuItem.addEventListener("command", this); menuPopup.appendChild(menuItem); menuPopup.addEventListener("popupshowing", this); win.addEventListener("unload", this, {once:true}); } detachFromWindow(win) { win.removeEventListener("unload", this, {once:true}); // this might be unnecessary, but do anyway const menu = win.document.getElementById("menu-deepl-translate"); menu.parentNode.removeEventListener("popupshowing", this); menu.parentNode.removeChild(menu); } handleEvent({type, target}) { switch(type) { case "popupshowing": this.handlePopup(target.ownerGlobal); break; case "command": this.beginTranslate(target.ownerGlobal.gContextMenu?.contentData); break; case "unload": this.detachFromWindow(target.ownerGlobal); break; } } handlePopup(win) { let selectionText = win.gContextMenu?.contentData?.selectionInfo?.text; win.document.getElementById("menu-deepl-translate").hidden = !selectionText; } beginTranslate(contextMenuContentData) { if (!contextMenuContentData) return; const win = contextMenuContentData.browser.ownerGlobal; const selectionText = contextMenuContentData.selectionInfo?.fullText; const targetIdentifier = contextMenuContentData.context?.targetIdentifier; const screenX = contextMenuContentData.context?.screenX ?? contextMenuContentData.context?.screenXDevPx / win.devicePixelRatio; const screenY = contextMenuContentData.context?.screenY ?? contextMenuContentData.context?.screenYDevPx / win.devicePixelRatio; const browser = contextMenuContentData.browser; const browserBoundingRect = browser.getBoundingClientRect(); const fixupX = browser.ownerGlobal.outerWidth - browserBoundingRect.left - browserBoundingRect.width; const fixupY = 20 + browser.ownerGlobal.outerHeight - browserBoundingRect.top - browserBoundingRect.height; const actor = contextMenuContentData.frameBrowsingContext.currentWindowGlobal.getActor("DLTranslator"); actor.sendAsyncMessage("DLT:CreatePopup", { targetIdentifier, screenX, screenY, fixupX, fixupY, fromLang: null, toLang: null, sourceText: selectionText, }); } }(); this.DLTranslatorParent = class extends JSWindowActorParent { receiveMessage({name, data}) { switch(name) { case "DLT:OpenTranlatorInTab": const win = this.browsingContext.top.embedderElement.ownerGlobal; win.openLinkIn(`https://www.deepl.com/translator#${data.sourceLang}/${data.targetLang}/${encodeURIComponent(data.sourceText)}`, "tab", { relatedToCurrent: true, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), } ); break; } } } } else { Cu.importGlobalProperties(["fetch"]); this.EXPORTED_SYMBOLS = ["DLTranslatorChild"]; this.DLPopupTranslator = class { constructor(win, x, y, sourceText) { this.sourceLang = "EN"; this.targetLang = win.windowGlobalChild.getActor("DLTranslator").defaultLang; this.sourceText = sourceText.trim(); const popup = this.popup = win.document.createElement("div"); Object.assign(popup.style, { position: "absolute", top: `${win.scrollY + y}px`, left: `${win.scrollX + x}px`, width: "400px", maxHeight: "200px", fontFamily: "sans-serif", fontSize: "16px", color: "black", background: "floralwhite", border: "1px solid darkgray", borderRadius: "3px", boxShadow: "3px 3px 5px lightgray", transition: "opacity 0.2s ease", zIndex: "1000", }); const flex = win.document.createElement("div"); Object.assign(flex.style, { display: "flex", maxHeight: "200px", flexDirection: "column", }); const header = win.document.createElement("div"); Object.assign(header.style, { display: "flex", height: "auto", margin: "2px 5px 1px", fontSize: "smaller", alignItems: "center", }); const logo = win.document.createElement("div"); logo.textContent = "DeepL ほんやくくん"; Object.assign(logo.style, { width: "auto", fontWeight: "bold", flexGrow: "1", }); header.appendChild(logo); const langSelector = win.document.createElement("select"); for (let [lang, desc] of Object.entries(supportedLangs)) { const option = win.document.createElement("option"); option.value = lang; option.textContent = desc; langSelector.appendChild(option); } langSelector.value = this.targetLang; Object.assign(langSelector.style, { width: "auto", marginRight: "5px", }); langSelector.addEventListener("change", this); header.appendChild(langSelector); const more = win.document.createElement("div"); more.className = "deepl-translator-more"; more.textContent = "more"; Object.assign(more.style, { width: "auto", cursor: "pointer", }); more.addEventListener("click", this); header.appendChild(more); flex.appendChild(header); const box = win.document.createElement("div"); box.className = "deepl-translator-box"; Object.assign(box.style, { height: "auto", overflow: "auto", background: "white", padding: "2px", margin: "1px 5px 5px", border: "1px solid darkgray", flexGrow: "1", whiteSpace: "pre-wrap", }); flex.appendChild(box); this.popup.appendChild(flex); win.document.body.appendChild(popup); win.setTimeout(() => win.addEventListener("click", this), 0); } handleEvent(event) { const {type, target} = event; switch(type) { case "click": if (!this.popup.contains(target)) { target.ownerGlobal.removeEventListener("click", this); this.popup.addEventListener("transitionend", ({target}) => { target.parentNode.removeChild(target); }, {once:true}); this.popup.style.opacity = 0; } else if (target.className === "deepl-translator-more") { const actor = target.ownerGlobal.windowGlobalChild.getActor("DLTranslator"); actor.sendAsyncMessage("DLT:OpenTranlatorInTab", { sourceText: this.sourceText, sourceLang: this.sourceLang, targetLang: this.targetLang, }); event.stopPropagation(); } break; case "change": this.targetLang = target.value; this.translate(null, this.targetLang); break; } } setText(text, color) { let box = this.popup.querySelector(".deepl-translator-box"); if (color) box.style.color = color; else box.style.color = null; box.textContent = text; } fetchWithPrivilege(url, request) { return new Promise((resolve, reject) => { const {method, headers, body, referrer} = request; let origin = referrer ? referrer : url; const channel = NetUtil.newChannel({ uri: NetUtil.newURI(url), loadingPrincipal: Services.scriptSecurityManager.createContentPrincipal(NetUtil.newURI(origin), {}), contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER, securityFlags: Ci.nsILoadInfo.SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT || Ci.nsILoadInfo.SEC_REQUIRE_CORS_DATA_INHERITS, }); channel.QueryInterface(Ci.nsIHttpChannel); channel.loadFlags |= Ci.nsIRequest.LOAD_ANONYMOUS; channel.requestMethod = method || "GET"; if (headers) { for (const [name, value] of Object.entries(headers)) { if (channel.setNewReferrerInfo && name.toLowerCase() === "referer") { channel.setNewReferrerInfo( value, Ci.nsIReferrerInfo.UNSAFE_URL, true ); } else { channel.setRequestHeader(name, value, false); } } } if (body) { channel.QueryInterface(Ci.nsIUploadChannel2); const converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; channel.explicitSetUploadStream(converter.convertToInputStream(body), null, -1, method, false); } NetUtil.asyncFetch(channel, (stream, status) => { if (!Components.isSuccessCode(status)) { let e = Components.Exception("", status); reject(new Error(`Error while loading ${url}: ${e.name}`)); } let text = NetUtil.readInputStreamToString(stream, stream.available()); stream.close(); resolve({ ok: channel.requestSucceeded, status: channel.responseStatus, statusText: channel.responseStatusText, contentType: channel.getResponseHeader("content-type"), text }); }); }); } translateUsingBackdoor(from, to) { const getTimestamp = text => { let now = new Date().getTime(); let count = 1; let match = text.match(/i/g); if (match) { count += match.length; } return now + count - now % count; }; this.fetchWithPrivilege("https://www2.deepl.com/jsonrpc", { method: "POST", referrer: "https://www.deepl.com/translator", headers: { "Content-Type": "application/json", Referer: "https://www.deepl.com/translator", }, body: JSON.stringify({ jsonrpc: "2.0", method: "LMT_handle_texts", params: { texts: [{text: this.sourceText}], splitting: "newlines", lang: { target_lang: to.slice(0, 2), source_lang_user_selected: from ? from : "auto", }, timestamp: getTimestamp(this.sourceText), }, id: 1000000+Math.floor(Math.random()*99000000), }, null, 4), }).then(resp => { if (!resp.ok && !resp.contentType.startsWith("application/json")) { throw new Error(`Server returned ${resp.status} ${resp.statusText}`); } return JSON.parse(resp.text); }).then(json => { if (json.error) throw new Error(`Error code ${json.error.code}: ${json.error.message}`); if (!json.result?.texts) throw new Error("Unknown error occurred"); this.setText(json.result.texts[0].text); this.sourceLang = json.result.lang; }).catch(e => { this.setText(e.message, "red"); Cu.reportError(e); }); } translate(from, to) { this.setText("翻訳中...", "lightgray"); if (to) { this.popup.querySelector("select").value = this.targetLang = to; this.popup.ownerGlobal.windowGlobalChild.getActor("DLTranslator").defaultLang = to; } if (!apiKey) return this.translateUsingBackdoor(from, this.targetLang); const body = new FormData(); body.append("text", this.sourceText); body.append("target_lang", this.targetLang); body.append("auth_key", apiKey); if (from) body.append("source_lang", from); return fetch(`${apiEndpoint}/translate`, { method: "POST", referrerPolicy: "no-referrer", credentials: "omit", body, }).then(resp => { if (!resp.ok && resp.status != 400) { throw new Error(`Server returned ${resp.status} ${resp.statusText}`); } return resp.json(); }).then(json => { if (!json.translations) throw new Error(`${json.message}: ${json.detail}`); this.setText(json.translations[0].text); this.sourceLang = json.translations[0].detected_source_language; fetch(`${apiEndpoint}/usage`, { referrerPolicy: "no-referrer", credentials: "omit", headers: { Authorization: `DeepL-Auth-Key ${apiKey}`, }, }).then(resp => { if (!resp.ok) throw new Error(); return resp.json(); }).then(json => { this.popup.title = `Quota: ${(100*json.character_count/json.character_limit).toPrecision(2)}% (${json.character_count} / ${json.character_limit})`; }).catch(()=>{}); }).catch(e => { this.setText(e.message, "red"); Cu.reportError(e); }); } } this.DLTranslatorChild = class extends JSWindowActorChild { actorCreated() { this.defaultLang = defaultLang; this.keyRepeat = 0; } createPopupWithScreenCoordinate(screenX, screenY, sourceText) { let x = screenX - this.contentWindow.screenX - this.contentWindow.outerWidth + this.contentWindow.innerWidth; let y = screenY - this.contentWindow.screenY - this.contentWindow.outerHeight + this.contentWindow.innerHeight; return this.createPopupWithClientCoordinate(x, y, sourceText); } createPopupWithClientCoordinate(clientX, clientY, sourceText) { let x = clientX; let y = clientY; let clientWidth = this.contentWindow.document.documentElement.clientWidth; let clientHeight = this.contentWindow.document.documentElement.clientHeight; if (x + 400 > clientWidth) x = clientWidth - 400; if (y + 200 > clientHeight) y = clientHeight - 200; x = Math.max(x, 0); y = Math.max(y, 0); return new DLPopupTranslator(this.contentWindow, x, y, sourceText); } createPopupWithSelection() { const selection = this.contentWindow.getSelection(); const text = selection.toString().trim(); if (text) { let rect = selection.getRangeAt(0).getBoundingClientRect(); return this.createPopupWithClientCoordinate(rect.left, rect.top+rect.height, text); } return null; } receiveMessage({name, data}) { switch(name) { case "DLT:CreatePopup": let fixupX = 0; let fixupY = 0; if (data.fixupX) fixupX = data.fixupX; if (data.fixupY) fixupY = data.fixupY; this.createPopupWithScreenCoordinate(data.screenX+fixupX, data.screenY+fixupY, data.sourceText).translate(data.fromLang, data.toLang); break; case "DLT:CreatePopupWithClientCoordinate": this.createPopupWithClientCoordinate(data.clientX, data.clientY, data.sourceText).translate(data.fromLang, data.toLang); break; } } handleEvent(event) { switch (event.type) { case "keyup": if (event.code === hotkey.code && this.contentWindow.getSelection()?.toString()) { if (!this.keyRepeat) { new Promise((resolve, reject) => { this.hotkeyResolver = resolve; this.hotkeyRejector = reject; this.contentWindow.setTimeout(() => reject(), hotkey.timeout); }).then(() => { this.keyRepeat = 0; this.hotkeyResolver = null; this.hotkeyRejector = null; this.createPopupWithSelection()?.translate(null, this.defaultLang); }).catch(() => { this.keyRepeat = 0; this.hotkeyResolver = null; this.hotkeyRejector = null; }); } if (++this.keyRepeat === hotkey.repeat) { this.hotkeyResolver(); } } else if (this.keyRepeat) { this.hotkeyRejector(); } break; } } } } } else { try { if (parseInt(Services.appinfo.version) < 101) { ChromeUtils.import(Components.stack.filename).DLTranslator.attachToWindow(window); } else { const fileHandler = Services.io.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); const scriptFile = fileHandler.getFileFromURLSpec(Components.stack.filename); const resourceHandler = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler); if (!resourceHandler.hasSubstitution("deepl-ucjs")) { resourceHandler.setSubstitution("deepl-ucjs", Services.io.newFileURI(scriptFile.parent)); } ChromeUtils.import(`resource://deepl-ucjs/${encodeURIComponent(scriptFile.leafName)}?${scriptFile.lastModifiedTime}`).DLTranslator.attachToWindow(window); } } catch(e) {} }
Without apikey, the script would translate text through backdoor, there will be some restrictions.
Due to Deepl unsuitable Chinese service, I modified the script to use Baidu translation API
// ==UserScript==// @name Baidu Translator// @author Ryan, BSTweaker// @include main// @compatibility Firefox 78+// @homepageURL https://github.com/benzBrake/FirefoxCustomize/tree/master/userChromeJS// @description 在上下文菜单中添加使用百度翻译所选文本的功能// @note 从 DLTranslator (https://bitbucket.org/BSTweaker/userchromejs/src/master/DeepLTranslator.uc.js)修改而来// @charset UTF-8// ==/UserScript==const BDT_OPTIONS = { defaultLang: "zh", enableContextMenu: true, hotkey: { enabled: true, code: "AltLeft", repeat: 2, timeout: 500, }, supportedLangs: { //"ara": "Arabic", //"bul": "Bulgarian", //"cs": "Czech", //"dan": "Danish", "de": "German", //"el": "Greek", "en": "English", //"est": "Estonian", //"fin": "Finnish", //"fra": "French", //"hu": "Hungarian", //"it": "Italian", //"jp": "Japanese", //"lit": "Lithuanian", //"lav": "Latvian", //"nl": "Dutch", //"pl": "Polish", "pt": "Portuguese", "pot": "Portuguese (Brazilian)", //"rom": "Romanian", //"ru": "Russian", //"sk": "Slovak", //"slo": "Slovenian", "spa": "Spanish", //"swe": "Swedish", "th": "Thai", "vie": "Vietnamese", "zh": "简体中文", "cht": "繁體中文", "wyw": "文言文", }}if (typeof window === "undefined" || globalThis !== window) { const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); ChromeUtils.defineModuleGetter(this, "ContentDOMReference", "resource://gre/modules/ContentDOMReference.jsm"); ChromeUtils.defineModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); if (!Services.appinfo.remoteType) { this.EXPORTED_SYMBOLS = ["BDTranslator", "BDTranslatorParent"]; try { const actorParams = { parent: { moduleURI: __URI__, }, child: { moduleURI: __URI__, events: {}, }, allFrames: true, messageManagerGroups: ["browsers"], matches: [`*://*/*`], }; if (BDT_OPTIONS.hotkey.enabled) { if (BDT_OPTIONS.hotkey.repeat <= 0) BDT_OPTIONS.hotkey.repeat = 2; if (BDT_OPTIONS.hotkey.timeout <= 0) BDT_OPTIONS.hotkey.timeout = 500; actorParams.child.events.keyup = {}; } ChromeUtils.registerWindowActor("BDTranslator", actorParams); } catch (e) { Cu.reportError(e); } this.BDTranslatorParent = class extends JSWindowActorParent { receiveMessage({ name, data }) { // https://searchfox.org/mozilla-central/rev/43ee5e789b079e94837a21336e9ce2420658fd19/browser/actors/ContextMenuParent.sys.mjs#60-63 let browser = this.browsingContext.top.embedderElement; let win = browser.ownerGlobal; const { BDTranslator } = win; switch (name) { case "BDT:OpenTranlatorInTab": BDTranslator.translateTextInNewTab(data.sourceText, data.from, data.to); break; case "BDT:TranslateText": BDTranslator.translateText(data.sourceText, data.from, data.to).then(result => { this.sendAsyncMessage("BDT:TranslateReulult", { ...data, resultObject: result }) }) break; } } } } else { Cu.importGlobalProperties(["fetch"]); this.EXPORTED_SYMBOLS = ["BDTranslatorChild"]; const BDPopupTranslator = { popup: null, show(win, x, y, sourceText, resultObject) { const options = BDT_OPTIONS; if (resultObject && "trans_result" in resultObject) { this.fromLang = resultObject["trans_result"].from || "auto"; this.targetLang = resultObject["trans_result"].to || options.defaultLang } else { this.fromLang = "auto"; this.targetLang = options.defaultLang; } this.sourceText = sourceText.trim(); if (!win.document.getElementById("baidu-translator")) { this.popup = win.document.createElement("div"); this.popup.id = "baidu-translator" Object.assign(this.popup.style, { position: "absolute", top: `${win.scrollY + y}px`, left: `${win.scrollX + x}px`, width: "400px", maxHeight: "200px", fontFamily: "sans-serif", fontSize: "16px", color: "black", background: "floralwhite", border: "1px solid darkgray", borderRadius: "3px", boxShadow: "3px 3px 5px lightgray", transition: "opacity 0.2s ease", zIndex: "1000", }); const flex = win.document.createElement("div"); Object.assign(flex.style, { display: "flex", maxHeight: "200px", flexDirection: "column", }); const header = win.document.createElement("div"); Object.assign(header.style, { display: "flex", height: "auto", margin: "2px 5px 1px", fontSize: "smaller", alignItems: "center", }); const logo = win.document.createElement("div"); logo.textContent = "翻译结果"; Object.assign(logo.style, { width: "auto", fontWeight: "bold", flexGrow: "1", }); header.appendChild(logo); const langSelector = win.document.createElement("select"); for (let [lang, desc] of Object.entries(options.supportedLangs)) { const option = win.document.createElement("option"); option.value = lang; option.textContent = desc; langSelector.appendChild(option); } langSelector.value = this.targetLang; Object.assign(langSelector.style, { width: "auto", marginRight: "5px", }); langSelector.addEventListener("change", this); header.appendChild(langSelector); const more = win.document.createElement("div"); more.className = "baidu-translator-more"; more.textContent = "更多"; Object.assign(more.style, { width: "auto", cursor: "pointer", }); more.addEventListener("click", this); header.appendChild(more); flex.appendChild(header); const box = win.document.createElement("div"); box.className = "baidu-translator-box"; Object.assign(box.style, { height: "auto", overflow: "auto", background: "white", padding: "2px", margin: "1px 5px 5px", border: "1px solid darkgray", flexGrow: "1", whiteSpace: "pre-wrap", }); flex.appendChild(box); this.popup.appendChild(flex); win.document.body.appendChild(this.popup); win.setTimeout(() => win.addEventListener("click", this), 0); } else { this.setPos(x, y); } if (resultObject && "trans_result" in resultObject) { let data = resultObject.trans_result.data; this.setText(data.map(el => el.dst).join("\n")); } }, handleEvent(event) { const { type, target } = event; const actor = target.ownerGlobal.windowGlobalChild.getActor("BDTranslator"); switch (type) { case "click": if (!this.popup.contains(target)) { target.ownerGlobal.removeEventListener("click", this); this.popup.addEventListener("transitionend", ({ target }) => { target.parentNode.removeChild(target); }, { once: true }); this.popup.style.opacity = 0; } else if (target.className === "baidu-translator-more") { actor.sendAsyncMessage("BDT:OpenTranlatorInTab", { sourceText: this.sourceText, from: this.fromLang, to: this.targetLang, }); event.stopPropagation(); } break; case "change": this.targetLang = target.value; this.translate(actor, this.sourceText, this.fromLang, this.targetLang); break; } }, setPos(x, y) { Object.assign(this.popup.style, { top: `${win.scrollY + y}px`, left: `${win.scrollX + x}px`, opacity: 1 }); }, setText(text, color) { let box = this.popup.querySelector(".baidu-translator-box"); if (color) box.style.color = color; else box.style.color = null; box.textContent = text; }, translate(actor, text, from, to) { this.setText("正在翻译中...", "lightgray"); actor.sendAsyncMessage("BDT:TranslateText", { sourceText: text, from: from || this.fromLang, to: to || this.targetLang }); } } this.BDTranslatorChild = class extends JSWindowActorChild { actorCreated() { this.keyRepeat = 0; } createPopupWithScreenCoordinate(screenX, screenY, sourceText, resultObject) { let x = screenX - this.contentWindow.screenX - this.contentWindow.outerWidth + this.contentWindow.innerWidth; let y = screenY - this.contentWindow.screenY - this.contentWindow.outerHeight + this.contentWindow.innerHeight; this.createPopupWithClientCoordinate(x, y, sourceText, resultObject); } createPopupWithClientCoordinate(clientX, clientY, sourceText, resultObject) { let x = clientX; let y = clientY; let clientWidth = this.contentWindow.document.documentElement.clientWidth; let clientHeight = this.contentWindow.document.documentElement.clientHeight; if (x + 400 > clientWidth) x = clientWidth - 400; if (y + 200 > clientHeight) y = clientHeight - 200; x = Math.max(x, 0); y = Math.max(y, 0); if (resultObject) { BDPopupTranslator.show(this.contentWindow, x, y, sourceText, resultObject); } else { BDPopupTranslator.show(this.contentWindow, x, y, sourceText); BDPopupTranslator.translate(this.contentWindow.windowGlobalChild.getActor("BDTranslator"), sourceText); } } createPopupWithSelection() { const selection = this.contentWindow.getSelection(); const text = selection.toString().trim(); if (text) { let rect = selection.getRangeAt(0).getBoundingClientRect(); return this.createPopupWithClientCoordinate(rect.left, rect.top + rect.height, text); } return null; } receiveMessage({ name, data }) { switch (name) { case "BDT:CreatePopup": let fixupX = 0; let fixupY = 0; if (data.fixupX) fixupX = data.fixupX; if (data.fixupY) fixupY = data.fixupY; this.createPopupWithScreenCoordinate(data.screenX + fixupX, data.screenY + fixupY, data.sourceText, data.resultObject); break; case "BDT:TranslateReulult": let resultObject = data.resultObject; if (resultObject && "trans_result" in resultObject) { let data = resultObject.trans_result.data; BDPopupTranslator.setText(data.map(el => el.dst).join("\n")); } else { BDPopupTranslator.setText("翻译失败!", "red"); } break; case "BDT:CreatePopupWithClientCoordinate": this.createPopupWithClientCoordinate(data.clientX, data.clientY, data.sourceText).translate(data.fromLang, data.toLang); break; } } handleEvent(event) { switch (event.type) { case "keyup": if (event.code === BDT_OPTIONS.hotkey.code && this.contentWindow.getSelection()?.toString()) { if (!this.keyRepeat) { new Promise((resolve, reject) => { this.hotkeyResolver = resolve; this.hotkeyRejector = reject; this.contentWindow.setTimeout(() => reject(), BDT_OPTIONS.hotkey.timeout); }).then(() => { this.keyRepeat = 0; this.hotkeyResolver = null; this.hotkeyRejector = null; this.createPopupWithSelection(); }).catch(() => { this.keyRepeat = 0; this.hotkeyResolver = null; this.hotkeyRejector = null; }); } if (++this.keyRepeat === BDT_OPTIONS.hotkey.repeat) { this.hotkeyResolver(); } } else if (this.keyRepeat) { this.hotkeyRejector(); } 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("bdt-ucjs")) { resourceHandler.setSubstitution("bdt-ucjs", Services.io.newFileURI(scriptFile.parent)); } ChromeUtils.import(`resource://bdt-ucjs/${encodeURIComponent(scriptFile.leafName)}?${scriptFile.lastModifiedTime}`); } } catch (e) { console.error(e) } (function () { window.BDTranslator = { get appVersion() { delete this.appVersion; return this.appVersion = parseFloat(Services.appinfo.version); }, init: async function () { window.addEventListener('unload', this, false); /** * 获取必备头 */ let respText = await (await fetch("https://fanyi.baidu.com")).text(); this.gtk = /window\.gtk = ('|")(.*?)('|")/.exec(respText)[2]; this.token = /token: ('|")(.*?)('|")/.exec(respText)[2]; if (BDT_OPTIONS.enableContextMenu) this.addContextMenuitem(); }, /** * 添加右键菜单 */ addContextMenuitem() { const menuitem = $C("menuitem", { id: 'menu-translate-selected', label: "翻译选中文本" }); menuitem.addEventListener('command', this, false); this.menuitem = $('contentAreaContextMenu').appendChild(menuitem); $('contentAreaContextMenu').addEventListener('popupshowing', this); }, /** * 通过 API 获取语言 * @param {string} text 待检测文本 * @returns */ checkLang: async function (text) { const rawText = text.replace(/[\uD800-\uDBFF]$/, "").slice(0, 50); const data = new URLSearchParams(); data.append('query', rawText); const options = { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: data, }; try { const response = await fetch('https://fanyi.baidu.com/langdetect', options); const { lan } = await response.json(); return lan; } catch (error) { console.log(error); return; } }, /** * 网页翻译接口 * * @param {string} text 带翻译文本 * @param {string} from 源语言,不提供此参数则自动检测 * @param {string} to 目标语言,不提供则默认翻译为默认语言 * @returns */ translateText: async function (text, from, to) { if (!from) { from = await this.checkLang(text); } to || (to = BDT_OPTIONS.defaultLang); const processedText = text.length > 30 ? (text.substring(0, 10) + text.substring(~~(text.length / 2) - 5, ~~(text.length / 2) + 5) + text.substring(text.length - 10)) : text; const data = new URLSearchParams(); data.append('from', from); data.append('to', to); data.append('query', text); data.append('simple_means_flag', '3'); data.append('sign', calcTk(processedText, this.gtk)); data.append('token', this.token); data.append('domain', 'common'); const options = { method: 'POST', headers: { 'referer': 'https://fanyi.baidu.com', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', }, body: data, }; try { const response = await fetch('https://fanyi.baidu.com/v2transapi', options); const res = await response.json(); return res; // Process the response as needed } catch (error) { console.log(error); return; } }, /** * 打开翻译网页 * @param {string} text 待翻译文本 * @param {string} from 源语言 * @param {string} to 目标语言 */ translateTextInNewTab: function (text, from, to) { const urlTemplate = "https://fanyi.baidu.com/#{sourceLang}/{targetLang}/{sourceText}"; const url = urlTemplate.replace("{sourceLang}", from).replace("{targetLang}", to).replace("{sourceText}", text) if (this.appVersion < 78) { openUILinkIn(url, 'tab', false, null); } else { openWebLinkIn(url, 'tab', { postData: null, triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({ userContextId: gBrowser.selectedBrowser.getAttribute( "userContextId" ) }) }); } }, /** * 事件处理 * @param {*} event */ handleEvent: function (event) { switch (event.type) { case "unload": this.uninit(); break; case "command": this.beginTranslate(event.target.ownerGlobal.gContextMenu?.contentData); break; case "popupshowing": this.popupshowing(event.target.ownerGlobal); break; } }, /** * 点击菜单开始翻译 * * @param {*} contextMenuContentData * @returns */ beginTranslate: async function (contextMenuContentData) { if (!contextMenuContentData) return; const win = contextMenuContentData.browser.ownerGlobal; const selectionText = contextMenuContentData.selectionInfo?.fullText; const targetIdentifier = contextMenuContentData.context?.targetIdentifier; const screenX = contextMenuContentData.context?.screenX ?? contextMenuContentData.context?.screenXDevPx / win.devicePixelRatio; const screenY = contextMenuContentData.context?.screenY ?? contextMenuContentData.context?.screenYDevPx / win.devicePixelRatio; const browser = contextMenuContentData.browser; const browserBoundingRect = browser.getBoundingClientRect(); const fixupX = browser.ownerGlobal.outerWidth - browserBoundingRect.left - browserBoundingRect.width; const fixupY = 20 + browser.ownerGlobal.outerHeight - browserBoundingRect.top - browserBoundingRect.height; const actor = contextMenuContentData.frameBrowsingContext.currentWindowGlobal.getActor("BDTranslator"); let translatedResult = await this.translateText(selectionText); actor.sendAsyncMessage("BDT:CreatePopup", { targetIdentifier, screenX, screenY, fixupX, fixupY, sourceText: selectionText, resultObject: translatedResult }); }, /** * 没有选中文本的时候隐藏右键菜单 * @param {ChromeWindow} win */ popupshowing(win) { let selectionText = win.gContextMenu?.contentData?.selectionInfo?.text; this.menuitem.hidden = !selectionText; }, uninit: async function () { window.removeEventListener('unload', this, false); $('contentAreaContextMenu').removeEventListener('popupshowing', this); if (this.menuitem) this.menuitem.parentNode.removeChild(this.menuitem); delete window.BDTranslator; } } function $(id) { return document.getElementById(id); } function $C(tag, attrs, skipAttrs) { var el; if (!tag) return el; attrs = attrs || {}; skipAttrs = skipAttrs || []; if (tag.startsWith('html:')) el = document.createElement(tag); else el = document.createXULElement(tag); return $A(el, attrs, skipAttrs); } function $A(el, attrs, skipAttrs) { skipAttrs = skipAttrs || []; if (attrs) Object.keys(attrs).forEach(function (key) { if (!skipAttrs.includes(key)) { if (typeof attrs[key] === 'function') el.setAttribute(key, "(" + attrs[key].toString() + ").call(this, event);"); else el.setAttribute(key, attrs[key]); } }); return el; } /** 签名计算 */ function calcTk(a, b) { var d = b.split("."); b = Number(d[0]) || 0; for (var e = [], f = 0, g = 0; g < a.length; g++) { var k = a.charCodeAt(g); 128 > k ? e[f++] = k : (2048 > k ? e[f++] = k >> 6 | 192 : (55296 == (k & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (k = 65536 + ((k & 1023) << 10) + (a.charCodeAt(++g) & 1023), e[f++] = k >> 18 | 240, e[f++] = k >> 12 & 63 | 128) : e[f++] = k >> 12 | 224, e[f++] = k >> 6 & 63 | 128), e[f++] = k & 63 | 128) } a = b; for (f = 0; f < e.length; f++)a = Fo(a + e[f], "+-a^+6"); a = Fo(a, "+-3^+b+-f"); a ^= Number(d[1]) || 0; 0 > a && (a = (a & 2147483647) + 2147483648); a %= 1E6; return a.toString() + "." + (a ^ b) } function Fo(a, b) { for (var c = 0; c < b.length - 2; c += 3) { var d = b.charAt(c + 2); d = "a" <= d ? d.charCodeAt(0) - 87 : Number(d); d = "+" == b.charAt(c + 1) ? a >>> d : a << d; a = "+" == b.charAt(c) ? a + d & 4294967295 : a ^ d } return a } window.BDTranslator.init(); })()}
You can try this userchrome.js script
// ==UserScript==
// @name AutoCopySelectionText.uc.js
// @description 自动复制选中文本(ScrLk 亮起时不复制)
// @author Ryan
// @version 2022.07.28
// @compatibility Firefox 87
// @charset UTF-8
// @system windows
// @license MIT License
// @include main
// @shutdown window.AutoCopySelectionText.destroy();
// @homepageURL https://github.com/benzBrake/FirefoxCustomize/tree/master/userChromeJS
// @version 2022.07.28 网页支持文本框
// @version 2022.07.18 支持长按延时
// @version 2022.07.16 重写代码,支持热插拔,采用 异步消息,支持 Firefox 内置页面
// @version 2022.07.13 初始化版本
// ==/UserScript==
(function () {
class AutoCopySelectionText {
constructor() {
Components.utils.import("resource://gre/modules/ctypes.jsm");
// will be transfered to control by toolbar button
let user32 = ctypes.open("user32.dll");
this.getKeyState = user32.declare('GetKeyState', ctypes.winapi_abi, ctypes.bool, ctypes.int);
function frameScript() {
const { Services } = Components.utils.import(
"resource://gre/modules/Services.jsm"
);
// implement read from about:config preferences in future
var WAIT_TIME = 0; // Change it to any number as you want
var TRIM_SELECTION = true; // remove spaces before and after the string
// Do not modify below ------------------------------------------
var LONG_PRESS = false;
var TIMEOUT_ID = null;
function handleEvent(event) {
if (event.button !== 0) return; // only trigger when left button up
if (TIMEOUT_ID)
content.clearTimeout(TIMEOUT_ID);
const focusedElement =
Services.focus.focusedElement ||
event.originalTarget.ownerDocument?.activeElement;
switch (event.type) {
case 'mousemove':
TIMEOUT_ID = content.setTimeout(function () {
LONG_PRESS = true;
}, WAIT_TIME);
case 'mouseup':
// copy text on mouse button up
if (LONG_PRESS) {
let data = { text: getSelection(content, focusedElement) }
sendSyncMessage("acst_selectionData", data);
}
break;
}
LONG_PRESS = false;
}
// From addMenuPlus.uc.js
function getSelection(win, focusedElement) {
win || (win = content);
var selection = win.getSelection().toString();
if (!selection) {
let element = focusedElement;
let isOnTextInput = function (elem) {
return elem instanceof HTMLTextAreaElement ||
(elem instanceof HTMLInputElement && elem.mozIsTextField(true));
};
if (isOnTextInput(element)) {
selection = element.value.substring(element.selectionStart,
element.selectionEnd);
}
}
if (TRIM_SELECTION && selection) {
selection = selection.replace(/^\s+/, "")
.replace(/\s+$/, "")
.replace(/\s+/g, " ");
}
return selection;
}
["mousemove", "mouseup"].forEach((t) => addEventListener(t, handleEvent, false));
function receiveMessage(message) {
switch (message.name) {
case 'acst_destroy':
["mousemove", "mouseup"].forEach((t) => removeEventListener(t, handleEvent, false));
removeMessageListener("acst_destroy", receiveMessage);
handleEvent = null;
receiveMessage = null;
break;
}
}
addMessageListener("acst_destroy", receiveMessage);
}
let frameScriptURI = 'data:application/javascript,'
+ encodeURIComponent('(' + frameScript.toString() + ')()');
window.messageManager.loadFrameScript(frameScriptURI, true);
window.messageManager.addMessageListener("acst_selectionData", this);
}
receiveMessage(message) {
switch (message.name) {
case 'acst_selectionData':
if (this.getKeyState(0x91)) return;
if (message.data.text)
Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper).copyString(message.data.text);
break;
}
}
destroy() {
window.messageManager.broadcastAsyncMessage("acst_destroy");
window.messageManager.removeMessageListener("acst_selectionData", this);
delete window.AutoCopySelectionText;
}
}
window.AutoCopySelectionText = new AutoCopySelectionText();
})()
Alles anzeigen