Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 5da2ab5

Browse files
committed
Bug 858326 - Uplift Add-on SDK changeset 99d7f27c7e
1 parent c6eafdb commit 5da2ab5

34 files changed

Lines changed: 1355 additions & 73 deletions

addon-sdk/source/doc/dev-guide-source/credits.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ We'd like to thank our many Jetpack project contributors! They include:
157157
* slash
158158
* Markus Stange
159159
* Dan Stevens
160+
* [J. Ryan Stinnett](https://github.com/jryans)
160161
* [Mihai Sucan](https://github.com/mihaisucan)
161162

162163
<!--end-->

addon-sdk/source/doc/module-source/sdk/page-mod.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
<!-- This Source Code Form is subject to the terms of the Mozilla Public
32
- License, v. 2.0. If a copy of the MPL was not distributed with this
43
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
@@ -58,8 +57,8 @@ In this case files are specified by a URL typically constructed using the
5857

5958
pageMod.PageMod({
6059
include: "*.mozilla.org",
61-
contentScriptFile: [self.data.url("jquery-1.7.min.js"),
62-
self.data.url("my-script.js")]
60+
contentScriptFile: [data.url("jquery-1.7.min.js"),
61+
data.url("my-script.js")]
6362
});
6463

6564
<div class="warning">

addon-sdk/source/doc/module-source/sdk/tabs.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ This is an optional property.
169169
@prop [onReady] {function}
170170
A callback function that will be registered for 'ready' event.
171171
This is an optional property.
172+
@prop [onLoad] {function}
173+
A callback function that will be registered for 'load' event.
174+
This is an optional property.
175+
@prop [onPageShow] {function}
176+
A callback function that will be registered for 'pageshow' event.
177+
This is an optional property.
172178
@prop [onActivate] {function}
173179
A callback function that will be registered for 'activate' event.
174180
This is an optional property.
@@ -332,6 +338,47 @@ content can be used.
332338
Listeners are passed the tab object.
333339
</api>
334340

341+
<api name="load">
342+
@event
343+
344+
This event is emitted when the page for the tab's content is loaded. It is
345+
equivalent to the `load` event for the given content page.
346+
347+
A single tab will emit this event every time the page is loaded: so it will be
348+
emitted again if the tab's location changes or the content is reloaded.
349+
350+
After this event has been emitted, all properties relating to the tab's
351+
content can be used.
352+
353+
This is fired after the `ready` event on DOM content pages and can be used
354+
for pages that do not have a `DOMContentLoaded` event, like images.
355+
356+
@argument {Tab}
357+
Listeners are passed the tab object.
358+
</api>
359+
360+
<api name="pageshow">
361+
@event
362+
363+
This event is emitted when the page for the tab's content is potentially
364+
from the cache. It is equivilent to the [pageshow](https://developer.mozilla.org/en-US/docs/DOM/Mozilla_event_reference/pageshow) event for the given
365+
content page.
366+
367+
After this event has been emitted, all properties relating to the tab's
368+
content can be used.
369+
370+
While the `ready` and `load` events will not be fired when a user uses the back
371+
or forward buttons to navigate history, the `pageshow` event will be fired.
372+
If the `persisted` argument is true, then the contents were loaded from the
373+
bfcache.
374+
375+
@argument {Tab}
376+
Listeners are passed the tab object.
377+
@argument {persisted}
378+
Listeners are passed a boolean value indicating whether or not the page
379+
was loaded from the [bfcache](https://developer.mozilla.org/en-US/docs/Working_with_BFCache) or not.
380+
</api>
381+
335382
<api name="activate">
336383
@event
337384

addon-sdk/source/lib/sdk/addon/runner.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ const { when: unload } = require('../system/unload');
1616
const { loadReason } = require('../self');
1717
const { rootURI } = require("@loader/options");
1818
const globals = require('../system/globals');
19+
const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
20+
getService(Ci.nsIAppShellService);
1921

2022
const NAME2TOPIC = {
2123
'Firefox': 'sessionstore-windows-restored',
@@ -70,8 +72,18 @@ function wait(reason, options) {
7072
}
7173

7274
function startup(reason, options) {
73-
if (reason === 'startup')
75+
// Try accessing hidden window to guess if we are running during firefox
76+
// startup, so that we should wait for session restore event before
77+
// running the addon
78+
let initialized = false;
79+
try {
80+
appShellService.hiddenDOMWindow;
81+
initialized = true;
82+
}
83+
catch(e) {}
84+
if (reason === 'startup' || !initialized) {
7485
return wait(reason, options);
86+
}
7587

7688
// Inject globals ASAP in order to have console API working ASAP
7789
Object.defineProperties(options.loader.globals, descriptor(globals));
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
"use strict";
5+
6+
module.metadata = {
7+
"stability": "unstable"
8+
};
9+
10+
const { events } = require("../window/events");
11+
const { filter } = require("../event/utils");
12+
const { isBrowser } = require("../window/utils");
13+
14+
// TODO: `isBrowser` detects weather window is a browser by checking
15+
// `windowtype` attribute, which means that all 'open' events will be
16+
// filtered out since document is not loaded yet. Maybe we can find a better
17+
// implementation for `isBrowser`. Either way it's not really needed yet
18+
// neither window tracker provides this event.
19+
20+
exports.events = filter(function({target}) isBrowser(target), events);

addon-sdk/source/lib/sdk/deprecated/unit-test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,12 @@ TestRunner.prototype = {
270270
this.waitUntilCallback = null;
271271
if (this.test.passed == 0 && this.test.failed == 0) {
272272
this._logTestFailed("empty test");
273+
if ("testMessage" in this.console) {
274+
this.console.testMessage(false, false, this.test.name, "Empty test");
275+
}
276+
else {
277+
this.console.error("fail:", "Empty test")
278+
}
273279
this.failed++;
274280
this.test.failed++;
275281
}
@@ -414,6 +420,12 @@ TestRunner.prototype = {
414420

415421
function tiredOfWaiting() {
416422
self._logTestFailed("timed out");
423+
if ("testMessage" in self.console) {
424+
self.console.testMessage(false, false, self.test.name, "Timed out");
425+
}
426+
else {
427+
self.console.error("fail:", "Timed out")
428+
}
417429
if (self.waitUntilCallback) {
418430
self.waitUntilCallback(true);
419431
self.waitUntilCallback = null;

addon-sdk/source/lib/sdk/event/core.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,20 @@ function emit(target, type, message /*, ...*/) {
9595
*/
9696
emit.lazy = function lazy(target, type, message /*, ...*/) {
9797
let args = Array.slice(arguments, 2);
98-
let listeners = observers(target, type).slice();
98+
let state = observers(target, type);
99+
let listeners = state.slice();
99100
let index = 0;
100101
let count = listeners.length;
101102

102103
// If error event and there are no handlers then print error message
103104
// into a console.
104105
if (count === 0 && type === 'error') console.exception(message);
105106
while (index < count) {
106-
try { yield listeners[index].apply(target, args); }
107+
try {
108+
let listener = listeners[index];
109+
// Dispatch only if listener is still registered.
110+
if (~state.indexOf(listener)) yield listener.apply(target, args);
111+
}
107112
catch (error) {
108113
// If exception is not thrown by a error listener and error listener is
109114
// registered emit `error` event. Otherwise dump exception to the console.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
"use strict";
6+
7+
module.metadata = {
8+
"stability": "unstable"
9+
};
10+
11+
let { emit, on, off } = require("./core");
12+
13+
// Simple utility function takes event target, event type and optional
14+
// `options.capture` and returns node style event stream that emits "data"
15+
// events every time event of that type occurs on the given `target`.
16+
function open(target, type, options) {
17+
let output = {};
18+
let capture = options && options.capture ? true : false;
19+
20+
target.addEventListener(type, function(event) {
21+
emit(output, "data", event);
22+
}, capture);
23+
24+
return output;
25+
}
26+
exports.open = open;

addon-sdk/source/lib/sdk/event/target.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ const EventTarget = Class({
7575
// than intended. This way we make sure all arguments are passed and only
7676
// one listener is removed at most.
7777
off(this, type, listener);
78+
},
79+
off: function(type, listener) {
80+
off(this, type, listener)
7881
}
7982
});
8083
exports.EventTarget = EventTarget;
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
"use strict";
5+
6+
module.metadata = {
7+
"stability": "unstable"
8+
};
9+
10+
let { emit, on, off } = require("./core");
11+
12+
// This module provides set of high order function for working with event
13+
// streams (streams in a NodeJS style that dispatch data, end and error
14+
// events).
15+
16+
// Function takes a `target` object and returns set of implicit references
17+
// (non property references) it keeps. This basically allows defining
18+
// references between objects without storing the explicitly. See transform for
19+
// more details.
20+
let refs = (function() {
21+
let refSets = new WeakMap();
22+
return function refs(target) {
23+
if (!refSets.has(target)) refSets.set(target, new Set());
24+
return refSets.get(target);
25+
}
26+
})();
27+
28+
function transform(f, input) {
29+
let output = {};
30+
31+
// Since event listeners don't prevent `input` to be GC-ed we wanna presrve
32+
// it until `output` can be GC-ed. There for we add implicit reference which
33+
// is removed once `input` ends.
34+
refs(output).add(input);
35+
36+
function next(data) emit(output, "data", data);
37+
on(input, "error", function(error) emit(output, "error", error));
38+
on(input, "end", function() {
39+
refs(output).delete(input);
40+
emit(output, "end");
41+
});
42+
on(input, "data", function(data) f(data, next));
43+
return output;
44+
}
45+
46+
// High order event transformation function that takes `input` event channel
47+
// and returns transformation containing only events on which `p` predicate
48+
// returns `true`.
49+
function filter(predicate, input) {
50+
return transform(function(data, next) {
51+
if (predicate(data)) next(data)
52+
}, input);
53+
}
54+
exports.filter = filter;
55+
56+
// High order function that takes `input` and returns input of it's values
57+
// mapped via given `f` function.
58+
function map(f, input) transform(function(data, next) next(f(data)), input)
59+
exports.map = map;
60+
61+
// High order function that takes `input` stream of streams and merges them
62+
// into single event stream. Like flatten but time based rather than order
63+
// based.
64+
function merge(inputs) {
65+
let output = {};
66+
let open = 1;
67+
let state = [];
68+
output.state = state;
69+
refs(output).add(inputs);
70+
71+
function end(input) {
72+
open = open - 1;
73+
refs(output).delete(input);
74+
if (open === 0) emit(output, "end");
75+
}
76+
function error(e) emit(output, "error", e);
77+
function forward(input) {
78+
state.push(input);
79+
open = open + 1;
80+
on(input, "end", function() end(input));
81+
on(input, "error", error);
82+
on(input, "data", function(data) emit(output, "data", data));
83+
}
84+
85+
// If `inputs` is an array treat it as a stream.
86+
if (Array.isArray(inputs)) {
87+
inputs.forEach(forward)
88+
end(inputs)
89+
}
90+
else {
91+
on(inputs, "end", function() end(inputs));
92+
on(inputs, "error", error);
93+
on(inputs, "data", forward);
94+
}
95+
96+
return output;
97+
}
98+
exports.merge = merge;
99+
100+
function expand(f, inputs) merge(map(f, inputs))
101+
exports.expand = expand;

0 commit comments

Comments
 (0)