mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-25 18:07:31 +09:00
[PMkit] Add the shim for 'sdk/ui/button'
This commit is contained in:
parent
8c7026864a
commit
982a4b4507
3 changed files with 251 additions and 1 deletions
|
|
@ -85,10 +85,18 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
|
|||
'sdk/ui/toolbar.js',
|
||||
]
|
||||
|
||||
if CONFIG['MC_PALEMOON']:
|
||||
EXTRA_JS_MODULES.commonjs.sdk.ui += [
|
||||
'sdk/ui/buttons.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.commonjs.sdk.ui.button += [
|
||||
'sdk/ui/button/action.js',
|
||||
'sdk/ui/button/contract.js',
|
||||
'sdk/ui/button/toggle.js',
|
||||
]
|
||||
|
||||
EXTRA_PP_JS_MODULES.commonjs.sdk.ui.button += [
|
||||
'sdk/ui/button/view.js',
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -20,14 +20,19 @@ const { isObject, isNil } = require('../../lang/type');
|
|||
|
||||
const { getMostRecentBrowserWindow } = require('../../window/utils');
|
||||
const { ignoreWindow } = require('../../private-browsing/utils');
|
||||
#ifdef MC_PALEMOON
|
||||
const { buttons } = require('../buttons');
|
||||
#else
|
||||
const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
|
||||
const { AREA_PANEL, AREA_NAVBAR } = CustomizableUI;
|
||||
#endif
|
||||
|
||||
const { events: viewEvents } = require('./view/events');
|
||||
|
||||
const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
|
||||
|
||||
const views = new Map();
|
||||
#ifndef MC_PALEMOON
|
||||
const customizedWindows = new WeakMap();
|
||||
|
||||
const buttonListener = {
|
||||
|
|
@ -65,19 +70,25 @@ CustomizableUI.addListener(buttonListener);
|
|||
require('../../system/unload').when( _ =>
|
||||
CustomizableUI.removeListener(buttonListener)
|
||||
);
|
||||
#endif
|
||||
|
||||
function getNode(id, window) {
|
||||
return !views.has(id) || ignoreWindow(window)
|
||||
? null
|
||||
#ifdef MC_PALEMOON
|
||||
: buttons.getNode(id, window);
|
||||
#else
|
||||
: CustomizableUI.getWidget(id).forWindow(window).node
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef MC_PALEMOON
|
||||
function isInToolbar(id) {
|
||||
let placement = CustomizableUI.getPlacementOfWidget(id);
|
||||
|
||||
return placement && CustomizableUI.getAreaType(placement.area) === 'toolbar';
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
function getImage(icon, isInToolbar, pixelRatio) {
|
||||
let targetSize = (isInToolbar ? 18 : 32) * pixelRatio;
|
||||
|
|
@ -110,7 +121,11 @@ function getImage(icon, isInToolbar, pixelRatio) {
|
|||
}
|
||||
|
||||
function nodeFor(id, window=getMostRecentBrowserWindow()) {
|
||||
#ifdef MC_PALEMOON
|
||||
return getNode(id, window);
|
||||
#else
|
||||
return customizedWindows.has(window) ? null : getNode(id, window);
|
||||
#endif
|
||||
};
|
||||
exports.nodeFor = nodeFor;
|
||||
|
||||
|
|
@ -120,14 +135,23 @@ function create(options) {
|
|||
if (views.has(id))
|
||||
throw new Error('The ID "' + id + '" seems already used.');
|
||||
|
||||
#ifdef MC_PALEMOON
|
||||
buttons.createButton({
|
||||
#else
|
||||
CustomizableUI.createWidget({
|
||||
#endif
|
||||
id: id,
|
||||
#ifdef MC_PALEMOON
|
||||
|
||||
onBuild: function(document, _id) {
|
||||
#else
|
||||
type: 'custom',
|
||||
removable: true,
|
||||
defaultArea: AREA_NAVBAR,
|
||||
allowedAreas: [ AREA_PANEL, AREA_NAVBAR ],
|
||||
|
||||
onBuild: function(document) {
|
||||
#endif
|
||||
let window = document.defaultView;
|
||||
|
||||
let node = document.createElementNS(XUL_NS, 'toolbarbutton');
|
||||
|
|
@ -137,16 +161,28 @@ function create(options) {
|
|||
if (ignoreWindow(window))
|
||||
node.style.display = 'none';
|
||||
|
||||
#ifdef MC_PALEMOON
|
||||
node.setAttribute('id', _id);
|
||||
#else
|
||||
node.setAttribute('id', this.id);
|
||||
#endif
|
||||
node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional badged-button');
|
||||
#ifndef MC_PALEMOON
|
||||
node.setAttribute('type', type);
|
||||
#endif
|
||||
node.setAttribute('label', label);
|
||||
node.setAttribute('tooltiptext', label);
|
||||
node.setAttribute('image', image);
|
||||
#ifdef MC_PALEMOON
|
||||
node.setAttribute('pmkit-button', 'true');
|
||||
#else
|
||||
node.setAttribute('constrain-size', 'true');
|
||||
#endif
|
||||
|
||||
views.set(id, {
|
||||
#ifndef MC_PALEMOON
|
||||
area: this.currentArea,
|
||||
#endif
|
||||
icon: icon,
|
||||
label: label
|
||||
});
|
||||
|
|
@ -172,7 +208,11 @@ function dispose(id) {
|
|||
if (!views.has(id)) return;
|
||||
|
||||
views.delete(id);
|
||||
#ifdef MC_PALEMOON
|
||||
buttons.destroyButton(id);
|
||||
#else
|
||||
CustomizableUI.destroyWidget(id);
|
||||
#endif
|
||||
}
|
||||
exports.dispose = dispose;
|
||||
|
||||
|
|
@ -180,8 +220,12 @@ function setIcon(id, window, icon) {
|
|||
let node = getNode(id, window);
|
||||
|
||||
if (node) {
|
||||
#ifdef MC_PALEMOON
|
||||
let image = getImage(icon, true, window.devicePixelRatio);
|
||||
#else
|
||||
icon = customizedWindows.has(window) ? views.get(id).icon : icon;
|
||||
let image = getImage(icon, isInToolbar(id), window.devicePixelRatio);
|
||||
#endif
|
||||
|
||||
node.setAttribute('image', image);
|
||||
}
|
||||
|
|
|
|||
198
toolkit/jetpack/sdk/ui/buttons.js
Normal file
198
toolkit/jetpack/sdk/ui/buttons.js
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
* PMkit shim for 'sdk/ui/button', (c) JustOff, 2017 */
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental",
|
||||
"engines": {
|
||||
"Palemoon": "> 27"
|
||||
}
|
||||
};
|
||||
|
||||
const { Ci, Cc } = require('chrome');
|
||||
const prefs = require('../preferences/service');
|
||||
|
||||
const buttonsList = new Map();
|
||||
const LOCATION_PREF_ROOT = "extensions.sdk-button-location.";
|
||||
|
||||
let gWindowListener;
|
||||
|
||||
function getLocation(id) {
|
||||
let toolbarId = "nav-bar", nextItemId = "";
|
||||
let location = prefs.get(LOCATION_PREF_ROOT + id);
|
||||
if (location && location.indexOf(",") !== -1) {
|
||||
[toolbarId, nextItemId] = location.split(",");
|
||||
}
|
||||
return [toolbarId, nextItemId];
|
||||
}
|
||||
|
||||
function saveLocation(id, toolbarId, nextItemId) {
|
||||
let _toolbarId = toolbarId || "";
|
||||
let _nextItemId = nextItemId || "";
|
||||
prefs.set(LOCATION_PREF_ROOT + id, [_toolbarId, _nextItemId].join(","));
|
||||
}
|
||||
|
||||
// Insert button into window
|
||||
function insertButton(aWindow, id, onBuild) {
|
||||
// Build button and save reference to it
|
||||
let doc = aWindow.document;
|
||||
let b = onBuild(doc, id);
|
||||
aWindow[id] = b;
|
||||
|
||||
// Add to the customization palette
|
||||
let toolbox = doc.getElementById("navigator-toolbox");
|
||||
toolbox.palette.appendChild(b);
|
||||
|
||||
// Retrieve button location from preferences
|
||||
let [toolbarId, nextItemId] = getLocation(id);
|
||||
let toolbar = toolbarId != "" && doc.getElementById(toolbarId);
|
||||
|
||||
if (toolbar) {
|
||||
let nextItem = doc.getElementById(nextItemId);
|
||||
// If nextItem not in toolbar then retrieve it by reading currentset attribute
|
||||
if (!(nextItem && nextItem.parentNode && nextItem.parentNode.id == toolbarId)) {
|
||||
nextItem = null;
|
||||
let currentSet = toolbar.getAttribute("currentset");
|
||||
let ids = (currentSet == "__empty") ? [] : currentSet.split(",");
|
||||
let idx = ids.indexOf(id);
|
||||
if (idx != -1) {
|
||||
for (let i = idx; i < ids.length; i++) {
|
||||
nextItem = doc.getElementById(ids[i]);
|
||||
if (nextItem)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally insert button in the right toolbar and in the right position
|
||||
toolbar.insertItem(id, nextItem, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove button from window
|
||||
function removeButton(aWindow, id) {
|
||||
let b = aWindow[id];
|
||||
b.parentNode.removeChild(b);
|
||||
delete aWindow[id];
|
||||
}
|
||||
|
||||
// Save locations of buttons after customization
|
||||
function afterCustomize(e) {
|
||||
for (let [id] of buttonsList) {
|
||||
let toolbox = e.target;
|
||||
let b = toolbox.parentNode.querySelector("#" + id);
|
||||
let toolbarId = null, nextItemId = null;
|
||||
if (b) {
|
||||
let parent = b.parentNode;
|
||||
let nextItem = b.nextSibling;
|
||||
if (parent && parent.localName == "toolbar") {
|
||||
toolbarId = parent.id;
|
||||
nextItemId = nextItem && nextItem.id;
|
||||
}
|
||||
}
|
||||
saveLocation(id, toolbarId, nextItemId);
|
||||
}
|
||||
}
|
||||
|
||||
// Global window observer
|
||||
function browserWindowObserver(handlers) {
|
||||
this.handlers = handlers;
|
||||
}
|
||||
|
||||
browserWindowObserver.prototype = {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "domwindowopened") {
|
||||
aSubject.QueryInterface(Ci.nsIDOMWindow).addEventListener("load", this, false);
|
||||
} else if (aTopic == "domwindowclosed") {
|
||||
if (aSubject.document.documentElement.getAttribute("windowtype") == "navigator:browser") {
|
||||
this.handlers.onShutdown(aSubject);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent: function(aEvent) {
|
||||
let aWindow = aEvent.currentTarget;
|
||||
aWindow.removeEventListener(aEvent.type, this, false);
|
||||
|
||||
if (aWindow.document.documentElement.getAttribute("windowtype") == "navigator:browser") {
|
||||
this.handlers.onStartup(aWindow);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Run on every window startup
|
||||
function browserWindowStartup(aWindow) {
|
||||
for (let [id, onBuild] of buttonsList) {
|
||||
insertButton(aWindow, id, onBuild);
|
||||
}
|
||||
aWindow.addEventListener("aftercustomization", afterCustomize, false);
|
||||
};
|
||||
|
||||
// Run on every window shutdown
|
||||
function browserWindowShutdown(aWindow) {
|
||||
for (let [id, onBuild] of buttonsList) {
|
||||
removeButton(aWindow, id);
|
||||
}
|
||||
aWindow.removeEventListener("aftercustomization", afterCustomize, false);
|
||||
}
|
||||
|
||||
// Main object
|
||||
const buttons = {
|
||||
createButton: function(aProperties) {
|
||||
// If no buttons were inserted yet, setup global window observer
|
||||
if (buttonsList.size == 0) {
|
||||
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
|
||||
gWindowListener = new browserWindowObserver({
|
||||
onStartup: browserWindowStartup,
|
||||
onShutdown: browserWindowShutdown
|
||||
});
|
||||
ww.registerNotification(gWindowListener);
|
||||
}
|
||||
|
||||
// Add button to list
|
||||
buttonsList.set(aProperties.id, aProperties.onBuild);
|
||||
|
||||
// Inster button to all open windows
|
||||
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
|
||||
let winenu = wm.getEnumerator("navigator:browser");
|
||||
while (winenu.hasMoreElements()) {
|
||||
let win = winenu.getNext();
|
||||
insertButton(win, aProperties.id, aProperties.onBuild);
|
||||
// When first button inserted, add afterCustomize listener
|
||||
if (buttonsList.size == 1) {
|
||||
win.addEventListener("aftercustomization", afterCustomize, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
destroyButton: function(id) {
|
||||
// Remove button from list
|
||||
buttonsList.delete(id);
|
||||
|
||||
// If no more buttons exist, remove global window observer
|
||||
if (buttonsList.size == 0) {
|
||||
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
|
||||
ww.unregisterNotification(gWindowListener);
|
||||
gWindowListener = null;
|
||||
}
|
||||
|
||||
// Remove button from all open windows
|
||||
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
|
||||
let winenu = wm.getEnumerator("navigator:browser");
|
||||
while (winenu.hasMoreElements()) {
|
||||
let win = winenu.getNext();
|
||||
removeButton(win, id);
|
||||
// If no more buttons exist, remove afterCustomize listener
|
||||
if (buttonsList.size == 0) {
|
||||
win.removeEventListener("aftercustomization", afterCustomize, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getNode: function(id, window) {
|
||||
return window[id];
|
||||
}
|
||||
};
|
||||
|
||||
exports.buttons = buttons;
|
||||
Loading…
Add table
Add a link
Reference in a new issue