mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
parent
284013b5c1
commit
09aed864d0
@ -96,7 +96,7 @@ package.json modified: please re-run 'cfx run'
|
||||
alt="Mozilla icon widget" />
|
||||
|
||||
Run `cfx run` again, and it will run an instance of Firefox. In the
|
||||
bottom-right corner of the browser you'll see an icon with the Firefox
|
||||
bottom-right corner of the browser you'll see an icon with the Mozilla
|
||||
logo. Click the icon, and a new tab will open with
|
||||
[http://www.mozilla.org/](http://www.mozilla.org/) loaded into it.
|
||||
|
||||
|
@ -89,7 +89,7 @@ to support private browsing, refer to the
|
||||
var utils = require('sdk/window/utils');
|
||||
var browserWindow = utils.getMostRecentBrowserWindow();
|
||||
var window = browserWindow.content; // `window` object for the current webpage
|
||||
utils.getToplevelWindw(window) == browserWindow // => true
|
||||
utils.getToplevelWindow(window) == browserWindow // => true
|
||||
|
||||
@param window {nsIDOMWindow}
|
||||
@returns {nsIDOMWindow}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
Binary file not shown.
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 15 KiB |
@ -137,6 +137,14 @@ const ContentWorker = Object.freeze({
|
||||
registerMethod = chromeSetInterval;
|
||||
else
|
||||
throw new Error("Unknown timer kind: " + timer.kind);
|
||||
|
||||
if (typeof timer.fun == 'string') {
|
||||
let code = timer.fun;
|
||||
timer.fun = () => chromeAPI.sandbox.evaluate(exports, code);
|
||||
} else if (typeof timer.fun != 'function') {
|
||||
throw new Error('Unsupported callback type' + typeof timer.fun);
|
||||
}
|
||||
|
||||
let id = registerMethod(onFire, timer.delay);
|
||||
function onFire() {
|
||||
try {
|
||||
@ -145,12 +153,47 @@ const ContentWorker = Object.freeze({
|
||||
timer.fun.apply(null, timer.args);
|
||||
} catch(e) {
|
||||
console.exception(e);
|
||||
let wrapper = {
|
||||
instanceOfError: instanceOf(e, Error),
|
||||
value: e,
|
||||
};
|
||||
if (wrapper.instanceOfError) {
|
||||
wrapper.value = {
|
||||
message: e.message,
|
||||
fileName: e.fileName,
|
||||
lineNumber: e.lineNumber,
|
||||
stack: e.stack,
|
||||
name: e.name,
|
||||
};
|
||||
}
|
||||
pipe.emit('error', wrapper);
|
||||
}
|
||||
}
|
||||
_timers[id] = timer;
|
||||
return id;
|
||||
}
|
||||
|
||||
// copied from sdk/lang/type.js since modules are not available here
|
||||
function instanceOf(value, Type) {
|
||||
var isConstructorNameSame;
|
||||
var isConstructorSourceSame;
|
||||
|
||||
// If `instanceof` returned `true` we know result right away.
|
||||
var isInstanceOf = value instanceof Type;
|
||||
|
||||
// If `instanceof` returned `false` we do ducktype check since `Type` may be
|
||||
// from a different sandbox. If a constructor of the `value` or a constructor
|
||||
// of the value's prototype has same name and source we assume that it's an
|
||||
// instance of the Type.
|
||||
if (!isInstanceOf && value) {
|
||||
isConstructorNameSame = value.constructor.name === Type.name;
|
||||
isConstructorSourceSame = String(value.constructor) == String(Type);
|
||||
isInstanceOf = (isConstructorNameSame && isConstructorSourceSame) ||
|
||||
instanceOf(Object.getPrototypeOf(value), Type);
|
||||
}
|
||||
return isInstanceOf;
|
||||
}
|
||||
|
||||
function unregisterTimer(id) {
|
||||
if (!(id in _timers))
|
||||
return;
|
||||
|
@ -13,6 +13,7 @@ const { validateOptions } = require('../deprecated/api-utils');
|
||||
const { isValidURI, URL } = require('../url');
|
||||
const file = require('../io/file');
|
||||
const { contract } = require('../util/contract');
|
||||
const { isString, instanceOf } = require('../lang/type');
|
||||
|
||||
const LOCAL_URI_SCHEMES = ['resource', 'data'];
|
||||
|
||||
@ -32,7 +33,7 @@ const valid = {
|
||||
msg: 'The `contentURL` option must be a valid URL.'
|
||||
},
|
||||
contentScriptFile: {
|
||||
is: ['undefined', 'null', 'string', 'array'],
|
||||
is: ['undefined', 'null', 'string', 'array', 'object'],
|
||||
map: ensureNull,
|
||||
ok: function(value) {
|
||||
if (value === null)
|
||||
@ -40,8 +41,13 @@ const valid = {
|
||||
|
||||
value = [].concat(value);
|
||||
|
||||
// Make sure every item is a local file URL.
|
||||
// Make sure every item is a string or an
|
||||
// URL instance, and also a local file URL.
|
||||
return value.every(function (item) {
|
||||
|
||||
if (!isString(item) && !(item instanceof URL))
|
||||
return false;
|
||||
|
||||
try {
|
||||
return ~LOCAL_URI_SCHEMES.indexOf(URL(item).scheme);
|
||||
}
|
||||
|
@ -108,6 +108,27 @@ const Symbiont = Worker.resolve({
|
||||
|
||||
this._frame = frame;
|
||||
|
||||
if (getDocShell(frame)) {
|
||||
this._reallyInitFrame(frame);
|
||||
}
|
||||
else {
|
||||
if (this._waitForFrame) {
|
||||
observers.remove('content-document-global-created', this._waitForFrame);
|
||||
}
|
||||
this._waitForFrame = this.__waitForFrame.bind(this, frame);
|
||||
observers.add('content-document-global-created', this._waitForFrame);
|
||||
}
|
||||
},
|
||||
|
||||
__waitForFrame: function _waitForFrame(frame, win, topic) {
|
||||
if (frame.contentWindow == win) {
|
||||
observers.remove('content-document-global-created', this._waitForFrame);
|
||||
delete this._waitForFrame;
|
||||
this._reallyInitFrame(frame);
|
||||
}
|
||||
},
|
||||
|
||||
_reallyInitFrame: function _reallyInitFrame(frame) {
|
||||
getDocShell(frame).allowJavascript = this.allow.script;
|
||||
frame.setAttribute("src", this._contentURL);
|
||||
|
||||
@ -179,6 +200,11 @@ const Symbiont = Worker.resolve({
|
||||
* This listener is registered in `Symbiont._initFrame`.
|
||||
*/
|
||||
_unregisterListener: function _unregisterListener() {
|
||||
if (this._waitForFrame) {
|
||||
observers.remove('content-document-global-created', this._waitForFrame);
|
||||
delete this._waitForFrame;
|
||||
}
|
||||
|
||||
if (!this._loadListener)
|
||||
return;
|
||||
if (this._loadEvent == "start") {
|
||||
|
@ -202,8 +202,15 @@ const WorkerSandbox = EventEmitter.compose({
|
||||
clearInterval: 'r'
|
||||
}
|
||||
},
|
||||
sandbox: {
|
||||
evaluate: evaluate,
|
||||
__exposedProps__: {
|
||||
evaluate: 'r',
|
||||
}
|
||||
},
|
||||
__exposedProps__: {
|
||||
timers: 'r'
|
||||
timers: 'r',
|
||||
sandbox: 'r',
|
||||
}
|
||||
};
|
||||
let onEvent = this._onContentEvent.bind(this);
|
||||
@ -233,6 +240,19 @@ const WorkerSandbox = EventEmitter.compose({
|
||||
self._addonWorker._onContentScriptEvent.apply(self._addonWorker, arguments);
|
||||
});
|
||||
|
||||
// unwrap, recreate and propagate async Errors thrown from content-script
|
||||
this.on("error", function onError({instanceOfError, value}) {
|
||||
if (self._addonWorker) {
|
||||
let error = value;
|
||||
if (instanceOfError) {
|
||||
error = new Error(value.message, value.fileName, value.lineNumber);
|
||||
error.stack = value.stack;
|
||||
error.name = value.name;
|
||||
}
|
||||
self._addonWorker._emit('error', error);
|
||||
}
|
||||
});
|
||||
|
||||
// Inject `addon` global into target document if document is trusted,
|
||||
// `addon` in document is equivalent to `self` in content script.
|
||||
if (worker._injectInDocument) {
|
||||
|
@ -36,7 +36,7 @@ const observers = function observers(target, type) {
|
||||
* The listener function that processes the event.
|
||||
*/
|
||||
function on(target, type, listener) {
|
||||
if (typeof(listener) !== 'function')
|
||||
if (typeof(listener) !== 'function')
|
||||
throw new Error(BAD_LISTENER);
|
||||
|
||||
let listeners = observers(target, type);
|
||||
@ -56,9 +56,9 @@ exports.on = on;
|
||||
* The listener function that processes the event.
|
||||
*/
|
||||
function once(target, type, listener) {
|
||||
on(target, type, function observer() {
|
||||
on(target, type, function observer(...args) {
|
||||
off(target, type, observer);
|
||||
listener.apply(target, arguments);
|
||||
listener.apply(target, args);
|
||||
});
|
||||
}
|
||||
exports.once = once;
|
||||
@ -74,40 +74,24 @@ exports.once = once;
|
||||
* Event target object.
|
||||
* @param {String} type
|
||||
* The type of event.
|
||||
* @params {Object|Number|String|Boolean} message
|
||||
* First argument that will be passed to listeners.
|
||||
* @params {Object|Number|String|Boolean} ...
|
||||
* More arguments that will be passed to listeners.
|
||||
* @params {Object|Number|String|Boolean} args
|
||||
* Arguments that will be passed to listeners.
|
||||
*/
|
||||
function emit(target, type, message /*, ...*/) {
|
||||
for each (let item in emit.lazy.apply(emit.lazy, arguments)) {
|
||||
// We just iterate, iterator take care of emitting events.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is very experimental feature that you should not use unless absolutely
|
||||
* need it. Also it may be removed at any point without any further notice.
|
||||
*
|
||||
* Creates lazy iterator of return values of listeners. You can think of it
|
||||
* as lazy array of return values of listeners for the `emit` with the given
|
||||
* arguments.
|
||||
*/
|
||||
emit.lazy = function lazy(target, type, message /*, ...*/) {
|
||||
let args = Array.slice(arguments, 2);
|
||||
function emit (target, type, ...args) {
|
||||
let state = observers(target, type);
|
||||
let listeners = state.slice();
|
||||
let index = 0;
|
||||
let count = listeners.length;
|
||||
let index = 0;
|
||||
|
||||
// If error event and there are no handlers then print error message
|
||||
// into a console.
|
||||
if (count === 0 && type === 'error') console.exception(message);
|
||||
if (count === 0 && type === 'error') console.exception(args[0]);
|
||||
while (index < count) {
|
||||
try {
|
||||
let listener = listeners[index];
|
||||
// Dispatch only if listener is still registered.
|
||||
if (~state.indexOf(listener)) yield listener.apply(target, args);
|
||||
if (~state.indexOf(listener))
|
||||
listener.apply(target, args);
|
||||
}
|
||||
catch (error) {
|
||||
// If exception is not thrown by a error listener and error listener is
|
||||
@ -115,8 +99,10 @@ emit.lazy = function lazy(target, type, message /*, ...*/) {
|
||||
if (type !== 'error') emit(target, 'error', error);
|
||||
else console.exception(error);
|
||||
}
|
||||
index = index + 1;
|
||||
index++;
|
||||
}
|
||||
// Also emit on `"*"` so that one could listen for all events.
|
||||
if (type !== '*') emit(target, '*', type, ...args);
|
||||
}
|
||||
exports.emit = emit;
|
||||
|
||||
@ -145,7 +131,7 @@ function off(target, type, listener) {
|
||||
}
|
||||
else if (length === 1) {
|
||||
let listeners = event(target);
|
||||
Object.keys(listeners).forEach(function(type) delete listeners[type]);
|
||||
Object.keys(listeners).forEach(type => delete listeners[type]);
|
||||
}
|
||||
}
|
||||
exports.off = off;
|
||||
@ -171,7 +157,7 @@ exports.count = count;
|
||||
* Dictionary of listeners.
|
||||
*/
|
||||
function setListeners(target, listeners) {
|
||||
Object.keys(listeners || {}).forEach(function onEach(key) {
|
||||
Object.keys(listeners || {}).forEach(key => {
|
||||
let match = EVENT_TYPE_PATTERN.exec(key);
|
||||
let type = match && match[1].toLowerCase();
|
||||
let listener = listeners[key];
|
||||
|
@ -11,6 +11,10 @@ module.metadata = {
|
||||
const { Cc, Ci, Cr } = require("chrome");
|
||||
const apiUtils = require("./deprecated/api-utils");
|
||||
const errors = require("./deprecated/errors");
|
||||
const { isString, isUndefined, instanceOf } = require('./lang/type');
|
||||
const { URL } = require('./url');
|
||||
|
||||
const NOTIFICATION_DIRECTIONS = ["auto", "ltr", "rtl"];
|
||||
|
||||
try {
|
||||
let alertServ = Cc["@mozilla.org/alerts-service;1"].
|
||||
@ -36,7 +40,7 @@ exports.notify = function notifications_notify(options) {
|
||||
};
|
||||
function notifyWithOpts(notifyFn) {
|
||||
notifyFn(valOpts.iconURL, valOpts.title, valOpts.text, !!clickObserver,
|
||||
valOpts.data, clickObserver);
|
||||
valOpts.data, clickObserver, valOpts.tag, valOpts.dir, valOpts.lang);
|
||||
}
|
||||
try {
|
||||
notifyWithOpts(notify);
|
||||
@ -66,15 +70,32 @@ function validateOptions(options) {
|
||||
is: ["string", "undefined"]
|
||||
},
|
||||
iconURL: {
|
||||
is: ["string", "undefined"]
|
||||
is: ["string", "undefined", "object"],
|
||||
ok: function(value) {
|
||||
return isUndefined(value) || isString(value) || (value instanceof URL);
|
||||
},
|
||||
msg: "`iconURL` must be a string or an URL instance."
|
||||
},
|
||||
onClick: {
|
||||
is: ["function", "undefined"]
|
||||
},
|
||||
text: {
|
||||
is: ["string", "undefined"]
|
||||
is: ["string", "undefined", "number"]
|
||||
},
|
||||
title: {
|
||||
is: ["string", "undefined", "number"]
|
||||
},
|
||||
tag: {
|
||||
is: ["string", "undefined", "number"]
|
||||
},
|
||||
dir: {
|
||||
is: ["string", "undefined"],
|
||||
ok: function(value) {
|
||||
return isUndefined(value) || ~NOTIFICATION_DIRECTIONS.indexOf(value);
|
||||
},
|
||||
msg: '`dir` option must be one of: "auto", "ltr" or "rtl".'
|
||||
},
|
||||
lang: {
|
||||
is: ["string", "undefined"]
|
||||
}
|
||||
});
|
||||
|
@ -136,18 +136,18 @@ const PageMod = Loader.compose(EventEmitter, {
|
||||
|
||||
_applyOnExistingDocuments: function _applyOnExistingDocuments() {
|
||||
let mod = this;
|
||||
// Returns true if the tab match one rule
|
||||
let tabs = getAllTabs().filter(function (tab) {
|
||||
return mod.include.matchesAny(getTabURI(tab));
|
||||
});
|
||||
let tabs = getAllTabs();
|
||||
|
||||
tabs.forEach(function (tab) {
|
||||
// Fake a newly created document
|
||||
let window = getTabContentWindow(tab);
|
||||
if (has(mod.attachTo, "top"))
|
||||
if (has(mod.attachTo, "top") && mod.include.matchesAny(getTabURI(tab)))
|
||||
mod._onContent(window);
|
||||
if (has(mod.attachTo, "frame"))
|
||||
getFrames(window).forEach(mod._onContent);
|
||||
if (has(mod.attachTo, "frame")) {
|
||||
getFrames(window).
|
||||
filter((iframe) => mod.include.matchesAny(iframe.location.href)).
|
||||
forEach(mod._onContent);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -130,6 +130,10 @@ const Request = Class({
|
||||
request(this).contentType = validateSingleOption('contentType', value);
|
||||
},
|
||||
get response() { return request(this).response; },
|
||||
delete: function() {
|
||||
runRequest('DELETE', this);
|
||||
return this;
|
||||
},
|
||||
get: function() {
|
||||
runRequest('GET', this);
|
||||
return this;
|
||||
|
@ -13,6 +13,7 @@ const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL, getTabConten
|
||||
const { emit } = require('../event/core');
|
||||
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
|
||||
const { when: unload } = require('../system/unload');
|
||||
const { viewFor } = require('../event/core');
|
||||
const { EVENTS } = require('./events');
|
||||
|
||||
const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
|
||||
@ -33,7 +34,7 @@ const Tab = Class({
|
||||
// TabReady
|
||||
let onReady = tabInternals.onReady = onTabReady.bind(this);
|
||||
tab.browser.addEventListener(EVENTS.ready.dom, onReady, false);
|
||||
|
||||
|
||||
let onPageShow = tabInternals.onPageShow = onTabPageShow.bind(this);
|
||||
tab.browser.addEventListener(EVENTS.pageshow.dom, onPageShow, false);
|
||||
|
||||
@ -176,6 +177,10 @@ const Tab = Class({
|
||||
});
|
||||
exports.Tab = Tab;
|
||||
|
||||
// Implement `viewFor` polymorphic function for the Tab
|
||||
// instances.
|
||||
viewFor.define(Tab, x => tabNS(x).tab);
|
||||
|
||||
function cleanupTab(tab) {
|
||||
let tabInternals = tabNS(tab);
|
||||
if (!tabInternals.tab)
|
||||
|
@ -13,9 +13,10 @@ const { getFaviconURIForLocation } = require("../io/data");
|
||||
const { activateTab, getOwnerWindow, getBrowserForTab, getTabTitle, setTabTitle,
|
||||
getTabURL, setTabURL, getTabContentType, getTabId } = require('./utils');
|
||||
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
|
||||
const viewNS = require('sdk/core/namespace').ns();
|
||||
const { deprecateUsage } = require('sdk/util/deprecate');
|
||||
const { getURL } = require('sdk/url/utils');
|
||||
const viewNS = require('../core/namespace').ns();
|
||||
const { deprecateUsage } = require('../util/deprecate');
|
||||
const { getURL } = require('../url/utils');
|
||||
const { viewFor } = require('../view/core');
|
||||
|
||||
// Array of the inner instances of all the wrapped tabs.
|
||||
const TABS = [];
|
||||
@ -64,6 +65,7 @@ const TabTrait = Trait.compose(EventEmitter, {
|
||||
|
||||
viewNS(this._public).tab = this._tab;
|
||||
getPBOwnerWindow.implement(this._public, getChromeTab);
|
||||
viewFor.implement(this._public, getTabView);
|
||||
|
||||
// Add tabs to getURL method
|
||||
getURL.implement(this._public, (function (obj) this._public.url).bind(this));
|
||||
@ -97,7 +99,7 @@ const TabTrait = Trait.compose(EventEmitter, {
|
||||
if (event.target == this._contentDocument)
|
||||
this._emit(EVENTS.ready.name, this._public);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Internal listener that emits public event 'load' when the page of this
|
||||
* tab is loaded, for triggering on non-HTML content, bug #671305
|
||||
@ -272,6 +274,10 @@ function getChromeTab(tab) {
|
||||
return getOwnerWindow(viewNS(tab).tab);
|
||||
}
|
||||
|
||||
// Implement `viewFor` polymorphic function for the Tab
|
||||
// instances.
|
||||
const getTabView = tab => viewNS(tab).tab;
|
||||
|
||||
function Tab(options, existingOnly) {
|
||||
let chromeTab = options.tab;
|
||||
for each (let tab in TABS) {
|
||||
|
@ -16,13 +16,12 @@ var method = require("method/core");
|
||||
// it returns `null`. You can implement this method for
|
||||
// this type to define what the result should be for it.
|
||||
let getNodeView = method("getNodeView");
|
||||
getNodeView.define(function(value) {
|
||||
if (value instanceof Ci.nsIDOMNode)
|
||||
return value;
|
||||
return null;
|
||||
});
|
||||
|
||||
getNodeView.define(x =>
|
||||
x instanceof Ci.nsIDOMNode ? x :
|
||||
x instanceof Ci.nsIDOMWindow ? x :
|
||||
null);
|
||||
exports.getNodeView = getNodeView;
|
||||
exports.viewFor = getNodeView;
|
||||
|
||||
let getActiveView = method("getActiveView");
|
||||
exports.getActiveView = getActiveView;
|
||||
|
@ -26,6 +26,8 @@ const ERR_CONTENT = "No content or contentURL property found. Widgets must "
|
||||
"position.",
|
||||
ERR_DESTROYED = "The widget has been destroyed and can no longer be used.";
|
||||
|
||||
const INSERTION_PREF_ROOT = "extensions.sdk-widget-inserted.";
|
||||
|
||||
// Supported events, mapping from DOM event names to our event names
|
||||
const EVENTS = {
|
||||
"click": "click",
|
||||
@ -33,6 +35,11 @@ const EVENTS = {
|
||||
"mouseout": "mouseout",
|
||||
};
|
||||
|
||||
// In the Australis menu panel, normally widgets should be treated like
|
||||
// normal toolbarbuttons. If they're any wider than this margin, we'll
|
||||
// treat them as wide widgets instead, which fill up the width of the panel:
|
||||
const AUSTRALIS_PANEL_WIDE_WIDGET_CUTOFF = 70;
|
||||
|
||||
const { validateOptions } = require("./deprecated/api-utils");
|
||||
const panels = require("./panel");
|
||||
const { EventEmitter, EventEmitterTrait } = require("./deprecated/events");
|
||||
@ -45,8 +52,8 @@ const { WindowTracker } = require("./deprecated/window-utils");
|
||||
const { isBrowser } = require("./window/utils");
|
||||
const { setTimeout } = require("./timers");
|
||||
const unload = require("./system/unload");
|
||||
const { uuid } = require("./util/uuid");
|
||||
const { getNodeView } = require("./view/core");
|
||||
const prefs = require('./preferences/service');
|
||||
|
||||
// Data types definition
|
||||
const valid = {
|
||||
@ -215,6 +222,13 @@ let model = {
|
||||
|
||||
};
|
||||
|
||||
function saveInserted(widgetId) {
|
||||
prefs.set(INSERTION_PREF_ROOT + widgetId, true);
|
||||
}
|
||||
|
||||
function haveInserted(widgetId) {
|
||||
return prefs.has(INSERTION_PREF_ROOT + widgetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main Widget class: entry point of the widget API
|
||||
@ -555,6 +569,9 @@ let browserManager = {
|
||||
let idx = this.items.indexOf(item);
|
||||
if (idx > -1)
|
||||
this.items.splice(idx, 1);
|
||||
},
|
||||
propagateCurrentset: function browserManager_propagateCurrentset(id, currentset) {
|
||||
this.windows.forEach(function (w) w.doc.getElementById(id).setAttribute("currentset", currentset));
|
||||
}
|
||||
};
|
||||
|
||||
@ -605,36 +622,14 @@ BrowserWindow.prototype = {
|
||||
if (this.window.CustomizableUI) {
|
||||
let placement = this.window.CustomizableUI.getPlacementOfWidget(node.id);
|
||||
if (!placement) {
|
||||
if (haveInserted(node.id)) {
|
||||
return;
|
||||
}
|
||||
placement = {area: 'nav-bar', position: undefined};
|
||||
saveInserted(node.id);
|
||||
}
|
||||
this.window.CustomizableUI.addWidgetToArea(node.id, placement.area, placement.position);
|
||||
|
||||
// Depending on when this gets called, we might be in the right place now. In that case,
|
||||
// don't run the following code.
|
||||
if (node.parentNode != palette) {
|
||||
return;
|
||||
}
|
||||
// Otherwise, insert:
|
||||
let container = this.doc.getElementById(placement.area);
|
||||
if (container.customizationTarget) {
|
||||
container = container.customizationTarget;
|
||||
}
|
||||
|
||||
if (placement.position !== undefined) {
|
||||
// Find a position:
|
||||
let items = this.window.CustomizableUI.getWidgetIdsInArea(placement.area);
|
||||
let itemIndex = placement.position;
|
||||
for (let l = items.length; itemIndex < l; itemIndex++) {
|
||||
let realItems = container.getElementsByAttribute("id", items[itemIndex]);
|
||||
if (realItems[0]) {
|
||||
container.insertBefore(node, realItems[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node.parentNode != container) {
|
||||
container.appendChild(node);
|
||||
}
|
||||
this.window.CustomizableUI.ensureWidgetPlacedInWindow(node.id, this.window);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -650,10 +645,14 @@ BrowserWindow.prototype = {
|
||||
}
|
||||
|
||||
// if widget isn't in any toolbar, add it to the addon-bar
|
||||
// TODO: we may want some "first-launch" module to do this only on very
|
||||
// first execution
|
||||
let needToPropagateCurrentset = false;
|
||||
if (!container) {
|
||||
if (haveInserted(node.id)) {
|
||||
return;
|
||||
}
|
||||
container = this.doc.getElementById("addon-bar");
|
||||
saveInserted(node.id);
|
||||
needToPropagateCurrentset = true;
|
||||
// TODO: find a way to make the following code work when we use "cfx run":
|
||||
// http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#8586
|
||||
// until then, force display of addon bar directly from sdk code
|
||||
@ -684,9 +683,11 @@ BrowserWindow.prototype = {
|
||||
// Otherwise, this code will collide with other instance of Widget module
|
||||
// during Firefox startup. See bug 685929.
|
||||
if (ids.indexOf(id) == -1) {
|
||||
container.setAttribute("currentset", container.currentSet);
|
||||
let set = container.currentSet;
|
||||
container.setAttribute("currentset", set);
|
||||
// Save DOM attribute in order to save position on new window opened
|
||||
this.window.document.persist(container.id, "currentset");
|
||||
browserManager.propagateCurrentset(container.id, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -736,7 +737,6 @@ WidgetChrome.prototype.update = function WC_update(updatedItem, property, value)
|
||||
WidgetChrome.prototype._createNode = function WC__createNode() {
|
||||
// XUL element container for widget
|
||||
let node = this._doc.createElement("toolbaritem");
|
||||
let guid = String(uuid());
|
||||
|
||||
// Temporary work around require("self") failing on unit-test execution ...
|
||||
let jetpackID = "testID";
|
||||
@ -753,6 +753,14 @@ WidgetChrome.prototype._createNode = function WC__createNode() {
|
||||
// Bug 626326: Prevent customize toolbar context menu to appear
|
||||
node.setAttribute("context", "");
|
||||
|
||||
// For use in styling by the browser
|
||||
node.setAttribute("sdkstylewidget", "true");
|
||||
// Mark wide widgets as such:
|
||||
if (this.window.CustomizableUI &&
|
||||
this._widget.width > AUSTRALIS_PANEL_WIDE_WIDGET_CUTOFF) {
|
||||
node.classList.add("panel-wide-item");
|
||||
}
|
||||
|
||||
// TODO move into a stylesheet, configurable by consumers.
|
||||
// Either widget.style, exposing the style object, or a URL
|
||||
// (eg, can load local stylesheet file).
|
||||
@ -784,6 +792,13 @@ WidgetChrome.prototype.fill = function WC_fill() {
|
||||
// until the node is attached to a document.
|
||||
this.node.appendChild(iframe);
|
||||
|
||||
var label = this._doc.createElement("label");
|
||||
label.setAttribute("value", this._widget.label);
|
||||
label.className = "toolbarbutton-text";
|
||||
label.setAttribute("crop", "right");
|
||||
label.setAttribute("flex", "1");
|
||||
this.node.appendChild(label);
|
||||
|
||||
// add event handlers
|
||||
this.addEventHandlers();
|
||||
|
||||
|
@ -12,6 +12,7 @@ const unload = require('../system/unload');
|
||||
const { isWindowPrivate } = require('../window/utils');
|
||||
const { EventTarget } = require('../event/target');
|
||||
const { getOwnerWindow: getPBOwnerWindow } = require('../private-browsing/window/utils');
|
||||
const { viewFor } = require('../view/core');
|
||||
const { deprecateUsage } = require('../util/deprecate');
|
||||
|
||||
const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec, consider using require("sdk/tabs") instead';
|
||||
@ -48,6 +49,7 @@ const BrowserWindow = Class({
|
||||
});
|
||||
exports.BrowserWindow = BrowserWindow;
|
||||
|
||||
getPBOwnerWindow.define(BrowserWindow, function(window) {
|
||||
return windowNS(window).window;
|
||||
});
|
||||
const getWindowView = window => windowNS(window).window;
|
||||
|
||||
getPBOwnerWindow.define(BrowserWindow, getWindowView);
|
||||
viewFor.define(BrowserWindow, getWindowView);
|
||||
|
@ -22,6 +22,7 @@ const { Cc, Ci, Cr } = require('chrome'),
|
||||
const { windowNS } = require('../window/namespace');
|
||||
const { isPrivateBrowsingSupported } = require('../self');
|
||||
const { ignoreWindow } = require('sdk/private-browsing/utils');
|
||||
const { viewFor } = require('../view/core');
|
||||
|
||||
/**
|
||||
* Window trait composes safe wrappers for browser window that are E10S
|
||||
@ -76,6 +77,7 @@ const BrowserWindowTrait = Trait.compose(
|
||||
|
||||
windowNS(this._public).window = this._window;
|
||||
getOwnerWindow.implement(this._public, getChromeWindow);
|
||||
viewFor.implement(this._public, getChromeWindow);
|
||||
|
||||
return this;
|
||||
},
|
||||
@ -84,6 +86,7 @@ const BrowserWindowTrait = Trait.compose(
|
||||
_onLoad: function() {
|
||||
try {
|
||||
this._initWindowTabTracker();
|
||||
this._loaded = true;
|
||||
}
|
||||
catch(e) {
|
||||
this._emit('error', e);
|
||||
@ -94,9 +97,12 @@ const BrowserWindowTrait = Trait.compose(
|
||||
_onUnload: function() {
|
||||
if (!this._window)
|
||||
return;
|
||||
this._destroyWindowTabTracker();
|
||||
if (this._loaded)
|
||||
this._destroyWindowTabTracker();
|
||||
|
||||
this._emitOnObject(browserWindows, 'close', this._public);
|
||||
this._window = null;
|
||||
windowNS(this._public).window = null;
|
||||
// Removing reference from the windows array.
|
||||
windows.splice(windows.indexOf(this), 1);
|
||||
this._removeAllListeners();
|
||||
|
@ -76,9 +76,6 @@ function Worker(options) {
|
||||
["pageshow", "pagehide", "detach", "message", "error"].forEach(function(key) {
|
||||
trait.on(key, function() {
|
||||
emit.apply(emit, [worker, key].concat(Array.slice(arguments)));
|
||||
// Workaround lack of ability to listen on all events by emulating
|
||||
// such ability. This will become obsolete once Bug 821065 is fixed.
|
||||
emit.apply(emit, [worker, "*", key].concat(Array.slice(arguments)));
|
||||
});
|
||||
});
|
||||
traits.set(worker, trait);
|
||||
|
5
addon-sdk/source/test/fixtures/test-contentScriptFile.js
vendored
Normal file
5
addon-sdk/source/test/fixtures/test-contentScriptFile.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/* 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/. */
|
||||
|
||||
self.postMessage("msg from contentScriptFile");
|
@ -44,16 +44,9 @@ exports["test multiple tabs"] = function(assert, done) {
|
||||
|
||||
on(events, "data", handler);
|
||||
function handler ({type, target, timeStamp}) {
|
||||
// ignore about:blank pages and *-document-global-created
|
||||
// events that are not very consistent.
|
||||
// ignore http:// requests, as Fennec's `about:home` page
|
||||
// displays add-ons a user could install
|
||||
if (target.URL !== "about:blank" &&
|
||||
target.URL !== "about:home" &&
|
||||
!target.URL.match(/^https?:\/\//i) &&
|
||||
type !== "chrome-document-global-created" &&
|
||||
type !== "content-document-global-created")
|
||||
eventFilter(type, target, () => {
|
||||
actual.push(type + " -> " + target.URL)
|
||||
});
|
||||
}
|
||||
|
||||
let window = getMostRecentBrowserWindow();
|
||||
@ -92,12 +85,9 @@ exports["test nested frames"] = function(assert, done) {
|
||||
let actual = [];
|
||||
on(events, "data", handler);
|
||||
function handler ({type, target, timeStamp}) {
|
||||
// ignore about:blank pages and *-global-created
|
||||
// events that are not very consistent.
|
||||
if (target.URL !== "about:blank" &&
|
||||
type !== "chrome-document-global-created" &&
|
||||
type !== "content-document-global-created")
|
||||
eventFilter(type, target, () => {
|
||||
actual.push(type + " -> " + target.URL)
|
||||
});
|
||||
}
|
||||
|
||||
let window = getMostRecentBrowserWindow();
|
||||
@ -126,4 +116,20 @@ exports["test nested frames"] = function(assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
// ignore about:blank pages and *-document-global-created
|
||||
// events that are not very consistent.
|
||||
// ignore http:// requests, as Fennec's `about:home` page
|
||||
// displays add-ons a user could install
|
||||
// ignore local `searchplugins` files loaded
|
||||
// Calls callback if passes filter
|
||||
function eventFilter (type, target, callback) {
|
||||
if (target.URL !== "about:blank" &&
|
||||
target.URL !== "about:home" &&
|
||||
!target.URL.match(/^https?:\/\//i) &&
|
||||
!target.URL.match(/searchplugins/) &&
|
||||
type !== "chrome-document-global-created" &&
|
||||
type !== "content-document-global-created")
|
||||
|
||||
callback();
|
||||
}
|
||||
require("test").run(exports);
|
||||
|
@ -6,6 +6,7 @@
|
||||
const { Loader } = require('sdk/content/loader');
|
||||
const self = require("sdk/self");
|
||||
const fixtures = require("./fixtures");
|
||||
const { URL } = require('sdk/url');
|
||||
|
||||
exports['test:contentURL'] = function(assert) {
|
||||
let loader = Loader(),
|
||||
@ -204,6 +205,28 @@ exports['test:contentScriptFile'] = function(assert) {
|
||||
);
|
||||
}
|
||||
|
||||
let data = 'data:text/html,test';
|
||||
try {
|
||||
loader.contentScriptFile = [ { toString: () => data } ];
|
||||
test.fail('must throw when non-URL object is set');
|
||||
} catch(e) {
|
||||
assert.equal(
|
||||
'The `contentScriptFile` option must be a local URL or an array of URLs.',
|
||||
e.message
|
||||
);
|
||||
}
|
||||
|
||||
loader.contentScriptFile = new URL(data);
|
||||
assert.ok(
|
||||
loader.contentScriptFile instanceof URL,
|
||||
'must be able to set `contentScriptFile` to an instance of URL'
|
||||
);
|
||||
assert.equal(
|
||||
data,
|
||||
loader.contentScriptFile.toString(),
|
||||
'setting `contentScriptFile` to an instance of URL should preserve the url'
|
||||
);
|
||||
|
||||
loader.contentScriptFile = undefined;
|
||||
assert.equal(
|
||||
null,
|
||||
|
@ -17,6 +17,10 @@ const { LoaderWithHookedConsole } = require("sdk/test/loader");
|
||||
const { Worker } = require("sdk/content/worker");
|
||||
const { close } = require("sdk/window/helpers");
|
||||
const { set: setPref } = require("sdk/preferences/service");
|
||||
const { isArray } = require("sdk/lang/type");
|
||||
const { URL } = require('sdk/url');
|
||||
const fixtures = require("./fixtures");
|
||||
|
||||
const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
|
||||
|
||||
const DEFAULT_CONTENT_URL = "data:text/html;charset=utf-8,foo";
|
||||
@ -396,8 +400,116 @@ exports["test:ensure console.xxx works in cs"] = WorkerTest(
|
||||
}
|
||||
);
|
||||
|
||||
exports["test:setTimeout works with string argument"] = WorkerTest(
|
||||
"data:text/html;charset=utf-8,<script>var docVal=5;</script>",
|
||||
function(assert, browser, done) {
|
||||
let worker = Worker({
|
||||
window: browser.contentWindow,
|
||||
contentScript: "new " + function ContentScriptScope() {
|
||||
// must use "window.scVal" instead of "var csVal"
|
||||
// since we are inside ContentScriptScope function.
|
||||
// i'm NOT putting code-in-string inside code-in-string </YO DAWG>
|
||||
window.csVal = 13;
|
||||
setTimeout("self.postMessage([" +
|
||||
"csVal, " +
|
||||
"window.docVal, " +
|
||||
"'ContentWorker' in window, " +
|
||||
"'UNWRAP_ACCESS_KEY' in window, " +
|
||||
"'getProxyForObject' in window, " +
|
||||
"])", 1);
|
||||
},
|
||||
contentScriptWhen: "ready",
|
||||
onMessage: function([csVal, docVal, chrome1, chrome2, chrome3]) {
|
||||
// test timer code is executed in the correct context
|
||||
assert.equal(csVal, 13, "accessing content-script values");
|
||||
assert.notEqual(docVal, 5, "can't access document values (directly)");
|
||||
assert.ok(!chrome1 && !chrome2 && !chrome3, "nothing is leaked from chrome");
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
exports["test:setTimeout can\"t be cancelled by content"] = WorkerTest(
|
||||
exports["test:setInterval works with string argument"] = WorkerTest(
|
||||
DEFAULT_CONTENT_URL,
|
||||
function(assert, browser, done) {
|
||||
let count = 0;
|
||||
let worker = Worker({
|
||||
window: browser.contentWindow,
|
||||
contentScript: "setInterval('self.postMessage(1)', 50)",
|
||||
contentScriptWhen: "ready",
|
||||
onMessage: function(one) {
|
||||
count++;
|
||||
assert.equal(one, 1, "got " + count + " message(s) from setInterval");
|
||||
if (count >= 3) done();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
exports["test:setInterval async Errors passed to .onError"] = WorkerTest(
|
||||
DEFAULT_CONTENT_URL,
|
||||
function(assert, browser, done) {
|
||||
let count = 0;
|
||||
let worker = Worker({
|
||||
window: browser.contentWindow,
|
||||
contentScript: "setInterval(() => { throw Error('ubik') }, 50)",
|
||||
contentScriptWhen: "ready",
|
||||
onError: function(err) {
|
||||
count++;
|
||||
assert.equal(err.message, "ubik",
|
||||
"error (corectly) propagated " + count + " time(s)");
|
||||
if (count >= 3) done();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
exports["test:setTimeout throws array, passed to .onError"] = WorkerTest(
|
||||
DEFAULT_CONTENT_URL,
|
||||
function(assert, browser, done) {
|
||||
let worker = Worker({
|
||||
window: browser.contentWindow,
|
||||
contentScript: "setTimeout(function() { throw ['array', 42] }, 1)",
|
||||
contentScriptWhen: "ready",
|
||||
onError: function(arr) {
|
||||
assert.ok(isArray(arr),
|
||||
"the type of thrown/propagated object is array");
|
||||
assert.ok(arr.length==2,
|
||||
"the propagated thrown array is the right length");
|
||||
assert.equal(arr[1], 42,
|
||||
"element inside the thrown array correctly propagated");
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
exports["test:setTimeout string arg with SyntaxError to .onError"] = WorkerTest(
|
||||
DEFAULT_CONTENT_URL,
|
||||
function(assert, browser, done) {
|
||||
let worker = Worker({
|
||||
window: browser.contentWindow,
|
||||
contentScript: "setTimeout('syntax 123 error', 1)",
|
||||
contentScriptWhen: "ready",
|
||||
onError: function(err) {
|
||||
assert.equal(err.name, "SyntaxError",
|
||||
"received SyntaxError thrown from bad code in string argument to setTimeout");
|
||||
assert.ok('fileName' in err,
|
||||
"propagated SyntaxError contains a fileName property");
|
||||
assert.ok('stack' in err,
|
||||
"propagated SyntaxError contains a stack property");
|
||||
assert.equal(err.message, "missing ; before statement",
|
||||
"propagated SyntaxError has the correct (helpful) message");
|
||||
assert.equal(err.lineNumber, 1,
|
||||
"propagated SyntaxError was thrown on the right lineNumber");
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
exports["test:setTimeout can't be cancelled by content"] = WorkerTest(
|
||||
"data:text/html;charset=utf-8,<script>var documentValue=true;</script>",
|
||||
function(assert, browser, done) {
|
||||
|
||||
@ -700,4 +812,21 @@ exports["test:global postMessage"] = WorkerTest(
|
||||
}
|
||||
);
|
||||
|
||||
exports['test:conentScriptFile as URL instance'] = WorkerTest(
|
||||
DEFAULT_CONTENT_URL,
|
||||
function(assert, browser, done) {
|
||||
|
||||
let url = new URL(fixtures.url("test-contentScriptFile.js"));
|
||||
let worker = Worker({
|
||||
window: browser.contentWindow,
|
||||
contentScriptFile: url,
|
||||
onMessage: function(msg) {
|
||||
assert.equal(msg, "msg from contentScriptFile",
|
||||
"received a wrong message from contentScriptFile");
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
require("test").run(exports);
|
||||
|
@ -222,23 +222,24 @@ exports['test count'] = function(assert) {
|
||||
assert.equal(count(target, 'foo'), 0, 'listeners unregistered');
|
||||
};
|
||||
|
||||
exports['test emit.lazy'] = function(assert) {
|
||||
let target = {}, boom = Error('boom!'), errors = [], actual = []
|
||||
exports['test listen to all events'] = function(assert) {
|
||||
let actual = [];
|
||||
let target = {};
|
||||
|
||||
on(target, 'error', function error(e) errors.push(e))
|
||||
on(target, 'foo', message => actual.push(message));
|
||||
on(target, '*', (type, ...message) => {
|
||||
actual.push([type].concat(message));
|
||||
});
|
||||
|
||||
emit(target, 'foo', 'hello');
|
||||
assert.equal(actual[0], 'hello',
|
||||
'non-wildcard listeners still work');
|
||||
assert.deepEqual(actual[1], ['foo', 'hello'],
|
||||
'wildcard listener called');
|
||||
|
||||
on(target, 'a', function() 1);
|
||||
on(target, 'a', function() {});
|
||||
on(target, 'a', function() 2);
|
||||
on(target, 'a', function() { throw boom });
|
||||
on(target, 'a', function() 3);
|
||||
|
||||
for each (let value in emit.lazy(target, 'a'))
|
||||
actual.push(value);
|
||||
|
||||
assert.deepEqual(actual, [ 1, undefined, 2, 3 ],
|
||||
'all results were collected');
|
||||
assert.deepEqual(errors, [ boom ], 'errors reporetd');
|
||||
emit(target, 'bar', 'goodbye');
|
||||
assert.deepEqual(actual[2], ['bar', 'goodbye'],
|
||||
'wildcard listener called for unbound event name');
|
||||
};
|
||||
|
||||
require('test').run(exports);
|
||||
|
@ -5,7 +5,7 @@
|
||||
'use strict';
|
||||
|
||||
const { on, emit } = require("sdk/event/core");
|
||||
const { filter, map, merge, expand } = require("sdk/event/utils");
|
||||
const { filter, map, merge, expand, pipe } = require("sdk/event/utils");
|
||||
const $ = require("./event/helpers");
|
||||
|
||||
function isEven(x) !(x % 2)
|
||||
@ -163,7 +163,96 @@ exports["test expand"] = function(assert) {
|
||||
|
||||
assert.deepEqual(actual, ["a1", "b1", "a2", "c1", "c2", "b2", "a3"],
|
||||
"all inputs data merged into one");
|
||||
}
|
||||
};
|
||||
|
||||
exports["test pipe"] = function (assert, done) {
|
||||
let src = {};
|
||||
let dest = {};
|
||||
|
||||
let aneventCount = 0, multiargsCount = 0;
|
||||
let wildcardCount = {};
|
||||
|
||||
on(dest, 'an-event', arg => {
|
||||
assert.equal(arg, 'my-arg', 'piped argument to event');
|
||||
++aneventCount;
|
||||
check();
|
||||
});
|
||||
on(dest, 'multiargs', (...data) => {
|
||||
assert.equal(data[0], 'a', 'multiple arguments passed via pipe');
|
||||
assert.equal(data[1], 'b', 'multiple arguments passed via pipe');
|
||||
assert.equal(data[2], 'c', 'multiple arguments passed via pipe');
|
||||
++multiargsCount;
|
||||
check();
|
||||
});
|
||||
|
||||
on(dest, '*', (name, ...data) => {
|
||||
wildcardCount[name] = (wildcardCount[name] || 0) + 1;
|
||||
if (name === 'multiargs') {
|
||||
assert.equal(data[0], 'a', 'multiple arguments passed via pipe, wildcard');
|
||||
assert.equal(data[1], 'b', 'multiple arguments passed via pipe, wildcard');
|
||||
assert.equal(data[2], 'c', 'multiple arguments passed via pipe, wildcard');
|
||||
}
|
||||
if (name === 'an-event')
|
||||
assert.equal(data[0], 'my-arg', 'argument passed via pipe, wildcard');
|
||||
check();
|
||||
});
|
||||
|
||||
pipe(src, dest);
|
||||
|
||||
for (let i = 0; i < 3; i++)
|
||||
emit(src, 'an-event', 'my-arg');
|
||||
|
||||
emit(src, 'multiargs', 'a', 'b', 'c');
|
||||
|
||||
function check () {
|
||||
if (aneventCount === 3 && multiargsCount === 1 &&
|
||||
wildcardCount['an-event'] === 3 &&
|
||||
wildcardCount['multiargs'] === 1)
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
exports["test pipe multiple targets"] = function (assert) {
|
||||
let src1 = {};
|
||||
let src2 = {};
|
||||
let middle = {};
|
||||
let dest = {};
|
||||
|
||||
pipe(src1, middle);
|
||||
pipe(src2, middle);
|
||||
pipe(middle, dest);
|
||||
|
||||
let middleFired = 0;
|
||||
let destFired = 0;
|
||||
let src1Fired = 0;
|
||||
let src2Fired = 0;
|
||||
|
||||
on(src1, '*', () => src1Fired++);
|
||||
on(src2, '*', () => src2Fired++);
|
||||
on(middle, '*', () => middleFired++);
|
||||
on(dest, '*', () => destFired++);
|
||||
|
||||
emit(src1, 'ev');
|
||||
assert.equal(src1Fired, 1, 'event triggers in source in pipe chain');
|
||||
assert.equal(middleFired, 1, 'event passes through the middle of pipe chain');
|
||||
assert.equal(destFired, 1, 'event propagates to end of pipe chain');
|
||||
assert.equal(src2Fired, 0, 'event does not fire on alternative chain routes');
|
||||
|
||||
emit(src2, 'ev');
|
||||
assert.equal(src2Fired, 1, 'event triggers in source in pipe chain');
|
||||
assert.equal(middleFired, 2,
|
||||
'event passes through the middle of pipe chain from different src');
|
||||
assert.equal(destFired, 2,
|
||||
'event propagates to end of pipe chain from different src');
|
||||
assert.equal(src1Fired, 1, 'event does not fire on alternative chain routes');
|
||||
|
||||
emit(middle, 'ev');
|
||||
assert.equal(middleFired, 3,
|
||||
'event triggers in source of pipe chain');
|
||||
assert.equal(destFired, 3,
|
||||
'event propagates to end of pipe chain from middle src');
|
||||
assert.equal(src1Fired, 1, 'event does not fire on alternative chain routes');
|
||||
assert.equal(src2Fired, 1, 'event does not fire on alternative chain routes');
|
||||
};
|
||||
|
||||
require('test').run(exports);
|
||||
|
@ -24,6 +24,53 @@ exports.testOnClick = function (assert) {
|
||||
loader.unload();
|
||||
};
|
||||
|
||||
exports['test:numbers and URLs in options'] = function(assert) {
|
||||
let [loader] = makeLoader(module);
|
||||
let notifs = loader.require('sdk/notifications');
|
||||
let opts = {
|
||||
title: 123,
|
||||
text: 45678,
|
||||
// must use in-loader `sdk/url` module for the validation type check to work
|
||||
iconURL: loader.require('sdk/url').URL('data:image/png,blah')
|
||||
};
|
||||
try {
|
||||
notifs.notify(opts);
|
||||
assert.pass('using numbers and URLs in options works');
|
||||
} catch (e) {
|
||||
assert.fail('using numbers and URLs in options must not throw');
|
||||
}
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
exports['test:new tag, dir and lang options'] = function(assert) {
|
||||
let [loader] = makeLoader(module);
|
||||
let notifs = loader.require('sdk/notifications');
|
||||
let opts = {
|
||||
title: 'best',
|
||||
tag: 'tagging',
|
||||
lang: 'en'
|
||||
};
|
||||
|
||||
try {
|
||||
opts.dir = 'ttb';
|
||||
notifs.notify(opts);
|
||||
assert.fail('`dir` option must not accept TopToBottom direction.');
|
||||
} catch (e) {
|
||||
assert.equal(e.message,
|
||||
'`dir` option must be one of: "auto", "ltr" or "rtl".');
|
||||
}
|
||||
|
||||
try {
|
||||
opts.dir = 'rtl';
|
||||
notifs.notify(opts);
|
||||
assert.pass('`dir` option accepts "rtl" direction.');
|
||||
} catch (e) {
|
||||
assert.fail('`dir` option must accept "rtl" direction.');
|
||||
}
|
||||
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
// Returns [loader, mockAlertService].
|
||||
function makeLoader(module) {
|
||||
let loader = Loader(module);
|
||||
|
@ -430,6 +430,50 @@ exports.testWorksWithExistingTabs = function(assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
exports.testExistingFrameDoesntMatchInclude = function(assert, done) {
|
||||
let iframeURL = 'data:text/html;charset=utf-8,UNIQUE-TEST-STRING-42';
|
||||
let iframe = '<iframe src="' + iframeURL + '" />';
|
||||
let url = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframe);
|
||||
tabs.open({
|
||||
url: url,
|
||||
onReady: function onReady(tab) {
|
||||
let pagemod = new PageMod({
|
||||
include: url,
|
||||
attachTo: ['existing', 'frame'],
|
||||
onAttach: function() {
|
||||
assert.fail("Existing iframe URL doesn't match include, must not attach to anything");
|
||||
}
|
||||
});
|
||||
timer.setTimeout(function() {
|
||||
assert.pass("PageMod didn't attach to anything")
|
||||
pagemod.destroy();
|
||||
tab.close(done);
|
||||
}, 250);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.testExistingOnlyFrameMatchesInclude = function(assert, done) {
|
||||
let iframeURL = 'data:text/html;charset=utf-8,UNIQUE-TEST-STRING-43';
|
||||
let iframe = '<iframe src="' + iframeURL + '" />';
|
||||
let url = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframe);
|
||||
tabs.open({
|
||||
url: url,
|
||||
onReady: function onReady(tab) {
|
||||
let pagemod = new PageMod({
|
||||
include: iframeURL,
|
||||
attachTo: ['existing', 'frame'],
|
||||
onAttach: function(worker) {
|
||||
assert.equal(iframeURL, worker.url,
|
||||
"PageMod attached to existing iframe when only it matches include rules");
|
||||
pagemod.destroy();
|
||||
tab.close(done);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.testTabWorkerOnMessage = function(assert, done) {
|
||||
let { browserWindows } = require("sdk/windows");
|
||||
let tabs = require("sdk/tabs");
|
||||
|
@ -245,15 +245,14 @@ exports.testMultipleOnMessageCallbacks = function(assert, done) {
|
||||
let page = Page({
|
||||
contentScript: "self.postMessage('')",
|
||||
contentScriptWhen: "end",
|
||||
onMessage: function() count += 1
|
||||
onMessage: () => count += 1
|
||||
});
|
||||
page.on('message', function() count += 2);
|
||||
page.on('message', function() count *= 3);
|
||||
page.on('message', function()
|
||||
page.on('message', () => count += 2);
|
||||
page.on('message', () => count *= 3);
|
||||
page.on('message', () =>
|
||||
assert.equal(count, 9, "All callbacks were called, in order."));
|
||||
page.on('message', function() done());
|
||||
|
||||
}
|
||||
page.on('message', done);
|
||||
};
|
||||
|
||||
exports.testLoadContentPage = function(assert, done) {
|
||||
let page = Page({
|
||||
|
@ -210,6 +210,27 @@ exports.testInvalidJSON = function (assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
exports.testDelete = function (assert, done) {
|
||||
let srv = startServerAsync(port, basePath);
|
||||
|
||||
srv.registerPathHandler("/test-delete",
|
||||
function handle(request, response) {
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
});
|
||||
|
||||
Request({
|
||||
url: "http://localhost:" + port + "/test-delete",
|
||||
onComplete: function (response) {
|
||||
// We cannot access the METHOD of the request to verify it's set
|
||||
// correctly.
|
||||
assert.equal(response.text, "");
|
||||
assert.equal(response.statusText, "OK");
|
||||
assert.equal(response.headers["Content-Type"], "text/plain");
|
||||
srv.stop(done);
|
||||
}
|
||||
}).delete();
|
||||
};
|
||||
|
||||
exports.testHead = function (assert, done) {
|
||||
let srv = startServerAsync(port, basePath);
|
||||
|
||||
|
@ -41,7 +41,7 @@ exports.testSetGetBool = function(assert) {
|
||||
};
|
||||
|
||||
// TEST: setting and getting preferences with special characters work
|
||||
exports.testSpecialChars = function(assert) {
|
||||
exports.testSpecialChars = function(assert, done) {
|
||||
let chars = specialChars.split("");
|
||||
let len = chars.length;
|
||||
|
||||
@ -54,7 +54,7 @@ exports.testSpecialChars = function(assert) {
|
||||
|
||||
// end test
|
||||
if (++count == len)
|
||||
test.done();
|
||||
done();
|
||||
})
|
||||
sp[char] = rand;
|
||||
});
|
||||
|
@ -7,6 +7,8 @@ const tabs = require("sdk/tabs"); // From addon-kit
|
||||
const windowUtils = require("sdk/deprecated/window-utils");
|
||||
const { getTabForWindow } = require('sdk/tabs/helpers');
|
||||
const app = require("sdk/system/xul-app");
|
||||
const { viewFor } = require("sdk/view/core");
|
||||
const { getTabId } = require("sdk/tabs/utils");
|
||||
|
||||
// The primary test tab
|
||||
var primaryTab;
|
||||
@ -136,4 +138,17 @@ exports["test behavior on close"] = function(assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
exports["test viewFor(tab)"] = (assert, done) => {
|
||||
tabs.once("open", tab => {
|
||||
const view = viewFor(tab);
|
||||
assert.ok(view, "view is returned");
|
||||
assert.equal(getTabId(view), tab.id, "tab has a same id");
|
||||
|
||||
tab.close();
|
||||
done();
|
||||
});
|
||||
|
||||
tabs.open({ url: "about:mozilla" });
|
||||
}
|
||||
|
||||
require("test").run(exports);
|
||||
|
@ -18,6 +18,7 @@ const self = require("sdk/self");
|
||||
const windowUtils = require("sdk/deprecated/window-utils");
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { close } = require("sdk/window/helpers");
|
||||
const unload = require("sdk/system/unload");
|
||||
const fixtures = require("./fixtures");
|
||||
|
||||
let jetpackID = "testID";
|
||||
@ -51,7 +52,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// Test basic construct/destroy
|
||||
AddonsMgrListener.onInstalling();
|
||||
let w = widgets.Widget({ id: "fooID", label: "foo", content: "bar" });
|
||||
let w = widgets.Widget({ id: "basic-construct-destroy", label: "foo", content: "bar" });
|
||||
AddonsMgrListener.onInstalled();
|
||||
assert.equal(widgetCount(), widgetStartCount + 1, "panel has correct number of child elements after widget construction");
|
||||
|
||||
@ -69,7 +70,7 @@ exports.testConstructor = function(assert, done) {
|
||||
let loader = Loader(module);
|
||||
let widgetsFromLoader = loader.require("sdk/widget");
|
||||
let widgetStartCount = widgetCount();
|
||||
let w = widgetsFromLoader.Widget({ id: "fooID", label: "foo", content: "bar" });
|
||||
let w = widgetsFromLoader.Widget({ id: "destroy-on-unload", label: "foo", content: "bar" });
|
||||
assert.equal(widgetCount(), widgetStartCount + 1, "widget has been correctly added");
|
||||
loader.unload();
|
||||
assert.equal(widgetCount(), widgetStartCount, "widget has been destroyed on module unload");
|
||||
@ -94,25 +95,25 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// Test no content or image
|
||||
assert.throws(
|
||||
function() widgets.Widget({id: "fooID", label: "foo"}),
|
||||
function() widgets.Widget({id: "no-content-throws", label: "foo"}),
|
||||
/^No content or contentURL property found\. Widgets must have one or the other\.$/,
|
||||
"throws on no content");
|
||||
|
||||
// Test empty content, no image
|
||||
assert.throws(
|
||||
function() widgets.Widget({id:"fooID", label: "foo", content: ""}),
|
||||
function() widgets.Widget({id:"empty-content-throws", label: "foo", content: ""}),
|
||||
/^No content or contentURL property found\. Widgets must have one or the other\.$/,
|
||||
"throws on empty content");
|
||||
|
||||
// Test empty image, no content
|
||||
assert.throws(
|
||||
function() widgets.Widget({id:"fooID", label: "foo", image: ""}),
|
||||
function() widgets.Widget({id:"empty-image-throws", label: "foo", image: ""}),
|
||||
/^No content or contentURL property found\. Widgets must have one or the other\.$/,
|
||||
"throws on empty content");
|
||||
|
||||
// Test empty content, empty image
|
||||
assert.throws(
|
||||
function() widgets.Widget({id:"fooID", label: "foo", content: "", image: ""}),
|
||||
function() widgets.Widget({id:"empty-image-and-content-throws", label: "foo", content: "", image: ""}),
|
||||
/^No content or contentURL property found. Widgets must have one or the other\.$/,
|
||||
"throws on empty content");
|
||||
|
||||
@ -138,14 +139,14 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// Test position restore on create/destroy/create
|
||||
// Create 3 ordered widgets
|
||||
let w1 = widgets.Widget({id: "first", label:"first", content: "bar"});
|
||||
let w2 = widgets.Widget({id: "second", label:"second", content: "bar"});
|
||||
let w3 = widgets.Widget({id: "third", label:"third", content: "bar"});
|
||||
let w1 = widgets.Widget({id: "position-first", label:"first", content: "bar"});
|
||||
let w2 = widgets.Widget({id: "position-second", label:"second", content: "bar"});
|
||||
let w3 = widgets.Widget({id: "position-third", label:"third", content: "bar"});
|
||||
// Remove the middle widget
|
||||
assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is the second widget inserted");
|
||||
w2.destroy();
|
||||
assert.equal(widgetNode(1).getAttribute("label"), "third", "second widget is removed, so second widget is now the third one");
|
||||
w2 = widgets.Widget({id: "second", label:"second", content: "bar"});
|
||||
w2 = widgets.Widget({id: "position-second", label:"second", content: "bar"});
|
||||
assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is created again, at the same location");
|
||||
// Cleanup this testcase
|
||||
AddonsMgrListener.onUninstalling();
|
||||
@ -160,14 +161,14 @@ exports.testConstructor = function(assert, done) {
|
||||
let anotherWidgetsInstance = loader.require("sdk/widget");
|
||||
assert.ok(container().collapsed, "UI is hidden when no widgets");
|
||||
AddonsMgrListener.onInstalling();
|
||||
let w1 = widgets.Widget({id: "foo", label: "foo", content: "bar"});
|
||||
let w1 = widgets.Widget({id: "ui-unhide", label: "foo", content: "bar"});
|
||||
// Ideally we would let AddonsMgrListener display the addon bar
|
||||
// But, for now, addon bar is immediatly displayed by sdk code
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=627484
|
||||
assert.ok(!container().collapsed, "UI is already visible when we just added the widget");
|
||||
AddonsMgrListener.onInstalled();
|
||||
assert.ok(!container().collapsed, "UI become visible when we notify AddonsMgrListener about end of addon installation");
|
||||
let w2 = anotherWidgetsInstance.Widget({id: "bar", label: "bar", content: "foo"});
|
||||
let w2 = anotherWidgetsInstance.Widget({id: "ui-stay-open", label: "bar", content: "foo"});
|
||||
assert.ok(!container().collapsed, "UI still visible when we add a second widget");
|
||||
AddonsMgrListener.onUninstalling();
|
||||
w1.destroy();
|
||||
@ -214,7 +215,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// text widget
|
||||
tests.push(function testTextWidget() testSingleWidget({
|
||||
id: "text",
|
||||
id: "text-single",
|
||||
label: "text widget",
|
||||
content: "oh yeah",
|
||||
contentScript: "self.postMessage(document.body.innerHTML);",
|
||||
@ -278,7 +279,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// event: onclick + content
|
||||
tests.push(function testOnclickEventContent() testSingleWidget({
|
||||
id: "click",
|
||||
id: "click-content",
|
||||
label: "click test widget - content",
|
||||
content: "<div id='me'>foo</div>",
|
||||
contentScript: "var evt = new MouseEvent('click', {button: 0});" +
|
||||
@ -293,7 +294,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// event: onmouseover + content
|
||||
tests.push(function testOnmouseoverEventContent() testSingleWidget({
|
||||
id: "mouseover",
|
||||
id: "mouseover-content",
|
||||
label: "mouseover test widget - content",
|
||||
content: "<div id='me'>foo</div>",
|
||||
contentScript: "var evt = new MouseEvent('mouseover'); " +
|
||||
@ -308,7 +309,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// event: onmouseout + content
|
||||
tests.push(function testOnmouseoutEventContent() testSingleWidget({
|
||||
id: "mouseout",
|
||||
id: "mouseout-content",
|
||||
label: "mouseout test widget - content",
|
||||
content: "<div id='me'>foo</div>",
|
||||
contentScript: "var evt = new MouseEvent('mouseout');" +
|
||||
@ -323,7 +324,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// event: onclick + image
|
||||
tests.push(function testOnclickEventImage() testSingleWidget({
|
||||
id: "click",
|
||||
id: "click-image",
|
||||
label: "click test widget - image",
|
||||
contentURL: fixtures.url("moz_favicon.ico"),
|
||||
contentScript: "var evt = new MouseEvent('click'); " +
|
||||
@ -338,7 +339,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// event: onmouseover + image
|
||||
tests.push(function testOnmouseoverEventImage() testSingleWidget({
|
||||
id: "mouseover",
|
||||
id: "mouseover-image",
|
||||
label: "mouseover test widget - image",
|
||||
contentURL: fixtures.url("moz_favicon.ico"),
|
||||
contentScript: "var evt = new MouseEvent('mouseover');" +
|
||||
@ -353,7 +354,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// event: onmouseout + image
|
||||
tests.push(function testOnmouseoutEventImage() testSingleWidget({
|
||||
id: "mouseout",
|
||||
id: "mouseout-image",
|
||||
label: "mouseout test widget - image",
|
||||
contentURL: fixtures.url("moz_favicon.ico"),
|
||||
contentScript: "var evt = new MouseEvent('mouseout'); " +
|
||||
@ -380,7 +381,7 @@ exports.testConstructor = function(assert, done) {
|
||||
// test updating widget content
|
||||
let loads = 0;
|
||||
tests.push(function testUpdatingWidgetContent() testSingleWidget({
|
||||
id: "content",
|
||||
id: "content-updating",
|
||||
label: "content update test widget",
|
||||
content: "<div id='me'>foo</div>",
|
||||
contentScript: "self.postMessage(1)",
|
||||
@ -403,7 +404,7 @@ exports.testConstructor = function(assert, done) {
|
||||
let url2 = "data:text/html;charset=utf-8,<body>nistel</body>";
|
||||
|
||||
tests.push(function testUpdatingContentURL() testSingleWidget({
|
||||
id: "content",
|
||||
id: "content-url-updating",
|
||||
label: "content update test widget",
|
||||
contentURL: url1,
|
||||
contentScript: "self.postMessage(document.location.href);",
|
||||
@ -426,7 +427,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// test tooltip
|
||||
tests.push(function testTooltip() testSingleWidget({
|
||||
id: "text",
|
||||
id: "text-with-tooltip",
|
||||
label: "text widget",
|
||||
content: "oh yeah",
|
||||
tooltip: "foo",
|
||||
@ -456,7 +457,7 @@ exports.testConstructor = function(assert, done) {
|
||||
// test updating widget tooltip
|
||||
let updated = false;
|
||||
tests.push(function testUpdatingTooltip() testSingleWidget({
|
||||
id: "tooltip",
|
||||
id: "tooltip-updating",
|
||||
label: "tooltip update test widget",
|
||||
tooltip: "foo",
|
||||
content: "<div id='me'>foo</div>",
|
||||
@ -472,7 +473,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// test allow attribute
|
||||
tests.push(function testDefaultAllow() testSingleWidget({
|
||||
id: "allow",
|
||||
id: "allow-default",
|
||||
label: "allow.script attribute",
|
||||
content: "<script>document.title = 'ok';</script>",
|
||||
contentScript: "self.postMessage(document.title)",
|
||||
@ -484,7 +485,7 @@ exports.testConstructor = function(assert, done) {
|
||||
}));
|
||||
|
||||
tests.push(function testExplicitAllow() testSingleWidget({
|
||||
id: "allow",
|
||||
id: "allow-explicit",
|
||||
label: "allow.script attribute",
|
||||
allow: {script: true},
|
||||
content: "<script>document.title = 'ok';</script>",
|
||||
@ -497,7 +498,7 @@ exports.testConstructor = function(assert, done) {
|
||||
}));
|
||||
|
||||
tests.push(function testExplicitDisallow() testSingleWidget({
|
||||
id: "allow",
|
||||
id: "allow-explicit-disallow",
|
||||
label: "allow.script attribute",
|
||||
content: "<script>document.title = 'ok';</script>",
|
||||
allow: {script: false},
|
||||
@ -521,11 +522,11 @@ exports.testConstructor = function(assert, done) {
|
||||
function widgetCount2() container() ? container().querySelectorAll('[id^="widget\:"]').length : 0;
|
||||
let widgetStartCount2 = widgetCount2();
|
||||
|
||||
let w1Opts = {id:"first", label: "first widget", content: "first content"};
|
||||
let w1Opts = {id:"first-multi-window", label: "first widget", content: "first content"};
|
||||
let w1 = testSingleWidget(w1Opts);
|
||||
assert.equal(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first widget");
|
||||
|
||||
let w2Opts = {id:"second", label: "second widget", content: "second content"};
|
||||
let w2Opts = {id:"second-multi-window", label: "second widget", content: "second content"};
|
||||
let w2 = testSingleWidget(w2Opts);
|
||||
assert.equal(widgetCount2(), widgetStartCount2 + 2, "2nd window has correct number of child elements after second widget");
|
||||
|
||||
@ -542,7 +543,7 @@ exports.testConstructor = function(assert, done) {
|
||||
tests.push(function testWindowClosing() {
|
||||
// 1/ Create a new widget
|
||||
let w1Opts = {
|
||||
id:"first",
|
||||
id:"first-win-closing",
|
||||
label: "first widget",
|
||||
content: "first content",
|
||||
contentScript: "self.port.on('event', function () self.port.emit('event'))"
|
||||
@ -595,7 +596,7 @@ exports.testConstructor = function(assert, done) {
|
||||
});
|
||||
});
|
||||
|
||||
if (!australis) {
|
||||
if (false) {
|
||||
tests.push(function testAddonBarHide() {
|
||||
const tabBrowser = require("sdk/deprecated/tab-browser");
|
||||
|
||||
@ -614,11 +615,13 @@ exports.testConstructor = function(assert, done) {
|
||||
assert.ok(container2().collapsed,
|
||||
"2nd window starts with an hidden addon-bar");
|
||||
|
||||
let w1Opts = {id:"first", label: "first widget", content: "first content"};
|
||||
let w1Opts = {id:"first-addonbar-hide", label: "first widget", content: "first content"};
|
||||
let w1 = testSingleWidget(w1Opts);
|
||||
assert.equal(widgetCount2(), widgetStartCount2 + 1,
|
||||
"2nd window has correct number of child elements after" +
|
||||
"widget creation");
|
||||
assert.ok(!container().collapsed, "1st window has a visible addon-bar");
|
||||
assert.ok(!container2().collapsed, "2nd window has a visible addon-bar");
|
||||
w1.destroy();
|
||||
assert.equal(widgetCount2(), widgetStartCount2,
|
||||
"2nd window has correct number of child elements after" +
|
||||
@ -637,7 +640,7 @@ exports.testConstructor = function(assert, done) {
|
||||
|
||||
// test widget.width
|
||||
tests.push(function testWidgetWidth() testSingleWidget({
|
||||
id: "text",
|
||||
id: "text-test-width",
|
||||
label: "test widget.width",
|
||||
content: "test width",
|
||||
width: 200,
|
||||
@ -661,7 +664,7 @@ exports.testConstructor = function(assert, done) {
|
||||
// test click handler not respond to right-click
|
||||
let clickCount = 0;
|
||||
tests.push(function testNoRightClick() testSingleWidget({
|
||||
id: "click-content",
|
||||
id: "right-click-content",
|
||||
label: "click test widget - content",
|
||||
content: "<div id='me'>foo</div>",
|
||||
contentScript: // Left click
|
||||
@ -762,7 +765,7 @@ exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
|
||||
let origMessage = "foo";
|
||||
const widgets = require("sdk/widget");
|
||||
let widget = widgets.Widget({
|
||||
id: "foo",
|
||||
id: "widget-messaging",
|
||||
label: "foo",
|
||||
content: "<bar>baz</bar>",
|
||||
contentScriptWhen: "end",
|
||||
@ -782,7 +785,7 @@ exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
|
||||
exports.testWidgetViews = function testWidgetViews(assert, done) {
|
||||
const widgets = require("sdk/widget");
|
||||
let widget = widgets.Widget({
|
||||
id: "foo",
|
||||
id: "widget-views",
|
||||
label: "foo",
|
||||
content: "<bar>baz</bar>",
|
||||
contentScriptWhen: "ready",
|
||||
@ -805,7 +808,7 @@ exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(assert, done)
|
||||
const widgets = require("sdk/widget");
|
||||
let view = null;
|
||||
let widget = widgets.Widget({
|
||||
id: "foo",
|
||||
id: "widget-view-ui-events",
|
||||
label: "foo",
|
||||
content: "<div id='me'>foo</div>",
|
||||
contentScript: "var evt = new MouseEvent('click', {button: 0});" +
|
||||
@ -830,7 +833,7 @@ exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(assert, done)
|
||||
exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(assert, done) {
|
||||
const widgets = require("sdk/widget");
|
||||
let widget = widgets.Widget({
|
||||
id: "foo",
|
||||
id: "widget-view-custom-events",
|
||||
label: "foo",
|
||||
content: "<div id='me'>foo</div>",
|
||||
contentScript: "self.port.emit('event', 'ok');",
|
||||
@ -853,7 +856,7 @@ exports.testWidgetViewsTooltip = function testWidgetViewsTooltip(assert, done) {
|
||||
const widgets = require("sdk/widget");
|
||||
|
||||
let widget = new widgets.Widget({
|
||||
id: "foo",
|
||||
id: "widget-views-tooltip",
|
||||
label: "foo",
|
||||
content: "foo"
|
||||
});
|
||||
@ -879,7 +882,7 @@ exports.testWidgetMove = function testWidgetMove(assert, done) {
|
||||
let gotFirstReady = false;
|
||||
|
||||
let widget = widgets.Widget({
|
||||
id: "foo",
|
||||
id: "widget-move",
|
||||
label: label,
|
||||
content: "<bar>baz</bar>",
|
||||
contentScriptWhen: "ready",
|
||||
@ -947,7 +950,7 @@ exports.testWidgetWithPound = function testWidgetWithPound(assert, done) {
|
||||
|
||||
exports.testContentScriptOptionsOption = function(assert, done) {
|
||||
let widget = require("sdk/widget").Widget({
|
||||
id: "fooz",
|
||||
id: "widget-script-options",
|
||||
label: "fooz",
|
||||
content: "fooz",
|
||||
contentScript: "self.postMessage( [typeof self.options.d, self.options] );",
|
||||
@ -1051,6 +1054,34 @@ exports.testSVGWidget = function(assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
exports.testReinsertion = function(assert, done) {
|
||||
const WIDGETID = "test-reinsertion";
|
||||
let windowUtils = require("sdk/deprecated/window-utils");
|
||||
let browserWindow = windowUtils.activeBrowserWindow;
|
||||
let widget = require("sdk/widget").Widget({
|
||||
id: "test-reinsertion",
|
||||
label: "test reinsertion",
|
||||
content: "Test",
|
||||
});
|
||||
let realWidgetId = "widget:" + jetpackID + "-" + WIDGETID;
|
||||
// Remove the widget:
|
||||
if (australis) {
|
||||
browserWindow.CustomizableUI.removeWidgetFromArea(realWidgetId);
|
||||
} else {
|
||||
let widget = browserWindow.document.getElementById(realWidgetId);
|
||||
let container = widget.parentNode;
|
||||
container.currentSet = container.currentSet.replace("," + realWidgetId, "");
|
||||
container.setAttribute("currentset", container.currentSet);
|
||||
container.ownerDocument.persist(container.id, "currentset");
|
||||
}
|
||||
|
||||
const tabBrowser = require("sdk/deprecated/tab-browser");
|
||||
tabBrowser.addTab("about:blank", { inNewWindow: true, onLoad: function(e) {
|
||||
assert.equal(e.target.defaultView.document.getElementById(realWidgetId), null);
|
||||
close(e.target.defaultView).then(done);
|
||||
}});
|
||||
};
|
||||
|
||||
if (!australis) {
|
||||
exports.testNavigationBarWidgets = function testNavigationBarWidgets(assert, done) {
|
||||
let w1 = widgets.Widget({id: "1st", label: "1st widget", content: "1"});
|
||||
|
@ -5,6 +5,9 @@
|
||||
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const { browserWindows } = require('sdk/windows');
|
||||
const { viewFor } = require('sdk/view/core');
|
||||
const { Ci } = require("chrome");
|
||||
const { isBrowser, getWindowTitle } = require("sdk/window/utils");
|
||||
|
||||
// TEST: browserWindows Iterator
|
||||
exports.testBrowserWindowsIterator = function(assert) {
|
||||
@ -55,4 +58,23 @@ exports.testWindowActivateMethod_simple = function(assert) {
|
||||
'Active tab is active after window.activate() call');
|
||||
};
|
||||
|
||||
exports["test getView(window)"] = function(assert, done) {
|
||||
browserWindows.once("open", window => {
|
||||
const view = viewFor(window);
|
||||
|
||||
assert.ok(view instanceof Ci.nsIDOMWindow, "view is a window");
|
||||
assert.ok(isBrowser(view), "view is a browser window");
|
||||
assert.equal(getWindowTitle(view), window.title,
|
||||
"window has a right title");
|
||||
|
||||
window.close();
|
||||
window.destroy();
|
||||
assert.equal(viewFor(window), null, "window view is gone");
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
browserWindows.open({ url: "data:text/html,<title>yo</title>" });
|
||||
};
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
|
Loading…
Reference in New Issue
Block a user