<commit_before>// ==UserScript==
// @name            StyloaiX
// @author          xiaoxiaoflood
// @include         *
// @startup         UC.styloaix.exec(win);
// @shutdown        UC.styloaix.destroy();
// @onlyonce
// ==/UserScript==

// inspired by legacy Stylish and https://github.com/Endor8/userChrome.js/blob/master/Updates%202019/UserCSSLoader.uc.js
// editor forked from Stylish - minor changes to edit.xhtml, but edit.js almost completely rewritten, with improvements and bug fixes.
// icon from old Stylish

// search for "userChromeJS.styloaix" in about:config to change settings.

(function () {

  UC.styloaix = {
    exec: function (win) {
      if (win.location.href !== _uc.BROWSERCHROME)
        return;

      const { AppConstants, CustomizableUI, document, Services } = win;
      if (AppConstants.MOZ_APP_NAME !== 'thunderbird') {
        if (!CustomizableUI.getPlacementOfWidget('styloaix-button')) {
          CustomizableUI.createWidget({
            id: 'styloaix-button',
            type: 'custom',
            defaultArea: CustomizableUI.AREA_NAVBAR,
            onBuild: (doc) => {
              return this.createButton(doc);
            }
          });
        }
      } else {
        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(this.PREF_FIRSTRUN)) {
          xPref.set(this.PREF_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(win.location.href, toolbar.id, 'currentset');
          toolbar.setAttribute('currentset', toolbar.currentSet);
        }

        this.tbButtons.push(btn);
      }
    },

    init: function () {
      xPref.lock(this.PREF_MOZDOCUMENT, true);
      xPref.set(this.PREF_FIRSTRUN, true, true);
      xPref.set(this.PREF_DISABLED, false, true);
      xPref.set(this.PREF_STYLESDISABLED, '[]', true);
      xPref.set(this.PREF_INSTANTCHECK, true, true);
      xPref.set(this.PREF_INSTANTPREVIEW, true, true);
      xPref.set(this.PREF_INSTANTINTERVAL, 500, true);
      xPref.set(this.PREF_LINEWRAPPING, true, true);
      xPref.set(this.PREF_OPENINWINDOW, true, true);

      this.prefListener = xPref.addListener(this.PREF_STYLESDISABLED, (sDisabled) => {
        let newSet;
        try {
          newSet = new Set(JSON.parse(sDisabled));
        } catch {
          xPref.set(this.PREF_STYLESDISABLED, JSON.stringify([...this.disabledStyles]));
          return;
        }

        this.styles.forEach(style => {
          if ((style.enabled && newSet.has(style.fullName)) ||
              (!style.enabled && !newSet.has(style.fullName)))
            this.toggleStyle(style);
        });
      });
      this.prefListenerAll = xPref.addListener(this.PREF_DISABLED, (disabled) => {
        this.toggleAll({disable: disabled});
        this.btnClasses.reverse();
        _uc.windows((doc) => {
          let enabledBtn = doc.getElementById('styloaix-enabled');
          enabledBtn.label = disabled ? 'Disabled' : 'Enabled';
          enabledBtn.setAttribute('checked', !disabled);
          doc.getElementById('styloaix-button').classList.replace(...this.btnClasses);
          doc.getElementById('styloaix-reload-all').disabled = disabled;
        });
      });

      this.disabledStyles = new DisabledSet(JSON.parse(xPref.get(this.PREF_STYLESDISABLED)).sort((a, b) => a[0].localeCompare(b[0])));

      this.UserStyle = UserStyle;

      if (!this.enabled)
        this.btnClasses.reverse();

      this.loadStyles();

      _uc.sss.loadAndRegisterSheet(this.STYLE.url, this.STYLE.type);
    },

    createButton (doc) {
      let btn = _uc.createElement(doc, 'toolbarbutton', {
        id: 'styloaix-button',
        label: 'StyloaiX',
        tooltiptext: 'StyloaiX',
        type: 'menu',
        class: 'toolbarbutton-1 chromeclass-toolbar-additional ' + this.btnClasses[1],
        onclick: 'if (event.button === 1 && event.target.id == this.id) UC.styloaix.enabled = !UC.styloaix.enabled;'
      });

      let popup = _uc.createElement(doc, 'menupopup', {id: 'styloaix-popup'});
      btn.appendChild(popup);
      btn.addEventListener('popupshowing', this.populateMenu);

      let disabled = xPref.get(this.PREF_DISABLED);
      let toggleBtn = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-enabled',
        label: disabled ? 'Disabled' : 'Enabled',
        type: 'checkbox',
        checked: !disabled,
        oncommand: 'UC.styloaix.enabled = !UC.styloaix.enabled;'
      });
      popup.appendChild(toggleBtn);
      
      let menuseparator = _uc.createElement(doc, 'menuseparator');
      popup.appendChild(menuseparator);

      let reloadAllBtn = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-reload-all',
        label: 'Reload All Styles',
        disabled: !this.enabled,
        oncommand: 'UC.styloaix.toggleAll({reload: true});'
      });
      popup.appendChild(reloadAllBtn);

      let openFolderBtn = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-open-folder',
        label: 'Open folder',
        oncommand: 'UC.styloaix.CSSDIR.launch();'
      });
      popup.appendChild(openFolderBtn);

      let newStyleMenu = _uc.createElement(doc, 'menu', {
        id: 'styloaix-new-style',
        label: 'New Style'
      });

      let newStylePopup = _uc.createElement(doc, 'menupopup', {id: 'styloaix-newstyle-popup'});

      let newPageStyleBtn = _uc.createElement(doc, 'menuitem', {
        label: 'For this page',
        oncommand: 'UC.styloaix.openEditor({url: gBrowser.currentURI.specIgnoringRef, type: "url"});'
      });
      newStylePopup.appendChild(newPageStyleBtn);

      let newSiteStyleBtn = _uc.createElement(doc, 'menuitem', {
        label: 'For this site',
        oncommand: 'let host = gBrowser.currentURI.asciiHost; UC.styloaix.openEditor({url: host || gBrowser.currentURI.specIgnoringRef, type: host ? "domain" : "url"});'
      });
      newStylePopup.appendChild(newSiteStyleBtn);

      let newStyle = _uc.createElement(doc, 'menuitem', {
        label: 'Blank Style',
        oncommand: 'UC.styloaix.openEditor();'
      });
      newStylePopup.appendChild(newStyle);

      newStyleMenu.appendChild(newStylePopup);
      popup.appendChild(newStyleMenu);

      let separatorBeforeStyles = _uc.createElement(doc, 'menuseparator', {id: 'styloaix-separator'});
      separatorBeforeStyles.hidden = !this.styles.size;
      popup.appendChild(separatorBeforeStyles);
      btn._separator = separatorBeforeStyles;

      let stylePopup = _uc.createElement(doc, 'menupopup', {id: 'styloaix-style-context'});

      let styleEdit = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-style-edit',
        label: 'Edit',
        oncommand: 'UC.styloaix.openEditor({id: this.parentNode.triggerNode._style.fullName})'
      });
      stylePopup.appendChild(styleEdit);

      let styleReload = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-style-reload',
        label: 'Reload',
        oncommand: 'this.parentNode.triggerNode._style.reload()'
      });
      stylePopup.appendChild(styleReload);

      let styleDelete = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-style-delete',
        label: 'Delete',
        oncommand: 'this.parentNode.triggerNode._style.delete()'
      });
      stylePopup.appendChild(styleDelete);

      doc.getElementById('mainPopupSet').appendChild(stylePopup);
      
      return btn;
    },

    get enabled () {
      return !xPref.get(this.PREF_DISABLED);
    },

    set enabled (val) {
      xPref.set(this.PREF_DISABLED, !val);
    },

    loadStyles: function() {
      let files = this.CSSDIR.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
      while (files.hasMoreElements()) {
        let file = files.getNext().QueryInterface(Ci.nsIFile);
        if (file.leafName.endsWith('.css')) {
          let style = new UserStyle(file);
        }
      }

      if (this.enabled)
        this.toggleAll({disable: false});
    },

    toggleAll: function ({disable = this.enabled, reload = false} = {}) {
      this.styles.forEach(style => {
        if (style.enabled)
          this.toggleStyle(style, {aStatus: !disable, changeStatus: false, forced: true});
      });<commit_msg>styloaix: inject agent_sheets one at a time #157<commit_after>// ==UserScript==
// @name            StyloaiX
// @author          xiaoxiaoflood
// @include         *
// @startup         UC.styloaix.exec(win);
// @shutdown        UC.styloaix.destroy();
// @onlyonce
// ==/UserScript==

// inspired by legacy Stylish and https://github.com/Endor8/userChrome.js/blob/master/Updates%202019/UserCSSLoader.uc.js
// editor forked from Stylish - minor changes to edit.xhtml, but edit.js almost completely rewritten, with improvements and bug fixes.
// icon from old Stylish

// search for "userChromeJS.styloaix" in about:config to change settings.

(function () {
  const { requestAnimationFrame } = window;

  UC.styloaix = {
    exec: function (win) {
      if (win.location.href !== _uc.BROWSERCHROME)
        return;

      const { AppConstants, CustomizableUI, document, Services } = win;
      if (AppConstants.MOZ_APP_NAME !== 'thunderbird') {
        if (!CustomizableUI.getPlacementOfWidget('styloaix-button')) {
          CustomizableUI.createWidget({
            id: 'styloaix-button',
            type: 'custom',
            defaultArea: CustomizableUI.AREA_NAVBAR,
            onBuild: (doc) => {
              return this.createButton(doc);
            }
          });
        }
      } else {
        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(this.PREF_FIRSTRUN)) {
          xPref.set(this.PREF_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(win.location.href, toolbar.id, 'currentset');
          toolbar.setAttribute('currentset', toolbar.currentSet);
        }

        this.tbButtons.push(btn);
      }
    },

    init: function () {
      xPref.lock(this.PREF_MOZDOCUMENT, true);
      xPref.set(this.PREF_FIRSTRUN, true, true);
      xPref.set(this.PREF_DISABLED, false, true);
      xPref.set(this.PREF_STYLESDISABLED, '[]', true);
      xPref.set(this.PREF_INSTANTCHECK, true, true);
      xPref.set(this.PREF_INSTANTPREVIEW, true, true);
      xPref.set(this.PREF_INSTANTINTERVAL, 500, true);
      xPref.set(this.PREF_LINEWRAPPING, true, true);
      xPref.set(this.PREF_OPENINWINDOW, true, true);

      this.prefListener = xPref.addListener(this.PREF_STYLESDISABLED, (sDisabled) => {
        let newSet;
        try {
          newSet = new Set(JSON.parse(sDisabled));
        } catch {
          xPref.set(this.PREF_STYLESDISABLED, JSON.stringify([...this.disabledStyles]));
          return;
        }

        this.styles.forEach(style => {
          if ((style.enabled && newSet.has(style.fullName)) ||
              (!style.enabled && !newSet.has(style.fullName)))
            this.toggleStyle(style);
        });
      });
      this.prefListenerAll = xPref.addListener(this.PREF_DISABLED, (disabled) => {
        this.toggleAll({disable: disabled});
        this.btnClasses.reverse();
        _uc.windows((doc) => {
          let enabledBtn = doc.getElementById('styloaix-enabled');
          enabledBtn.label = disabled ? 'Disabled' : 'Enabled';
          enabledBtn.setAttribute('checked', !disabled);
          doc.getElementById('styloaix-button').classList.replace(...this.btnClasses);
          doc.getElementById('styloaix-reload-all').disabled = disabled;
        });
      });

      this.disabledStyles = new DisabledSet(JSON.parse(xPref.get(this.PREF_STYLESDISABLED)).sort((a, b) => a[0].localeCompare(b[0])));

      this.UserStyle = UserStyle;

      if (!this.enabled)
        this.btnClasses.reverse();

      this.loadStyles();

      _uc.sss.loadAndRegisterSheet(this.STYLE.url, this.STYLE.type);
    },

    createButton (doc) {
      let btn = _uc.createElement(doc, 'toolbarbutton', {
        id: 'styloaix-button',
        label: 'StyloaiX',
        tooltiptext: 'StyloaiX',
        type: 'menu',
        class: 'toolbarbutton-1 chromeclass-toolbar-additional ' + this.btnClasses[1],
        onclick: 'if (event.button === 1 && event.target.id == this.id) UC.styloaix.enabled = !UC.styloaix.enabled;'
      });

      let popup = _uc.createElement(doc, 'menupopup', {id: 'styloaix-popup'});
      btn.appendChild(popup);
      btn.addEventListener('popupshowing', this.populateMenu);

      let disabled = xPref.get(this.PREF_DISABLED);
      let toggleBtn = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-enabled',
        label: disabled ? 'Disabled' : 'Enabled',
        type: 'checkbox',
        checked: !disabled,
        oncommand: 'UC.styloaix.enabled = !UC.styloaix.enabled;'
      });
      popup.appendChild(toggleBtn);
      
      let menuseparator = _uc.createElement(doc, 'menuseparator');
      popup.appendChild(menuseparator);

      let reloadAllBtn = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-reload-all',
        label: 'Reload All Styles',
        disabled: !this.enabled,
        oncommand: 'UC.styloaix.toggleAll({reload: true});'
      });
      popup.appendChild(reloadAllBtn);

      let openFolderBtn = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-open-folder',
        label: 'Open folder',
        oncommand: 'UC.styloaix.CSSDIR.launch();'
      });
      popup.appendChild(openFolderBtn);

      let newStyleMenu = _uc.createElement(doc, 'menu', {
        id: 'styloaix-new-style',
        label: 'New Style'
      });

      let newStylePopup = _uc.createElement(doc, 'menupopup', {id: 'styloaix-newstyle-popup'});

      let newPageStyleBtn = _uc.createElement(doc, 'menuitem', {
        label: 'For this page',
        oncommand: 'UC.styloaix.openEditor({url: gBrowser.currentURI.specIgnoringRef, type: "url"});'
      });
      newStylePopup.appendChild(newPageStyleBtn);

      let newSiteStyleBtn = _uc.createElement(doc, 'menuitem', {
        label: 'For this site',
        oncommand: 'let host = gBrowser.currentURI.asciiHost; UC.styloaix.openEditor({url: host || gBrowser.currentURI.specIgnoringRef, type: host ? "domain" : "url"});'
      });
      newStylePopup.appendChild(newSiteStyleBtn);

      let newStyle = _uc.createElement(doc, 'menuitem', {
        label: 'Blank Style',
        oncommand: 'UC.styloaix.openEditor();'
      });
      newStylePopup.appendChild(newStyle);

      newStyleMenu.appendChild(newStylePopup);
      popup.appendChild(newStyleMenu);

      let separatorBeforeStyles = _uc.createElement(doc, 'menuseparator', {id: 'styloaix-separator'});
      separatorBeforeStyles.hidden = !this.styles.size;
      popup.appendChild(separatorBeforeStyles);
      btn._separator = separatorBeforeStyles;

      let stylePopup = _uc.createElement(doc, 'menupopup', {id: 'styloaix-style-context'});

      let styleEdit = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-style-edit',
        label: 'Edit',
        oncommand: 'UC.styloaix.openEditor({id: this.parentNode.triggerNode._style.fullName})'
      });
      stylePopup.appendChild(styleEdit);

      let styleReload = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-style-reload',
        label: 'Reload',
        oncommand: 'this.parentNode.triggerNode._style.reload()'
      });
      stylePopup.appendChild(styleReload);

      let styleDelete = _uc.createElement(doc, 'menuitem', {
        id: 'styloaix-style-delete',
        label: 'Delete',
        oncommand: 'this.parentNode.triggerNode._style.delete()'
      });
      stylePopup.appendChild(styleDelete);

      doc.getElementById('mainPopupSet').appendChild(stylePopup);
      
      return btn;
    },

    get enabled () {
      return !xPref.get(this.PREF_DISABLED);
    },

    set enabled (val) {
      xPref.set(this.PREF_DISABLED, !val);
    },

    loadStyles: function() {
      let files = this.CSSDIR.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
      while (files.hasMoreElements()) {
        let file = files.getNext().QueryInterface(Ci.nsIFile);
        if (file.leafName.endsWith('.css')) {
          let style = new UserStyle(file);
        }
      }

      if (this.enabled)
        this.toggleAll({disable: false});
    },

    toggleAll: function ({disable = this.enabled, reload = false} = {}) {
     let agSheets = [];
      this.styles.forEach(style => {
        if (style.enabled) {
          if (style.type === 0)
            agSheets.push(style);
          else
            this.toggleStyle(style, {aStatus: !disable, changeStatus: false, forced: true});
        }
      });

      let prevTs;
      for (let style of agSheets) {
        const step = ts => {
          if (prevTs !== ts) {
            prevTs = ts;
            this.toggleStyle(style, {aStatus: !disable, changeStatus: false, forced: true});
          } else {
            requestAnimationFrame(step);
          }
        }
        requestAnimationFrame(step);
      }

{'fraction_non_alphanumeric': 0.14008991508020202, 'fraction_numerical': 0.0018871066215241162, 'mean_word_length': 2.6569920844327175, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 18, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5963834', 'n_tokens_mistral': 5712, 'n_tokens_neox': 5594, 'n_words': 924}