Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firefox 115 cannot verify addon #233

Closed
TheGrave opened this issue Jun 29, 2023 · 118 comments
Closed

Firefox 115 cannot verify addon #233

TheGrave opened this issue Jun 29, 2023 · 118 comments

Comments

@TheGrave
Copy link

Today I upgraded from 114 to 115 and ka-boom:

https://ibb.co/ykx7FFh
https://ibb.co/yhGqgr8

@onemen
Copy link
Owner

onemen commented Jun 29, 2023

  1. Remove Tab Mix and close Firefox.
  2. Open Firefox go to firefox-scripts and make sure you have the latest versions, If you need to update the files follow the instructions as if you are installing it for the first time.
  3. After installing firefox-scripts close Firefox.
  4. Open Firefox and download latest Tab mix.
  5. install Tab mix

@TheGrave
Copy link
Author

Firefox scripts have not been updated for years, they are installed and working. I removed TabMix and now I can no longer install it due to the same error - unsigned add-on.

@TheGrave
Copy link
Author

After multiple tries, Firefox crashes and whatnot I managed to re-install it as a temporary add-on. Something got messed up in FF 115.

@TheGrave TheGrave reopened this Jun 29, 2023
@TheGrave
Copy link
Author

TheGrave commented Jun 29, 2023

Nope, sorry, this is ongoing. Same story after re-launching Firefox. Extension can now be loaded only as a temporary add-on.

@onemen
Copy link
Owner

onemen commented Jun 30, 2023

Firefox scripts have not been updated for years.

It was updated, this year.

Just go to firefox-scripts and follow the instruction from start.

you can try to clear your profile cache, to to about config, find your profile, and follow the link to 'Local Directory' where Firefox save your profile cache, and remove it
profile

other option is to create new profile, if you do, make sure to install firefox-scripts files in the new profile chrome/utils

read this for more tips #159

@TheGrave
Copy link
Author

TheGrave commented Jun 30, 2023

I installed it in Jan 2023. Checked all files MD5 sums, they are good.

I'm on Ubuntu, I cleared the startup cache - made my laptop freeze a few times till I got it to run successfully. There are other issues with this version of FF too but downgrading doesn't let me in - asks me to create a new profile cause it MIGHT corrupt my bookmarks or whatever. I'll see if I can get around this bs somehow.

@TheGrave
Copy link
Author

TheGrave commented Jun 30, 2023

Noticed the following error but not sure what's causing it:

Missing chrome or resource URL: chrome://userchromejs/content/userChrome.jsm

As mentioned firefox-scripts files are as they should be. Permissions are OK, files are OK...I'm running out of ideas.

P.P. Got it, it's a cosmetic error. userChrome.jsm is included only in the package that is used for both scripts and extensions so it's non-presence shouldn't affect anything. extracted it to get rid of the error but I still cannot install the add-on except as a temporary one.

@onemen
Copy link
Owner

onemen commented Jul 1, 2023

@TheGrave ,

I have tested Firefox beta and nightly on my ubuntu with Oracle VM VirtualBox and Tab Mix Plus work as before.

It look like firefox-scripts files was installed in your profile correctly, however the scripts that need to activate the code that allow legacy extensions to work on modern Firefox wan not installed or maybe removed when you upgraded to Firefox 115.

If you are using Firefox snap the location for the binary script changed since Firefox 108 snap.
Follow the information I have provided last year from this link

If you are using regular non-snap Firefox go to about:support look in the path from Application Binary and make sure the files:
BINARY_PATH/config.js and BINARY_PATH/defaults/pref/config-prefs.js exist and that they are up-to-date

@TheGrave
Copy link
Author

TheGrave commented Jul 1, 2023

No snap, only official repos and .js files are latest versions, correct permissions and where they should be or...see official guide:

xiaoxiaoflood/firefox-scripts#8 (comment)

Path is given as:

/usr/lib/firefox/browser/defaults/preferences/config-prefs.js

Yours renders to:

/usr/lib/firefox/defaults/pref/config-prefs.js

Which is the correct one?

I have it in both places now, still the same story.

@onemen
Copy link
Owner

onemen commented Jul 1, 2023

the correct path is ...../firefox/defaults/pref/config-prefs.js

config.js must be in ...../firefox/config.js

when you open Firefox, check before anything else if you see any messages in the Browser console regarding the config.js file

@TheGrave
Copy link
Author

TheGrave commented Jul 1, 2023

Nope, no errors regarding the config files in either view:

https://ibb.co/pPCYYDM

@onemen
Copy link
Owner

onemen commented Jul 1, 2023

the file config.js have to be in the same folder with firefox.exe

@onemen
Copy link
Owner

onemen commented Jul 1, 2023

Follow this steps to identify any errors from config.js

  • in about:config set browser.dom.window.dump.enabled to true
  • close Firefox
  • replace BINARY_PATH/config.js with this version, the file config.js have to be in the same folder with firefox.exe
  • open terminal from your desktop and enter this commnad, replace the PATH_TO_BINARY with your path
    "/PATH_TO_BINARY/firefox-bin" -console > log.txt 2>&1
    this comand will start firefox and creat log.txt in your desktop folder
  • report what is the content of the log file.
// skip 1st line
lockPref('xpinstall.signatures.required', false)
lockPref('extensions.install_origins.enabled', false)

try {
  dump('start config.js\n')
  const cmanifest = Cc['@mozilla.org/file/directory_service;1'].getService(Ci.nsIProperties).get('UChrm', Ci.nsIFile);
  cmanifest.append('utils');
  cmanifest.append('chrome.manifest');
  Components.manager.QueryInterface(Ci.nsIComponentRegistrar).autoRegister(cmanifest);

  const objRef = ChromeUtils.import('resource://gre/modules/addons/AddonSettings.jsm');
  const temp = Object.assign({}, Object.getOwnPropertyDescriptors(objRef.AddonSettings), {
    REQUIRE_SIGNING: { value: false }
  });
  objRef.AddonSettings = Object.defineProperties({}, temp);

  Cu.import('chrome://userchromejs/content/BootstrapLoader.jsm');
} catch (ex) {
  dump(ex)
};

try {
  Cu.import('chrome://userchromejs/content/userChrome.jsm');
} catch (ex) {
  dump(ex)
};

@TheGrave
Copy link
Author

TheGrave commented Jul 2, 2023

the file config.js have to be in the same folder with firefox.exe

I keep repeating that I'm on Ubuntu, there is no firefox.exe here :)

Here are the log contents:

`start config.js

ATTENTION: default value of option mesa_glthread overridden by environment.
ATTENTION: default value of option mesa_glthread overridden by environment.
ATTENTION: default value of option mesa_glthread overridden by environment.

console.warn: TopSitesFeed: Failed to fetch data from Contile server: cacheHeader is null`

@onemen
Copy link
Owner

onemen commented Jul 2, 2023

I have no idea why it doesn't work for you

@117649
Copy link
Contributor

117649 commented Jul 2, 2023

@TheGrave How about run this :(await AddonManager.getAddonByID("{dc572301-7619-498c-a57d-39143191b318}")).__AddonInternal__.signedState = AddonManager.SIGNEDSTATE_NOT_REQUIRED in the browser console then clear startup cache and restart browser?

@TheGrave
Copy link
Author

TheGrave commented Jul 2, 2023

I think something is missing in this command, I get "AddonManager is not defined".

@halt76
Copy link

halt76 commented Jul 3, 2023

Doesn't work on latest version.
try this.
xiaoxiaoflood/firefox-scripts@66e896e

@117649
Copy link
Contributor

117649 commented Jul 3, 2023

I think something is missing in this command, I get "AddonManager is not defined".

Run that in this console https://imgbb.com/pPCYYDM

@TheGrave
Copy link
Author

TheGrave commented Jul 4, 2023

I think something is missing in this command, I get "AddonManager is not defined".

Run that in this console https://imgbb.com/pPCYYDM

There is only a filter field in this console. As ignorant as I am I think this is JS code that needs to be executed so definitely not the place.

@TheGrave
Copy link
Author

TheGrave commented Jul 4, 2023

Doesn't work on latest version. try this. xiaoxiaoflood/firefox-scripts@66e896e

Not following. This looks like an old patch to me, are you experiencing the problem as well in Firefox 115?

@halt76
Copy link

halt76 commented Jul 4, 2023

Doesn't work on latest version. try this. xiaoxiaoflood/firefox-scripts@66e896e

Not following. This looks like an old patch to me, are you experiencing the problem as well in Firefox 115?

This will solve the problem of not being able to validate the certificate.

@onemen
Copy link
Owner

onemen commented Jul 4, 2023

@TheGrave ,

run this is your browser console
ChromeUtils.import('resource://gre/modules/addons/AddonSettings.jsm').AddonSettings.REQUIRE_SIGNING

If the output is false in mean your config.js work as expected and the problem is in another place. if the output is true then the problem is in config.js

report back and we continue to search for solution...

@TheGrave
Copy link
Author

TheGrave commented Jul 4, 2023

@TheGrave ,

run this is your browser console ChromeUtils.import('resource://gre/modules/addons/AddonSettings.jsm').AddonSettings.REQUIRE_SIGNING

If the output is false in mean your config.js work as expected and the problem is in another place. if the output is true then the problem is in config.js

report back and we continue to search for solution...

https://ibb.co/GRGxJ0X

@TheGrave
Copy link
Author

TheGrave commented Jul 4, 2023

I revisited some of your previous tips and re-did the dumping in the log file. Now I got something interesting:

> cat log.txt start config.js ATTENTION: default value of option mesa_glthread overridden by environment. ATTENTION: default value of option mesa_glthread overridden by environment. ATTENTION: default value of option mesa_glthread overridden by environment. console.warn: TopSitesFeed: Failed to fetch data from Contile server: cacheHeader is null JavaScript error: undefined, line 0: Error: Missing host permission for the tab JavaScript error: undefined, line 0: Error: Missing host permission for the tab JavaScript error: undefined, line 0: Error: Missing host permission for the tab JavaScript error: undefined, line 0: Error: Missing host permission for the tab JavaScript error: undefined, line 0: Error: Missing host permission for the tab JavaScript error: undefined, line 0: Error: Missing host permission for the tab JavaScript error: moz-extension://1b8c3205-3227-40b8-89ce-163bf8944c36/scripts/services/ExtensionMessagingService.js, line 89: Error: Promised response from onMessage listener went out of scope

@TheGrave
Copy link
Author

TheGrave commented Jul 4, 2023

Doesn't work on latest version. try this. xiaoxiaoflood/firefox-scripts@66e896e

Not following. This looks like an old patch to me, are you experiencing the problem as well in Firefox 115?

This will solve the problem of not being able to validate the certificate.

After reverting the files to this commit the only thing happend is my browser got screwed REAL BAD :) No tabs shown, no extensions loaded, drop-down menus can be pulled but no item can be entered.

@117649
Copy link
Contributor

117649 commented Jul 4, 2023

@TheGrave ,
run this is your browser console ChromeUtils.import('resource://gre/modules/addons/AddonSettings.jsm').AddonSettings.REQUIRE_SIGNING
If the output is false in mean your config.js work as expected and the problem is in another place. if the output is true then the problem is in config.js
report back and we continue to search for solution...

https://ibb.co/GRGxJ0X

This console
image

Its called browser toolbox.

@onemen
Copy link
Owner

onemen commented Jul 4, 2023

@TheGrave

always use the browser console when debugging Firefox or extension. the console you open is the page console.

try this command again from the browser console
ChromeUtils.import('resource://gre/modules/addons/AddonSettings.jsm').AddonSettings.REQUIRE_SIGNING

console

@gelirhil
Copy link

don't remove cmanifest.append('chrome.manifest'); on windows 10

Nothing changed, still This add-on could not be installed because it appears to be corrupt.

I attached all my config files in current state (cmanifest.append('chrome.manifest'); was returned to config.js). I chose "only extensions" option for firefox-scripts so no userChrome.jsm for me.
config.zip

@Shahius
Copy link

Shahius commented Jul 15, 2023

@gelirhil,
Same here. Still cannot install. Same message.
Windows 10 and 117.0a1
So, I checked everything, looks correct. Tried this and that, but no luck. So, I am just coming here and hope to read something that will resolve the issue. Some clue to try. So far, I am returning back to Waterfox Classic or Basilisk browser. I cannot live without TabMixPlus.

@marty60
Copy link

marty60 commented Jul 15, 2023

TMP v1.0.0-pre.16 installed for me in 115.0 - 117.0. Try changing the config.js file to this, it's Dumby's code who manages the Custom Buttons addon

config.zip

@gelirhil
Copy link

Sorry for confusion. I believe now it was my mistake. I incorrectly placed firefox-scripts files into \profile\chrome\ instead of \profile\chrome\utils\. After fixing this TMP successfully installed and now continues to make me happy.

I'm attaching once again all my current config files. cmanifest.append('chrome.manifest'); presents in config.js
config.zip

@Brenex
Copy link

Brenex commented Jul 15, 2023

Thanks, #233 (comment) fixed it for me on OSX 13.4.1 and firefox 115.0.2

@Shahius
Copy link

Shahius commented Jul 15, 2023

Sorry for confusion. I believe now it was my mistake. I incorrectly placed firefox-scripts files into \profile\chrome\ instead of \profile\chrome\utils\. After fixing this TMP successfully installed and now continues to make me happy.

I'm attaching once again all my current config files. cmanifest.append('chrome.manifest'); presents in config.js config.zip

Thank you. I took files from your archive. All is working now for me too. Thank you!

@AzraelGH
Copy link

AzraelGH commented Jul 18, 2023

@onemen thank YOU for your work!
#233 (comment) works on 115.0.2 Win10

@marty60 and @gelirhil your Config also worked.

@Massimo-B
Copy link

I replaced the config.js file from https://raw.githubusercontent.com/xiaoxiaoflood/firefox-scripts/master/fx-folder.zip with https://github.com/xiaoxiaoflood/firefox-scripts/blob/66e896ec1514499557b64ce205104b04cdb8444a/installation-folder/config.js.

Solved the issue for www-client/firefox-bin-115.0.2 on Gentoo with installation in /opt/firefox .

@decembre
Copy link

Thanks for the config.js config.zip.

I also took files from your archive and copy them to the right place... after reading carefully your explanations.

I resume (if i don't make a mistake):

  • In firefox.exe, your config.js and the "default" folder.
  • I my "chrome" folder of my Firefox Profile, your "utils" folder.

AND All is working now for me too for:

115.0.3 Firefox Release
July 27, 2023

Thank you guys !
;-)

@markus88at
Copy link

Thanks a lot for all these tips in here, I managed to install TMP via the config.zip archive posted by decembre on 117.0b3 Developer Edition (it includes the config.js, config-prefs.js and %ffprofile%/chrome/utils directory).
The only problem left is that it royally screws up the context menus and the setting menu for me, which makes it kinda unusable again - any hints about that?
image
image

@onemen
Copy link
Owner

onemen commented Aug 5, 2023

Uninstall Tab mix.
Download an install latest vesion

@markus88at
Copy link

Interesting, while I used the same XPI as before (it was the latest), it works properly now after I simply reinstalled TMP again. Could have figured myself, thanks!

@AbolfazlP9
Copy link

AbolfazlP9 commented Sep 5, 2023

Hi @onemen .
I'm using the last ver. of FF.
I can't install the last ver. of TMP.
I do everything correctly, but I can't install it.
TMP

@onemen
Copy link
Owner

onemen commented Sep 5, 2023

firefox

  1. Install latest scripts to your Application Binary folder, config scripts.
  2. Profile Folder is the path to create chrome folder and install utils folder in it.
  3. Remove Tab mix extension.
  4. got to about:config and set extensions.experiments.enabled to true
  5. Open about:support and click "Clear startup cache…" to force Firefox to load userChromeJS on the next startup.
  6. Start Firefox again.
  7. Install Tab mix again.

@foxtom22
Copy link

foxtom22 commented Sep 6, 2023

1. Install latest scripts to your Application Binary folder, [config scripts](https://github.com/onemen/TabMixPlus/files/12257459/fx-folder.zip).
2. Profile Folder is the path to create chrome folder and install [utils](https://github.com/onemen/TabMixPlus/files/12257460/utils_extensions_and_scripts.zip) folder in it.
3. Remove Tab mix extension.
4. got to `about:config` and set `extensions.experiments.enabled` to `true`
5. Open about:support and click "Clear startup cache…" to force Firefox to load userChromeJS on the next startup.
6. Start Firefox again.
7. Install Tab mix again.

Not working here sadly

@onemen
Copy link
Owner

onemen commented Sep 7, 2023

try to create new profile

@AbolfazlP9
Copy link

firefox

1. Install latest scripts to your Application Binary folder, [config scripts](https://github.com/onemen/TabMixPlus/files/12257459/fx-folder.zip).

2. Profile Folder is the path to create chrome folder and install [utils](https://github.com/onemen/TabMixPlus/files/12257460/utils_extensions_and_scripts.zip) folder in it.

3. Remove Tab mix extension.

4. got to `about:config` and set `extensions.experiments.enabled` to `true`

5. Open about:support and click "Clear startup cache…" to force Firefox to load userChromeJS on the next startup.

6. Start Firefox again.

7. Install Tab mix again.

Thank you so much @onemen
It worked.

@Massimo-B
Copy link

Almost every Firefox update I need to fix something like removing TMP extension, reinstalling all the custom JS, it's getting a lot of work to keep that addon working just for getting multi-line tabs. This time, updated to Firefox 117.0, it is not sufficient to just uninstall TMP. Again I need to check if there is any change on those custom JS. Any idea?

@TheGrave
Copy link
Author

TheGrave commented Sep 11, 2023

Almost every Firefox update I need to fix something like removing TMP extension, reinstalling all the custom JS, it's getting a lot of work to keep that addon working just for getting multi-line tabs. This time, updated to Firefox 117.0, it is not sufficient to just uninstall TMP. Again I need to check if there is any change on those custom JS. Any idea?

Script it. At least on Windows you have some workaround. Firefox Scripts hasn't been fixed for Linux for the 2+ months since I reported this bug.

@117649
Copy link
Contributor

117649 commented Sep 11, 2023

Almost every Firefox update I need to fix something like removing TMP extension, reinstalling all the custom JS, it's getting a lot of work to keep that addon working just for getting multi-line tabs. This time, updated to Firefox 117.0, it is not sufficient to just uninstall TMP. Again I need to check if there is any change on those custom JS. Any idea?

Have the fixes in place before you grant permission to the update.
You can have the ff open let it install the update but don't agree to restart instead put all the fixes in place at this time then you can restart and have a seamless update.
If an add-on is disabled by ff due to scripts are failed it can not be manually re-enabled. You can only either go through the console or reinstall it.

@Massimo-B
Copy link

Script it. At least on Windows you have some workaround. Firefox Scripts hasn't been fixed for Linux for the 2+ months since I reported this bug.

That means there is no patch of the scripts for Linux right now and I need to patch it manually?
Ok, again. What do I need?
I know how to script it, but I don't know where to get the patch from this time again.

@117649
Copy link
Contributor

117649 commented Sep 11, 2023

Script it. At least on Windows you have some workaround. Firefox Scripts hasn't been fixed for Linux for the 2+ months since I reported this bug.

That means there is no patch of the scripts for Linux right now and I need to patch it manually? Ok, again. What do I need? I know how to script it, but I don't know where to get the patch from this time again.

#237 (comment)
It should work for linux plus you know where to put them on linux(I don't).

@TheGrave
Copy link
Author

It doesn't. You get an empty screen Firefox and the app is unusable, been reported multiple times. Test it in a VM.

@TheGrave
Copy link
Author

Script it. At least on Windows you have some workaround. Firefox Scripts hasn't been fixed for Linux for the 2+ months since I reported this bug.

That means there is no patch of the scripts for Linux right now and I need to patch it manually? Ok, again. What do I need? I know how to script it, but I don't know where to get the patch from this time again.

Patch it manually with what exactly? I haven't seen a working version of firefox-scripts for versions above 115 on Ubuntu and I tested all suggestions in the tickets related to this bug in both repos.

@Massimo-B
Copy link

I'm going to take a break with TMP on Linux now...
Only important features for me are multi-line tabs and Auto-reload.

@TheGrave
Copy link
Author

I'm going to take a break with TMP on Linux now... Only important features for me are multi-line tabs and Auto-reload.

I'm going to look for alternatives too. This has become too much of a burden to deal with and I'm tired of trashing a working browser on a regular basis with these scripts.

@TheGrave
Copy link
Author

TheGrave commented Sep 14, 2023

I'm going to take a break with TMP on Linux now... Only important features for me are multi-line tabs and Auto-reload.

I figured it. What is missing from this guide:

#237 (comment)

is that you need a file called rebuild_userChrome.uc.js in the chrome folder with the following contents:

// ==UserScript==
// @name userChromeJS Manager
// @include main
// @author xiaoxiaoflood
// @onlyonce
// ==/UserScript==

// original: https://github.com/alice0775/userChrome.js/blob/master/rebuild_userChrome.uc.xul

UC.rebuild = {
PREF_TOOLSBUTTON: 'userChromeJS.showtoolbutton',
PREF_OPENWITHSYSTEMDEFAULT: 'userChromeJS.openWithSystemDefault',

menues: [],

onpopup: function (event) {
let document = event.target.ownerDocument;

if (event.target != document.getElementById('userChromejs_options'))
  return;

while (document.getElementById('uc-menuseparator').nextSibling) {
  document.getElementById('uc-menuseparator').nextSibling.remove();
}

let enabled = xPref.get(_uc.PREF_ENABLED);

let mi = event.target.appendChild(this.elBuilder(document, 'menuitem', {
  label: enabled ? 'Enabled' : 'Disabled (click to Enable)',
  oncommand: 'xPref.set(_uc.PREF_ENABLED, ' + !enabled + ');',
  type: 'checkbox',
  checked: enabled
}));

if (Object.keys(_uc.scripts).length > 1)
  event.target.appendChild(this.elBuilder(document, 'menuseparator'));

Object.values(_uc.scripts).sort((a, b) => a.name.localeCompare(b.name)).forEach(script => {
  if (script.filename === _uc.ALWAYSEXECUTE) {
    return;
  }

  mi = event.target.appendChild(this.elBuilder(document, 'menuitem', {
    label: script.name ? script.name : script.filename,
    onclick: 'UC.rebuild.clickScriptMenu(event)',
    onmouseup: 'UC.rebuild.shouldPreventHide(event)',
    type: 'checkbox',
    checked: script.isEnabled,
    class: 'userChromejs_script',
    restartless: !!script.shutdown
  }));
  mi.filename = script.filename;
  let homepage = script.homepageURL || script.downloadURL || script.updateURL || script.reviewURL;
  if (homepage)
    mi.setAttribute('homeURL', homepage);
  mi.setAttribute('tooltiptext', `
    Left-Click: Enable/Disable
    Middle-Click: Enable/Disable and keep this menu open
    Right-Click: Edit
    Ctrl + Left-Click: Reload Script
    Ctrl + Middle-Click: Open Homepage
    Ctrl + Right-Click: Uninstall
  `.replace(/^\n| {2,}/g, '') + (script.description ? '\nDescription: ' + script.description : '')
                              + (homepage ? '\nHomepage: ' + homepage : ''));

  event.target.appendChild(mi);
});

document.getElementById('showToolsMenu').setAttribute('label', 'Switch to ' + (this.showToolButton ? 'button in Navigation Bar' : 'item in Tools Menu'));

},

onHamPopup: function (aEvent) {
const enabledMenuItem = aEvent.target.querySelector('#appMenu-userChromeJS-enabled');
enabledMenuItem.checked = xPref.get(_uc.PREF_ENABLED);

// Clear existing scripts menu entries
const scriptsSeparator = aEvent.target.querySelector('#appMenu-userChromeJS-scriptsSeparator');
while (scriptsSeparator.nextSibling) {
  scriptsSeparator.nextSibling.remove();
}

// Populate with new entries
let scriptMenuItems = [];
Object.values(_uc.scripts).sort((a, b) => a.name.localeCompare(b.name)).forEach(script => {
  if (_uc.ALWAYSEXECUTE.includes(script.filename))
    return;

  let scriptMenuItem = UC.rebuild.createMenuItem(scriptsSeparator.ownerDocument, null, null, script.name ? script.name : script.filename);
  scriptMenuItem.setAttribute('onclick', 'UC.rebuild.clickScriptMenu(event)');
  scriptMenuItem.type = 'checkbox';
  scriptMenuItem.checked = script.isEnabled;
  scriptMenuItem.setAttribute('restartless', !!script.shutdown);
  scriptMenuItem.filename = script.filename;
  let homepage = script.homepageURL || script.downloadURL || script.updateURL || script.reviewURL;
  if (homepage)
    scriptMenuItem.setAttribute('homeURL', homepage);
  scriptMenuItem.setAttribute('tooltiptext', `
    Left-Click: Enable/Disable
    Middle-Click: Enable/Disable and keep this menu open
    Right-Click: Edit
    Ctrl + Left-Click: Reload Script
    Ctrl + Middle-Click: Open Homepage
    Ctrl + Right-Click: Uninstall
  `.replace(/^\n| {2,}/g, '') + (script.description ? '\nDescription: ' + script.description : '')
                              + (homepage ? '\nHomepage: ' + homepage : ''));      
  scriptMenuItems.push(scriptMenuItem);
});

scriptsSeparator.parentElement.append(...scriptMenuItems);
},

clickScriptMenu: function (event) {
const { target } = event;
const { gBrowser } = event.view;
const script = _uc.scripts[target.filename];
switch (event.button) {
case 0:
this.toggleScript(script);
if (event.ctrlKey)
this.toggleScript(script);
break;
case 1:
if (event.ctrlKey) {
let url = target.getAttribute('homeURL');
if (url) {
gBrowser.addTab(url, { triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}) });
}
} else {
this.toggleScript(script);
if (target.tagName === 'toolbarbutton')
target.setAttribute('checked', script.isEnabled);
}
break;
case 2:
if (event.ctrlKey)
this.uninstall(script);
else
this.launchEditor(script);
}
},

shouldPreventHide: function (event) {
if (event.button == 1 && !event.ctrlKey) {
const menuitem = event.target;
menuitem.setAttribute('closemenu', 'none');
menuitem.parentNode.addEventListener('popuphidden', () => {
menuitem.removeAttribute('closemenu');
}, { once: true });
}
},

launchEditor: function (script) {
let editor = xPref.get('view_source.editor.path');
let useSystemDefault = xPref.get(this.PREF_OPENWITHSYSTEMDEFAULT);
if (!editor && !useSystemDefault) {
let obj = { value: 'C:\WINDOWS\system32\notepad.exe' };
if (Services.prompt.prompt(null, 'userChromeJS', 'Editor not defined. Paste the full path of your text editor or click cancel to use system default.', obj, null, { value: 0 })) {
editor = obj.value;
xPref.set('view_source.editor.path', editor);
} else
useSystemDefault = xPref.set(this.PREF_OPENWITHSYSTEMDEFAULT, true);
}
if (useSystemDefault) {
script.file.launch();
} else {
let editorArgs = [];
let args = Services.prefs.getCharPref('view_source.editor.args');
if (args) {
const argumentRE = /"([^"]+)"|(\S+)/g;
while (argumentRE.test(args)) {
editorArgs.push(RegExp.$1 || RegExp.$2);
}
}
editorArgs.push(script.file.path);
try {
let appfile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
appfile.initWithPath(editor);
let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
process.init(appfile);
process.run(false, editorArgs, editorArgs.length, {});
} catch {
alert('Can't open the editor. Go to about:config and set editor's path in view_source.editor.path.');
}
}
},

restart: function () {
Services.appinfo.invalidateCachesOnRestart();

let cancelQuit = Cc['@mozilla.org/supports-PRBool;1'].createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, 'quit-application-requested', 'restart');

if (cancelQuit.data)
  return;

if (Services.appinfo.inSafeMode)
  Services.startup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
else
  Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);

},

toggleScript: function (script) {
if (script.isEnabled) {
xPref.set(_uc.PREF_SCRIPTSDISABLED, script.filename + ',' + xPref.get(_uc.PREF_SCRIPTSDISABLED));
} else {
xPref.set(_uc.PREF_SCRIPTSDISABLED, xPref.get(_uc.PREF_SCRIPTSDISABLED).replace(new RegExp('^' + script.filename + ',|,' + script.filename), ''));
}

if (xPref.get(_uc.PREF_ENABLED) && script.isEnabled && !_uc.everLoaded.includes(script.id)) {
  this.install(script);
} else if (script.isRunning && !!script.shutdown) {
  this.shutdown(script);
}

},

toggleUI: function (byaboutconfig = false, startup = false) {
this.showToolButton = xPref.get(this.PREF_TOOLSBUTTON);
if (!byaboutconfig && !startup) {
this.showToolButton = xPref.set(this.PREF_TOOLSBUTTON, !this.showToolButton);
}

_uc.windows((doc) => {
  doc.getElementById('userChromebtnMenu').hidden = this.showToolButton;
  doc.getElementById('userChromejs_Tools_Menu').hidden = !this.showToolButton;
  if (this.showToolButton) {
    doc.getElementById('userChromejs_Tools_Menu').appendChild(doc.getElementById('userChromejs_options'));
  } else if (!startup) {
    doc.getElementById('userChromebtnMenu').appendChild(doc.getElementById('userChromejs_options'));
  }
});

},

createMenuItem: function (doc, id, icon, label, command) {
const menuItem = doc.createXULElement('toolbarbutton');
menuItem.className = 'subviewbutton subviewbutton-iconic';
if (id)
menuItem.id = 'appMenu-userChromeJS-' + id;
menuItem.label = label;
menuItem.style.listStyleImage = icon;
if (command)
menuItem.setAttribute('oncommand', command);
return menuItem;
},

install: function (script) {
script = _uc.getScriptData(script.file);
Services.obs.notifyObservers(null, 'startupcache-invalidate');
_uc.windows((doc, win, loc) => {
if (win._uc && script.regex.test(loc.href)) {
_uc.loadScript(script, win);
}
}, false);
},

uninstall: function(script) {
if (!Services.prompt.confirm(null, 'userChromeJS', 'Do you want to uninstall this script? The file will be deleted.'))
return;

this.shutdown(script);
script.file.remove(false);
xPref.set(_uc.PREF_SCRIPTSDISABLED, xPref.get(_uc.PREF_SCRIPTSDISABLED).replace(new RegExp('^' + script.filename + ',|,' + script.filename), ''));

},

shutdown: function (script) {
if (script.shutdown) {
_uc.windows((doc, win, loc) => {
if (script.regex.test(loc.href)) {
try {
eval(script.shutdown);
} catch (ex) {
Cu.reportError(ex);
}
if (script.onlyonce)
return true;
}
}, false);
script.isRunning = false;
}
},

elBuilder: function (doc, tag, props) {
let el = doc.createXULElement(tag);
for (let p in props) {
el.setAttribute(p, props[p]);
}
return el;
},

init: function () {
this.showToolButton = xPref.get(this.PREF_TOOLSBUTTON);
if (this.showToolButton === undefined) {
this.showToolButton = xPref.set(this.PREF_TOOLSBUTTON, false, true);
}

xPref.addListener(this.PREF_TOOLSBUTTON, function (value, prefPath) {
  UC.rebuild.toggleUI(true);
});

xPref.addListener(_uc.PREF_ENABLED, function (value, prefPath) {
  Object.values(_uc.scripts).forEach(script => {
    if (script.filename == _uc.ALWAYSEXECUTE)
      return;
    if (value && script.isEnabled && !_uc.everLoaded.includes(script.id)) {
      UC.rebuild.install(script);
    } else if (!value && script.isRunning && !!script.shutdown) {
      UC.rebuild.shutdown(script);
    }
  });
});

if (AppConstants.MOZ_APP_NAME !== 'thunderbird') {
  const { CustomizableUI } = window;
  CustomizableUI.createWidget({
    id: 'userChromebtnMenu',
    type: 'custom',
    defaultArea: CustomizableUI.AREA_NAVBAR,
    onBuild: (doc) => {
      return this.createButton(doc);
    }
  });
} else {
  const { document, location } = window;
  const btn = this.createButton(document);
  btn.setAttribute('removable', true);
  const toolbar = document.querySelector('toolbar[customizable=true].chromeclass-toolbar');
  if (toolbar.parentElement.palette)
    toolbar.parentElement.palette.appendChild(btn);
  else
    toolbar.appendChild(btn);

  if (xPref.get('userChromeJS.firstRun') !== false) {
    xPref.set('userChromeJS.firstRun', false);
    if (!toolbar.getAttribute('currentset').split(',').includes(btn.id)) {
      toolbar.appendChild(btn);
      toolbar.setAttribute('currentset', toolbar.currentSet);
      Services.xulStore.persist(toolbar, 'currentset');
    }
  } else {
    toolbar.currentSet = Services.xulStore.getValue(location.href, toolbar.id, 'currentset');
    toolbar.setAttribute('currentset', toolbar.currentSet);
  }
}

},

createButton (aDocument) {
let toolbaritem = UC.rebuild.elBuilder(aDocument, 'toolbarbutton', {
id: 'userChromebtnMenu',
label: 'userChromeJS',
tooltiptext: 'userChromeJS Manager',
type: 'menu',
class: 'toolbarbutton-1 chromeclass-toolbar-additional',
style: 'list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABeSURBVDhPY6AKSCms+x+SkPMfREOFwACXOAYYNQBVITrGJQ7CUO0IA0jFUO0QA3BhkEJs4iAM1Y4bgBTBDIAKkQYGlwHYMFQZbgBSBDIAF4Yqww3QbUTHUGWUAAYGAEyi7ERKirMnAAAAAElFTkSuQmCC)',
});

let mp = UC.rebuild.elBuilder(aDocument, 'menupopup', {
  id: 'userChromejs_options',
  onpopupshowing: 'UC.rebuild.onpopup(event);',
  oncontextmenu: 'event.preventDefault();'
});
toolbaritem.appendChild(mp);

let mg = mp.appendChild(aDocument.createXULElement('menugroup'));
mg.setAttribute('id', 'uc-menugroup');

let mi1 = UC.rebuild.elBuilder(aDocument, 'menuitem', {
  id: 'userChromejs_openChromeFolder',
  label: 'Open chrome directory',
  class: 'menuitem-iconic',
  flex: '1',
  style: 'list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABe0lEQVQ4jc3N2ytDARwH8J83/wRKefU3zFBCSnlQSnkQpSiFFLk8OMQmxLBZLos2I7ckM3PmMmEredF23Ma2GrPjkuFsvh7mstTqnDff+jx+v1+ifxEZ43zPYFyIld3FHWYxzlRRA5mdXFi3c4vpvbuo3TvU6z2CnHEKf4djRd9bLYnyDldkYtuPqZ1b0TIYF2StlkTK6eaQ080ht+eLgkPeH/nflGc/8hRRVNB7BuVaAGPWILRsDCsfl4bl0bMaQGHfOaho4AL9pns0GPyo04vTYPCjz3SP4sELUInqEkObPNoXA5IMmoMoHbkClWncUG8/QLnOS6K2PqJc6wZVjl9jyvYMtfVJEp3tGVWTN6Bq3Q2M9hBmDl4kMTpCqJ32gOr1XmHp+BUrJ2+SLB2/onHWK1DLvG95lOU/Nk4FbLnCcbHcL/OpgFGWj7Qt+AxUo7an12qOHM1Gb6R5zgcxmozecLVq31YxvJ9GRJRARElElExEKSIlf3USPgHT/mSv7iPTOwAAAABJRU5ErkJggg==)',
  oncommand: 'Services.dirsvc.get(\'UChrm\', Ci.nsIFile).launch();'
});
mg.appendChild(mi1);

let tb = UC.rebuild.elBuilder(aDocument, 'menuitem', {
  id: 'userChromejs_restartApp',
  class: 'menuitem-iconic',
  tooltiptext: 'Restart ' + _uc.BROWSERNAME,
  style: 'list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB20lEQVQ4jY2Tv2sUURDHZ/bX7eW0ChJBRFKIRRCRIEHuzVvfrYmkSiFXSSoLERERy5B/wcIuqG9mN5VecUWwCqkOEQsLKysLsQgSxEJEgsVYeJfsHXuY4tvN9zMzzHxBVXFS8Gy1kRaZi8U+iCV7HIq73Xqez9XWThoDsRvg6QDY6Ji8+RMK9dLSztcCoMhnkc27YxPth0I7oVAPhT5WYD9ScfkYALYWYxQa/OvU/h5ztg5bi3G1U2vbXUFPb4fT/EzELRwBYraPRvSE7eW6XVUV4en1JjLtARtFoYGqInRfd0Nk8wXYaCzZ/WnmkZrengc2v4GNNr1bglPiFoaj/5orV1r/A6gqhkI9YKMB0yY0OF9GsV/jIts9iVlVMeJscwhgOKmpqoDpGNDg5YuB0HYg9lUotINCuxFn/bN+9czUFZj6wEYDsRsQle7W+NPQ/uhEdUpLOw/cPgQ2OlPcvAoJZ90qICnc2tQzlist9GYAbDRk2lNVhFDs3YmXPUjkxp3JR2qWbgk9fRj9S+Olu6SqCJHYJ+DN5xnOryHT+wrsG7J9g0x9ZPup2iAS1z6aKi076+mLzoVRmKJpYeL2YSC2aBadc1PTOB7n3AXe3guYHiberZ0u8tm62r99Gyd0lo7sIAAAAABJRU5ErkJggg==)',
  oncommand: 'UC.rebuild.restart();'
});
mg.appendChild(tb);

let mn = UC.rebuild.elBuilder(aDocument, 'menu', {
  id: 'uc-manageMenu',
  label: 'Settings',
  class: 'menuitem-iconic',
  style: 'list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAADJUlEQVQ4ja1TS0wTQRgean0/ovFgTDxpjDc9Gg8mvSrnKhFSC8VpCuyyu22Xbdm2s7Rdt48t7kIhEJEIYiKKphZK0CoRLVYlHiAEFYMng4+bF6nUjgfbuiocTPwuM5P83/d/8z8AWAMIIX3xWvHHCYxG44a1OOuCIIhd2rfZbN7yTwIURe0+D8lAbSO3aLI21xgMBn2dzXbQZLM/MNkcEwRNnyw6rFhTAEK4ESGkc/L8IacgY1Hpw1xbbLWBFT5QrRe/+GM92Bfpxg4Xkotf3LSuGAAA1DcypC/cnWuL9a5yQQXzUifmApewR4pjUenLESzKQAi3rUmmaXqrpYF0WBqYDrtXynnDceyR1JW7E5Opqcwz9Ul2pr+zb+gdF2jHnlAnvkC6piw2WmikHCeKEj+dmWDTuSZXEPsiXdgb6Sr4o/HlV4uLZ5LJZDnz0tLSkeE7YyMt/nbcFuvBrqCCqyGdhhBuLAtF2jvE1osd+UCsZ8Xhi3yfnMqYNYZ1pcB0Or1X6bm64BLVvCcczwflrrcsy+4sBVaMjo7u6R248ZDiJaz0Ds4PDAxs1woAAIDBYNADAMBIIsU6BRm7RWUlm31x+rduAQCAEFICDkEu+MTYuMZJGUajcQNCQBeU2ivZNrng8ssfNYNb7FQ9caCusSUrRLsLFtL9ppogdhUnuCxWSniursHnFtWCwyvlqmttNUA7U1bSeYnxSNgXin91CtFCdT1hLwkghPSltYAQ7rcy/LI3HM+7RaUAKfdnjuP2lB0NjyQq3X45R7eK2ImiuIkV8mdNVsZspnaXYqpq4XGzjXneIsjY7g1hkvPjvsHhm9o6AlVVN2ezL6oyz2fsATn+yemLYModxDWQfm2luAmTjXlsaXbnWvwxTPNS4XZy/Nrj6em6ZDJ57Lc50mJyKlNDugLfPJKaY4UovsB4MeEKYE+oI0/z4mr3laFUKpXa/BfxV3uRHgCg43n/YZITvtfTPEYh9f1Y+tGDy4M3X1oZTx4yXsyjYFhT/PV3DSG0Y3Z+oen6rcT92fn5Uwgh3dzc3L7xe5P9T57OXE4kEkfXJf8P/ABlOH7kn81/zwAAAABJRU5ErkJggg==)'
});
mp.appendChild(mn);

let mp2 = mn.appendChild(aDocument.createXULElement('menupopup'));

let mi2 = UC.rebuild.elBuilder(aDocument, 'menuitem', {
  id: 'showToolsMenu',
  label: 'Switch display mode',
  class: 'menuitem-iconic',
  style: 'list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADdklEQVQ4jXWTbUwUdADG/7zccZ6lQ/pgcDJEEEGBO8/hmLQY9mKOmFvyEi93IIISSSMGxx0Hw0QKJJCOI3CxGM0IhEASjDsQ1lgdRuqcE4N0RznTjPFSDGJwvz64nOX6bc+35+XTI8R/KRXOG6LFwcAEj+7d2b4PI3L8ltQZiuuKaGmp5yER8JT/Sco/0e+JylP1xNfuXTrWEU/+BQ26Pi3vnk8ioyWG10pU9lj9S4VjY2Pyp4cbcxP36PyW83tTKBnMwDhwiCJrGkXWVIzWNIoH0ikezCTxTBRROcG9k5O2dY/Dp5qKwyN0W5aMgxkYLKkYrakYB7XorAnorPEUWOLJ749D159E6dBRIj7cRIhW8fmj5dJI16jc4L78vhQK+zUYrCkUDrxJtS0P6+12hu3dDNu7sNw+R8vVahK+2E1onQyvHOE4YIyIFOv3i7gEU+RyoUVD2dBbXL9v46tbLRiHkum8cYbv7SNcsdsA6L/RTVCVMzvNMkJq5GyMF50iMNnDktV2gNPfGrj3xxT/MDL1NcXDSRgGEzh+6TArLNM+2sy2SkFYgxxVnZwtWdK7Iizbe67hu3Lml2bAAQ6H43HJ+IOrvDeiRdunYmFllnOXWwioEuxqlKGskxGgk/4lIt7xX6keLsJ06QSnLAbG719jaXmJin4d+t5UDraGENOhYGFlnq4fWlHXyon6dCORTV5s1UkdQpn+/ERa66tkdu0jpTOcb36+yIO5GcJN7rzS5kHPZAe/LPzK7Moq9/6cY2LWzs2Htzjc+gbe2U4zwnO/c2XQcRlq81p2mASt45/x4+/TKKsk7GoW7DuroGein99WYRqYnJsn5eM4fIwueGucrojgrPW+vkekUyEmN7bXCppvtnFnEYoHijhxWU/yhRcIa1xLzWg9vT9d48X31XiXCALL3AjUuhcIIYSI0ccU+BgEwSZX3u49Qr2tjXrblzSMnueD4QZebtqGss4FZYUH/icFoSY5Co3T3cT6LHchhBCx5thnFAnSi0FlMnbUSgg46UxguQtBFS4EV7qhrn0WtXkNyjo3Qj+Ss/moZHF7uvvr//qC37EN6xSxLmf98iSOkBoZKvMadtY/ksosR2mSE1Qmw0cjsXunuUT/7yO9tK57vZMl7ZuzpHf8C6SLW/XSVf9cybRPquvopmRng2emeO5J/98W5fyDGAVpggAAAABJRU5ErkJggg==)',
  oncommand: 'UC.rebuild.toggleUI();'
});
mp2.appendChild(mi2);

let sep = mp.appendChild(aDocument.createXULElement('menuseparator'));
sep.setAttribute('id', 'uc-menuseparator');

let mi = UC.rebuild.elBuilder(aDocument, 'menu', {
  id: 'userChromejs_Tools_Menu',
  label: 'userChromeJS Manager',
  tooltiptext: 'UC Script Manager',
  class: 'menu-iconic',
  image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABeSURBVDhPY6AKSCms+x+SkPMfREOFwACXOAYYNQBVITrGJQ7CUO0IA0jFUO0QA3BhkEJs4iAM1Y4bgBTBDIAKkQYGlwHYMFQZbgBSBDIAF4Yqww3QbUTHUGWUAAYGAEyi7ERKirMnAAAAAElFTkSuQmCC',
});
aDocument.getElementById(AppConstants.MOZ_APP_NAME !== 'thunderbird' ? 'devToolsSeparator' : 'prefSep').insertAdjacentElement('afterend', mi);//taskPopup

let menupopup = aDocument.getElementById('userChromejs_options');
UC.rebuild.menues.forEach(menu => {
  menupopup.insertBefore(menu, aDocument.getElementById('uc-menuseparator'));
})

let pi = aDocument.createProcessingInstruction(
  'xml-stylesheet',
  'type="text/css" href="data:text/css;utf-8,' + encodeURIComponent(`
  #userChromejs_options menuitem[restartless="true"] {
    color: blue;
  }
  #userChromejs_restartApp {
    width: 34px;
  }
  `.replace(/[\r\n\t]/g, '')) + '"'
);
aDocument.insertBefore(pi, aDocument.documentElement);

aDocument.defaultView.setTimeout((() => UC.rebuild.toggleUI(false, true)), 1000);

const viewCache = aDocument.getElementById('appMenu-viewCache')?.content || aDocument.getElementById('appMenu-multiView');

if (viewCache) {
  const userChromeJsPanel = aDocument.createXULElement('panelview');
  userChromeJsPanel.id = 'appMenu-userChromeJsView';
  userChromeJsPanel.className = 'PanelUI-subView';
  userChromeJsPanel.addEventListener('ViewShowing', UC.rebuild.onHamPopup);
  const subviewBody = aDocument.createXULElement('vbox');
  subviewBody.className = 'panel-subview-body';
  subviewBody.appendChild(UC.rebuild.createMenuItem(aDocument, 'openChrome', 'url(chrome://browser/skin/folder.svg)', 'Open chrome directory', 'Services.dirsvc.get(\'UChrm\', Ci.nsIFile).launch();'));
  subviewBody.appendChild(UC.rebuild.createMenuItem(aDocument, 'restart', 'url(chrome://browser/skin/reload.svg)', 'Restart ' + _uc.BROWSERNAME, 'UC.rebuild.restart();'));
  subviewBody.appendChild(aDocument.createXULElement('toolbarseparator'));
  const enabledMenuItem = UC.rebuild.createMenuItem(aDocument, 'enabled', null, 'Enabled', 'xPref.set(_uc.PREF_ENABLED, !!this.checked)');
  enabledMenuItem.type = 'checkbox';
  subviewBody.appendChild(enabledMenuItem);
  const scriptsSeparator = aDocument.createXULElement('toolbarseparator');
  scriptsSeparator.id = 'appMenu-userChromeJS-scriptsSeparator';
  subviewBody.appendChild(scriptsSeparator);
  userChromeJsPanel.appendChild(subviewBody);
  viewCache.appendChild(userChromeJsPanel);

  const scriptsButton = aDocument.createXULElement('toolbarbutton');
  scriptsButton.id = 'appMenu-userChromeJS-button';
  scriptsButton.className = 'subviewbutton subviewbutton-iconic subviewbutton-nav';
  scriptsButton.label = 'User Scripts';
  scriptsButton.style.listStyleImage = 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABeSURBVDhPY6AKSCms+x+SkPMfREOFwACXOAYYNQBVITrGJQ7CUO0IA0jFUO0QA3BhkEJs4iAM1Y4bgBTBDIAKkQYGlwHYMFQZbgBSBDIAF4Yqww3QbUTHUGWUAAYGAEyi7ERKirMnAAAAAElFTkSuQmCC)';
  scriptsButton.setAttribute('closemenu', 'none');
  scriptsButton.setAttribute('oncommand', 'PanelUI.showSubView(\'appMenu-userChromeJsView\', this)');

  const addonsButton = aDocument.getElementById('appMenu-extensions-themes-button') ?? aDocument.getElementById('appmenu_addons') ?? viewCache.querySelector('#appMenu-extensions-themes-button');
  addonsButton.parentElement.insertBefore(scriptsButton, addonsButton);
}

return toolbaritem;

}
}

UC.rebuild.init();

Bloody piece'o'crap is working again in Ubuntu now.

@onemen onemen closed this as completed Oct 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests