From 653b19aa1e732f56453db383504fe8a5438bda5a Mon Sep 17 00:00:00 2001 From: Akshay Nair Date: Sun, 8 Feb 2026 13:15:45 +0530 Subject: Enable firefox --- modules/firefox.home/chrome/utils/userChrome.js | 272 ++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 modules/firefox.home/chrome/utils/userChrome.js (limited to 'modules/firefox.home/chrome/utils/userChrome.js') diff --git a/modules/firefox.home/chrome/utils/userChrome.js b/modules/firefox.home/chrome/utils/userChrome.js new file mode 100644 index 0000000..1870bee --- /dev/null +++ b/modules/firefox.home/chrome/utils/userChrome.js @@ -0,0 +1,272 @@ +'use strict'; + +(() => { + ChromeUtils.defineESModuleGetters(globalThis, { + xPref: 'chrome://userchromejs/content/xPref.sys.mjs', + Management: 'resource://gre/modules/Extension.sys.mjs', + AppConstants: 'resource://gre/modules/AppConstants.sys.mjs', + }); + + let UC = { + webExts: new Map(), + sidebar: new Map(), + sandboxes: new WeakMap() + }; + + let _uc = { + ALWAYSEXECUTE: 'rebuild_userChrome.uc.js', + BROWSERCHROME: AppConstants.MOZ_APP_NAME == 'thunderbird' ? 'chrome://messenger/content/messenger.xhtml' : 'chrome://browser/content/browser.xhtml', + BROWSERTYPE: AppConstants.MOZ_APP_NAME == 'thunderbird' ? 'mail:3pane' : 'navigator:browser', + BROWSERNAME: AppConstants.MOZ_APP_NAME.charAt(0).toUpperCase() + AppConstants.MOZ_APP_NAME.slice(1), + PREF_ENABLED: 'userChromeJS.enabled', + PREF_SCRIPTSDISABLED: 'userChromeJS.scriptsDisabled', + + chromedir: Services.dirsvc.get('UChrm', Ci.nsIFile), + scriptsDir: '', + + sss: Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService), + + getScripts: function () { + this.scripts = {}; + let files = this.chromedir.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator); + while (files.hasMoreElements()) { + let file = files.getNext().QueryInterface(Ci.nsIFile); + if (/\.uc\.js$/i.test(file.leafName)) { + _uc.getScriptData(file); + } + } + }, + + getScriptData: function (aFile) { + let aContent = this.readFile(aFile); + let header = (aContent.match(/^\/\/ ==UserScript==\s*\n(?:.*\n)*?\/\/ ==\/UserScript==\s*\n/m) || [''])[0]; + let match, rex = { + include: [], + exclude: [] + }; + let findNextRe = /^\/\/ @(include|exclude)\s+(.+)\s*$/gm; + while ((match = findNextRe.exec(header))) { + rex[match[1]].push(match[2].replace(/^main$/i, _uc.BROWSERCHROME).replace(/\*/g, '.*?')); + } + if (!rex.include.length) { + rex.include.push(_uc.BROWSERCHROME); + } + let exclude = rex.exclude.length ? '(?!' + rex.exclude.join('$|') + '$)' : ''; + + let def = ['', '']; + let author = (header.match(/\/\/ @author\s+(.+)\s*$/im) || def)[1]; + let filename = aFile.leafName || ''; + + return this.scripts[filename] = { + filename: filename, + file: aFile, + url: Services.io.getProtocolHandler('file').QueryInterface(Ci.nsIFileProtocolHandler).getURLSpecFromDir(this.chromedir) + filename, + name: (header.match(/\/\/ @name\s+(.+)\s*$/im) || def)[1], + description: (header.match(/\/\/ @description\s+(.+)\s*$/im) || def)[1], + version: (header.match(/\/\/ @version\s+(.+)\s*$/im) || def)[1], + author: (header.match(/\/\/ @author\s+(.+)\s*$/im) || def)[1], + regex: new RegExp('^' + exclude + '(' + (rex.include.join('|') || '.*') + ')$', 'i'), + id: (header.match(/\/\/ @id\s+(.+)\s*$/im) || ['', filename.split('.uc.js')[0] + '@' + (author || 'userChromeJS')])[1], + homepageURL: (header.match(/\/\/ @homepageURL\s+(.+)\s*$/im) || def)[1], + downloadURL: (header.match(/\/\/ @downloadURL\s+(.+)\s*$/im) || def)[1], + updateURL: (header.match(/\/\/ @updateURL\s+(.+)\s*$/im) || def)[1], + optionsURL: (header.match(/\/\/ @optionsURL\s+(.+)\s*$/im) || def)[1], + startup: (header.match(/\/\/ @startup\s+(.+)\s*$/im) || def)[1], + shutdown: (header.match(/\/\/ @shutdown\s+(.+)\s*$/im) || def)[1], + onlyonce: /\/\/ @onlyonce\b/.test(header), + isRunning: false, + get isEnabled() { + return (xPref.get(_uc.PREF_SCRIPTSDISABLED) || '').split(',').indexOf(this.filename) == -1; + } + } + }, + + readFile: function (aFile, metaOnly = false) { + let stream = Cc['@mozilla.org/network/file-input-stream;1'].createInstance(Ci.nsIFileInputStream); + stream.init(aFile, 0x01, 0, 0); + let cvstream = Cc['@mozilla.org/intl/converter-input-stream;1'].createInstance(Ci.nsIConverterInputStream); + cvstream.init(stream, 'UTF-8', 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + let content = '', + data = {}; + while (cvstream.readString(4096, data)) { + content += data.value; + if (metaOnly && content.indexOf('// ==/UserScript==') > 0) { + break; + } + } + cvstream.close(); + return content.replace(/\r\n?/g, '\n'); + }, + + everLoaded: [], + + loadScript: function (script, win) { + if (!script.regex.test(win.location.href) || (script.filename != this.ALWAYSEXECUTE && !script.isEnabled)) { + return; + } + + if (script.onlyonce && script.isRunning) { + if (script.startup) { + Cu.evalInSandbox(`(function(script, win){${script.startup}})`, this.getSandbox(win))(script, win); + } + return; + } + + try { + Services.scriptloader.loadSubScript(script.url + '?' + script.file.lastModifiedTime, + script.onlyonce ? { window: win } : win); + script.isRunning = true; + if (script.startup) { + Cu.evalInSandbox(`(function(script, win){${script.startup}})`, this.getSandbox(win))(script, win); + } + if (!script.shutdown) { + this.everLoaded.push(script.id); + } + } catch (ex) { + Cu.reportError(ex); + } + }, + + getSandbox: function (doc) { + if (!UC.sandboxes) UC.sandboxes = new WeakMap(); + let global = Cu.getGlobalForObject(doc); + if (UC.sandboxes.has(global)) + return UC.sandboxes.get(global); + let sb = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal(), { + sandboxPrototype: global, + sameZoneAs: global, + wantXrays: false, + sandboxName: 'UCJS:Sandbox' + }); + UC.sandboxes.set(global, sb); + global.addEventListener('unload', () => { + UC.sandboxes.delete(global); + Cu.nukeSandbox(sb); + }); + return sb; + }, + + windows: function (fun, onlyBrowsers = true) { + let windows = Services.wm.getEnumerator(onlyBrowsers ? this.BROWSERTYPE : null); + while (windows.hasMoreElements()) { + let win = windows.getNext(); + if (!win._uc) + continue; + if (!onlyBrowsers) { + let frames = win.docShell.getAllDocShellsInSubtree(Ci.nsIDocShellTreeItem.typeAll, Ci.nsIDocShell.ENUMERATE_FORWARDS); + let res = frames.some(frame => { + let fWin = frame.domWindow; + let {document, location} = fWin; + if (fun(document, fWin, location)) + return true; + }); + if (res) + break; + } else { + let {document, location} = win; + if (fun(document, win, location)) + break; + } + } + }, + + createElement: function (doc, tag, atts, XUL = true) { + let el = XUL ? doc.createXULElement(tag) : doc.createElement(tag); + for (let att in atts) { + if (att.startsWith('on')) + el.addEventListener(att.slice(2), typeof atts[att] == "string" ? + Cu.evalInSandbox(`(function(event){${atts[att]}})`, this.getSandbox(doc)) : atts[att]); + else + el.setAttribute(att, atts[att]); + } + return el + } + }; + + if (xPref.get(_uc.PREF_ENABLED) === undefined) { + xPref.set(_uc.PREF_ENABLED, true, true); + } + + if (xPref.get(_uc.PREF_SCRIPTSDISABLED) === undefined) { + xPref.set(_uc.PREF_SCRIPTSDISABLED, '', true); + } + + let UserChrome_js = { + observe: function (aSubject) { + if ( + AppConstants.MOZ_APP_NAME == "thunderbird" && + aSubject?.location?.href.startsWith("chrome://messenger/content") + ) { + aSubject.addEventListener("DOMContentLoaded", () => { + this.load(aSubject); + }, {once: true}) + } else { + aSubject.addEventListener('DOMContentLoaded', this, {once: true}); + } + }, + + handleEvent: function (aEvent) { + let document = aEvent.originalTarget; + let window = document.defaultView; + if (window.document.isInitialDocument) { + this.load(window.parent); + } else { + this.load(window); + } + }, + + load: function (window) { + let location = window.location; + + if (!this.sharedWindowOpened && location.href == 'chrome://extensions/content/dummy.xhtml') { + this.sharedWindowOpened = true; + + Management.on('extension-browser-inserted', function (topic, browser) { + browser.messageManager.addMessageListener('Extension:BackgroundViewLoaded', this.messageListener.bind(this)); + }.bind(this)); + } else if (/^(chrome:(?!\/\/global\/content\/commonDialog\.x?html)|about:(?!blank))/i.test(location.href)) { + window.UC = UC; + window._uc = _uc; + window.xPref = xPref; + if (window._gBrowser) // bug 1443849 + window.gBrowser = window._gBrowser; + + if (xPref.get(_uc.PREF_ENABLED)) { + Object.values(_uc.scripts).forEach(script => { + _uc.loadScript(script, window); + }); + } else if (!UC.rebuild) { + _uc.loadScript(_uc.scripts[_uc.ALWAYSEXECUTE], window); + } + } + }, + + messageListener: function (msg) { + const browser = msg.target; + const { addonId } = browser._contentPrincipal; + + browser.messageManager.removeMessageListener('Extension:BackgroundViewLoaded', this.messageListener); + + if (browser.ownerGlobal.location.href == 'chrome://extensions/content/dummy.xhtml') { + UC.webExts.set(addonId, browser); + Services.obs.notifyObservers(null, 'UCJS:WebExtLoaded', addonId); + } else { + let win = browser.ownerGlobal.windowRoot.ownerGlobal; + UC.sidebar.get(addonId)?.set(win, browser) || UC.sidebar.set(addonId, new Map([[win, browser]])); + Services.obs.notifyObservers(win, 'UCJS:SidebarLoaded', addonId); + } + } + }; + + if (!Services.appinfo.inSafeMode) { + _uc.chromedir.append(_uc.scriptsDir); + _uc.getScripts(); + let windows = Services.wm.getEnumerator(null); + while (windows.hasMoreElements()) { + let win = windows.getNext(); + if (!('UC' in win)) + UserChrome_js.load(win) + } + Services.obs.addObserver(UserChrome_js, 'chrome-document-global-created', false); + } +})(); -- cgit v1.3.1