author | Phil Ringnalda <philringnalda@gmail.com> |
Tue, 11 Mar 2014 22:18:17 -0700 | |
changeset 173152 | 34941dd46be6611af8ba6c741afc7294afe65cd9 |
parent 173151 | 31f9a148b33cb6f6eb509df29a339b5de4f65254 |
child 173153 | e7f97fa8a86b2be9e451f33cb15d558134e16231 |
push id | 26391 |
push user | cbook@mozilla.com |
push date | Wed, 12 Mar 2014 11:20:34 +0000 |
treeherder | mozilla-central@a56837cfc67c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 982379, 981361 |
milestone | 30.0a1 |
backs out | bd0463063293e9e2fdfcea2dce80bc849316af0f |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
deleted file mode 100644 --- a/addon-sdk/source/lib/sdk/input/customizable-ui.js +++ /dev/null @@ -1,40 +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"; - -const { Cu } = require("chrome"); - -// Because Firefox Holly, we still need to check if `CustomizableUI` is -// available. Once Australis will officially land, we can safely remove it. -// See Bug 959142 -try { - Cu.import("resource:///modules/CustomizableUI.jsm", {}); -} -catch (e) { - throw Error("Unsupported Application: The module" + module.id + - " does not support this application."); -} - -const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {}); -const { receive } = require("../event/utils"); -const { InputPort } = require("./system"); -const { object} = require("../util/sequence"); -const { getOuterId } = require("../window/utils"); - -const Input = function() {}; -Input.prototype = Object.create(InputPort.prototype); - -Input.prototype.onCustomizeStart = function (window) { - receive(this, object([getOuterId(window), true])); -} - -Input.prototype.onCustomizeEnd = function (window) { - receive(this, object([getOuterId(window), null])); -} - -Input.prototype.addListener = input => CustomizableUI.addListener(input); - -Input.prototype.removeListener = input => CustomizableUI.removeListener(input); - -exports.CustomizationInput = Input;
--- a/addon-sdk/source/lib/sdk/input/system.js +++ b/addon-sdk/source/lib/sdk/input/system.js @@ -43,39 +43,33 @@ const InputPort = function InputPort({id // InputPort type implements `Input` signal interface. InputPort.prototype = new Input(); InputPort.prototype.constructor = InputPort; // When port is started (which is when it's subgraph get's // first subscriber) actual observer is registered. InputPort.start = input => { - input.addListener(input); + addObserver(input, input.topic, false); // Also register add-on unload observer to end this signal // when that happens. addObserver(input, addonUnloadTopic, false); }; InputPort.prototype[start] = InputPort.start; -InputPort.addListener = input => addObserver(input, input.topic, false); -InputPort.prototype.addListener = InputPort.addListener; - // When port is stopped (which is when it's subgraph has no // no subcribers left) an actual observer unregistered. // Note that port stopped once it ends as well (which is when // add-on is unloaded). InputPort.stop = input => { - input.removeListener(input); + removeObserver(input, input.topic); removeObserver(input, addonUnloadTopic); }; InputPort.prototype[stop] = InputPort.stop; -InputPort.removeListener = input => removeObserver(input, input.topic); -InputPort.prototype.removeListener = InputPort.removeListener; - // `InputPort` also implements `nsIObserver` interface and // `nsISupportsWeakReference` interfaces as it's going to be used as such. InputPort.prototype.QueryInterface = function(iid) { if (!iid.equals(Ci.nsIObserver) && !iid.equals(Ci.nsISupportsWeakReference)) throw Cr.NS_ERROR_NO_INTERFACE; return this; };
--- a/addon-sdk/source/lib/sdk/panel.js +++ b/addon-sdk/source/lib/sdk/panel.js @@ -8,16 +8,17 @@ module.metadata = { "stability": "stable", "engines": { "Firefox": "*" } }; const { Ci } = require("chrome"); +const { validateOptions: valid } = require('./deprecated/api-utils'); const { setTimeout } = require('./timers'); const { isPrivateBrowsingSupported } = require('./self'); const { isWindowPBSupported } = require('./private-browsing/utils'); const { Class } = require("./core/heritage"); const { merge } = require("./util/object"); const { WorkerHost, detach, attach, destroy } = require("./content/utils"); const { Worker } = require("./content/worker"); const { Disposable } = require("./core/disposable"); @@ -25,46 +26,39 @@ const { contract: loaderContract } = req const { contract } = require("./util/contract"); const { on, off, emit, setListeners } = require("./event/core"); const { EventTarget } = require("./event/target"); const domPanel = require("./panel/utils"); const { events } = require("./panel/events"); const systemEvents = require("./system/events"); const { filter, pipe, stripListeners } = require("./event/utils"); const { getNodeView, getActiveView } = require("./view/core"); -const { isNil, isObject, isNumber } = require("./lang/type"); +const { isNil, isObject } = require("./lang/type"); const { getAttachEventType } = require("./content/utils"); -const { number, boolean, object } = require('./deprecated/api-utils'); -let isRect = ({top, right, bottom, left}) => [top, right, bottom, left]. - some(value => isNumber(value) && !isNaN(value)); - -let isSDKObj = obj => obj instanceof Class; +let number = { is: ['number', 'undefined', 'null'] }; +let boolean = { is: ['boolean', 'undefined', 'null'] }; let rectContract = contract({ top: number, right: number, bottom: number, left: number }); -let position = { - is: object, - map: v => (isNil(v) || isSDKObj(v) || !isObject(v)) ? v : rectContract(v), - ok: v => isNil(v) || isSDKObj(v) || (isObject(v) && isRect(v)), - msg: 'The option "position" must be a SDK object registered as anchor; ' + - 'or an object with one or more of the following keys set to numeric ' + - 'values: top, right, bottom, left.' +let rect = { + is: ['object', 'undefined', 'null'], + map: function(v) isNil(v) || !isObject(v) ? v : rectContract(v) } let displayContract = contract({ width: number, height: number, focus: boolean, - position: position + position: rect }); let panelContract = contract(merge({}, displayContract.rules, loaderContract.rules)); function isDisposed(panel) !views.has(panel); let panels = new WeakMap(); @@ -177,32 +171,32 @@ const Panel = Class({ // reatached once panel content is ready. detach(workerFor(this)); }, /* Public API: Panel.isShowing */ get isShowing() !isDisposed(this) && domPanel.isOpen(viewFor(this)), /* Public API: Panel.show */ - show: function show(options={}, anchor) { + show: function show(options, anchor) { if (options instanceof Ci.nsIDOMElement) { [anchor, options] = [options, null]; } if (anchor instanceof Ci.nsIDOMElement) { console.warn( "Passing a DOM node to Panel.show() method is an unsupported " + "feature that will be soon replaced. " + "See: https://bugzilla.mozilla.org/show_bug.cgi?id=878877" ); } let model = modelFor(this); let view = viewFor(this); - let anchorView = getNodeView(anchor || options.position); + let anchorView = getNodeView(anchor); options = merge({ position: model.position, width: model.width, height: model.height, defaultWidth: model.defaultWidth, defaultHeight: model.defaultHeight, focus: model.focus @@ -240,32 +234,31 @@ const Panel = Class({ } }); exports.Panel = Panel; // Note must be defined only after value to `Panel` is assigned. getActiveView.define(Panel, viewFor); // Filter panel events to only panels that are create by this module. -let panelEvents = filter(events, ({target}) => panelFor(target)); +let panelEvents = filter(events, function({target}) panelFor(target)); // Panel events emitted after panel has being shown. -let shows = filter(panelEvents, ({type}) => type === "popupshown"); +let shows = filter(panelEvents, function({type}) type === "popupshown"); // Panel events emitted after panel became hidden. -let hides = filter(panelEvents, ({type}) => type === "popuphidden"); +let hides = filter(panelEvents, function({type}) type === "popuphidden"); // Panel events emitted after content inside panel is ready. For different // panels ready may mean different state based on `contentScriptWhen` attribute. // Weather given event represents readyness is detected by `getAttachEventType` // helper function. -let ready = filter(panelEvents, ({type, target}) => +let ready = filter(panelEvents, function({type, target}) getAttachEventType(modelFor(panelFor(target))) === type); // Forward panel show / hide events to panel's own event listeners. -on(shows, "data", ({target}) => emit(panelFor(target), "show")); - -on(hides, "data", ({target}) => emit(panelFor(target), "hide")); +on(shows, "data", function({target}) emit(panelFor(target), "show")); +on(hides, "data", function({target}) emit(panelFor(target), "hide")); on(ready, "data", function({target}) { let worker = workerFor(panelFor(target)); attach(worker, domPanel.getContentDocument(target).defaultView); });
--- a/addon-sdk/source/lib/sdk/panel/utils.js +++ b/addon-sdk/source/lib/sdk/panel/utils.js @@ -18,18 +18,16 @@ const { create: createFrame, swapFrameLo const { window: addonWindow } = require("../addon/window"); const { isNil } = require("../lang/type"); const events = require("../system/events"); const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; function calculateRegion({ position, width, height, defaultWidth, defaultHeight }, rect) { - position = position || {}; - let x, y; let hasTop = !isNil(position.top); let hasRight = !isNil(position.right); let hasBottom = !isNil(position.bottom); let hasLeft = !isNil(position.left); let hasWidth = !isNil(width); let hasHeight = !isNil(height); @@ -124,42 +122,24 @@ function display(panel, options, anchor) // in order to, be positioned properly panel.style.margin = "0"; let viewportRect = document.defaultView.gBrowser.getBoundingClientRect(); ({x, y, width, height}) = calculateRegion(options, viewportRect); } else { - // The XUL Panel has an arrow, so the margin needs to be reset - // to the default value. - panel.style.margin = ""; - let { CustomizableUI, window } = anchor.ownerDocument.defaultView; - - // In Australis, widgets may be positioned in an overflow panel or the - // menu panel. - // In such cases clicking this widget will hide the overflow/menu panel, - // and the widget's panel will show instead. - if (CustomizableUI) { - let node = anchor; - ({anchor}) = CustomizableUI.getWidget(anchor.id).forWindow(window); - - // if `node` is not the `anchor` itself, it means the widget is - // positioned in a panel, therefore we have to hide it before show - // the widget's panel in the same anchor - if (node !== anchor) - CustomizableUI.hidePanelForNode(anchor); - } - width = width || defaultWidth; height = height || defaultHeight; // Open the popup by the anchor. let rect = anchor.getBoundingClientRect(); + let window = anchor.ownerDocument.defaultView; + let zoom = getScreenPixelsPerCSSPixel(window); let screenX = rect.left + window.mozInnerScreenX * zoom; let screenY = rect.top + window.mozInnerScreenY * zoom; // Set up the vertical position of the popup relative to the anchor // (always display the arrow on anchor center) let horizontal, vertical; if (screenY > window.screen.availHeight / 2 + height)
--- a/addon-sdk/source/lib/sdk/system.js +++ b/addon-sdk/source/lib/sdk/system.js @@ -7,16 +7,17 @@ module.metadata = { "stability": "unstable" }; const { Cc, Ci, CC } = require('chrome'); const options = require('@loader/options'); const file = require('./io/file'); const runtime = require("./system/runtime"); +var cfxArgs = require("@test/options"); const appStartup = Cc['@mozilla.org/toolkit/app-startup;1']. getService(Ci.nsIAppStartup); const appInfo = Cc["@mozilla.org/xre/app-info;1"]. getService(Ci.nsIXULAppInfo); const directoryService = Cc['@mozilla.org/file/directory_service;1']. getService(Ci.nsIProperties); @@ -64,22 +65,23 @@ exports.exit = function exit(code) { // This is used by 'cfx' to find out exit code. if ('resultFile' in options && options.resultFile) { let mode = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE; let stream = openFile(options.resultFile, mode); let status = code ? 'FAIL' : 'OK'; stream.write(status, status.length); stream.flush(); stream.close(); + if (cfxArgs.parseable) { + console.log('wrote to resultFile'); + } } - if (code == 0) { - forcedExit = true; - } - appStartup.quit(code ? E_ATTEMPT : E_FORCE); + forcedExit = true; + appStartup.quit(E_FORCE); }; // Adapter for nodejs's stdout & stderr: // http://nodejs.org/api/process.html#process_process_stdout let stdout = Object.freeze({ write: dump, end: dump }); exports.stdout = stdout; exports.stderr = stdout;
--- a/addon-sdk/source/lib/sdk/test/runner.js +++ b/addon-sdk/source/lib/sdk/test/runner.js @@ -2,31 +2,39 @@ * 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": "experimental" }; +var { setTimeout } = require("../timers"); var { exit, stdout } = require("../system"); var cfxArgs = require("@test/options"); function runTests(findAndRunTests) { var harness = require("./harness"); function onDone(tests) { stdout.write("\n"); var total = tests.passed + tests.failed; stdout.write(tests.passed + " of " + total + " tests passed.\n"); if (tests.failed == 0) { - if (tests.passed === 0) + if (tests.passed === 0) { stdout.write("No tests were run\n"); - exit(0); + } + + setTimeout(function() { + if (cfxArgs.parseable) { + console.log('calling exit(0)'); + } + exit(0); + }, 0); } else { if (cfxArgs.verbose || cfxArgs.parseable) printFailedTests(tests, stdout.write); exit(1); } }; // We may have to run test on next cycle, otherwise XPCOM components
--- a/addon-sdk/source/lib/sdk/ui/button/action.js +++ b/addon-sdk/source/lib/sdk/ui/button/action.js @@ -21,17 +21,16 @@ catch (e) { ' does not support this application.'); } const { Class } = require('../../core/heritage'); const { merge } = require('../../util/object'); const { Disposable } = require('../../core/disposable'); const { on, off, emit, setListeners } = require('../../event/core'); const { EventTarget } = require('../../event/target'); -const { getNodeView } = require('../../view/core'); const view = require('./view'); const { buttonContract, stateContract } = require('./contract'); const { properties, render, state, register, unregister, getDerivedStateFor } = require('../state'); const { events: stateEvents } = require('../state/events'); const { events: viewEvents } = require('./view/events'); const events = require('../../event/utils'); @@ -85,20 +84,16 @@ const ActionButton = Class({ get id() this.state().id, click: function click() { view.click(toWidgetId(this.id)) } }); exports.ActionButton = ActionButton; identify.define(ActionButton, ({id}) => toWidgetId(id)); -getNodeView.define(ActionButton, button => - view.nodeFor(toWidgetId(button.id)) -); - let actionButtonStateEvents = events.filter(stateEvents, e => e.target instanceof ActionButton); let actionButtonViewEvents = events.filter(viewEvents, e => buttons.has(e.target)); let clickEvents = events.filter(actionButtonViewEvents, e => e.type === 'click'); let updateEvents = events.filter(actionButtonViewEvents, e => e.type === 'update');
--- a/addon-sdk/source/lib/sdk/ui/button/toggle.js +++ b/addon-sdk/source/lib/sdk/ui/button/toggle.js @@ -21,17 +21,16 @@ catch (e) { ' does not support this application.'); } const { Class } = require('../../core/heritage'); const { merge } = require('../../util/object'); const { Disposable } = require('../../core/disposable'); const { on, off, emit, setListeners } = require('../../event/core'); const { EventTarget } = require('../../event/target'); -const { getNodeView } = require('../../view/core'); const view = require('./view'); const { toggleButtonContract, toggleStateContract } = require('./contract'); const { properties, render, state, register, unregister, setStateFor, getStateFor, getDerivedStateFor } = require('../state'); const { events: stateEvents } = require('../state/events'); const { events: viewEvents } = require('./view/events'); const events = require('../../event/utils'); @@ -86,20 +85,16 @@ const ToggleButton = Class({ get id() this.state().id, click: function click() view.click(toWidgetId(this.id)) }); exports.ToggleButton = ToggleButton; identify.define(ToggleButton, ({id}) => toWidgetId(id)); -getNodeView.define(ToggleButton, button => - view.nodeFor(toWidgetId(button.id)) -); - let toggleButtonStateEvents = events.filter(stateEvents, e => e.target instanceof ToggleButton); let toggleButtonViewEvents = events.filter(viewEvents, e => buttons.has(e.target)); let clickEvents = events.filter(toggleButtonViewEvents, e => e.type === 'click'); let updateEvents = events.filter(toggleButtonViewEvents, e => e.type === 'update');
--- a/addon-sdk/source/lib/sdk/ui/button/view.js +++ b/addon-sdk/source/lib/sdk/ui/button/view.js @@ -103,21 +103,16 @@ function getImage(icon, isInToolbar, pix } if (image.indexOf('./') === 0) return data.url(image.substr(2)); return image; } -function nodeFor(id, window=getMostRecentBrowserWindow()) { - return customizedWindows.has(window) ? null : getNode(id, window); -}; -exports.nodeFor = nodeFor; - function create(options) { let { id, label, icon, type } = options; if (views.has(id)) throw new Error('The ID "' + id + '" seems already used.'); CustomizableUI.createWidget({ id: id, @@ -183,40 +178,41 @@ function setIcon(id, window, icon) { let image = getImage(icon, isInToolbar(id), window.devicePixelRatio); node.setAttribute('image', image); } } exports.setIcon = setIcon; function setLabel(id, window, label) { - let node = nodeFor(id, window); + let node = customizedWindows.has(window) ? null : getNode(id, window); if (node) { node.setAttribute('label', label); node.setAttribute('tooltiptext', label); } } exports.setLabel = setLabel; function setDisabled(id, window, disabled) { - let node = nodeFor(id, window); + let node = customizedWindows.has(window) ? null : getNode(id, window); if (node) node.disabled = disabled; } exports.setDisabled = setDisabled; function setChecked(id, window, checked) { - let node = nodeFor(id, window); + let node = customizedWindows.has(window) ? null : getNode(id, window); if (node) node.checked = checked; } exports.setChecked = setChecked; function click(id) { - let node = nodeFor(id); + let window = getMostRecentBrowserWindow(); + let node = customizedWindows.has(window) ? null : getNode(id, window); if (node) node.click(); } exports.click = click;
--- a/addon-sdk/source/lib/sdk/ui/frame/model.js +++ b/addon-sdk/source/lib/sdk/ui/frame/model.js @@ -27,27 +27,27 @@ const { id: addonID, data: { url: resolv const { Frames } = require("../../input/frame"); const output = new OutputPort({ id: "frame-change" }); const mailbox = new OutputPort({ id: "frame-mailbox" }); const input = Frames; -const makeID = url => +const urlToId = url => ("frame-" + addonID + "-" + url). split("/").join("-"). split(".").join("-"). replace(/[^A-Za-z0-9_\-]/g, ""); const validate = contract({ - name: { + id: { is: ["string", "undefined"], ok: x => /^[a-z][a-z0-9-_]+$/i.test(x), - msg: "The `option.name` must be a valid alphanumeric string (hyphens and " + + msg: "The `option.id` must be a valid alphanumeric string (hyphens and " + "underscores are allowed) starting with letter." }, url: { map: x => x.toString(), is: ["string"], ok: x => isLocalURL(x), msg: "The `options.url` must be a valid local URI." } @@ -83,17 +83,17 @@ const Message = function({type, data, so const frames = new Map(); const sources = new Map(); const Frame = Class({ extends: EventTarget, implements: [Disposable, Source], initialize: function(params={}) { const options = validate(params); - const id = makeID(options.name || options.url); + const id = options.id || urlToId(options.url); if (frames.has(id)) throw Error("Frame with this id already exists: " + id); const initial = { id: id, url: resolve(options.url) }; this.id = id; setListeners(this, params);
--- a/addon-sdk/source/lib/sdk/ui/state.js +++ b/addon-sdk/source/lib/sdk/ui/state.js @@ -14,17 +14,17 @@ module.metadata = { const { Ci } = require('chrome'); const events = require('../event/utils'); const { events: browserEvents } = require('../browser/events'); const { events: tabEvents } = require('../tab/events'); const { events: stateEvents } = require('./state/events'); -const { windows, isInteractive, getFocusedBrowser } = require('../window/utils'); +const { windows, isInteractive, getMostRecentBrowserWindow } = require('../window/utils'); const { getActiveTab, getOwnerWindow } = require('../tabs/utils'); const { ignoreWindow } = require('../private-browsing/utils'); const { freeze } = Object; const { merge } = require('../util/object'); const { on, off, emit } = require('../event/core'); @@ -42,17 +42,17 @@ const ERR_INVALID_TARGET = 'The state ca 'Only window, tab and registered component are valid targets.'; const isWindow = thing => thing instanceof Ci.nsIDOMWindow; const isTab = thing => thing.tagName && thing.tagName.toLowerCase() === 'tab'; const isActiveTab = thing => isTab(thing) && thing === getActiveTab(getOwnerWindow(thing)); const isEnumerable = window => !ignoreWindow(window); const browsers = _ => windows('navigator:browser', { includePrivate: true }).filter(isInteractive); -const getMostRecentTab = _ => getActiveTab(getFocusedBrowser()); +const getMostRecentTab = _ => getActiveTab(getMostRecentBrowserWindow()); function getStateFor(component, target) { if (!isRegistered(component)) throw new Error(ERR_UNREGISTERED); if (!components.has(component)) return null; @@ -167,17 +167,17 @@ function properties(contract) { return Object.create(Object.prototype, descriptor); } exports.properties = properties; function state(contract) { return { state: function state(target, state) { - let nativeTarget = target === 'window' ? getFocusedBrowser() + let nativeTarget = target === 'window' ? getMostRecentBrowserWindow() : target === 'tab' ? getMostRecentTab() : viewFor(target); if (!nativeTarget && target !== this && !isNil(target)) throw new Error('target not allowed.'); target = nativeTarget || target;
--- a/addon-sdk/source/lib/sdk/ui/toolbar/view.js +++ b/addon-sdk/source/lib/sdk/ui/toolbar/view.js @@ -11,23 +11,21 @@ module.metadata = { }; const { Cu } = require("chrome"); const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {}); const { subscribe, send, Reactor, foldp, lift, merges } = require("../../event/utils"); const { InputPort } = require("../../input/system"); const { OutputPort } = require("../../output/system"); const { Interactive } = require("../../input/browser"); -const { CustomizationInput } = require("../../input/customizable-ui"); const { pairs, map, isEmpty, object, each, keys, values } = require("../../util/sequence"); const { curry, flip } = require("../../lang/functional"); const { patch, diff } = require("diffpatcher/index"); const prefs = require("../../preferences/service"); -const { getByOuterId } = require("../../window/utils"); const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; const PREF_ROOT = "extensions.sdk-toolbar-collapsed."; // There are two output ports one for publishing changes that occured // and the other for change requests. Later is synchronous and is only // consumed here. Note: it needs to be synchronous to avoid race conditions @@ -35,19 +33,18 @@ const PREF_ROOT = "extensions.sdk-toolba // toolbar is destroyed between the ticks. const output = new OutputPort({ id: "toolbar-changed" }); const syncoutput = new OutputPort({ id: "toolbar-change", sync: true }); // Merge disptached changes and recevied changes from models to keep state up to // date. const Toolbars = foldp(patch, {}, merges([new InputPort({ id: "toolbar-changed" }), new InputPort({ id: "toolbar-change" })])); -const State = lift((toolbars, windows, customizable) => - ({windows: windows, toolbars: toolbars, customizable: customizable}), - Toolbars, Interactive, new CustomizationInput()); +const State = lift((toolbars, windows) => ({windows: windows, toolbars: toolbars}), + Toolbars, Interactive); // Shared event handler that makes `event.target.parent` collapsed. // Used as toolbar's close buttons click handler. const collapseToolbar = event => { const toolbar = event.target.parentNode; toolbar.collapsed = true; }; @@ -86,111 +83,77 @@ const attributesChanged = mutations => { // it back. In addition it set's up a listener and observer to communicate // state changes. const addView = curry((options, {document}) => { let view = document.createElementNS(XUL_NS, "toolbar"); view.setAttribute("id", options.id); view.setAttribute("collapsed", options.collapsed); view.setAttribute("toolbarname", options.title); view.setAttribute("pack", "end"); - view.setAttribute("customizable", "false"); - view.setAttribute("style", "padding: 2px 0; max-height: 40px;"); + view.setAttribute("defaultset", options.items.join(",")); + view.setAttribute("customizable", true); + view.setAttribute("style", "max-height: 40px;"); view.setAttribute("mode", "icons"); view.setAttribute("iconsize", "small"); view.setAttribute("context", "toolbar-context-menu"); - view.setAttribute("class", "toolbar-primary chromeclass-toolbar"); - - let label = document.createElementNS(XUL_NS, "label"); - label.setAttribute("value", options.title); - label.setAttribute("collapsed", "true"); - view.appendChild(label); let closeButton = document.createElementNS(XUL_NS, "toolbarbutton"); closeButton.setAttribute("id", "close-" + options.id); closeButton.setAttribute("class", "close-icon"); closeButton.setAttribute("customizable", false); closeButton.addEventListener("command", collapseToolbar); view.appendChild(closeButton); - // In order to have a close button not costumizable, aligned on the right, - // leaving the customizable capabilities of Australis, we need to create - // a toolbar inside a toolbar. - // This is should be a temporary hack, we should have a proper XBL for toolbar - // instead. See: - // https://bugzilla.mozilla.org/show_bug.cgi?id=982005 - let toolbar = document.createElementNS(XUL_NS, "toolbar"); - toolbar.setAttribute("id", "inner-" + options.id); - toolbar.setAttribute("defaultset", options.items.join(",")); - toolbar.setAttribute("customizable", "true"); - toolbar.setAttribute("style", "-moz-appearance: none; overflow: hidden"); - toolbar.setAttribute("mode", "icons"); - toolbar.setAttribute("iconsize", "small"); - toolbar.setAttribute("context", "toolbar-context-menu"); - toolbar.setAttribute("flex", "1"); - - view.insertBefore(toolbar, closeButton); - const observer = new document.defaultView.MutationObserver(attributesChanged); observer.observe(view, { attributes: true, attributeFilter: ["collapsed", "toolbarname"] }); const toolbox = document.getElementById("navigator-toolbox"); toolbox.appendChild(view); }); const viewAdd = curry(flip(addView)); const removeView = curry((id, {document}) => { const view = document.getElementById(id); if (view) view.remove(); }); -const updateView = curry((id, {title, collapsed, isCustomizing}, {document}) => { +const updateView = curry((id, {title, collapsed}, {document}) => { const view = document.getElementById(id); - - if (!view) - return; - - if (title) + if (view && title) view.setAttribute("toolbarname", title); - - if (collapsed !== void(0)) + if (view && collapsed !== void(0)) view.setAttribute("collapsed", Boolean(collapsed)); - - if (isCustomizing !== void(0)) { - view.querySelector("label").collapsed = !isCustomizing; - view.querySelector("toolbar").style.visibility = isCustomizing - ? "hidden" : "visible"; - } }); -const viewUpdate = curry(flip(updateView)); + // Utility function used to register toolbar into CustomizableUI. const registerToolbar = state => { // If it's first additon register toolbar as customizableUI component. - CustomizableUI.registerArea("inner-" + state.id, { + CustomizableUI.registerArea(state.id, { type: CustomizableUI.TYPE_TOOLBAR, legacy: true, - defaultPlacements: [...state.items] + defaultPlacements: [...state.items, "close-" + state.id] }); }; // Utility function used to unregister toolbar from the CustomizableUI. const unregisterToolbar = CustomizableUI.unregisterArea; const reactor = new Reactor({ onStep: (present, past) => { const delta = diff(past, present); each(([id, update]) => { // If update is `null` toolbar is removed, in such case // we unregister toolbar and remove it from each window // it was added to. if (update === null) { - unregisterToolbar("inner-" + id); + unregisterToolbar(id); each(removeView(id), values(past.windows)); send(output, object([id, null])); } else if (past.toolbars[id]) { // If `collapsed` state for toolbar was updated, persist // it for a future sessions. if (update.collapsed !== void(0)) @@ -222,23 +185,17 @@ const reactor = new Reactor({ } }, pairs(delta.toolbars)); // Add views to every window that was added. each(window => { if (window) each(viewAdd(window), values(past.toolbars)); }, values(delta.windows)); - - each(([id, isCustomizing]) => { - each(viewUpdate(getByOuterId(id), {isCustomizing: !!isCustomizing}), - keys(present.toolbars)); - - }, pairs(delta.customizable)) }, onEnd: state => { each(id => { - unregisterToolbar("inner-" + id); + unregisterToolbar(id); each(removeView(id), values(state.windows)); }, keys(state.toolbars)); } }); reactor.run(State);
--- a/addon-sdk/source/lib/sdk/widget.js +++ b/addon-sdk/source/lib/sdk/widget.js @@ -439,20 +439,38 @@ const WidgetViewTrait = LightTrait.compo if ("click" == type || type.indexOf("mouse") == 0) this._baseWidget._onEvent(type, this._public); else this._baseWidget._onEvent(type, eventData); // Special case for click events: if the widget doesn't have a click // handler, but it does have a panel, display the panel. if ("click" == type && !this._listeners("click").length && this.panel) { + // In Australis, widgets may be positioned in an overflow panel or the + // menu panel. + // In such cases clicking this widget will hide the overflow/menu panel, + // and the widget's panel will show instead. + + let anchor = domNode; + let { CustomizableUI, window } = domNode.ownerDocument.defaultView; + + if (CustomizableUI) { + ({anchor}) = CustomizableUI.getWidget(domNode.id).forWindow(window); + + // if `anchor` is not the `domNode` itself, it means the widget is + // positioned in a panel, therefore we have to hide it before show + // the widget's panel in the same anchor + if (anchor !== domNode) + CustomizableUI.hidePanelForNode(domNode); + } + // This kind of ugly workaround, instead we should implement // `getNodeView` for the `Widget` class itself, but that's kind of // hard without cleaning things up. - this.panel.show(null, getNodeView.implement({}, () => domNode)); + this.panel.show(null, getNodeView.implement({}, () => anchor)); } }, _isInWindow: function WidgetView__isInWindow(window) { return windowsAPI.BrowserWindow({ window: this._chrome.window }) == window; }, @@ -772,49 +790,38 @@ WidgetChrome.prototype._createNode = fun node.style.minWidth = this._widget.width + "px"; this.node = node; } // Initial population of a widget's content. WidgetChrome.prototype.fill = function WC_fill() { - let { node, _doc: document } = this; - // Create element - let iframe = document.createElement("iframe"); + var iframe = this._doc.createElement("iframe"); iframe.setAttribute("type", "content"); iframe.setAttribute("transparent", "transparent"); iframe.style.overflow = "hidden"; iframe.style.height = "16px"; iframe.style.maxHeight = "16px"; iframe.style.width = this._widget.width + "px"; iframe.setAttribute("flex", "1"); iframe.style.border = "none"; iframe.style.padding = "0px"; // Do this early, because things like contentWindow are null // until the node is attached to a document. - node.appendChild(iframe); + this.node.appendChild(iframe); - let label = document.createElement("label"); + var label = this._doc.createElement("label"); label.setAttribute("value", this._widget.label); label.className = "toolbarbutton-text"; label.setAttribute("crop", "right"); label.setAttribute("flex", "1"); - node.appendChild(label); - - // This toolbarbutton is created to provide a more consistent user experience - // during customization, see: - // https://bugzilla.mozilla.org/show_bug.cgi?id=959640 - let button = document.createElement("toolbarbutton"); - button.setAttribute("label", this._widget.label); - button.setAttribute("crop", "right"); - button.className = "toolbarbutton-1 chromeclass-toolbar-additional"; - node.appendChild(button); + this.node.appendChild(label); // add event handlers this.addEventHandlers(); // set content this.setContent(); }
--- a/addon-sdk/source/lib/sdk/window/utils.js +++ b/addon-sdk/source/lib/sdk/window/utils.js @@ -14,18 +14,16 @@ const { defer } = require('sdk/core/prom const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1']. getService(Ci.nsIWindowWatcher); const appShellService = Cc['@mozilla.org/appshell/appShellService;1']. getService(Ci.nsIAppShellService); const WM = Cc['@mozilla.org/appshell/window-mediator;1']. getService(Ci.nsIWindowMediator); const io = Cc['@mozilla.org/network/io-service;1']. getService(Ci.nsIIOService); -const FM = Cc["@mozilla.org/focus-manager;1"]. - getService(Ci.nsIFocusManager); const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; const BROWSER = 'navigator:browser', URI_BROWSER = 'chrome://browser/content/browser.xul', NAME = '_blank', FEATURES = 'chrome,all,dialog=no,non-private'; @@ -354,28 +352,16 @@ exports.isXULBrowser = isXULBrowser; function getFocusedWindow() { let window = WM.getMostRecentWindow(BROWSER); return window ? window.document.commandDispatcher.focusedWindow : null; } exports.getFocusedWindow = getFocusedWindow; /** - * Returns the focused browser window if any, or the most recent one. - * Opening new window, updates most recent window, but focus window - * changes later; so most recent window and focused window are not always - * the same. - */ -function getFocusedBrowser() { - let window = FM.activeWindow; - return isBrowser(window) ? window : getMostRecentBrowserWindow() -} -exports.getFocusedBrowser = getFocusedBrowser; - -/** * Returns the focused element in the most recent focused window */ function getFocusedElement() { let window = WM.getMostRecentWindow(BROWSER); return window ? window.document.commandDispatcher.focusedElement : null; } exports.getFocusedElement = getFocusedElement;
--- a/addon-sdk/source/python-lib/cuddlefish/__init__.py +++ b/addon-sdk/source/python-lib/cuddlefish/__init__.py @@ -538,29 +538,33 @@ def initializer(env_root, args, out=sys. print >>out, '*', args[1], 'package directory created' except OSError: print >>out, '*', args[1], 'already exists, testing if directory is empty' # avoid clobbering existing files, but we tolerate things like .git existing = [fn for fn in os.listdir(path) if not fn.startswith(".")] if existing: print >>err, 'This command must be run in an empty directory.' return {"result":1} - for d in ['lib','data','test']: + for d in ['lib','data','test','doc']: os.mkdir(os.path.join(path,d)) print >>out, '*', d, 'directory created' + open(os.path.join(path,'README.md'),'w').write('') + print >>out, '* README.md written' jid = create_jid() print >>out, '* generated jID automatically:', jid open(os.path.join(path,'package.json'),'w').write(PACKAGE_JSON % {'name':addon.lower(), 'title':addon, 'id':jid }) print >>out, '* package.json written' open(os.path.join(path,'test','test-main.js'),'w').write(TEST_MAIN_JS) print >>out, '* test/test-main.js written' open(os.path.join(path,'lib','main.js'),'w').write('') print >>out, '* lib/main.js written' + open(os.path.join(path,'doc','main.md'),'w').write('') + print >>out, '* doc/main.md written' if len(args) == 1: print >>out, '\nYour sample add-on is now ready.' print >>out, 'Do "cfx test" to test it and "cfx run" to try it. Have fun!' else: print >>out, '\nYour sample add-on is now ready in the \'' + args[1] + '\' directory.' print >>out, 'Change to that directory, then do "cfx test" to test it, \nand "cfx run" to try it. Have fun!' return {"result":0, "jid":jid}
--- a/addon-sdk/source/python-lib/cuddlefish/runner.py +++ b/addon-sdk/source/python-lib/cuddlefish/runner.py @@ -731,16 +731,17 @@ def run_app(harness_root_dir, manifest_r sys.stderr.flush() if is_running_tests and parseable: match = PARSEABLE_TEST_NAME.search(new_chars) if match: test_name = match.group(1) if os.path.exists(resultfile): result = open(resultfile).read() if result: + sys.stderr.write("resultfile contained " + "'" + result + "'\n") if result in ['OK', 'FAIL']: done = True else: sys.stderr.write("Hrm, resultfile (%s) contained something weird (%d bytes)\n" % (resultfile, len(result))) sys.stderr.write("'"+result+"'\n") if enforce_timeouts: if time.time() - last_output_time > OUTPUT_TIMEOUT: raise Timeout("Test output exceeded timeout (%ds)." % @@ -749,17 +750,19 @@ def run_app(harness_root_dir, manifest_r raise Timeout("Test run exceeded timeout (%ds)." % RUN_TIMEOUT, test_name, parseable) except: runner.stop() raise else: runner.wait(10) finally: + sys.stderr.write("Done.\n") outf.close() + sys.stderr.write("Clean the profile.\n") if profile: profile.cleanup() print >>sys.stderr, "Total time: %f seconds" % (time.time() - starttime) if result == 'OK': print >>sys.stderr, "Program terminated successfully." return 0
--- a/addon-sdk/source/test/addons/addon-page/main.js +++ b/addon-sdk/source/test/addons/addon-page/main.js @@ -1,19 +1,25 @@ /* 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 = { + engines: { + 'Firefox': '*' + } +}; + const { isTabOpen, activateTab, openTab, closeTab, getTabURL, getWindowHoldingTab } = require('sdk/tabs/utils'); const windows = require('sdk/deprecated/window-utils'); const { LoaderWithHookedConsole } = require('sdk/test/loader'); const { setTimeout } = require('sdk/timers'); -const app = require("sdk/system/xul-app"); +const { is } = require('sdk/system/xul-app'); const tabs = require('sdk/tabs'); const isAustralis = "gCustomizeMode" in windows.activeBrowserWindow; const { set: setPref } = require("sdk/preferences/service"); const { defer } = require('sdk/core/promise'); const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings"; let uri = require('sdk/self').data.url('index.html'); @@ -33,20 +39,16 @@ function closeTabPromise(tab) { return promise; } function isChromeVisible(window) { let x = window.document.documentElement.getAttribute('disablechrome') return x !== 'true'; } -// Once Bug 903018 is resolved, just move the application testing to -// module.metadata.engines -if (app.is('Firefox')) { - exports['test add-on page deprecation message'] = function(assert) { let { loader, messages } = LoaderWithHookedConsole(module); loader.require('sdk/addon-page'); setPref(DEPRECATE_PREF, true); assert.equal(messages.length, 1, "only one error is dispatched"); assert.equal(messages[0].type, "error", "the console message is an error"); @@ -67,17 +69,17 @@ exports['test that add-on page has no ch assert.ok(isChromeVisible(window), 'chrome is visible for non addon page'); // need to do this in another turn to make sure event listener // that sets property has time to do that. setTimeout(function() { activateTab(tab); - assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis, + assert.equal(isChromeVisible(window), is('Fennec') || isAustralis, 'chrome is not visible for addon page'); closeTabPromise(tab).then(function() { assert.ok(isChromeVisible(window), 'chrome is visible again'); loader.unload(); assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload'); done(); }).then(null, assert.fail); @@ -93,17 +95,17 @@ exports['test that add-on page with hash assert.ok(isChromeVisible(window), 'chrome is visible for non addon page'); // need to do this in another turn to make sure event listener // that sets property has time to do that. setTimeout(function() { activateTab(tab); - assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis, + assert.equal(isChromeVisible(window), is('Fennec') || isAustralis, 'chrome is not visible for addon page'); closeTabPromise(tab).then(function() { assert.ok(isChromeVisible(window), 'chrome is visible again'); loader.unload(); assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload'); done(); }).then(null, assert.fail); @@ -119,17 +121,17 @@ exports['test that add-on page with quer assert.ok(isChromeVisible(window), 'chrome is visible for non addon page'); // need to do this in another turn to make sure event listener // that sets property has time to do that. setTimeout(function() { activateTab(tab); - assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis, + assert.equal(isChromeVisible(window), is('Fennec') || isAustralis, 'chrome is not visible for addon page'); closeTabPromise(tab).then(function() { assert.ok(isChromeVisible(window), 'chrome is visible again'); loader.unload(); assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload'); done(); }).then(null, assert.fail); @@ -145,17 +147,17 @@ exports['test that add-on page with hash assert.ok(isChromeVisible(window), 'chrome is visible for non addon page'); // need to do this in another turn to make sure event listener // that sets property has time to do that. setTimeout(function() { activateTab(tab); - assert.equal(isChromeVisible(window), app.is('Fennec') || isAustralis, + assert.equal(isChromeVisible(window), is('Fennec') || isAustralis, 'chrome is not visible for addon page'); closeTabPromise(tab).then(function() { assert.ok(isChromeVisible(window), 'chrome is visible again'); loader.unload(); assert.ok(!isTabOpen(tab), 'add-on page tab is closed on unload'); done(); }).then(null, assert.fail); @@ -178,13 +180,9 @@ exports['test that malformed uri is not closeTabPromise(tab).then(function() { loader.unload(); done(); }).then(null, assert.fail); }); }; -} else { - exports['test unsupported'] = (assert) => assert.pass('This application is unsupported.'); -} - require('sdk/test/runner').runTestsFromModule(module);
--- a/addon-sdk/source/test/addons/child_process/index.js +++ b/addon-sdk/source/test/addons/child_process/index.js @@ -1,39 +1,32 @@ /* 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"; -/** - * Ensures using child_process and underlying subprocess.jsm - * works within an addon - */ - const { exec } = require("sdk/system/child_process"); const { platform, pathFor } = require("sdk/system"); const PROFILE_DIR = pathFor("ProfD"); const isWindows = platform.toLowerCase().indexOf("win") === 0; -const app = require("sdk/system/xul-app"); -// Once Bug 903018 is resolved, just move the application testing to -// module.metadata.engines -if (app.is("Firefox")) { - exports["test child_process in an addon"] = (assert, done) => { - exec(isWindows ? "DIR /A-D" : "ls -al", { - cwd: PROFILE_DIR - }, (err, stdout, stderr) => { - assert.ok(!err, "no errors"); - assert.equal(stderr, "", "stderr is empty"); - assert.ok(/extensions\.ini/.test(stdout), "stdout output of `ls -al` finds files"); +/** + * Ensures using child_process and underlying subprocess.jsm + * works within an addon + */ +exports["test child_process in an addon"] = (assert, done) => { + exec(isWindows ? "DIR /A-D" : "ls -al", { + cwd: PROFILE_DIR + }, (err, stdout, stderr) => { + assert.ok(!err, "no errors"); + assert.equal(stderr, "", "stderr is empty"); + assert.ok(/extensions\.ini/.test(stdout), "stdout output of `ls -al` finds files"); - if (isWindows) - assert.ok(!/<DIR>/.test(stdout), "passing args works"); - else - assert.ok(/d(r[-|w][-|x]){3}/.test(stdout), "passing args works"); - done(); - }); - }; -} else { - exports["test unsupported"] = (assert) => assert.pass("This application is unsupported."); -} + if (isWindows) + assert.ok(!/<DIR>/.test(stdout), "passing args works"); + else + assert.ok(/d(r[-|w][-|x]){3}/.test(stdout), "passing args works"); + done(); + }); +}; + require("sdk/test/runner").runTestsFromModule(module);
--- a/addon-sdk/source/test/addons/places/main.js +++ b/addon-sdk/source/test/addons/places/main.js @@ -1,27 +1,24 @@ /* 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 = { + 'engines': { + 'Firefox': '*' + } +}; + const { safeMerge: merge } = require('sdk/util/object'); -const app = require("sdk/system/xul-app"); -// Once Bug 903018 is resolved, just move the application testing to -// module.metadata.engines -if (app.is('Firefox')) { - merge(module.exports, - require('./tests/test-places-bookmarks'), - require('./tests/test-places-events'), - require('./tests/test-places-favicon'), - require('./tests/test-places-history'), - require('./tests/test-places-host'), - require('./tests/test-places-utils') - ); -} else { - exports['test unsupported'] = (assert) => { - assert.pass('This application is unsupported.'); - }; -} +merge(module.exports, + require('./tests/test-places-bookmarks'), + require('./tests/test-places-events'), + require('./tests/test-places-favicon'), + require('./tests/test-places-history'), + require('./tests/test-places-host'), + require('./tests/test-places-utils') +); require('sdk/test/runner').runTestsFromModule(module);
--- a/addon-sdk/source/test/addons/simple-prefs-l10n/main.js +++ b/addon-sdk/source/test/addons/simple-prefs-l10n/main.js @@ -7,59 +7,51 @@ const { Cu } = require('chrome'); const sp = require('sdk/simple-prefs'); const app = require('sdk/system/xul-app'); const self = require('sdk/self'); const tabs = require('sdk/tabs'); const { preferencesBranch } = require('sdk/self'); const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {}); -// Once Bug 903018 is resolved, just move the application testing to -// module.metadata.engines -// -// This should work in Fennec, needs to be refactored to work, via bug 979645 -if (app.is('Firefox')) { - exports.testAOMLocalization = function(assert, done) { - tabs.open({ - url: 'about:addons', - onReady: function(tab) { - tab.attach({ - contentScriptWhen: 'end', - contentScript: 'function onLoad() {\n' + - 'unsafeWindow.removeEventListener("load", onLoad, false);\n' + - 'AddonManager.getAddonByID("' + self.id + '", function(aAddon) {\n' + - 'unsafeWindow.gViewController.viewObjects.detail.node.addEventListener("ViewChanged", function whenViewChanges() {\n' + - 'unsafeWindow.gViewController.viewObjects.detail.node.removeEventListener("ViewChanged", whenViewChanges, false);\n' + - 'setTimeout(function() {\n' + // TODO: figure out why this is necessary.. - 'self.postMessage({\n' + - 'somePreference: getAttributes(unsafeWindow.document.querySelector("setting[data-jetpack-id=\'' + self.id + '\']"))\n' + - '});\n' + - '}, 250);\n' + - '}, false);\n' + - 'unsafeWindow.gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);\n' + - '});\n' + - 'function getAttributes(ele) {\n' + - 'if (!ele) return {};\n' + - 'return {\n' + - 'title: ele.getAttribute("title")\n' + - '}\n' + +exports.testAOMLocalization = function(assert, done) { + tabs.open({ + url: 'about:addons', + onReady: function(tab) { + tab.attach({ + contentScriptWhen: 'end', + contentScript: 'function onLoad() {\n' + + 'unsafeWindow.removeEventListener("load", onLoad, false);\n' + + 'AddonManager.getAddonByID("' + self.id + '", function(aAddon) {\n' + + 'unsafeWindow.gViewController.viewObjects.detail.node.addEventListener("ViewChanged", function whenViewChanges() {\n' + + 'unsafeWindow.gViewController.viewObjects.detail.node.removeEventListener("ViewChanged", whenViewChanges, false);\n' + + 'setTimeout(function() {\n' + // TODO: figure out why this is necessary.. + 'self.postMessage({\n' + + 'somePreference: getAttributes(unsafeWindow.document.querySelector("setting[data-jetpack-id=\'' + self.id + '\']"))\n' + + '});\n' + + '}, 250);\n' + + '}, false);\n' + + 'unsafeWindow.gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);\n' + + '});\n' + + 'function getAttributes(ele) {\n' + + 'if (!ele) return {};\n' + + 'return {\n' + + 'title: ele.getAttribute("title")\n' + '}\n' + '}\n' + - // Wait for the load event ? - 'if (document.readyState == "complete") {\n' + - 'onLoad()\n' + - '} else {\n' + - 'unsafeWindow.addEventListener("load", onLoad, false);\n' + - '}\n', - onMessage: function(msg) { - // test somePreference - assert.equal(msg.somePreference.title, 'A', 'somePreference title is correct'); - tab.close(done); - } - }); - } - }); - } -} else { - exports['test unsupported'] = (assert) => assert.pass('This test is unsupported.'); + '}\n' + + // Wait for the load event ? + 'if (document.readyState == "complete") {\n' + + 'onLoad()\n' + + '} else {\n' + + 'unsafeWindow.addEventListener("load", onLoad, false);\n' + + '}\n', + onMessage: function(msg) { + // test somePreference + assert.equal(msg.somePreference.title, 'A', 'somePreference title is correct'); + tab.close(done); + } + }); + } + }); } require('sdk/test/runner').runTestsFromModule(module);
--- a/addon-sdk/source/test/test-functional.js +++ b/addon-sdk/source/test/test-functional.js @@ -433,38 +433,30 @@ exports["test debounce"] = (assert, done setTimeout(() => { assert.equal(counter, 2, "function able to be called again after wait"); done(); }, 150); }, 200); }; exports["test throttle"] = (assert, done) => { - let counter = 0; - let incr = function(){ counter++; }; - let throttledIncr = throttle(incr, 32); - throttledIncr(); - throttledIncr(); - throttledIncr(); - throttledIncr(); + let called = 0; + let attempt = 0; + let throttledFn = throttle(() => called++, 100); + let fn = () => ++attempt && throttledFn(); + + new Array(11).join(0).split("").forEach((_, i) => { + setTimeout(fn, 20 * (i+1)); + }); - assert.equal(counter, 1, 'incr was called immediately'); setTimeout(() => { - assert.equal(counter, 2, 'incr was throttled'); + assert.equal(called, 1, "function called atleast once during first throttle period"); + assert.ok(attempt >= 2, "function attempted to be called several times during first period"); + }, 50); + + setTimeout(() => { + assert.equal(called, 3, "function called again during second throttle period"); + assert.equal(attempt, 10, "function attempted to be called several times during second period"); done(); - }, 64); -}; - -exports["test throttle args"] = (assert, done) => { - let value = 0; - let update = function(val){ value = val; }; - let throttledUpdate = throttle(update, 32); - throttledUpdate(1); - throttledUpdate(2); - setTimeout(() => throttledUpdate(3), 64); - assert.equal(value, 1, 'updated to latest value'); - setTimeout(() => { - assert.equal(value, 3, 'updated to latest value'); - done(); - }, 96); + }, 300); }; require('test').run(exports);
--- a/addon-sdk/source/test/test-ui-frame.js +++ b/addon-sdk/source/test/test-ui-frame.js @@ -41,36 +41,36 @@ exports["test frame API"] = function*(as assert.throws(() => new Frame(), /The `options.url`/, "must provide url"); assert.throws(() => new Frame({ url: "http://mozilla.org/" }), /The `options.url`/, "options.url must be local url"); - assert.throws(() => new Frame({url: url, name: "4you" }), - /The `option.name` must be a valid/, - "can only take valid names"); + assert.throws(() => new Frame({url: url, id: "4you" }), + /The `option.id` must be a valid/, + "can only take valid ID's"); const f1 = new Frame({ url: url }); assert.ok(f1.id, "frame has an id"); assert.equal(f1.url, void(0), "frame has no url until it's loaded"); assert.equal(typeof(f1.postMessage), "function", "frames can postMessages"); const p1 = wait(f1, "register"); assert.throws(() => new Frame({ url: url }), /Frame with this id already exists/, "can't have two identical frames"); - const f2 = new Frame({ name: "frame-2", url: url }); - assert.pass("can create frame with same url but diff name"); + const f2 = new Frame({ id: "frame-2", url: url }); + assert.pass("can create frame with same url but diff id"); const p2 = wait(f2, "register"); yield p1; assert.pass("frame#1 was registered"); assert.equal(f1.url, url, "once registered it get's url"); yield p2; assert.pass("frame#2 was registered"); @@ -140,17 +140,17 @@ exports["test frame in toolbar"] = funct exports["test host to content messaging"] = function*(assert) { const url = "data:text/html,<script>new " + function() { window.addEventListener("message", (event) => { if (event.data === "ping!") event.source.postMessage("pong!", event.origin); }); } + "</script>"; - const f1 = new Frame({ name: "mailbox", url: url }); + const f1 = new Frame({ id: "mailbox", url: url }); const t1 = new Toolbar({ title: "mailbox", items: [f1] }); const e1 = yield wait(f1, "ready"); e1.source.postMessage("ping!", e1.origin); const pong = yield wait(f1, "message"); assert.equal(pong.data, "pong!", "received ping back"); t1.destroy(); @@ -164,17 +164,17 @@ exports["test content to host messaging" window.addEventListener("message", (event) => { if (event.data === "pong!") event.source.postMessage("end", event.origin); }); window.parent.postMessage("ping!", "*"); } + "</script>"; - const f1 = new Frame({ name: "inbox", url: url }); + const f1 = new Frame({ id: "inbox", url: url }); const t1 = new Toolbar({ title: "inbox", items: [f1] }); const e1 = yield wait(f1, "message"); assert.equal(e1.data, "ping!", "received ping from content"); e1.source.postMessage("pong!", e1.origin); const e2 = yield wait(f1, "message"); @@ -192,17 +192,17 @@ exports["test direct messaging"] = funct if (event.data === "inc") n = n + 1; if (event.data === "print") event.source.postMessage({ n: n }, event.origin); }); } + "</script>"; const w1 = getMostRecentBrowserWindow(); - const f1 = new Frame({ url: url, name: "mail-cluster" }); + const f1 = new Frame({ url: url, id: "mail-cluster" }); const t1 = new Toolbar({ title: "claster", items: [f1] }); yield wait(f1, "ready"); assert.pass("document loaded in window#1"); const w2 = open(); yield wait(f1, "ready");
--- a/addon-sdk/source/test/test-ui-toggle-button.js +++ b/addon-sdk/source/test/test-ui-toggle-button.js @@ -1015,54 +1015,16 @@ exports['test button click do not messin button.state(mainWindow, null); assert.equal(button.state(activeTab).icon, './icon.png', 'icon property for tab state, properly derived from window state'); loader.unload(); } -exports['test buttons can have anchored panels'] = function(assert, done) { - let loader = Loader(module); - let { ToggleButton } = loader.require('sdk/ui'); - let { Panel } = loader.require('sdk/panel'); - let { identify } = loader.require('sdk/ui/id'); - let { getActiveView } = loader.require('sdk/view/core'); - - let button = ToggleButton({ - id: 'my-button-22', - label: 'my button', - icon: './icon.png', - onChange: ({checked}) => checked && panel.show({position: button}) - }); - - let panel = Panel(); - - panel.once('show', () => { - let { document } = getMostRecentBrowserWindow(); - let buttonNode = document.getElementById(identify(button)); - let panelNode = getActiveView(panel); - - assert.ok(button.state('window').checked, - 'button is checked'); - - assert.equal(panelNode.getAttribute('type'), 'arrow', - 'the panel is a arrow type'); - - assert.strictEqual(buttonNode, panelNode.anchorNode, - 'the panel is anchored properly to the button'); - - loader.unload(); - - done(); - }); - - button.click(); -} - // If the module doesn't support the app we're being run in, require() will // throw. In that case, remove all tests above from exports, and add one dummy // test that passes. try { require('sdk/ui/button/toggle'); } catch (err) { if (!/^Unsupported Application/.test(err.message))
--- a/addon-sdk/source/test/test-ui-toolbar.js +++ b/addon-sdk/source/test/test-ui-toolbar.js @@ -7,22 +7,21 @@ module.metadata = { "engines": { "Firefox": "*" } }; const { Toolbar } = require("sdk/ui/toolbar"); const { Loader } = require("sdk/test/loader"); const { identify } = require("sdk/ui/id"); -const { getMostRecentBrowserWindow, open, getOuterId } = require("sdk/window/utils"); +const { getMostRecentBrowserWindow, open } = require("sdk/window/utils"); const { ready, close } = require("sdk/window/helpers"); const { defer } = require("sdk/core/promise"); -const { send, stop, Reactor } = require("sdk/event/utils"); +const { send } = require("sdk/event/utils"); const { object } = require("sdk/util/sequence"); -const { CustomizationInput } = require("sdk/input/customizable-ui"); const { OutputPort } = require("sdk/output/system"); const output = new OutputPort({ id: "toolbar-change" }); const wait = (toolbar, event) => { let { promise, resolve } = defer(); toolbar.once(event, resolve); return promise; }; @@ -353,125 +352,9 @@ exports["test title change"] = function* assert.equal(readTitle(t1, w2), "second title", "title updated in second window"); t1.destroy(); yield wait(t1, "detach"); yield close(w2); }; -exports["test toolbar is not customizable"] = function*(assert, done) { - const { window, document, gCustomizeMode } = getMostRecentBrowserWindow(); - const outerId = getOuterId(window); - const input = new CustomizationInput(); - const customized = defer(); - const customizedEnd = defer(); - - new Reactor({ onStep: value => { - if (value[outerId] === true) - customized.resolve(); - if (value[outerId] === null) - customizedEnd.resolve(); - }}).run(input); - - const toolbar = new Toolbar({ title: "foo" }); - - yield wait(toolbar, "attach"); - - let view = document.getElementById(toolbar.id); - let label = view.querySelector("label"); - let inner = view.querySelector("toolbar"); - - assert.equal(view.getAttribute("customizable"), "false", - "The outer toolbar is not customizable."); - - assert.ok(label.collapsed, - "The label is not displayed.") - - assert.equal(inner.getAttribute("customizable"), "true", - "The inner toolbar is customizable."); - - assert.equal(window.getComputedStyle(inner).visibility, "visible", - "The inner toolbar is visible."); - - // Enter in customization mode - gCustomizeMode.toggle(); - - yield customized.promise; - - assert.equal(view.getAttribute("customizable"), "false", - "The outer toolbar is not customizable."); - - assert.equal(label.collapsed, false, - "The label is displayed.") - - assert.equal(inner.getAttribute("customizable"), "true", - "The inner toolbar is customizable."); - - assert.equal(window.getComputedStyle(inner).visibility, "hidden", - "The inner toolbar is hidden."); - - // Exit from customization mode - gCustomizeMode.toggle(); - - yield customizedEnd.promise; - - assert.equal(view.getAttribute("customizable"), "false", - "The outer toolbar is not customizable."); - - assert.ok(label.collapsed, - "The label is not displayed.") - - assert.equal(inner.getAttribute("customizable"), "true", - "The inner toolbar is customizable."); - - assert.equal(window.getComputedStyle(inner).visibility, "visible", - "The inner toolbar is visible."); - - toolbar.destroy(); -}; - -exports["test button are attached to toolbar"] = function*(assert) { - const { document } = getMostRecentBrowserWindow(); - const { ActionButton, ToggleButton } = require("sdk/ui"); - const { identify } = require("sdk/ui/id"); - - let action = ActionButton({ - id: "btn-1", - label: "action", - icon: "./placeholder.png" - }); - - let toggle = ToggleButton({ - id: "btn-2", - label: "toggle", - icon: "./placeholder.png" - }); - - const toolbar = new Toolbar({ - title: "foo", - items: [action, toggle] - }); - - yield wait(toolbar, "attach"); - - let actionNode = document.getElementById(identify(action)); - let toggleNode = document.getElementById(identify(toggle)); - - assert.notEqual(actionNode, null, - "action button exists in the document"); - - assert.notEqual(actionNode, null, - "action button exists in the document"); - - assert.notEqual(toggleNode, null, - "toggle button exists in the document"); - - assert.equal(actionNode.nextElementSibling, toggleNode, - "action button is placed before toggle button"); - - assert.equal(actionNode.parentNode.parentNode.id, toolbar.id, - "buttons are placed in the correct toolbar"); - - toolbar.destroy(); -}; - require("sdk/test").run(exports);