mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-20 09:27:58 +01:00
Update :extensions with live update and buttons like :downloads. Rename to :addons.
--HG-- branch : key-processing
This commit is contained in:
@@ -1188,17 +1188,19 @@ var CommandLine = Module("commandline", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
withOutputToString: function (fn, self) {
|
withOutputToString: function (fn, self) {
|
||||||
let buffer = [];
|
|
||||||
dactyl.registerObserver("echoLine", observe, true);
|
dactyl.registerObserver("echoLine", observe, true);
|
||||||
dactyl.registerObserver("echoMultiline", observe, true);
|
dactyl.registerObserver("echoMultiline", observe, true);
|
||||||
|
|
||||||
|
let output = [];
|
||||||
function observe(str, highlight, dom) {
|
function observe(str, highlight, dom) {
|
||||||
buffer.push(dom && !isString(str) ? util.domToString(dom) : str);
|
output.push(dom && !isString(str) ? dom : str);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.savingOutput = true;
|
this.savingOutput = true;
|
||||||
dactyl.trapErrors.apply(dactyl, [fn, self].concat(Array.slice(arguments, 2)));
|
dactyl.trapErrors.apply(dactyl, [fn, self].concat(Array.slice(arguments, 2)));
|
||||||
this.savingOutput = false;
|
this.savingOutput = false;
|
||||||
return buffer.join("\n");
|
return output.map(function (elem) elem instanceof Node ? util.domToString(elem) : elem)
|
||||||
|
.join("\n");
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1527,14 +1527,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
},
|
},
|
||||||
|
|
||||||
commands: function () {
|
commands: function () {
|
||||||
commands.add(["addo[ns]"],
|
|
||||||
"Manage available Extensions and Themes",
|
|
||||||
function () {
|
|
||||||
dactyl.open("chrome://mozapps/content/extensions/extensions.xul",
|
|
||||||
{ from: "addons" });
|
|
||||||
},
|
|
||||||
{ argCount: "0" });
|
|
||||||
|
|
||||||
commands.add(["dia[log]"],
|
commands.add(["dia[log]"],
|
||||||
"Open a " + config.appName + " dialog",
|
"Open a " + config.appName + " dialog",
|
||||||
function (args) {
|
function (args) {
|
||||||
@@ -1592,255 +1584,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
literal: 0
|
literal: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
const addonErrors = array.toObject([
|
|
||||||
[AddonManager.ERROR_NETWORK_FAILURE, "A network error occurred"],
|
|
||||||
[AddonManager.ERROR_INCORRECT_HASH, "The downloaded file did not match the expected hash"],
|
|
||||||
[AddonManager.ERROR_CORRUPT_FILE, "The file appears to be corrupt"],
|
|
||||||
[AddonManager.ERROR_FILE_ACCESS, "There was an error accessing the filesystem"]]);
|
|
||||||
|
|
||||||
function listener(action, event)
|
|
||||||
function addonListener(install) {
|
|
||||||
if (typeof dactyl !== "undefined")
|
|
||||||
dactyl[install.error ? "echoerr" : "echomsg"](
|
|
||||||
"Add-on " + action + " " + event + ": " + (install.name || install.sourceURI.spec) +
|
|
||||||
(install.error ? ": " + addonErrors[install.error] : ""));
|
|
||||||
}
|
|
||||||
const addonListener = {
|
|
||||||
onNewInstall: function (install) {},
|
|
||||||
onExternalInstall: function (addon, existingAddon, needsRestart) {},
|
|
||||||
onDownloadStarted: listener("download", "started"),
|
|
||||||
onDownloadEnded: listener("download", "complete"),
|
|
||||||
onDownloadCancelled: listener("download", "cancelled"),
|
|
||||||
onDownloadFailed: listener("download", "failed"),
|
|
||||||
onDownloadProgress: function (install) {},
|
|
||||||
onInstallStarted: function (install) {},
|
|
||||||
onInstallEnded: listener("installation", "complete"),
|
|
||||||
onInstallCancelled: listener("installation", "cancelled"),
|
|
||||||
onInstallFailed: listener("installation", "failed")
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateAddons = Class("UpgradeListener", {
|
|
||||||
init: function init(addons) {
|
|
||||||
dactyl.assert(!addons.length || addons[0].findUpdates,
|
|
||||||
"Not available on " + config.host + " " + services.runtime.version);
|
|
||||||
this.remaining = addons;
|
|
||||||
this.upgrade = [];
|
|
||||||
dactyl.echomsg("Checking updates for addons: " + addons.map(function (a) a.name).join(", "));
|
|
||||||
for (let addon in values(addons))
|
|
||||||
addon.findUpdates(this, AddonManager.UPDATE_WHEN_USER_REQUESTED, null, null);
|
|
||||||
},
|
|
||||||
addonListener: {
|
|
||||||
__proto__: addonListener,
|
|
||||||
onDownloadStarted: function () {},
|
|
||||||
onDownloadEnded: function () {}
|
|
||||||
},
|
|
||||||
onUpdateAvailable: function (addon, install) {
|
|
||||||
this.upgrade.push(addon);
|
|
||||||
install.addListener(this.addonListener);
|
|
||||||
install.install();
|
|
||||||
},
|
|
||||||
onUpdateFinished: function (addon, error) {
|
|
||||||
this.remaining = this.remaining.filter(function (a) a != addon);
|
|
||||||
if (!this.remaining.length)
|
|
||||||
dactyl.echomsg(
|
|
||||||
this.upgrade.length
|
|
||||||
? "Installing updates for addons: " + this.upgrade.map(function (i) i.name).join(", ")
|
|
||||||
: "No addon updates found");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
function callResult(method) {
|
|
||||||
let args = Array.slice(arguments, 1);
|
|
||||||
return function (result) { result[method].apply(result, args); };
|
|
||||||
}
|
|
||||||
|
|
||||||
commands.add(["exta[dd]"],
|
|
||||||
"Install an extension",
|
|
||||||
function (args) {
|
|
||||||
let url = args[0];
|
|
||||||
let file = io.File(url);
|
|
||||||
function install(addonInstall) {
|
|
||||||
addonInstall.addListener(addonListener);
|
|
||||||
addonInstall.install();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file.exists())
|
|
||||||
AddonManager.getInstallForURL(url, install, "application/x-xpinstall");
|
|
||||||
else if (file.isReadable() && file.isFile())
|
|
||||||
AddonManager.getInstallForFile(file, install, "application/x-xpinstall");
|
|
||||||
else if (file.isDirectory())
|
|
||||||
dactyl.echoerr("Cannot install a directory: " + file.path.quote());
|
|
||||||
else
|
|
||||||
dactyl.echoerr("E484: Can't open file " + file.path);
|
|
||||||
}, {
|
|
||||||
argCount: "1",
|
|
||||||
completer: function (context) {
|
|
||||||
context.filters.push(function ({ item }) item.isDirectory() || /\.xpi$/.test(item.leafName));
|
|
||||||
completion.file(context);
|
|
||||||
},
|
|
||||||
literal: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: handle extension dependencies
|
|
||||||
[
|
|
||||||
{
|
|
||||||
name: "extde[lete]",
|
|
||||||
description: "Uninstall an extension",
|
|
||||||
action: callResult("uninstall"),
|
|
||||||
perm: "uninstall"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "exte[nable]",
|
|
||||||
description: "Enable an extension",
|
|
||||||
action: function (addon) addon.userDisabled = false,
|
|
||||||
filter: function ({ item }) item.userDisabled,
|
|
||||||
perm: "enable"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "extd[isable]",
|
|
||||||
description: "Disable an extension",
|
|
||||||
action: function (addon) addon.userDisabled = true,
|
|
||||||
filter: function ({ item }) !item.userDisabled,
|
|
||||||
perm: "disable"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "extr[ehash]",
|
|
||||||
description: "Reload an extension",
|
|
||||||
action: function (addon) {
|
|
||||||
dactyl.assert(dactyl.has("Gecko2"), "This command is not useful in this version of " + config.host);
|
|
||||||
util.timeout(function () {
|
|
||||||
addon.userDisabled = true;
|
|
||||||
addon.userDisabled = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
get filter() {
|
|
||||||
let ids = set(keys(JSON.parse(prefs.get("extensions.bootstrappedAddons", "{}"))));
|
|
||||||
return function ({ item }) !item.userDisabled && set.has(ids, item.id);
|
|
||||||
},
|
|
||||||
perm: "disable"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "extt[oggle]",
|
|
||||||
description: "Toggle an extension's enabled status",
|
|
||||||
action: function (addon) addon.userDisabled = !addon.userDisabled
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "extu[pdate]",
|
|
||||||
description: "Update an extension",
|
|
||||||
actions: updateAddons,
|
|
||||||
perm: "upgrade"
|
|
||||||
}
|
|
||||||
].forEach(function (command) {
|
|
||||||
let perm = command.perm && AddonManager["PERM_CAN_" + command.perm.toUpperCase()];
|
|
||||||
function ok(addon) !perm || addon.permissions & perm;
|
|
||||||
commands.add([command.name],
|
|
||||||
command.description,
|
|
||||||
function (args) {
|
|
||||||
let name = args[0];
|
|
||||||
if (args.bang)
|
|
||||||
dactyl.assert(!name, "E488: Trailing characters");
|
|
||||||
else
|
|
||||||
dactyl.assert(name, "E471: Argument required");
|
|
||||||
|
|
||||||
AddonManager.getAddonsByTypes(["extension"], dactyl.wrapCallback(function (list) {
|
|
||||||
if (!args.bang) {
|
|
||||||
list = list.filter(function (extension) extension.name == name);
|
|
||||||
if (list.length == 0)
|
|
||||||
return void dactyl.echoerr("E475: Invalid argument: " + name);
|
|
||||||
if (!list.every(ok))
|
|
||||||
return void dactyl.echoerr("Permission denied");
|
|
||||||
}
|
|
||||||
if (command.actions)
|
|
||||||
command.actions(list);
|
|
||||||
else
|
|
||||||
list.forEach(command.action);
|
|
||||||
}));
|
|
||||||
}, {
|
|
||||||
argCount: "?", // FIXME: should be "1"
|
|
||||||
bang: true,
|
|
||||||
completer: function (context) {
|
|
||||||
completion.extension(context);
|
|
||||||
context.filters.push(function ({ item }) ok(item));
|
|
||||||
if (command.filter)
|
|
||||||
context.filters.push(command.filter);
|
|
||||||
},
|
|
||||||
literal: 0
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
commands.add(["exto[ptions]", "extp[references]"],
|
|
||||||
"Open an extension's preference dialog",
|
|
||||||
function (args) {
|
|
||||||
AddonManager.getAddonsByTypes(["extension"], dactyl.wrapCallback(function (list) {
|
|
||||||
list = list.filter(function (extension) extension.name == args[0]);
|
|
||||||
if (!list.length || !list[0].optionsURL)
|
|
||||||
dactyl.echoerr("E474: Invalid argument");
|
|
||||||
else if (args.bang)
|
|
||||||
window.openDialog(list[0].optionsURL, "_blank", "chrome");
|
|
||||||
else
|
|
||||||
dactyl.open(list[0].optionsURL, { from: "extoptions" });
|
|
||||||
}));
|
|
||||||
}, {
|
|
||||||
argCount: "1",
|
|
||||||
bang: true,
|
|
||||||
completer: function (context) {
|
|
||||||
completion.extension(context);
|
|
||||||
context.filters.push(function ({ item }) item.isActive && item.optionsURL);
|
|
||||||
},
|
|
||||||
literal: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
commands.add(["extens[ions]", "exts"],
|
|
||||||
"List available extensions",
|
|
||||||
function (args) {
|
|
||||||
function addonExtra(e) {
|
|
||||||
let extra;
|
|
||||||
if (e.pendingOperations & AddonManager.PENDING_UNINSTALL)
|
|
||||||
extra = ["Disabled", "uninstalled"];
|
|
||||||
else if (e.pendingOperations & AddonManager.PENDING_DISABLE)
|
|
||||||
extra = ["Disabled", "disabled"];
|
|
||||||
else if (e.pendingOperations & AddonManager.PENDING_INSTALL)
|
|
||||||
extra = ["Enabled", "installed"];
|
|
||||||
else if (e.pendingOperations & AddonManager.PENDING_ENABLE)
|
|
||||||
extra = ["Enabled", "enabled"];
|
|
||||||
else if (e.pendingOperations & AddonManager.PENDING_UPGRADE)
|
|
||||||
extra = ["Enabled", "upgraded"];
|
|
||||||
if (extra)
|
|
||||||
return <> (<span highlight={extra[0]}>{extra[1]}</span>
|
|
||||||
 on restart)</>;
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
let waiting = true;
|
|
||||||
AddonManager.getAddonsByTypes(["extension"], function (extensions) {
|
|
||||||
if (args[0])
|
|
||||||
extensions = extensions.filter(function (extension) extension.name.indexOf(args[0]) >= 0);
|
|
||||||
extensions.sort(function (a, b) String.localeCompare(a.name, b.name));
|
|
||||||
|
|
||||||
if (extensions.length > 0)
|
|
||||||
commandline.commandOutput(
|
|
||||||
template.tabular(["Name", "Version", "Status", "Description"], [],
|
|
||||||
([template.icon({ icon: e.iconURL }, e.name),
|
|
||||||
e.version,
|
|
||||||
(e.isActive ? <span highlight="Enabled">enabled</span>
|
|
||||||
: <span highlight="Disabled">disabled</span>) +
|
|
||||||
addonExtra(e),
|
|
||||||
e.description]
|
|
||||||
for ([, e] in Iterator(extensions)))));
|
|
||||||
else if (filter)
|
|
||||||
dactyl.echoerr("Exxx: No extension matching " + filter.quote());
|
|
||||||
else
|
|
||||||
dactyl.echoerr("No extensions installed");
|
|
||||||
waiting = false;
|
|
||||||
});
|
|
||||||
if (commandline.savingOutput)
|
|
||||||
util.waitFor(function () !waiting);
|
|
||||||
},
|
|
||||||
{ argCount: "?" });
|
|
||||||
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name: "h[elp]",
|
name: "h[elp]",
|
||||||
|
|||||||
@@ -41,16 +41,11 @@
|
|||||||
<h2 tag="dialogs">Dialogs</h2>
|
<h2 tag="dialogs">Dialogs</h2>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>:addo :addons</tags>
|
<tags>:ao :addo :addons</tags>
|
||||||
<strut/>
|
<strut/>
|
||||||
<spec>:addo<oa>ns</oa></spec>
|
<spec>:addo<oa>ns</oa></spec>
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>Opens the add-on list.</p>
|
||||||
Opens the &dactyl.host; addon manager, where extensions and themes
|
|
||||||
may be installed, removed, disabled, and configured. See also
|
|
||||||
<ex>:extensions</ex>, <ex>:extadd</ex>, <ex>:extoptions</ex>,
|
|
||||||
<ex>:extenable</ex>, <ex>:extdisable</ex>, and <ex>:extdelete</ex>.
|
|
||||||
</p>
|
|
||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
@@ -129,16 +124,6 @@
|
|||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item>
|
|
||||||
<tags>:exts :extens :extensions</tags>
|
|
||||||
<spec>:extens<oa>ions</oa></spec>
|
|
||||||
<spec>:exts</spec>
|
|
||||||
<strut/>
|
|
||||||
<description>
|
|
||||||
<p>List all installed extensions.</p>
|
|
||||||
</description>
|
|
||||||
</item>
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>:exto :extoptions</tags>
|
<tags>:exto :extoptions</tags>
|
||||||
<spec>:exto<oa>ptions</oa><oa>!</oa> <a>extension</a></spec>
|
<spec>:exto<oa>ptions</oa><oa>!</oa> <a>extension</a></spec>
|
||||||
|
|||||||
515
common/modules/addons.jsm
Normal file
515
common/modules/addons.jsm
Normal file
@@ -0,0 +1,515 @@
|
|||||||
|
// Copyright (c) 2011 by Kris Maglione <maglione.k@gmail.com>
|
||||||
|
//
|
||||||
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
Components.utils.import("resource://dactyl/bootstrap.jsm");
|
||||||
|
defineModule("addons", {
|
||||||
|
exports: ["AddonManager", "Addons", "Addon", "addons"],
|
||||||
|
require: ["services"],
|
||||||
|
use: ["config", "io", "prefs", "template", "util"]
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
var callResult = function callResult(method) {
|
||||||
|
let args = Array.slice(arguments, 1);
|
||||||
|
return function (result) { result[method].apply(result, args); };
|
||||||
|
}
|
||||||
|
|
||||||
|
var listener = function listener(action, event)
|
||||||
|
function addonListener(install) {
|
||||||
|
this.dactyl[install.error ? "echoerr" : "echomsg"](
|
||||||
|
"Add-on " + action + " " + event + ": " + (install.name || install.sourceURI.spec) +
|
||||||
|
(install.error ? ": " + addonErrors[install.error] : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
var AddonListener = Class("AddonListener", {
|
||||||
|
init: function init(modules) {
|
||||||
|
this.dactyl = modules.dactyl;
|
||||||
|
},
|
||||||
|
|
||||||
|
onNewInstall: function (install) {},
|
||||||
|
onExternalInstall: function (addon, existingAddon, needsRestart) {},
|
||||||
|
onDownloadStarted: listener("download", "started"),
|
||||||
|
onDownloadEnded: listener("download", "complete"),
|
||||||
|
onDownloadCancelled: listener("download", "cancelled"),
|
||||||
|
onDownloadFailed: listener("download", "failed"),
|
||||||
|
onDownloadProgress: function (install) {},
|
||||||
|
onInstallStarted: function (install) {},
|
||||||
|
onInstallEnded: listener("installation", "complete"),
|
||||||
|
onInstallCancelled: listener("installation", "cancelled"),
|
||||||
|
onInstallFailed: listener("installation", "failed")
|
||||||
|
});
|
||||||
|
|
||||||
|
var updateAddons = Class("UpgradeListener", AddonListener, {
|
||||||
|
init: function init(addons, modules) {
|
||||||
|
init.supercall(this, modules);
|
||||||
|
|
||||||
|
util.assert(!addons.length || addons[0].findUpdates,
|
||||||
|
"Not available on " + config.host + " " + services.runtime.version);
|
||||||
|
|
||||||
|
this.remaining = addons;
|
||||||
|
this.upgrade = [];
|
||||||
|
this.dactyl.echomsg("Checking updates for addons: " + addons.map(function (a) a.name).join(", "));
|
||||||
|
for (let addon in values(addons))
|
||||||
|
addon.findUpdates(this, AddonManager.UPDATE_WHEN_USER_REQUESTED, null, null);
|
||||||
|
|
||||||
|
},
|
||||||
|
onUpdateAvailable: function (addon, install) {
|
||||||
|
this.upgrade.push(addon);
|
||||||
|
install.addListener(this);
|
||||||
|
install.install();
|
||||||
|
},
|
||||||
|
onUpdateFinished: function (addon, error) {
|
||||||
|
this.remaining = this.remaining.filter(function (a) a != addon);
|
||||||
|
if (!this.remaining.length)
|
||||||
|
this.dactyl.echomsg(
|
||||||
|
this.upgrade.length
|
||||||
|
? "Installing updates for addons: " + this.upgrade.map(function (i) i.name).join(", ")
|
||||||
|
: "No addon updates found");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var actions = {
|
||||||
|
delete: {
|
||||||
|
name: "extde[lete]",
|
||||||
|
description: "Uninstall an extension",
|
||||||
|
action: callResult("uninstall"),
|
||||||
|
perm: "uninstall"
|
||||||
|
},
|
||||||
|
enable: {
|
||||||
|
name: "exte[nable]",
|
||||||
|
description: "Enable an extension",
|
||||||
|
action: function (addon) addon.userDisabled = false,
|
||||||
|
filter: function ({ item }) item.userDisabled,
|
||||||
|
perm: "enable"
|
||||||
|
},
|
||||||
|
disable: {
|
||||||
|
name: "extd[isable]",
|
||||||
|
description: "Disable an extension",
|
||||||
|
action: function (addon) addon.userDisabled = true,
|
||||||
|
filter: function ({ item }) !item.userDisabled,
|
||||||
|
perm: "disable"
|
||||||
|
},
|
||||||
|
rehash: {
|
||||||
|
name: "extr[ehash]",
|
||||||
|
description: "Reload an extension",
|
||||||
|
action: function (addon) {
|
||||||
|
dactyl.assert(dactyl.has("Gecko2"), "This command is not useful in this version of " + config.host);
|
||||||
|
util.timeout(function () {
|
||||||
|
addon.userDisabled = true;
|
||||||
|
addon.userDisabled = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get filter() {
|
||||||
|
let ids = set(keys(JSON.parse(prefs.get("extensions.bootstrappedAddons", "{}"))));
|
||||||
|
return function ({ item }) !item.userDisabled && set.has(ids, item.id);
|
||||||
|
},
|
||||||
|
perm: "disable"
|
||||||
|
},
|
||||||
|
toggle: {
|
||||||
|
name: "extt[oggle]",
|
||||||
|
description: "Toggle an extension's enabled status",
|
||||||
|
action: function (addon) addon.userDisabled = !addon.userDisabled
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
name: "extu[pdate]",
|
||||||
|
description: "Update an extension",
|
||||||
|
actions: updateAddons,
|
||||||
|
perm: "upgrade"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var Addon = Class("Addon", {
|
||||||
|
init: function init(addon, list) {
|
||||||
|
this.addon = addon;
|
||||||
|
this.instance = this;
|
||||||
|
this.list = list;
|
||||||
|
|
||||||
|
this.nodes = {
|
||||||
|
commandTarget: this
|
||||||
|
};
|
||||||
|
util.xmlToDom(
|
||||||
|
<li highlight="Addon" key="row" xmlns:dactyl={NS} xmlns={XHTML}>
|
||||||
|
<span highlight="AddonName" key="name">
|
||||||
|
</span>
|
||||||
|
<span highlight="AddonVersion" key="version"/>
|
||||||
|
<span highlight="AddonStatus" key="status"/>
|
||||||
|
<span highlight="AddonButtons Buttons">
|
||||||
|
<a highlight="Button" key="enable">On </a>
|
||||||
|
<a highlight="Button" key="disable">Off</a>
|
||||||
|
<a highlight="Button" key="delete">Del</a>
|
||||||
|
<a highlight="Button" key="update">Upd</a>
|
||||||
|
</span>
|
||||||
|
<span highlight="AddonDescription" key="description"/>
|
||||||
|
</li>,
|
||||||
|
this.list.document, this.nodes);
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
commandAllowed: function commandAllowed(cmd) {
|
||||||
|
util.assert(set.has(actions, cmd), "Unknown command");
|
||||||
|
|
||||||
|
let action = actions[cmd];
|
||||||
|
if ("perm" in action && !(this.permissions & AddonManager["PERM_CAN_" + action.perm.toUpperCase()]))
|
||||||
|
return false;
|
||||||
|
if ("filter" in action && !action.filter({ item: this }))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
command: function command(cmd) {
|
||||||
|
util.assert(this.commandAllowed(cmd), "Command not allowed");
|
||||||
|
|
||||||
|
let action = actions[cmd];
|
||||||
|
if (action.action)
|
||||||
|
action.action.call(this.modules, this);
|
||||||
|
else
|
||||||
|
action.actions([this], this.list.modules);
|
||||||
|
},
|
||||||
|
|
||||||
|
compare: function compare(other) String.localeCompare(this.name, other.name),
|
||||||
|
|
||||||
|
get statusInfo() {
|
||||||
|
let info = this.isActive ? <span highlight="Enabled">enabled</span>
|
||||||
|
: <span highlight="Disabled">disabled</span>;
|
||||||
|
|
||||||
|
let pending;
|
||||||
|
if (this.pendingOperations & AddonManager.PENDING_UNINSTALL)
|
||||||
|
pending = ["Disabled", "uninstalled"];
|
||||||
|
else if (this.pendingOperations & AddonManager.PENDING_DISABLE)
|
||||||
|
pending = ["Disabled", "disabled"];
|
||||||
|
else if (this.pendingOperations & AddonManager.PENDING_INSTALL)
|
||||||
|
pending = ["Enabled", "installed"];
|
||||||
|
else if (this.pendingOperations & AddonManager.PENDING_ENABLE)
|
||||||
|
pending = ["Enabled", "enabled"];
|
||||||
|
else if (this.pendingOperations & AddonManager.PENDING_UPGRADE)
|
||||||
|
pending = ["Enabled", "upgraded"];
|
||||||
|
if (pending)
|
||||||
|
return <>{info} (<span highlight={pending[0]}>{pending[1]}</span>
|
||||||
|
 on restart)</>;
|
||||||
|
return info;
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function callee() {
|
||||||
|
let self = this;
|
||||||
|
function update(key, xml) {
|
||||||
|
let node = self.nodes[key];
|
||||||
|
while (node.firstChild)
|
||||||
|
node.removeChild(node.firstChild);
|
||||||
|
node.appendChild(util.xmlToDom(<>{xml}</>, self.list.document));
|
||||||
|
}
|
||||||
|
|
||||||
|
update("name", template.icon({ icon: this.iconURL }, this.name));
|
||||||
|
this.nodes.version.textContent = this.version;
|
||||||
|
update("status", this.statusInfo);
|
||||||
|
this.nodes.description.textContent = this.description;
|
||||||
|
|
||||||
|
for (let node in values(this.nodes))
|
||||||
|
if (node.update && node.update !== callee)
|
||||||
|
node.update();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
["cancelUninstall", "findUpdates", "getResourceURI", "hasResource",
|
||||||
|
"isCompatibleWith", "uninstall"].forEach(function (prop) {
|
||||||
|
Addon.prototype[prop] = function proxy() this.addon[prop].apply(this.addon, arguments);
|
||||||
|
});
|
||||||
|
|
||||||
|
["aboutURL", "appDisabled", "applyBackgroundUpdates", "blocklistState",
|
||||||
|
"contributors", "creator", "description", "developers", "homepageURL",
|
||||||
|
"iconURL", "id", "install", "installDate", "isActive", "isCompatible",
|
||||||
|
"isPlatformCompatible", "name", "operationsRequiringRestart",
|
||||||
|
"optionsURL", "pendingOperations", "pendingUpgrade", "permissions",
|
||||||
|
"providesUpdatesSecurely", "releaseNotesURI", "scope", "screenshots",
|
||||||
|
"size", "sourceURI", "translators", "type", "updateDate",
|
||||||
|
"userDisabled", "version"].forEach(function (prop) {
|
||||||
|
Object.defineProperty(Addon.prototype, prop, {
|
||||||
|
get: function get_proxy() this.addon[prop],
|
||||||
|
set: function set_proxy(val) this.addon[prop] = val
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var AddonList = Class("AddonList", {
|
||||||
|
init: function init(modules, types) {
|
||||||
|
this.modules = modules;
|
||||||
|
this.nodes = {};
|
||||||
|
this.addons = [];
|
||||||
|
this.ready = false;
|
||||||
|
|
||||||
|
AddonManager.getAddonsByTypes(types, this.closure(function (addons) {
|
||||||
|
addons.forEach(this.closure.addAddon);
|
||||||
|
this.ready = true;
|
||||||
|
this.update();
|
||||||
|
}));
|
||||||
|
AddonManager.addAddonListener(this);
|
||||||
|
},
|
||||||
|
cleanup: function cleanup() {
|
||||||
|
AddonManager.removeAddonListener(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
message: Class.memoize(function () {
|
||||||
|
|
||||||
|
util.xmlToDom(<ul highlight="Addons" key="list" xmlns={XHTML}>
|
||||||
|
<li highlight="AddonHead">
|
||||||
|
<span>Name</span>
|
||||||
|
<span>Version</span>
|
||||||
|
<span>Status</span>
|
||||||
|
<span/>
|
||||||
|
<span>Description</span>
|
||||||
|
</li>
|
||||||
|
</ul>, this.document, this.nodes);
|
||||||
|
|
||||||
|
return this.nodes.list;
|
||||||
|
}),
|
||||||
|
|
||||||
|
addAddon: function addAddon(addon) {
|
||||||
|
if (addon.id in this.addons)
|
||||||
|
this.update(addon);
|
||||||
|
else {
|
||||||
|
addon = Addon(addon, this);
|
||||||
|
this.addons[addon.id] = addon;
|
||||||
|
|
||||||
|
let index = values(this.addons).sort(function (a, b) a.compare(b))
|
||||||
|
.indexOf(addon);
|
||||||
|
|
||||||
|
this.nodes.list.insertBefore(addon.nodes.row,
|
||||||
|
this.nodes.list.childNodes[index + 1]);
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeAddon: function removeAddon(addon) {
|
||||||
|
if (addon.id in this.addons) {
|
||||||
|
this.nodes.list.removeChild(this.addons[addon.id].nodes.row);
|
||||||
|
delete this.addons[addon.id];
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
leave: function leave(stack) {
|
||||||
|
if (stack.pop)
|
||||||
|
this.cleanup();
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function update(addon) {
|
||||||
|
if (addon && addon.id in this.addons)
|
||||||
|
this.addons[addon.id].update();
|
||||||
|
if (this.ready)
|
||||||
|
this.modules.commandline.updateOutputHeight(false);
|
||||||
|
},
|
||||||
|
|
||||||
|
onDisabled: function (addon) { this.update(addon); },
|
||||||
|
onDisabling: function (addon) { this.update(addon); },
|
||||||
|
onEnabled: function (addon) { this.update(addon); },
|
||||||
|
onEnabling: function (addon) { this.update(addon); },
|
||||||
|
onInstalled: function (addon) { this.addAddon(addon); },
|
||||||
|
onInstalling: function (addon) { this.update(addon); },
|
||||||
|
onUninstalled: function (addon) { this.removeAddon(addon); },
|
||||||
|
onUninstalling: function (addon) { this.update(addon); },
|
||||||
|
onOperationCancelled: function (addon) { this.update(addon); },
|
||||||
|
onPropertyChanged: function onPropertyChanged(addon, properties) {}
|
||||||
|
});
|
||||||
|
|
||||||
|
var Addons = Module("addons", {
|
||||||
|
}, {
|
||||||
|
}, {
|
||||||
|
commands: function (dactyl, modules, window) {
|
||||||
|
const { commands, completion } = modules;
|
||||||
|
|
||||||
|
let addonListener = AddonListener(modules);
|
||||||
|
|
||||||
|
commands.add(["exta[dd]"],
|
||||||
|
"Install an extension",
|
||||||
|
function (args) {
|
||||||
|
let url = args[0];
|
||||||
|
let file = io.File(url);
|
||||||
|
function install(addonInstall) {
|
||||||
|
addonInstall.addListener(addonListener);
|
||||||
|
addonInstall.install();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.exists())
|
||||||
|
AddonManager.getInstallForURL(url, install, "application/x-xpinstall");
|
||||||
|
else if (file.isReadable() && file.isFile())
|
||||||
|
AddonManager.getInstallForFile(file, install, "application/x-xpinstall");
|
||||||
|
else if (file.isDirectory())
|
||||||
|
dactyl.echoerr("Cannot install a directory: " + file.path.quote());
|
||||||
|
else
|
||||||
|
dactyl.echoerr("E484: Can't open file " + file.path);
|
||||||
|
}, {
|
||||||
|
argCount: "1",
|
||||||
|
completer: function (context) {
|
||||||
|
context.filters.push(function ({ item }) item.isDirectory() || /\.xpi$/.test(item.leafName));
|
||||||
|
completion.file(context);
|
||||||
|
},
|
||||||
|
literal: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: handle extension dependencies
|
||||||
|
values(actions).forEach(function (command) {
|
||||||
|
let perm = command.perm && AddonManager["PERM_CAN_" + command.perm.toUpperCase()];
|
||||||
|
function ok(addon) !perm || addon.permissions & perm;
|
||||||
|
|
||||||
|
commands.add([command.name],
|
||||||
|
command.description,
|
||||||
|
function (args) {
|
||||||
|
let name = args[0];
|
||||||
|
if (args.bang)
|
||||||
|
dactyl.assert(!name, "E488: Trailing characters");
|
||||||
|
else
|
||||||
|
dactyl.assert(name, "E471: Argument required");
|
||||||
|
|
||||||
|
AddonManager.getAddonsByTypes(["extension"], dactyl.wrapCallback(function (list) {
|
||||||
|
if (!args.bang) {
|
||||||
|
list = list.filter(function (extension) extension.name == name);
|
||||||
|
if (list.length == 0)
|
||||||
|
return void dactyl.echoerr("E475: Invalid argument: " + name);
|
||||||
|
if (!list.every(ok))
|
||||||
|
return void dactyl.echoerr("Permission denied");
|
||||||
|
}
|
||||||
|
if (command.actions)
|
||||||
|
command.actions(list, this.modules);
|
||||||
|
else
|
||||||
|
list.forEach(command.action, this.modules);
|
||||||
|
}));
|
||||||
|
}, {
|
||||||
|
argCount: "?", // FIXME: should be "1"
|
||||||
|
bang: true,
|
||||||
|
completer: function (context) {
|
||||||
|
completion.extension(context);
|
||||||
|
context.filters.push(function ({ item }) ok(item));
|
||||||
|
if (command.filter)
|
||||||
|
context.filters.push(command.filter);
|
||||||
|
},
|
||||||
|
literal: 0
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
commands.add(["exto[ptions]", "extp[references]"],
|
||||||
|
"Open an extension's preference dialog",
|
||||||
|
function (args) {
|
||||||
|
AddonManager.getAddonsByTypes(["extension"], dactyl.wrapCallback(function (list) {
|
||||||
|
list = list.filter(function (extension) extension.name == args[0]);
|
||||||
|
if (!list.length || !list[0].optionsURL)
|
||||||
|
dactyl.echoerr("E474: Invalid argument");
|
||||||
|
else if (args.bang)
|
||||||
|
window.openDialog(list[0].optionsURL, "_blank", "chrome");
|
||||||
|
else
|
||||||
|
dactyl.open(list[0].optionsURL, { from: "extoptions" });
|
||||||
|
}));
|
||||||
|
}, {
|
||||||
|
argCount: "1",
|
||||||
|
bang: true,
|
||||||
|
completer: function (context) {
|
||||||
|
completion.extension(context);
|
||||||
|
context.filters.push(function ({ item }) item.isActive && item.optionsURL);
|
||||||
|
},
|
||||||
|
literal: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
commands.add(["addo[ns]", "ao"],
|
||||||
|
"List installed extensions",
|
||||||
|
function (args) {
|
||||||
|
let addons = AddonList(modules, ["extension"]);
|
||||||
|
modules.commandline.echo(addons);
|
||||||
|
|
||||||
|
if (modules.commandline.savingOutput)
|
||||||
|
util.waitFor(function () addons.ready);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!Ci.nsIExtensionManager || !services.extensionManager)
|
||||||
|
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||||
|
else
|
||||||
|
var AddonManager = {
|
||||||
|
getAddonByID: function (id, callback) {
|
||||||
|
callback = callback || util.identity;
|
||||||
|
let addon = id;
|
||||||
|
if (!isObject(addon))
|
||||||
|
addon = services.extensionManager.getItemForID(id);
|
||||||
|
if (!addon)
|
||||||
|
return callback(null);
|
||||||
|
addon = Object.create(addon);
|
||||||
|
|
||||||
|
function getRdfProperty(item, property) {
|
||||||
|
let resource = services.rdf.GetResource("urn:mozilla:item:" + item.id);
|
||||||
|
let value = "";
|
||||||
|
|
||||||
|
if (resource) {
|
||||||
|
let target = services.extensionManager.datasource.GetTarget(resource,
|
||||||
|
services.rdf.GetResource("http://www.mozilla.org/2004/em-rdf#" + property), true);
|
||||||
|
if (target && target instanceof Ci.nsIRDFLiteral)
|
||||||
|
value = target.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
["aboutURL", "creator", "description", "developers",
|
||||||
|
"homepageURL", "installDate", "optionsURL",
|
||||||
|
"releaseNotesURI", "updateDate"].forEach(function (item) {
|
||||||
|
memoize(addon, item, function (item) getRdfProperty(this, item));
|
||||||
|
});
|
||||||
|
|
||||||
|
update(addon, {
|
||||||
|
|
||||||
|
appDisabled: false,
|
||||||
|
|
||||||
|
installLocation: Class.memoize(function () services.extensionManager.getInstallLocation(this.id)),
|
||||||
|
getResourceURI: function getResourceURI(path) {
|
||||||
|
let file = this.installLocation.getItemFile(this.id, path);
|
||||||
|
return services.io.newFileURI(file);
|
||||||
|
},
|
||||||
|
|
||||||
|
isActive: getRdfProperty(addon, "isDisabled") != "true",
|
||||||
|
|
||||||
|
uninstall: function uninstall() {
|
||||||
|
services.extensionManager.uninstallItem(this.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
get userDisabled() getRdfProperty(addon, "userDisabled") === "true",
|
||||||
|
set userDisabled(val) {
|
||||||
|
services.extensionManager[val ? "disableItem" : "enableItem"](this.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return callback(addon);
|
||||||
|
},
|
||||||
|
getAddonsByTypes: function (types, callback) {
|
||||||
|
let res = [];
|
||||||
|
for (let [, type] in Iterator(types))
|
||||||
|
for (let [, item] in Iterator(services.extensionManager
|
||||||
|
.getItemList(Ci.nsIUpdateItem["TYPE_" + type.toUpperCase()], {})))
|
||||||
|
res.push(this.getAddonByID(item));
|
||||||
|
return (callback || util.identity)(res);
|
||||||
|
},
|
||||||
|
getInstallForFile: function (file, callback, mimetype) {
|
||||||
|
callback({
|
||||||
|
addListener: function () {},
|
||||||
|
install: function () {
|
||||||
|
services.extensionManager.installItemFromFile(file, "app-profile");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getInstallForURL: function (url, callback, mimetype) {
|
||||||
|
dactyl.assert(false, "Install by URL not implemented");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var addonErrors = array.toObject([
|
||||||
|
[AddonManager.ERROR_NETWORK_FAILURE, "A network error occurred"],
|
||||||
|
[AddonManager.ERROR_INCORRECT_HASH, "The downloaded file did not match the expected hash"],
|
||||||
|
[AddonManager.ERROR_CORRUPT_FILE, "The file appears to be corrupt"],
|
||||||
|
[AddonManager.ERROR_FILE_ACCESS, "There was an error accessing the filesystem"]]);
|
||||||
|
|
||||||
|
|
||||||
|
endModule();
|
||||||
|
|
||||||
|
} catch(e){ if (isString(e)) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
|
||||||
|
|
||||||
|
// vim: set fdm=marker sw=4 ts=4 et ft=javascript:
|
||||||
@@ -499,6 +499,8 @@ var ConfigBase = Class("ConfigBase", {
|
|||||||
Button::after content: "]"; color: gray; text-decoration: none !important;
|
Button::after content: "]"; color: gray; text-decoration: none !important;
|
||||||
Button:not([collapsed]) ~ Button:not([collapsed])::before content: "/[";
|
Button:not([collapsed]) ~ Button:not([collapsed])::before content: "/[";
|
||||||
|
|
||||||
|
Buttons
|
||||||
|
|
||||||
DownloadCell display: table-cell; padding: 0 1ex;
|
DownloadCell display: table-cell; padding: 0 1ex;
|
||||||
|
|
||||||
Downloads display: table; margin: 0; padding: 0;
|
Downloads display: table; margin: 0; padding: 0;
|
||||||
@@ -519,6 +521,21 @@ var ConfigBase = Class("ConfigBase", {
|
|||||||
DownloadTime
|
DownloadTime
|
||||||
DownloadTitle
|
DownloadTitle
|
||||||
|
|
||||||
|
AddonCell display: table-cell; padding: 0 1ex;
|
||||||
|
|
||||||
|
Addons display: table; margin: 0; padding: 0;
|
||||||
|
AddonHead;;;CompTitle display: table-row;
|
||||||
|
AddonHead>*;;;AddonCell
|
||||||
|
|
||||||
|
Addon display: table-row;
|
||||||
|
|
||||||
|
Addon>*;;;AddonCell
|
||||||
|
AddonButtons
|
||||||
|
AddonDescription
|
||||||
|
AddonName
|
||||||
|
AddonStatus
|
||||||
|
AddonVersion
|
||||||
|
|
||||||
// </css>
|
// </css>
|
||||||
]]></>, /
/g, "\n")),
|
]]></>, /
/g, "\n")),
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var Download = Class("Download", {
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span highlight="DownloadState" key="state"/>
|
<span highlight="DownloadState" key="state"/>
|
||||||
<span highlight="DownloadButtons">
|
<span highlight="DownloadButtons Buttons">
|
||||||
<a highlight="Button" key="pause">Pause</a>
|
<a highlight="Button" key="pause">Pause</a>
|
||||||
<a highlight="Button" key="remove">Remove</a>
|
<a highlight="Button" key="remove">Remove</a>
|
||||||
<a highlight="Button" key="resume">Resume</a>
|
<a highlight="Button" key="resume">Resume</a>
|
||||||
@@ -304,9 +304,6 @@ var Downloads = Module("downloads", {
|
|||||||
function (args) {
|
function (args) {
|
||||||
let downloads = DownloadList(modules);
|
let downloads = DownloadList(modules);
|
||||||
modules.commandline.echo(downloads);
|
modules.commandline.echo(downloads);
|
||||||
|
|
||||||
if (modules.commandline.savingOutput)
|
|
||||||
util.waitFor(function () downloads.document);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -148,7 +148,8 @@ var Overlay = Module("Overlay", {
|
|||||||
let prefix = [BASE, "resource://dactyl-local-content/"];
|
let prefix = [BASE, "resource://dactyl-local-content/"];
|
||||||
|
|
||||||
defineModule.time("load", null, function _load() {
|
defineModule.time("load", null, function _load() {
|
||||||
["base",
|
["addons",
|
||||||
|
"base",
|
||||||
"completion",
|
"completion",
|
||||||
"config",
|
"config",
|
||||||
"downloads",
|
"downloads",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ try {
|
|||||||
var global = this;
|
var global = this;
|
||||||
Components.utils.import("resource://dactyl/bootstrap.jsm");
|
Components.utils.import("resource://dactyl/bootstrap.jsm");
|
||||||
defineModule("services", {
|
defineModule("services", {
|
||||||
exports: ["AddonManager", "services"],
|
exports: ["services"],
|
||||||
use: ["util"]
|
use: ["util"]
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
@@ -86,84 +86,6 @@ var Services = Module("Services", {
|
|||||||
this.addClass("Xmlhttp", "@mozilla.org/xmlextras/xmlhttprequest;1", Ci.nsIXMLHttpRequest);
|
this.addClass("Xmlhttp", "@mozilla.org/xmlextras/xmlhttprequest;1", Ci.nsIXMLHttpRequest);
|
||||||
this.addClass("ZipReader", "@mozilla.org/libjar/zip-reader;1", Ci.nsIZipReader, "open");
|
this.addClass("ZipReader", "@mozilla.org/libjar/zip-reader;1", Ci.nsIZipReader, "open");
|
||||||
this.addClass("ZipWriter", "@mozilla.org/zipwriter;1", Ci.nsIZipWriter);
|
this.addClass("ZipWriter", "@mozilla.org/zipwriter;1", Ci.nsIZipWriter);
|
||||||
|
|
||||||
if (!Ci.nsIExtensionManager || !this.extensionManager)
|
|
||||||
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
|
||||||
else
|
|
||||||
global.AddonManager = {
|
|
||||||
getAddonByID: function (id, callback) {
|
|
||||||
callback = callback || util.identity;
|
|
||||||
let addon = id;
|
|
||||||
if (!isObject(addon))
|
|
||||||
addon = services.extensionManager.getItemForID(id);
|
|
||||||
if (!addon)
|
|
||||||
return callback(null);
|
|
||||||
addon = Object.create(addon);
|
|
||||||
|
|
||||||
function getRdfProperty(item, property) {
|
|
||||||
let resource = services.rdf.GetResource("urn:mozilla:item:" + item.id);
|
|
||||||
let value = "";
|
|
||||||
|
|
||||||
if (resource) {
|
|
||||||
let target = services.extensionManager.datasource.GetTarget(resource,
|
|
||||||
services.rdf.GetResource("http://www.mozilla.org/2004/em-rdf#" + property), true);
|
|
||||||
if (target && target instanceof Ci.nsIRDFLiteral)
|
|
||||||
value = target.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
["aboutURL", "creator", "description", "developers",
|
|
||||||
"homepageURL", "installDate", "optionsURL",
|
|
||||||
"releaseNotesURI", "updateDate"].forEach(function (item) {
|
|
||||||
memoize(addon, item, function (item) getRdfProperty(this, item));
|
|
||||||
});
|
|
||||||
|
|
||||||
update(addon, {
|
|
||||||
|
|
||||||
appDisabled: false,
|
|
||||||
|
|
||||||
installLocation: Class.memoize(function () services.extensionManager.getInstallLocation(this.id)),
|
|
||||||
getResourceURI: function getResourceURI(path) {
|
|
||||||
let file = this.installLocation.getItemFile(this.id, path);
|
|
||||||
return services.io.newFileURI(file);
|
|
||||||
},
|
|
||||||
|
|
||||||
isActive: getRdfProperty(addon, "isDisabled") != "true",
|
|
||||||
|
|
||||||
uninstall: function uninstall() {
|
|
||||||
services.extensionManager.uninstallItem(this.id);
|
|
||||||
},
|
|
||||||
|
|
||||||
get userDisabled() getRdfProperty(addon, "userDisabled") === "true",
|
|
||||||
set userDisabled(val) {
|
|
||||||
services.extensionManager[val ? "disableItem" : "enableItem"](this.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return callback(addon);
|
|
||||||
},
|
|
||||||
getAddonsByTypes: function (types, callback) {
|
|
||||||
let res = [];
|
|
||||||
for (let [, type] in Iterator(types))
|
|
||||||
for (let [, item] in Iterator(services.extensionManager
|
|
||||||
.getItemList(Ci.nsIUpdateItem["TYPE_" + type.toUpperCase()], {})))
|
|
||||||
res.push(this.getAddonByID(item));
|
|
||||||
return (callback || util.identity)(res);
|
|
||||||
},
|
|
||||||
getInstallForFile: function (file, callback, mimetype) {
|
|
||||||
callback({
|
|
||||||
addListener: function () {},
|
|
||||||
install: function () {
|
|
||||||
services.extensionManager.installItemFromFile(file, "app-profile");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getInstallForURL: function (url, callback, mimetype) {
|
|
||||||
dactyl.assert(false, "Install by URL not implemented");
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
reinit: function () {},
|
reinit: function () {},
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
and linking to source code locations).
|
and linking to source code locations).
|
||||||
- :downloads now opens a download list in the multi-line output
|
- :downloads now opens a download list in the multi-line output
|
||||||
buffer.
|
buffer.
|
||||||
|
- :extensions has been replaced with a more powerful :addons
|
||||||
- Added :cookies command.
|
- Added :cookies command.
|
||||||
* :extadd now supports remote URLs as well as local files on Firefox 4.
|
* :extadd now supports remote URLs as well as local files on Firefox 4.
|
||||||
* Added :if/:elseif/:else/:endif conditionals.
|
* Added :if/:elseif/:else/:endif conditionals.
|
||||||
|
|||||||
Reference in New Issue
Block a user