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