mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-20 15:27:32 +09:00
Move Add-on SDK source to toolkit/jetpack
This commit is contained in:
parent
0a03067ee3
commit
23b67db438
993 changed files with 484 additions and 100663 deletions
|
|
@ -1,193 +0,0 @@
|
|||
/* 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/. */
|
||||
'use strict';
|
||||
|
||||
module.metadata = {
|
||||
"stability": "unstable"
|
||||
};
|
||||
|
||||
const { Cc, Ci, Cu } = require('chrome');
|
||||
const { on } = require('../system/events');
|
||||
const { id, preferencesBranch } = require('../self');
|
||||
const { localizeInlineOptions } = require('../l10n/prefs');
|
||||
const { Services } = require("resource://gre/modules/Services.jsm");
|
||||
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
const { defer } = require("sdk/core/promise");
|
||||
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";;
|
||||
const DEFAULT_OPTIONS_URL = 'data:text/xml,<placeholder/>';
|
||||
|
||||
const VALID_PREF_TYPES = ['bool', 'boolint', 'integer', 'string', 'color',
|
||||
'file', 'directory', 'control', 'menulist', 'radio'];
|
||||
|
||||
const isFennec = require("sdk/system/xul-app").is("Fennec");
|
||||
|
||||
function enable({ preferences, id }) {
|
||||
let enabled = defer();
|
||||
|
||||
validate(preferences);
|
||||
|
||||
setDefaults(preferences, preferencesBranch);
|
||||
|
||||
// allow the use of custom options.xul
|
||||
AddonManager.getAddonByID(id, (addon) => {
|
||||
on('addon-options-displayed', onAddonOptionsDisplayed, true);
|
||||
enabled.resolve({ id: id });
|
||||
});
|
||||
|
||||
function onAddonOptionsDisplayed({ subject: doc, data }) {
|
||||
if (data === id) {
|
||||
let parent;
|
||||
|
||||
if (isFennec) {
|
||||
parent = doc.querySelector('.options-box');
|
||||
|
||||
// NOTE: This disable the CSS rule that makes the options invisible
|
||||
let item = doc.querySelector('#addons-details .addon-item');
|
||||
item.removeAttribute("optionsURL");
|
||||
} else {
|
||||
parent = doc.getElementById('detail-downloads').parentNode;
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
injectOptions({
|
||||
preferences: preferences,
|
||||
preferencesBranch: preferencesBranch,
|
||||
document: doc,
|
||||
parent: parent,
|
||||
id: id
|
||||
});
|
||||
localizeInlineOptions(doc);
|
||||
} else {
|
||||
throw Error("Preferences parent node not found in Addon Details. The configured custom preferences will not be visible.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return enabled.promise;
|
||||
}
|
||||
exports.enable = enable;
|
||||
|
||||
// centralized sanity checks
|
||||
function validate(preferences) {
|
||||
for (let { name, title, type, label, options } of preferences) {
|
||||
// make sure the title is set and non-empty
|
||||
if (!title)
|
||||
throw Error("The '" + name + "' pref requires a title");
|
||||
|
||||
// make sure that pref type is a valid inline option type
|
||||
if (!~VALID_PREF_TYPES.indexOf(type))
|
||||
throw Error("The '" + name + "' pref must be of valid type");
|
||||
|
||||
// if it's a control, make sure it has a label
|
||||
if (type === 'control' && !label)
|
||||
throw Error("The '" + name + "' control requires a label");
|
||||
|
||||
// if it's a menulist or radio, make sure it has options
|
||||
if (type === 'menulist' || type === 'radio') {
|
||||
if (!options)
|
||||
throw Error("The '" + name + "' pref requires options");
|
||||
|
||||
// make sure each option has a value and a label
|
||||
for (let item of options) {
|
||||
if (!('value' in item) || !('label' in item))
|
||||
throw Error("Each option requires both a value and a label");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: check that pref type matches default value type
|
||||
}
|
||||
}
|
||||
exports.validate = validate;
|
||||
|
||||
// initializes default preferences, emulates defaults/prefs.js
|
||||
function setDefaults(preferences, preferencesBranch) {
|
||||
const branch = Cc['@mozilla.org/preferences-service;1'].
|
||||
getService(Ci.nsIPrefService).
|
||||
getDefaultBranch('extensions.' + preferencesBranch + '.');
|
||||
for (let { name, value } of preferences) {
|
||||
switch (typeof value) {
|
||||
case 'boolean':
|
||||
branch.setBoolPref(name, value);
|
||||
break;
|
||||
case 'number':
|
||||
// must be integer, ignore otherwise
|
||||
if (value % 1 === 0) {
|
||||
branch.setIntPref(name, value);
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
let str = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
str.data = value;
|
||||
branch.setComplexValue(name, Ci.nsISupportsString, str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.setDefaults = setDefaults;
|
||||
|
||||
// dynamically injects inline options into about:addons page at runtime
|
||||
// NOTE: on Firefox Desktop the about:addons page is a xul page document,
|
||||
// on Firefox for Android the about:addons page is an xhtml page, to support both
|
||||
// the XUL xml namespace have to be enforced.
|
||||
function injectOptions({ preferences, preferencesBranch, document, parent, id }) {
|
||||
preferences.forEach(({name, type, hidden, title, description, label, options, on, off}) => {
|
||||
if (hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
let setting = document.createElementNS(XUL_NS, 'setting');
|
||||
setting.setAttribute('pref-name', name);
|
||||
setting.setAttribute('data-jetpack-id', id);
|
||||
setting.setAttribute('pref', 'extensions.' + preferencesBranch + '.' + name);
|
||||
setting.setAttribute('type', type);
|
||||
setting.setAttribute('title', title);
|
||||
if (description)
|
||||
setting.setAttribute('desc', description);
|
||||
|
||||
if (type === 'file' || type === 'directory') {
|
||||
setting.setAttribute('fullpath', 'true');
|
||||
}
|
||||
else if (type === 'control') {
|
||||
let button = document.createElementNS(XUL_NS, 'button');
|
||||
button.setAttribute('pref-name', name);
|
||||
button.setAttribute('data-jetpack-id', id);
|
||||
button.setAttribute('label', label);
|
||||
button.addEventListener('command', function() {
|
||||
Services.obs.notifyObservers(null, `${id}-cmdPressed`, name);
|
||||
}, true);
|
||||
setting.appendChild(button);
|
||||
}
|
||||
else if (type === 'boolint') {
|
||||
setting.setAttribute('on', on);
|
||||
setting.setAttribute('off', off);
|
||||
}
|
||||
else if (type === 'menulist') {
|
||||
let menulist = document.createElementNS(XUL_NS, 'menulist');
|
||||
let menupopup = document.createElementNS(XUL_NS, 'menupopup');
|
||||
for (let { value, label } of options) {
|
||||
let menuitem = document.createElementNS(XUL_NS, 'menuitem');
|
||||
menuitem.setAttribute('value', value);
|
||||
menuitem.setAttribute('label', label);
|
||||
menupopup.appendChild(menuitem);
|
||||
}
|
||||
menulist.appendChild(menupopup);
|
||||
setting.appendChild(menulist);
|
||||
}
|
||||
else if (type === 'radio') {
|
||||
let radiogroup = document.createElementNS(XUL_NS, 'radiogroup');
|
||||
for (let { value, label } of options) {
|
||||
let radio = document.createElementNS(XUL_NS, 'radio');
|
||||
radio.setAttribute('value', value);
|
||||
radio.setAttribute('label', label);
|
||||
radiogroup.appendChild(radio);
|
||||
}
|
||||
setting.appendChild(radiogroup);
|
||||
}
|
||||
|
||||
parent.appendChild(setting);
|
||||
});
|
||||
}
|
||||
exports.injectOptions = injectOptions;
|
||||
Loading…
Add table
Add a link
Reference in a new issue