Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 const { Cc, Ci, Cu } = require("chrome");
8 const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
9 const gcli = require("gcli/index");
10 const { Promise: promise } = require("resource://gre/modules/Promise.jsm");
12 const BRAND_SHORT_NAME = Cc["@mozilla.org/intl/stringbundle;1"]
13 .getService(Ci.nsIStringBundleService)
14 .createBundle("chrome://branding/locale/brand.properties")
15 .GetStringFromName("brandShortName");
17 /**
18 * Takes a function that uses a callback as its last parameter, and returns a
19 * new function that returns a promise instead.
20 * This should probably live in async-util
21 */
22 const promiseify = function(scope, functionWithLastParamCallback) {
23 return (...args) => {
24 return new Promise(resolve => {
25 args.push((...results) => {
26 resolve(results.length > 1 ? results : results[0]);
27 });
28 functionWithLastParamCallback.apply(scope, args);
29 });
30 }
31 };
33 // Convert callback based functions to promise based ones
34 const getAllAddons = promiseify(AddonManager, AddonManager.getAllAddons);
35 const getAddonsByTypes = promiseify(AddonManager, AddonManager.getAddonsByTypes);
37 /**
38 * Return a string array containing the pending operations on an addon
39 */
40 function pendingOperations(addon) {
41 let allOperations = [
42 "PENDING_ENABLE", "PENDING_DISABLE", "PENDING_UNINSTALL",
43 "PENDING_INSTALL", "PENDING_UPGRADE"
44 ];
45 return allOperations.reduce(function(operations, opName) {
46 return addon.pendingOperations & AddonManager[opName] ?
47 operations.concat(opName) :
48 operations;
49 }, []);
50 }
52 exports.items = [
53 {
54 item: "type",
55 name: "addon",
56 parent: "selection",
57 stringifyProperty: "name",
58 cacheable: true,
59 constructor: function() {
60 // Tell GCLI to clear the cache of addons when one is added or removed
61 let listener = {
62 onInstalled: addon => { this.clearCache(); },
63 onUninstalled: addon => { this.clearCache(); },
64 };
65 AddonManager.addAddonListener(listener);
66 },
67 lookup: function() {
68 return getAllAddons().then(addons => {
69 return addons.map(addon => {
70 let name = addon.name + " " + addon.version;
71 name = name.trim().replace(/\s/g, "_");
72 return { name: name, value: addon };
73 });
74 });
75 }
76 },
77 {
78 name: "addon",
79 description: gcli.lookup("addonDesc")
80 },
81 {
82 name: "addon list",
83 description: gcli.lookup("addonListDesc"),
84 returnType: "addonsInfo",
85 params: [{
86 name: "type",
87 type: {
88 name: "selection",
89 data: [ "dictionary", "extension", "locale", "plugin", "theme", "all" ]
90 },
91 defaultValue: "all",
92 description: gcli.lookup("addonListTypeDesc")
93 }],
94 exec: function(args, context) {
95 let types = (args.type === "all") ? null : [ args.type ];
96 return getAddonsByTypes(types).then(addons => {
97 addons = addons.map(function(addon) {
98 return {
99 name: addon.name,
100 version: addon.version,
101 isActive: addon.isActive,
102 pendingOperations: pendingOperations(addon)
103 };
104 });
105 return { addons: addons, type: args.type };
106 });
107 }
108 },
109 {
110 item: "converter",
111 from: "addonsInfo",
112 to: "view",
113 exec: function(addonsInfo, context) {
114 if (!addonsInfo.addons.length) {
115 return context.createView({
116 html: "<p>${message}</p>",
117 data: { message: gcli.lookup("addonNoneOfType") }
118 });
119 }
121 let headerLookups = {
122 "dictionary": "addonListDictionaryHeading",
123 "extension": "addonListExtensionHeading",
124 "locale": "addonListLocaleHeading",
125 "plugin": "addonListPluginHeading",
126 "theme": "addonListThemeHeading",
127 "all": "addonListAllHeading"
128 };
129 let header = gcli.lookup(headerLookups[addonsInfo.type] ||
130 "addonListUnknownHeading");
132 let operationLookups = {
133 "PENDING_ENABLE": "addonPendingEnable",
134 "PENDING_DISABLE": "addonPendingDisable",
135 "PENDING_UNINSTALL": "addonPendingUninstall",
136 "PENDING_INSTALL": "addonPendingInstall",
137 "PENDING_UPGRADE": "addonPendingUpgrade"
138 };
139 function lookupOperation(opName) {
140 let lookupName = operationLookups[opName];
141 return lookupName ? gcli.lookup(lookupName) : opName;
142 }
144 function arrangeAddons(addons) {
145 let enabledAddons = [];
146 let disabledAddons = [];
147 addons.forEach(function(addon) {
148 if (addon.isActive) {
149 enabledAddons.push(addon);
150 } else {
151 disabledAddons.push(addon);
152 }
153 });
155 function compareAddonNames(nameA, nameB) {
156 return String.localeCompare(nameA.name, nameB.name);
157 }
158 enabledAddons.sort(compareAddonNames);
159 disabledAddons.sort(compareAddonNames);
161 return enabledAddons.concat(disabledAddons);
162 }
164 function isActiveForToggle(addon) {
165 return (addon.isActive && ~~addon.pendingOperations.indexOf("PENDING_DISABLE"));
166 }
168 return context.createView({
169 html:
170 "<table>" +
171 " <caption>${header}</caption>" +
172 " <tbody>" +
173 " <tr foreach='addon in ${addons}'" +
174 " class=\"gcli-addon-${addon.status}\">" +
175 " <td>${addon.name} ${addon.version}</td>" +
176 " <td>${addon.pendingOperations}</td>" +
177 " <td>" +
178 " <span class='gcli-out-shortcut'" +
179 " data-command='addon ${addon.toggleActionName} ${addon.label}'" +
180 " onclick='${onclick}' ondblclick='${ondblclick}'" +
181 " >${addon.toggleActionMessage}</span>" +
182 " </td>" +
183 " </tr>" +
184 " </tbody>" +
185 "</table>",
186 data: {
187 header: header,
188 addons: arrangeAddons(addonsInfo.addons).map(function(addon) {
189 return {
190 name: addon.name,
191 label: addon.name.replace(/\s/g, "_") +
192 (addon.version ? "_" + addon.version : ""),
193 status: addon.isActive ? "enabled" : "disabled",
194 version: addon.version,
195 pendingOperations: addon.pendingOperations.length ?
196 (" (" + gcli.lookup("addonPending") + ": "
197 + addon.pendingOperations.map(lookupOperation).join(", ")
198 + ")") :
199 "",
200 toggleActionName: isActiveForToggle(addon) ? "disable": "enable",
201 toggleActionMessage: isActiveForToggle(addon) ?
202 gcli.lookup("addonListOutDisable") :
203 gcli.lookup("addonListOutEnable")
204 };
205 }),
206 onclick: context.update,
207 ondblclick: context.updateExec
208 }
209 });
210 }
211 },
212 {
213 name: "addon enable",
214 description: gcli.lookup("addonEnableDesc"),
215 params: [
216 {
217 name: "addon",
218 type: "addon",
219 description: gcli.lookup("addonNameDesc")
220 }
221 ],
222 exec: function(args, context) {
223 let name = (args.addon.name + " " + args.addon.version).trim();
224 if (args.addon.userDisabled) {
225 args.addon.userDisabled = false;
226 return gcli.lookupFormat("addonEnabled", [ name ]);
227 }
229 return gcli.lookupFormat("addonAlreadyEnabled", [ name ]);
230 }
231 },
232 {
233 name: "addon disable",
234 description: gcli.lookup("addonDisableDesc"),
235 params: [
236 {
237 name: "addon",
238 type: "addon",
239 description: gcli.lookup("addonNameDesc")
240 }
241 ],
242 exec: function(args, context) {
243 // If the addon is not disabled or is set to "click to play" then
244 // disable it. Otherwise display the message "Add-on is already
245 // disabled."
246 let name = (args.addon.name + " " + args.addon.version).trim();
247 if (!args.addon.userDisabled ||
248 args.addon.userDisabled === AddonManager.STATE_ASK_TO_ACTIVATE) {
249 args.addon.userDisabled = true;
250 return gcli.lookupFormat("addonDisabled", [ name ]);
251 }
253 return gcli.lookupFormat("addonAlreadyDisabled", [ name ]);
254 }
255 }
256 ];