// ==UserScript== // @name Status Bar // @author xiaoxiaoflood // @include main // @startup UC.statusBar.exec(win); // @shutdown UC.statusBar.destroy(); // @onlyonce // ==/UserScript== const { CustomizableUI, StatusPanel } = window; UC.statusBar = { PREF_ENABLED: 'userChromeJS.statusbar.enabled', PREF_STATUSTEXT: 'userChromeJS.statusbar.appendStatusText', get enabled() { return xPref.get(this.PREF_ENABLED); }, get textInBar() { return this.enabled && xPref.get(this.PREF_STATUSTEXT); }, init: function () { xPref.set(this.PREF_ENABLED, true, true); xPref.set(this.PREF_STATUSTEXT, true, true); this.enabledListener = xPref.addListener(this.PREF_ENABLED, (isEnabled) => { CustomizableUI.getWidget('status-dummybar').instances.forEach(dummyBar => { dummyBar.node.setAttribute('collapsed', !isEnabled); }); }); this.textListener = xPref.addListener(this.PREF_STATUSTEXT, (isEnabled) => { if (!UC.statusBar.enabled) return; _uc.windows((doc, win) => { let StatusPanel = win.StatusPanel; if (isEnabled) win.statusbar.textNode.appendChild(StatusPanel._labelElement); else StatusPanel.panel.appendChild(StatusPanel._labelElement); }); }); this.setStyle(); _uc.sss.loadAndRegisterSheet(this.STYLE.url, this.STYLE.type); CustomizableUI.registerArea('status-bar', {}); Services.obs.addObserver(this, 'browser-delayed-startup-finished'); }, exec: function (win) { let document = win.document; let StatusPanel = win.StatusPanel; let dummystatusbar = _uc.createElement(document, 'toolbar', { id: 'status-dummybar', toolbarname: 'Status Bar', hidden: 'true' }); dummystatusbar.collapsed = !this.enabled; dummystatusbar.setAttribute = function (att, value) { let result = Element.prototype.setAttribute.apply(this, arguments); if (att == 'collapsed') { let StatusPanel = win.StatusPanel; if (value === true) { xPref.set(UC.statusBar.PREF_ENABLED, false); win.statusbar.node.setAttribute('collapsed', true); StatusPanel.panel.appendChild(StatusPanel._labelElement); win.statusbar.node.parentNode.collapsed = true;; } else { xPref.set(UC.statusBar.PREF_ENABLED, true); win.statusbar.node.setAttribute('collapsed', false); if (UC.statusBar.textInBar) win.statusbar.textNode.appendChild(StatusPanel._labelElement); win.statusbar.node.parentNode.collapsed = false; } } return result; }; win.gNavToolbox.appendChild(dummystatusbar); win.statusbar.node = _uc.createElement(document, 'toolbar', { id: 'status-bar', customizable: 'true', context: 'toolbar-context-menu', mode: 'icons' }); win.statusbar.textNode = _uc.createElement(document, 'toolbaritem', { id: 'status-text', flex: '1', width: '100' }); if (this.textInBar) win.statusbar.textNode.appendChild(StatusPanel._labelElement); win.statusbar.node.appendChild(win.statusbar.textNode); win.eval('Object.defineProperty(StatusPanel, "_label", {' + Object.getOwnPropertyDescriptor(StatusPanel, '_label').set.toString().replace(/^set _label/, 'set').replace(/((\s+)this\.panel\.setAttribute\("inactive", "true"\);)/, '$2this._labelElement.value = val;$1') + ', enumerable: true, configurable: true});'); let bottomBox = document.createElement('vbox'); bottomBox.id = 'browser-bottombox'; bottomBox.append(win.statusbar.node); if (!this.enabled) bottomBox.collapsed = true; document.getElementById('fullscreen-and-pointerlock-wrapper').insertAdjacentElement('afterend', bottomBox); win.addEventListener('fullscreen', this.fsEvent); if (document.readyState === 'complete') this.observe(win); }, fsEvent: function (ev) { const { StatusPanel, fullScreen, statusbar } = ev.target; if (fullScreen) StatusPanel.panel.appendChild(StatusPanel._labelElement); else statusbar.textNode.appendChild(StatusPanel._labelElement); }, observe: function (win) { CustomizableUI.registerToolbarNode(win.statusbar.node); }, orig: Object.getOwnPropertyDescriptor(StatusPanel, '_label').set.toString(), setStyle: function () { this.STYLE = { url: Services.io.newURI('data:text/css;charset=UTF-8,' + encodeURIComponent(` @-moz-document url('${_uc.BROWSERCHROME}') { #status-bar { color: initial !important; background-color: var(--toolbar-non-lwt-bgcolor); } #status-text > #statuspanel-label { border-top: 0 !important; background-color: unset !important; color: #444; } #status-bar > #status-text { display: flex !important; justify-content: center !important; align-content: center !important; flex-direction: column !important; -moz-window-dragging: drag; } toolbarpaletteitem #status-text:before { content: "Status text"; color: red; border: 1px #aaa solid; border-radius: 3px; font-weight: bold; } #browser-bottombox:not([collapsed]) { border-top: 1px solid #BCBEBF !important; } :root[inFullscreen]:not([macOSNativeFullscreen]) #browser-bottombox { visibility: collapse !important; } } `)), type: _uc.sss.USER_SHEET } }, destroy: function () { const { CustomizableUI } = Services.wm.getMostRecentBrowserWindow(); xPref.removeListener(this.enabledListener); xPref.removeListener(this.textListener); CustomizableUI.unregisterArea('status-bar'); _uc.sss.unregisterSheet(this.STYLE.url, this.STYLE.type); _uc.windows((doc, win) => { const { eval, statusbar, StatusPanel } = win; eval('Object.defineProperty(StatusPanel, "_label", {' + this.orig.replace(/^set _label/, 'set') + ', enumerable: true, configurable: true});'); StatusPanel.panel.appendChild(StatusPanel._labelElement); doc.getElementById('status-dummybar').remove(); statusbar.node.remove(); win.removeEventListener('fullscreen', this.fsEvent); }); Services.obs.removeObserver(this, 'browser-delayed-startup-finished'); delete UC.statusBar; } } UC.statusBar.init();