mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to mozilla-inbound
This commit is contained in:
commit
dc43494b15
@ -1,10 +1,11 @@
|
||||
/* 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";
|
||||
|
||||
var self = require("sdk/self");
|
||||
var panels = require("sdk/panel");
|
||||
var widgets = require("sdk/widget");
|
||||
var { Panel } = require("sdk/panel");
|
||||
var { ToggleButton } = require("sdk/ui");
|
||||
|
||||
function replaceMom(html) {
|
||||
return html.replace("World", "Mom");
|
||||
@ -21,20 +22,18 @@ exports.main = function(options, callbacks) {
|
||||
helloHTML = replaceMom(helloHTML);
|
||||
|
||||
// ... and then create a panel that displays it.
|
||||
var myPanel = panels.Panel({
|
||||
contentURL: "data:text/html," + helloHTML
|
||||
var myPanel = Panel({
|
||||
contentURL: "data:text/html," + helloHTML,
|
||||
onHide: handleHide
|
||||
});
|
||||
|
||||
// Load the URL of the sample image.
|
||||
var iconURL = self.data.url("mom.png");
|
||||
|
||||
// Create a widget that displays the image. We'll attach the panel to it.
|
||||
// When you click the widget, the panel will pop up.
|
||||
widgets.Widget({
|
||||
var button = ToggleButton({
|
||||
id: "test-widget",
|
||||
label: "Mom",
|
||||
contentURL: iconURL,
|
||||
panel: myPanel
|
||||
icon: './mom.png',
|
||||
onChange: handleChange
|
||||
});
|
||||
|
||||
// If you run cfx with --static-args='{"quitWhenDone":true}' this program
|
||||
@ -42,3 +41,13 @@ exports.main = function(options, callbacks) {
|
||||
if (options.staticArgs.quitWhenDone)
|
||||
callbacks.quit();
|
||||
}
|
||||
|
||||
function handleChange(state) {
|
||||
if (state.checked) {
|
||||
myPanel.show({ position: button });
|
||||
}
|
||||
}
|
||||
|
||||
function handleHide() {
|
||||
button.state('window', { checked: false });
|
||||
}
|
||||
|
@ -3,9 +3,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
// Disable tests below for now.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=987348
|
||||
/*
|
||||
var m = require("main");
|
||||
var self = require("sdk/self");
|
||||
|
||||
@ -26,4 +23,3 @@ exports.testID = function(test) {
|
||||
test.assertEqual(self.data.url("sample.html"),
|
||||
"resource://reading-data-example-at-jetpack-dot-mozillalabs-dot-com/reading-data/data/sample.html");
|
||||
};
|
||||
*/
|
||||
|
@ -1,26 +1,34 @@
|
||||
/* 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";
|
||||
|
||||
var data = require("sdk/self").data;
|
||||
var { data } = require("sdk/self");
|
||||
var { ToggleButton } = require("sdk/ui");
|
||||
|
||||
var base64png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA" +
|
||||
"AABzenr0AAAASUlEQVRYhe3O0QkAIAwD0eyqe3Q993AQ3cBSUKpygfsNTy" +
|
||||
"N5ugbQpK0BAADgP0BRDWXWlwEAAAAAgPsA3rzDaAAAAHgPcGrpgAnzQ2FG" +
|
||||
"bWRR9AAAAABJRU5ErkJggg%3D%3D";
|
||||
|
||||
var reddit_panel = require("sdk/panel").Panel({
|
||||
width: 240,
|
||||
height: 320,
|
||||
contentURL: "http://www.reddit.com/.mobile?keep_extension=True",
|
||||
contentScriptFile: [data.url("jquery-1.4.4.min.js"),
|
||||
data.url("panel.js")]
|
||||
data.url("panel.js")],
|
||||
onHide: handleHide
|
||||
});
|
||||
|
||||
reddit_panel.port.on("click", function(url) {
|
||||
require("sdk/tabs").open(url);
|
||||
});
|
||||
|
||||
require("sdk/widget").Widget({
|
||||
let button = ToggleButton({
|
||||
id: "open-reddit-btn",
|
||||
label: "Reddit",
|
||||
contentURL: "http://www.reddit.com/static/favicon.ico",
|
||||
panel: reddit_panel
|
||||
icon: base64png,
|
||||
onChange: handleChange
|
||||
});
|
||||
|
||||
exports.main = function(options, callbacks) {
|
||||
@ -29,3 +37,13 @@ exports.main = function(options, callbacks) {
|
||||
if (options.staticArgs.quitWhenDone)
|
||||
callbacks.quit();
|
||||
};
|
||||
|
||||
function handleChange(state) {
|
||||
if (state.checked) {
|
||||
reddit_panel.show({ position: button });
|
||||
}
|
||||
}
|
||||
|
||||
function handleHide() {
|
||||
button.state('window', { checked: false });
|
||||
}
|
||||
|
@ -3,9 +3,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
// Disable tests below for now.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=987348
|
||||
/*
|
||||
var m = require("main");
|
||||
var self = require("sdk/self");
|
||||
|
||||
@ -23,4 +20,3 @@ exports.testMain = function(test) {
|
||||
exports.testData = function(test) {
|
||||
test.assert(self.data.load("panel.js").length > 0);
|
||||
};
|
||||
*/
|
||||
|
@ -107,7 +107,9 @@ const ContentWorker = Object.freeze({
|
||||
error: pipe.emit.bind(null, "console", "error"),
|
||||
debug: pipe.emit.bind(null, "console", "debug"),
|
||||
exception: pipe.emit.bind(null, "console", "exception"),
|
||||
trace: pipe.emit.bind(null, "console", "trace")
|
||||
trace: pipe.emit.bind(null, "console", "trace"),
|
||||
time: pipe.emit.bind(null, "console", "time"),
|
||||
timeEnd: pipe.emit.bind(null, "console", "timeEnd")
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -31,6 +31,9 @@ let detachFrom = method("detatchFrom");
|
||||
exports.detachFrom = detachFrom;
|
||||
|
||||
function attach(modification, target) {
|
||||
if (!modification)
|
||||
return;
|
||||
|
||||
let window = getTargetWindow(target);
|
||||
|
||||
attachTo(modification, window);
|
||||
@ -42,6 +45,9 @@ function attach(modification, target) {
|
||||
exports.attach = attach;
|
||||
|
||||
function detach(modification, target) {
|
||||
if (!modification)
|
||||
return;
|
||||
|
||||
if (target) {
|
||||
let window = getTargetWindow(target);
|
||||
detachFrom(modification, window);
|
||||
|
@ -67,3 +67,8 @@ function load(sandbox, uri) {
|
||||
}
|
||||
}
|
||||
exports.load = load;
|
||||
|
||||
/**
|
||||
* Forces the given `sandbox` to be freed immediately.
|
||||
*/
|
||||
exports.nuke = Cu.nukeSandbox
|
||||
|
@ -201,6 +201,10 @@ function createWorker (mod, window) {
|
||||
contentScript: mod.contentScript,
|
||||
contentScriptFile: mod.contentScriptFile,
|
||||
contentScriptOptions: mod.contentScriptOptions,
|
||||
// Bug 980468: Syntax errors from scripts can happen before the worker
|
||||
// can set up an error handler. They are per-mod rather than per-worker
|
||||
// so are best handled at the mod level.
|
||||
onError: (e) => emit(mod, 'error', e)
|
||||
});
|
||||
workers.set(mod, worker);
|
||||
pipe(worker, mod);
|
||||
|
@ -18,7 +18,7 @@ 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 { WorkerHost } = require("./content/utils");
|
||||
const { Worker } = require("./content/worker");
|
||||
const { Disposable } = require("./core/disposable");
|
||||
const { WeakReference } = require('./core/reference');
|
||||
@ -34,6 +34,8 @@ const { getNodeView, getActiveView } = require("./view/core");
|
||||
const { isNil, isObject, isNumber } = require("./lang/type");
|
||||
const { getAttachEventType } = require("./content/utils");
|
||||
const { number, boolean, object } = require('./deprecated/api-utils');
|
||||
const { Style } = require("./stylesheet/style");
|
||||
const { attach, detach } = require("./content/mod");
|
||||
|
||||
let isRect = ({top, right, bottom, left}) => [top, right, bottom, left].
|
||||
some(value => isNumber(value) && !isNaN(value));
|
||||
@ -63,7 +65,16 @@ let displayContract = contract({
|
||||
position: position
|
||||
});
|
||||
|
||||
let panelContract = contract(merge({}, displayContract.rules, loaderContract.rules));
|
||||
let panelContract = contract(merge({
|
||||
// contentStyle* / contentScript* are sharing the same validation constraints,
|
||||
// so they can be mostly reused, except for the messages.
|
||||
contentStyle: merge(Object.create(loaderContract.rules.contentScript), {
|
||||
msg: 'The `contentStyle` option must be a string or an array of strings.'
|
||||
}),
|
||||
contentStyleFile: merge(Object.create(loaderContract.rules.contentScriptFile), {
|
||||
msg: 'The `contentStyleFile` option must be a local URL or an array of URLs'
|
||||
})
|
||||
}, displayContract.rules, loaderContract.rules));
|
||||
|
||||
|
||||
function isDisposed(panel) !views.has(panel);
|
||||
@ -72,12 +83,13 @@ let panels = new WeakMap();
|
||||
let models = new WeakMap();
|
||||
let views = new WeakMap();
|
||||
let workers = new WeakMap();
|
||||
let styles = new WeakMap();
|
||||
|
||||
function viewFor(panel) views.get(panel)
|
||||
function modelFor(panel) models.get(panel)
|
||||
function panelFor(view) panels.get(view)
|
||||
function workerFor(panel) workers.get(panel)
|
||||
|
||||
const viewFor = (panel) => views.get(panel);
|
||||
const modelFor = (panel) => models.get(panel);
|
||||
const panelFor = (view) => panels.get(view);
|
||||
const workerFor = (panel) => workers.get(panel);
|
||||
const styleFor = (panel) => styles.get(panel);
|
||||
|
||||
// Utility function takes `panel` instance and makes sure it will be
|
||||
// automatically hidden as soon as other panel is shown.
|
||||
@ -125,6 +137,12 @@ const Panel = Class({
|
||||
}, panelContract(options));
|
||||
models.set(this, model);
|
||||
|
||||
if (model.contentStyle || model.contentStyleFile) {
|
||||
styles.set(this, Style({
|
||||
uri: model.contentStyleFile,
|
||||
source: model.contentStyle
|
||||
}));
|
||||
}
|
||||
|
||||
// Setup view
|
||||
let view = domPanel.make();
|
||||
@ -148,7 +166,8 @@ const Panel = Class({
|
||||
this.hide();
|
||||
off(this);
|
||||
|
||||
destroy(workerFor(this));
|
||||
workerFor(this).destroy();
|
||||
detach(styleFor(this));
|
||||
|
||||
domPanel.dispose(viewFor(this));
|
||||
|
||||
@ -177,7 +196,7 @@ const Panel = Class({
|
||||
domPanel.setURL(viewFor(this), model.contentURL);
|
||||
// Detach worker so that messages send will be queued until it's
|
||||
// reatached once panel content is ready.
|
||||
detach(workerFor(this));
|
||||
workerFor(this).detach();
|
||||
},
|
||||
|
||||
/* Public API: Panel.isShowing */
|
||||
@ -262,12 +281,25 @@ let hides = filter(panelEvents, ({type}) => type === "popuphidden");
|
||||
let ready = filter(panelEvents, ({type, target}) =>
|
||||
getAttachEventType(modelFor(panelFor(target))) === type);
|
||||
|
||||
// Styles should be always added as soon as possible, and doesn't makes them
|
||||
// depends on `contentScriptWhen`
|
||||
let start = filter(panelEvents, ({type}) => type === "document-element-inserted");
|
||||
|
||||
// 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(ready, "data", function({target}) {
|
||||
let worker = workerFor(panelFor(target));
|
||||
attach(worker, domPanel.getContentDocument(target).defaultView);
|
||||
on(ready, "data", ({target}) => {
|
||||
let panel = panelFor(target);
|
||||
let window = domPanel.getContentDocument(target).defaultView;
|
||||
|
||||
workerFor(panel).attach(window);
|
||||
});
|
||||
|
||||
on(start, "data", ({target}) => {
|
||||
let panel = panelFor(target);
|
||||
let window = domPanel.getContentDocument(target).defaultView;
|
||||
|
||||
attach(styleFor(panel), window);
|
||||
});
|
||||
|
@ -109,17 +109,21 @@ exports.pathFor = function pathFor(id) {
|
||||
*/
|
||||
exports.platform = runtime.OS.toLowerCase();
|
||||
|
||||
const [, architecture, compiler] = runtime.XPCOMABI ?
|
||||
runtime.XPCOMABI.match(/^([^-]*)-(.*)$/) :
|
||||
[, null, null];
|
||||
|
||||
/**
|
||||
* What processor architecture you're running on:
|
||||
* `'arm', 'ia32', or 'x64'`.
|
||||
*/
|
||||
exports.architecture = runtime.XPCOMABI.split('_')[0];
|
||||
exports.architecture = architecture;
|
||||
|
||||
/**
|
||||
* What compiler used for build:
|
||||
* `'msvc', 'n32', 'gcc2', 'gcc3', 'sunc', 'ibmc'...`
|
||||
*/
|
||||
exports.compiler = runtime.XPCOMABI.split('_')[1];
|
||||
exports.compiler = compiler;
|
||||
|
||||
/**
|
||||
* The application's build ID/date, for example "2004051604".
|
||||
|
@ -8,12 +8,13 @@ module.metadata = {
|
||||
'stability': 'unstable'
|
||||
};
|
||||
|
||||
const { Cc, Ci } = require('chrome');
|
||||
const { Cc, Ci, Cu } = require('chrome');
|
||||
const { Unknown } = require('../platform/xpcom');
|
||||
const { Class } = require('../core/heritage');
|
||||
const { ns } = require('../core/namespace');
|
||||
const { addObserver, removeObserver, notifyObservers } =
|
||||
Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
|
||||
const unloadSubject = require('@loader/unload');
|
||||
|
||||
const Subject = Class({
|
||||
extends: Unknown,
|
||||
@ -94,6 +95,10 @@ function on(type, listener, strong) {
|
||||
let observer = Observer(listener);
|
||||
observers[type] = observer;
|
||||
addObserver(observer, type, weak);
|
||||
// WeakRef gymnastics to remove all alive observers on unload
|
||||
let ref = Cu.getWeakReference(observer);
|
||||
weakRefs.set(observer, ref);
|
||||
stillAlive.set(ref, type);
|
||||
}
|
||||
}
|
||||
exports.on = on;
|
||||
@ -120,6 +125,31 @@ function off(type, listener) {
|
||||
let observer = observers[type];
|
||||
delete observers[type];
|
||||
removeObserver(observer, type);
|
||||
stillAlive.delete(weakRefs.get(observer));
|
||||
}
|
||||
}
|
||||
exports.off = off;
|
||||
|
||||
// must use WeakMap to keep reference to all the WeakRefs (!), see bug 986115
|
||||
let weakRefs = new WeakMap();
|
||||
|
||||
// and we're out of beta, we're releasing on time!
|
||||
let stillAlive = new Map();
|
||||
|
||||
on('sdk:loader:destroy', function onunload({ subject, data: reason }) {
|
||||
// using logic from ./unload, to avoid a circular module reference
|
||||
if (subject.wrappedJSObject === unloadSubject) {
|
||||
off('sdk:loader:destroy', onunload);
|
||||
|
||||
// don't bother
|
||||
if (reason === 'shutdown')
|
||||
return;
|
||||
|
||||
stillAlive.forEach( (type, ref) => {
|
||||
let observer = ref.get();
|
||||
if (observer)
|
||||
removeObserver(observer, type);
|
||||
})
|
||||
}
|
||||
// a strong reference
|
||||
}, true);
|
||||
|
@ -62,9 +62,11 @@ exports.LoaderWithHookedConsole = function (module, callback) {
|
||||
error: hook.bind("error"),
|
||||
debug: hook.bind("debug"),
|
||||
exception: hook.bind("exception"),
|
||||
time: hook.bind("time"),
|
||||
timeEnd: hook.bind("timeEnd"),
|
||||
__exposedProps__: {
|
||||
log: "rw", info: "rw", warn: "rw", error: "rw", debug: "rw",
|
||||
exception: "rw"
|
||||
exception: "rw", time: "rw", timeEnd: "rw"
|
||||
}
|
||||
}
|
||||
}),
|
||||
@ -105,9 +107,11 @@ exports.LoaderWithFilteredConsole = function (module, callback) {
|
||||
error: hook.bind("error"),
|
||||
debug: hook.bind("debug"),
|
||||
exception: hook.bind("exception"),
|
||||
time: hook.bind("time"),
|
||||
timeEnd: hook.bind("timeEnd"),
|
||||
__exposedProps__: {
|
||||
log: "rw", info: "rw", warn: "rw", error: "rw", debug: "rw",
|
||||
exception: "rw"
|
||||
exception: "rw", time: "rw", timeEnd: "rw"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -8,6 +8,7 @@ const { isLocalURL } = require('../../url');
|
||||
const { isNil, isObject, isString } = require('../../lang/type');
|
||||
const { required, either, string, boolean, object } = require('../../deprecated/api-utils');
|
||||
const { merge } = require('../../util/object');
|
||||
const { freeze } = Object;
|
||||
|
||||
function isIconSet(icons) {
|
||||
return Object.keys(icons).
|
||||
@ -16,6 +17,7 @@ function isIconSet(icons) {
|
||||
|
||||
let iconSet = {
|
||||
is: either(object, string),
|
||||
map: v => isObject(v) ? freeze(merge({}, v)) : v,
|
||||
ok: v => (isString(v) && isLocalURL(v)) || (isObject(v) && isIconSet(v)),
|
||||
msg: 'The option "icon" must be a local URL or an object with ' +
|
||||
'numeric keys / local URL values pair.'
|
||||
|
@ -253,9 +253,11 @@ const Sidebar = Class({
|
||||
remove(sidebars, this);
|
||||
|
||||
// stop tracking windows
|
||||
internals.tracker.unload();
|
||||
internals.tracker = null;
|
||||
if (internals.tracker) {
|
||||
internals.tracker.unload();
|
||||
}
|
||||
|
||||
internals.tracker = null;
|
||||
internals.windowNS = null;
|
||||
|
||||
views.delete(this);
|
||||
|
@ -382,8 +382,8 @@ exports["test:ensure console.xxx works in cs"] = WorkerTest(
|
||||
let calls = [];
|
||||
function onMessage(type, msg) {
|
||||
assert.equal(type, msg,
|
||||
"console.xxx(\"xxx\"), i.e. message is equal to the " +
|
||||
"console method name we are calling");
|
||||
"console.xxx(\"xxx\"), i.e. message is equal to the " +
|
||||
"console method name we are calling");
|
||||
calls.push(msg);
|
||||
}
|
||||
|
||||
@ -391,19 +391,23 @@ exports["test:ensure console.xxx works in cs"] = WorkerTest(
|
||||
let worker = loader.require("sdk/content/worker").Worker({
|
||||
window: browser.contentWindow,
|
||||
contentScript: "new " + function WorkerScope() {
|
||||
console.time("time");
|
||||
console.log("log");
|
||||
console.info("info");
|
||||
console.warn("warn");
|
||||
console.error("error");
|
||||
console.debug("debug");
|
||||
console.exception("exception");
|
||||
console.timeEnd("timeEnd");
|
||||
self.postMessage();
|
||||
},
|
||||
onMessage: function() {
|
||||
// Ensure that console methods are called in the same execution order
|
||||
const EXPECTED_CALLS = ["time", "log", "info", "warn", "error",
|
||||
"debug", "exception", "timeEnd"];
|
||||
assert.equal(JSON.stringify(calls),
|
||||
JSON.stringify(["log", "info", "warn", "error", "debug", "exception"]),
|
||||
"console has been called successfully, in the expected order");
|
||||
JSON.stringify(EXPECTED_CALLS),
|
||||
"console methods have been called successfully, in expected order");
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
@ -957,7 +957,7 @@ exports.testPageModCss = function(assert, done) {
|
||||
'data:text/html;charset=utf-8,<div style="background: silver">css test</div>', [{
|
||||
include: ["*", "data:*"],
|
||||
contentStyle: "div { height: 100px; }",
|
||||
contentStyleFile: data.url("pagemod-css-include-file.css")
|
||||
contentStyleFile: data.url("css-include-file.css")
|
||||
}],
|
||||
function(win, done) {
|
||||
let div = win.document.querySelector("div");
|
||||
@ -1531,4 +1531,32 @@ exports.testDetachOnUnload = function(assert, done) {
|
||||
})
|
||||
}
|
||||
|
||||
exports.testSyntaxErrorInContentScript = function(assert, done) {
|
||||
const url = "data:text/html;charset=utf-8,testSyntaxErrorInContentScript";
|
||||
let hitError = null;
|
||||
let attached = false;
|
||||
|
||||
testPageMod(assert, done, url, [{
|
||||
include: url,
|
||||
contentScript: 'console.log(23',
|
||||
|
||||
onAttach: function() {
|
||||
attached = true;
|
||||
},
|
||||
|
||||
onError: function(e) {
|
||||
hitError = e;
|
||||
}
|
||||
}],
|
||||
|
||||
function(win, done) {
|
||||
assert.ok(attached, "The worker was attached.");
|
||||
assert.notStrictEqual(hitError, null, "The syntax error was reported.");
|
||||
if (hitError)
|
||||
assert.equal(hitError.name, "SyntaxError", "The error thrown should be a SyntaxError");
|
||||
done();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
|
@ -25,6 +25,8 @@ const { URL } = require('sdk/url');
|
||||
const fixtures = require('./fixtures')
|
||||
|
||||
const SVG_URL = fixtures.url('mofo_logo.SVG');
|
||||
const CSS_URL = fixtures.url('css-include-file.css');
|
||||
|
||||
const Isolate = fn => '(' + fn + ')()';
|
||||
|
||||
function ignorePassingDOMNodeWarning(type, message) {
|
||||
@ -974,6 +976,88 @@ exports['test panel can be constructed without any arguments'] = function (asser
|
||||
assert.ok(true, "Creating a panel with no arguments does not throw");
|
||||
};
|
||||
|
||||
exports['test panel CSS'] = function(assert, done) {
|
||||
const loader = Loader(module);
|
||||
const { Panel } = loader.require('sdk/panel');
|
||||
|
||||
const { getActiveView } = loader.require('sdk/view/core');
|
||||
|
||||
const getContentWindow = panel =>
|
||||
getActiveView(panel).querySelector('iframe').contentWindow;
|
||||
|
||||
let panel = Panel({
|
||||
contentURL: 'data:text/html;charset=utf-8,' +
|
||||
'<div style="background: silver">css test</div>',
|
||||
contentStyle: 'div { height: 100px; }',
|
||||
contentStyleFile: CSS_URL,
|
||||
onShow: () => {
|
||||
ready(getContentWindow(panel)).then(({ document }) => {
|
||||
let div = document.querySelector('div');
|
||||
|
||||
assert.equal(div.clientHeight, 100, 'Panel contentStyle worked');
|
||||
assert.equal(div.offsetHeight, 120, 'Panel contentStyleFile worked');
|
||||
|
||||
loader.unload();
|
||||
done();
|
||||
}).then(null, assert.fail);
|
||||
}
|
||||
});
|
||||
|
||||
panel.show();
|
||||
};
|
||||
|
||||
exports['test panel CSS list'] = function(assert, done) {
|
||||
const loader = Loader(module);
|
||||
const { Panel } = loader.require('sdk/panel');
|
||||
|
||||
const { getActiveView } = loader.require('sdk/view/core');
|
||||
|
||||
const getContentWindow = panel =>
|
||||
getActiveView(panel).querySelector('iframe').contentWindow;
|
||||
|
||||
let panel = Panel({
|
||||
contentURL: 'data:text/html;charset=utf-8,' +
|
||||
'<div style="width:320px; max-width: 480px!important">css test</div>',
|
||||
contentStyleFile: [
|
||||
// Highlight evaluation order in this list
|
||||
"data:text/css;charset=utf-8,div { border: 1px solid black; }",
|
||||
"data:text/css;charset=utf-8,div { border: 10px solid black; }",
|
||||
// Highlight evaluation order between contentStylesheet & contentStylesheetFile
|
||||
"data:text/css;charset=utf-8s,div { height: 1000px; }",
|
||||
// Highlight precedence between the author and user style sheet
|
||||
"data:text/css;charset=utf-8,div { width: 200px; max-width: 640px!important}",
|
||||
],
|
||||
contentStyle: [
|
||||
"div { height: 10px; }",
|
||||
"div { height: 100px; }"
|
||||
],
|
||||
onShow: () => {
|
||||
ready(getContentWindow(panel)).then(({ window, document }) => {
|
||||
let div = document.querySelector('div');
|
||||
let style = window.getComputedStyle(div);
|
||||
|
||||
assert.equal(div.clientHeight, 100,
|
||||
'Panel contentStyle list is evaluated after contentStyleFile');
|
||||
|
||||
assert.equal(div.offsetHeight, 120,
|
||||
'Panel contentStyleFile list works');
|
||||
|
||||
assert.equal(style.width, '320px',
|
||||
'add-on author/page author stylesheet precedence works');
|
||||
|
||||
assert.equal(style.maxWidth, '480px',
|
||||
'add-on author/page author stylesheet !important precedence works');
|
||||
|
||||
loader.unload();
|
||||
done();
|
||||
}).then(null, assert.fail);
|
||||
}
|
||||
});
|
||||
|
||||
panel.show();
|
||||
};
|
||||
|
||||
|
||||
if (isWindowPBSupported) {
|
||||
exports.testGetWindow = function(assert, done) {
|
||||
let activeWindow = getMostRecentBrowserWindow();
|
||||
|
@ -2,7 +2,7 @@
|
||||
* 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/. */
|
||||
|
||||
const { sandbox, load, evaluate } = require('sdk/loader/sandbox');
|
||||
const { sandbox, load, evaluate, nuke } = require('sdk/loader/sandbox');
|
||||
const xulApp = require("sdk/system/xul-app");
|
||||
const fixturesURI = module.uri.split('test-sandbox.js')[0] + 'fixtures/';
|
||||
|
||||
@ -137,4 +137,30 @@ exports['test metadata'] = function(assert) {
|
||||
let self = require('sdk/self');
|
||||
}
|
||||
|
||||
exports['test nuke sandbox'] = function(assert) {
|
||||
|
||||
let fixture = sandbox('http://example.com');
|
||||
fixture.foo = 'foo';
|
||||
|
||||
let ref = evaluate(fixture, 'let a = {bar: "bar"}; a');
|
||||
|
||||
nuke(fixture);
|
||||
|
||||
assert.ok(Cu.isDeadWrapper(fixture), 'sandbox should be dead');
|
||||
|
||||
assert.throws(
|
||||
() => fixture.foo,
|
||||
/can't access dead object/,
|
||||
'property of nuked sandbox should not be accessible'
|
||||
);
|
||||
|
||||
assert.ok(Cu.isDeadWrapper(ref), 'ref to object from sandbox should be dead');
|
||||
|
||||
assert.throws(
|
||||
() => ref.bar,
|
||||
/can't access dead object/,
|
||||
'object from nuked sandbox should not be alive'
|
||||
);
|
||||
}
|
||||
|
||||
require('test').run(exports);
|
||||
|
@ -119,6 +119,30 @@ exports["test listeners are GC-ed"] = function(assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
exports["test alive listeners are removed on unload"] = function(assert) {
|
||||
let receivedFromWeak = [];
|
||||
let receivedFromStrong = [];
|
||||
let loader = Loader(module);
|
||||
let events = loader.require('sdk/system/events');
|
||||
|
||||
let type = 'test-alive-listeners-are-removed';
|
||||
const handler = (event) => receivedFromStrong.push(event);
|
||||
const weakHandler = (event) => receivedFromWeak.push(event);
|
||||
|
||||
events.on(type, handler, true);
|
||||
events.on(type, weakHandler);
|
||||
|
||||
events.emit(type, { data: 1 });
|
||||
assert.equal(receivedFromStrong.length, 1, "strong listener invoked");
|
||||
assert.equal(receivedFromWeak.length, 1, "weak listener invoked");
|
||||
|
||||
loader.unload();
|
||||
events.emit(type, { data: 2 });
|
||||
|
||||
assert.equal(receivedFromWeak.length, 1, "weak listener was removed");
|
||||
assert.equal(receivedFromStrong.length, 1, "strong listener was removed");
|
||||
};
|
||||
|
||||
exports["test handle nsIObserverService notifications"] = function(assert) {
|
||||
let ios = Cc['@mozilla.org/network/io-service;1']
|
||||
.getService(Ci.nsIIOService);
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var runtime = require("sdk/system/runtime");
|
||||
const runtime = require("sdk/system/runtime");
|
||||
|
||||
exports["test system runtime"] = function(assert) {
|
||||
assert.equal(typeof(runtime.inSafeMode), "boolean",
|
||||
@ -14,7 +14,7 @@ exports["test system runtime"] = function(assert) {
|
||||
"runtime.processType is a number");
|
||||
assert.equal(typeof(runtime.widgetToolkit), "string",
|
||||
"runtime.widgetToolkit is string");
|
||||
var XPCOMABI = typeof(runtime.XPCOMABI);
|
||||
const XPCOMABI = runtime.XPCOMABI;
|
||||
assert.ok(XPCOMABI === null || typeof(XPCOMABI) === "string",
|
||||
"runtime.XPCOMABI is string or null if not supported by platform");
|
||||
};
|
||||
|
37
addon-sdk/source/test/test-system.js
Normal file
37
addon-sdk/source/test/test-system.js
Normal file
@ -0,0 +1,37 @@
|
||||
/* 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 runtime = require("sdk/system/runtime");
|
||||
const system = require("sdk/system");
|
||||
|
||||
exports["test system architecture and compiler"] = function(assert) {
|
||||
|
||||
if (system.architecture !== null) {
|
||||
assert.equal(
|
||||
runtime.XPCOMABI.indexOf(system.architecture), 0,
|
||||
"system.architecture is starting substring of runtime.XPCOMABI"
|
||||
);
|
||||
}
|
||||
|
||||
if (system.compiler !== null) {
|
||||
assert.equal(
|
||||
runtime.XPCOMABI.indexOf(system.compiler),
|
||||
runtime.XPCOMABI.length - system.compiler.length,
|
||||
"system.compiler is trailing substring of runtime.XPCOMABI"
|
||||
);
|
||||
}
|
||||
|
||||
assert.ok(
|
||||
system.architecture === null || typeof(system.architecture) === "string",
|
||||
"system.architecture is string or null if not supported by platform"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
system.compiler === null || typeof(system.compiler) === "string",
|
||||
"system.compiler is string or null if not supported by platform"
|
||||
);
|
||||
};
|
||||
|
||||
require("test").run(exports);
|
@ -835,6 +835,44 @@ exports['test button state are snapshot'] = function(assert) {
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
exports['test button icon object is a snapshot'] = function(assert) {
|
||||
let loader = Loader(module);
|
||||
let { ActionButton } = loader.require('sdk/ui');
|
||||
|
||||
let icon = {
|
||||
'16': './foo.png'
|
||||
};
|
||||
|
||||
let button = ActionButton({
|
||||
id: 'my-button-17',
|
||||
label: 'my button',
|
||||
icon: icon
|
||||
});
|
||||
|
||||
assert.deepEqual(button.icon, icon,
|
||||
'button.icon has the same properties of the object set in the constructor');
|
||||
|
||||
assert.notEqual(button.icon, icon,
|
||||
'button.icon is not the same object of the object set in the constructor');
|
||||
|
||||
assert.throws(
|
||||
() => button.icon[16] = './bar.png',
|
||||
/16 is read-only/,
|
||||
'properties of button.icon are ready-only'
|
||||
);
|
||||
|
||||
let newIcon = {'16': './bar.png'};
|
||||
button.icon = newIcon;
|
||||
|
||||
assert.deepEqual(button.icon, newIcon,
|
||||
'button.icon has the same properties of the object set');
|
||||
|
||||
assert.notEqual(button.icon, newIcon,
|
||||
'button.icon is not the same object of the object set');
|
||||
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
exports['test button after destroy'] = function(assert) {
|
||||
let loader = Loader(module);
|
||||
let { ActionButton } = loader.require('sdk/ui');
|
||||
|
@ -844,6 +844,44 @@ exports['test button state are snapshot'] = function(assert) {
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
exports['test button icon object is a snapshot'] = function(assert) {
|
||||
let loader = Loader(module);
|
||||
let { ToggleButton } = loader.require('sdk/ui');
|
||||
|
||||
let icon = {
|
||||
'16': './foo.png'
|
||||
};
|
||||
|
||||
let button = ToggleButton({
|
||||
id: 'my-button-17',
|
||||
label: 'my button',
|
||||
icon: icon
|
||||
});
|
||||
|
||||
assert.deepEqual(button.icon, icon,
|
||||
'button.icon has the same properties of the object set in the constructor');
|
||||
|
||||
assert.notEqual(button.icon, icon,
|
||||
'button.icon is not the same object of the object set in the constructor');
|
||||
|
||||
assert.throws(
|
||||
() => button.icon[16] = './bar.png',
|
||||
/16 is read-only/,
|
||||
'properties of button.icon are ready-only'
|
||||
);
|
||||
|
||||
let newIcon = {'16': './bar.png'};
|
||||
button.icon = newIcon;
|
||||
|
||||
assert.deepEqual(button.icon, newIcon,
|
||||
'button.icon has the same properties of the object set');
|
||||
|
||||
assert.notEqual(button.icon, newIcon,
|
||||
'button.icon is not the same object of the object set');
|
||||
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
exports['test button after destroy'] = function(assert) {
|
||||
let loader = Loader(module);
|
||||
let { ToggleButton } = loader.require('sdk/ui');
|
||||
|
@ -52,6 +52,10 @@ function checkDebuggerPort() {
|
||||
// DebuggerServer.openListener detects that it isn't a file path (string),
|
||||
// and starts listening on the tcp port given here as command line argument.
|
||||
|
||||
if (!window.arguments) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the command line arguments that were passed to the b2g client
|
||||
let args = window.arguments[0].QueryInterface(Ci.nsICommandLine);
|
||||
|
||||
|
@ -5,6 +5,10 @@
|
||||
|
||||
let runAppObj;
|
||||
window.addEventListener('load', function() {
|
||||
if (!window.arguments) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the command line arguments that were passed to the b2g client
|
||||
let args = window.arguments[0].QueryInterface(Ci.nsICommandLine);
|
||||
let appname;
|
||||
|
@ -57,12 +57,19 @@ window.addEventListener('ContentStart', function() {
|
||||
};
|
||||
|
||||
// Get the command line arguments that were passed to the b2g client
|
||||
let args = window.arguments[0].QueryInterface(Ci.nsICommandLine);
|
||||
let screenarg;
|
||||
let args;
|
||||
try {
|
||||
// On Firefox Mulet, we don't always have a command line argument
|
||||
args = window.arguments[0].QueryInterface(Ci.nsICommandLine);
|
||||
} catch(e) {}
|
||||
|
||||
let screenarg = null;
|
||||
|
||||
// Get the --screen argument from the command line
|
||||
try {
|
||||
screenarg = args.handleFlagWithParam('screen', false);
|
||||
if (args) {
|
||||
screenarg = args.handleFlagWithParam('screen', false);
|
||||
}
|
||||
|
||||
// If there isn't one, use the default screen
|
||||
if (screenarg === null)
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="52c909ccead537f8f9dbf634f3e6639078a8b0bd">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
|
||||
|
@ -18,7 +18,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "a54e097e9e3384d885c0116d9c4ca15c1e1cd75e",
|
||||
"revision": "c766bc0d49af19f18788ad8ed0542b82db81f1d8",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -183,7 +183,6 @@
|
||||
@BINPATH@/components/dom_notification.xpt
|
||||
@BINPATH@/components/dom_html.xpt
|
||||
@BINPATH@/components/dom_indexeddb.xpt
|
||||
@BINPATH@/components/dom_inputmethod.xpt
|
||||
@BINPATH@/components/dom_offline.xpt
|
||||
@BINPATH@/components/dom_payment.xpt
|
||||
@BINPATH@/components/dom_json.xpt
|
||||
@ -457,6 +456,8 @@
|
||||
@BINPATH@/components/nsPlacesDBFlush.js
|
||||
@BINPATH@/components/nsPlacesAutoComplete.manifest
|
||||
@BINPATH@/components/nsPlacesAutoComplete.js
|
||||
@BINPATH@/components/UnifiedComplete.manifest
|
||||
@BINPATH@/components/UnifiedComplete.js
|
||||
@BINPATH@/components/nsPlacesExpiration.js
|
||||
@BINPATH@/components/PlacesProtocolHandler.js
|
||||
@BINPATH@/components/PlacesCategoriesStarter.js
|
||||
|
@ -122,7 +122,6 @@ tabbrowser {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.tab-close-button,
|
||||
.tab-background {
|
||||
/* Explicitly set the visibility to override the value (collapsed)
|
||||
* we inherit from #TabsToolbar[collapsed] upon opening a browser window. */
|
||||
@ -131,15 +130,28 @@ tabbrowser {
|
||||
transition: visibility 0ms 25ms;
|
||||
}
|
||||
|
||||
.tab-close-button:not([fadein]):not([pinned]),
|
||||
.tab-background:not([fadein]):not([pinned]) {
|
||||
visibility: hidden;
|
||||
/* Closing tabs are hidden without a delay. */
|
||||
transition-delay: 0ms;
|
||||
}
|
||||
|
||||
.tab-close-button,
|
||||
.tab-label {
|
||||
/* Explicitly set the visibility to override the value (collapsed)
|
||||
* we inherit from #TabsToolbar[collapsed] upon opening a browser window. */
|
||||
visibility: visible;
|
||||
transition: opacity 70ms 230ms,
|
||||
visibility 0ms 230ms;
|
||||
}
|
||||
|
||||
.tab-close-button:not([fadein]):not([pinned]),
|
||||
.tab-label:not([fadein]):not([pinned]) {
|
||||
visibility: collapse;
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.tab-throbber:not([fadein]):not([pinned]),
|
||||
.tab-label:not([fadein]):not([pinned]),
|
||||
.tab-icon-image:not([fadein]):not([pinned]) {
|
||||
display: none;
|
||||
}
|
||||
|
@ -81,6 +81,10 @@
|
||||
Components.classes["@mozilla.org/autocomplete/search;1?name=history"]
|
||||
.getService(Components.interfaces.mozIPlacesAutoComplete);
|
||||
</field>
|
||||
<field name="_unifiedComplete" readonly="true">
|
||||
Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
|
||||
.getService(Components.interfaces.mozIPlacesAutoComplete);
|
||||
</field>
|
||||
<field name="mTabBox" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "tabbox");
|
||||
</field>
|
||||
@ -744,8 +748,10 @@
|
||||
}
|
||||
|
||||
let autocomplete = this.mTabBrowser._placesAutocomplete;
|
||||
let unifiedComplete = this.mTabBrowser._unifiedComplete;
|
||||
if (this.mBrowser.registeredOpenURI) {
|
||||
autocomplete.unregisterOpenPage(this.mBrowser.registeredOpenURI);
|
||||
unifiedComplete.unregisterOpenPage(this.mBrowser.registeredOpenURI);
|
||||
delete this.mBrowser.registeredOpenURI;
|
||||
}
|
||||
// Tabs in private windows aren't registered as "Open" so
|
||||
@ -754,6 +760,7 @@
|
||||
(!PrivateBrowsingUtils.isWindowPrivate(window) ||
|
||||
PrivateBrowsingUtils.permanentPrivateBrowsing)) {
|
||||
autocomplete.registerOpenPage(aLocation);
|
||||
unifiedComplete.registerOpenPage(aLocation);
|
||||
this.mBrowser.registeredOpenURI = aLocation;
|
||||
}
|
||||
}
|
||||
@ -1672,12 +1679,6 @@
|
||||
|
||||
// kick the animation off
|
||||
t.setAttribute("fadein", "true");
|
||||
|
||||
// This call to adjustTabstrip is redundant but needed so that
|
||||
// when opening a second tab, the first tab's close buttons
|
||||
// appears immediately rather than when the transition ends.
|
||||
if (this.tabs.length - this._removingTabs.length == 2)
|
||||
this.tabContainer.adjustTabstrip();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
@ -1863,13 +1864,6 @@
|
||||
aTab.style.maxWidth = ""; // ensure that fade-out transition happens
|
||||
aTab.removeAttribute("fadein");
|
||||
|
||||
if (this.tabs.length - this._removingTabs.length == 1) {
|
||||
// The second tab just got closed and we will end up with a single
|
||||
// one. Remove the first tab's close button immediately (if needed)
|
||||
// rather than after the tabclose animation ends.
|
||||
this.tabContainer.adjustTabstrip();
|
||||
}
|
||||
|
||||
setTimeout(function (tab, tabbrowser) {
|
||||
if (tab.parentNode &&
|
||||
window.getComputedStyle(tab).maxWidth == "0.1px") {
|
||||
@ -1969,6 +1963,7 @@
|
||||
|
||||
if (browser.registeredOpenURI && !aTabWillBeMoved) {
|
||||
this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI);
|
||||
this._unifiedComplete.unregisterOpenPage(browser.registeredOpenURI);
|
||||
delete browser.registeredOpenURI;
|
||||
}
|
||||
|
||||
@ -2295,6 +2290,7 @@
|
||||
// If the current URI is registered as open remove it from the list.
|
||||
if (aOurBrowser.registeredOpenURI) {
|
||||
this._placesAutocomplete.unregisterOpenPage(aOurBrowser.registeredOpenURI);
|
||||
this._unifiedComplete.unregisterOpenPage(aOurBrowser.registeredOpenURI);
|
||||
delete aOurBrowser.registeredOpenURI;
|
||||
}
|
||||
|
||||
@ -3104,6 +3100,7 @@
|
||||
let browser = this.getBrowserAtIndex(i);
|
||||
if (browser.registeredOpenURI) {
|
||||
this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI);
|
||||
this._unifiedComplete.unregisterOpenPage(browser.registeredOpenURI);
|
||||
delete browser.registeredOpenURI;
|
||||
}
|
||||
browser.webProgress.removeProgressListener(this.mTabFilters[i]);
|
||||
|
@ -68,6 +68,12 @@
|
||||
this.inputField.addEventListener("overflow", this, false);
|
||||
this.inputField.addEventListener("underflow", this, false);
|
||||
|
||||
try {
|
||||
if (this._prefs.getBoolPref("unifiedcomplete")) {
|
||||
this.setAttribute("autocompletesearch", "unifiedcomplete");
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
var textBox = document.getAnonymousElementByAttribute(this,
|
||||
"anonid", "textbox-input-box");
|
||||
@ -599,6 +605,14 @@
|
||||
case "trimURLs":
|
||||
this._mayTrimURLs = this._prefs.getBoolPref(aData);
|
||||
break;
|
||||
case "unifiedcomplete":
|
||||
let useUnifiedComplete = false;
|
||||
try {
|
||||
useUnifiedComplete = this._prefs.getBoolPref(aData);
|
||||
} catch (ex) {}
|
||||
this.setAttribute("autocompletesearch",
|
||||
useUnifiedComplete ? "unifiedcomplete"
|
||||
: "urlinline history");
|
||||
}
|
||||
}
|
||||
]]></body>
|
||||
|
@ -386,6 +386,13 @@ let CustomizableUIInternal = {
|
||||
gPlacements.set(aName, placements);
|
||||
}
|
||||
gFuturePlacements.delete(aName);
|
||||
let existingAreaNodes = gBuildAreas.get(aName);
|
||||
if (existingAreaNodes) {
|
||||
for (let areaNode of existingAreaNodes) {
|
||||
this.notifyListeners("onAreaNodeUnregistered", aName, areaNode.customizationTarget,
|
||||
CustomizableUI.REASON_AREA_UNREGISTERED);
|
||||
}
|
||||
}
|
||||
gBuildAreas.delete(aName);
|
||||
} finally {
|
||||
this.endBatchUpdate(true);
|
||||
@ -458,6 +465,7 @@ let CustomizableUIInternal = {
|
||||
if (gDirtyAreaCache.has(area)) {
|
||||
this.buildArea(area, placements, aToolbar);
|
||||
}
|
||||
this.notifyListeners("onAreaNodeRegistered", area, aToolbar.customizationTarget);
|
||||
aToolbar.setAttribute("currentset", placements.join(","));
|
||||
} finally {
|
||||
this.endBatchUpdate();
|
||||
@ -699,6 +707,8 @@ let CustomizableUIInternal = {
|
||||
|
||||
let placements = gPlacements.get(CustomizableUI.AREA_PANEL);
|
||||
this.buildArea(CustomizableUI.AREA_PANEL, placements, aPanelContents);
|
||||
this.notifyListeners("onAreaNodeRegistered", CustomizableUI.AREA_PANEL, aPanelContents);
|
||||
|
||||
for (let child of aPanelContents.children) {
|
||||
if (child.localName != "toolbarbutton") {
|
||||
if (child.localName == "toolbaritem") {
|
||||
@ -839,6 +849,8 @@ let CustomizableUIInternal = {
|
||||
let areaProperties = gAreas.get(areaId);
|
||||
for (let node of areaNodes) {
|
||||
if (node.ownerDocument == document) {
|
||||
this.notifyListeners("onAreaNodeUnregistered", areaId, node.customizationTarget,
|
||||
CustomizableUI.REASON_WINDOW_CLOSED);
|
||||
if (areaProperties.has("overflowable")) {
|
||||
node.overflowable.uninit();
|
||||
node.overflowable = null;
|
||||
@ -2502,6 +2514,17 @@ this.CustomizableUI = {
|
||||
*/
|
||||
get PANEL_COLUMN_COUNT() 3,
|
||||
|
||||
/**
|
||||
* Constant indicating the reason the event was fired was a window closing
|
||||
*/
|
||||
get REASON_WINDOW_CLOSED() "window-closed",
|
||||
/**
|
||||
* Constant indicating the reason the event was fired was an area being
|
||||
* unregistered separately from window closing mechanics.
|
||||
*/
|
||||
get REASON_AREA_UNREGISTERED() "area-unregistered",
|
||||
|
||||
|
||||
/**
|
||||
* An iteratable property of windows managed by CustomizableUI.
|
||||
* Note that this can *only* be used as an iterator. ie:
|
||||
@ -2603,6 +2626,15 @@ this.CustomizableUI = {
|
||||
* - onWindowClosed(aWindow)
|
||||
* Fired when a window that has been managed by CustomizableUI has been
|
||||
* closed.
|
||||
* - onAreaNodeRegistered(aArea, aContainer)
|
||||
* Fired after an area node is first built when it is registered. This
|
||||
* is often when the window has opened, but in the case of add-ons,
|
||||
* could fire when the node has just been registered with CustomizableUI
|
||||
* after an add-on update or disable/enable sequence.
|
||||
* - onAreaNodeUnregistered(aArea, aContainer, aReason)
|
||||
* Fired when an area node is explicitly unregistered by an API caller,
|
||||
* or by a window closing. The aReason parameter indicates which of
|
||||
* these is the case.
|
||||
*/
|
||||
addListener: function(aListener) {
|
||||
CustomizableUIInternal.addListener(aListener);
|
||||
|
@ -236,11 +236,7 @@ CustomizeMode.prototype = {
|
||||
yield this._wrapToolbarItems();
|
||||
this.populatePalette();
|
||||
|
||||
this.visiblePalette.addEventListener("dragstart", this, true);
|
||||
this.visiblePalette.addEventListener("dragover", this, true);
|
||||
this.visiblePalette.addEventListener("dragexit", this, true);
|
||||
this.visiblePalette.addEventListener("drop", this, true);
|
||||
this.visiblePalette.addEventListener("dragend", this, true);
|
||||
this._addDragHandlers(this.visiblePalette);
|
||||
|
||||
window.gNavToolbox.addEventListener("toolbarvisibilitychange", this);
|
||||
|
||||
@ -402,11 +398,7 @@ CustomizeMode.prototype = {
|
||||
window.gNavToolbox.removeEventListener("toolbarvisibilitychange", this);
|
||||
|
||||
DragPositionManager.stop();
|
||||
this.visiblePalette.removeEventListener("dragstart", this, true);
|
||||
this.visiblePalette.removeEventListener("dragover", this, true);
|
||||
this.visiblePalette.removeEventListener("dragexit", this, true);
|
||||
this.visiblePalette.removeEventListener("drop", this, true);
|
||||
this.visiblePalette.removeEventListener("dragend", this, true);
|
||||
this._removeDragHandlers(this.visiblePalette);
|
||||
|
||||
yield this._unwrapToolbarItems();
|
||||
|
||||
@ -900,11 +892,7 @@ CustomizeMode.prototype = {
|
||||
this.areas = [];
|
||||
for (let area of CustomizableUI.areas) {
|
||||
let target = CustomizableUI.getCustomizeTargetForArea(area, window);
|
||||
target.addEventListener("dragstart", this, true);
|
||||
target.addEventListener("dragover", this, true);
|
||||
target.addEventListener("dragexit", this, true);
|
||||
target.addEventListener("drop", this, true);
|
||||
target.addEventListener("dragend", this, true);
|
||||
this._addDragHandlers(target);
|
||||
for (let child of target.children) {
|
||||
if (this.isCustomizableItem(child)) {
|
||||
yield this.deferredWrapToolbarItem(child, CustomizableUI.getPlaceForItem(child));
|
||||
@ -915,6 +903,14 @@ CustomizeMode.prototype = {
|
||||
}.bind(this)).then(null, ERROR);
|
||||
},
|
||||
|
||||
_addDragHandlers: function(aTarget) {
|
||||
aTarget.addEventListener("dragstart", this, true);
|
||||
aTarget.addEventListener("dragover", this, true);
|
||||
aTarget.addEventListener("dragexit", this, true);
|
||||
aTarget.addEventListener("drop", this, true);
|
||||
aTarget.addEventListener("dragend", this, true);
|
||||
},
|
||||
|
||||
_wrapItemsInArea: function(target) {
|
||||
for (let child of target.children) {
|
||||
if (this.isCustomizableItem(child)) {
|
||||
@ -923,6 +919,14 @@ CustomizeMode.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_removeDragHandlers: function(aTarget) {
|
||||
aTarget.removeEventListener("dragstart", this, true);
|
||||
aTarget.removeEventListener("dragover", this, true);
|
||||
aTarget.removeEventListener("dragexit", this, true);
|
||||
aTarget.removeEventListener("drop", this, true);
|
||||
aTarget.removeEventListener("dragend", this, true);
|
||||
},
|
||||
|
||||
_unwrapItemsInArea: function(target) {
|
||||
for (let toolbarItem of target.children) {
|
||||
if (this.isWrappedToolbarItem(toolbarItem)) {
|
||||
@ -939,11 +943,7 @@ CustomizeMode.prototype = {
|
||||
yield this.deferredUnwrapToolbarItem(toolbarItem);
|
||||
}
|
||||
}
|
||||
target.removeEventListener("dragstart", this, true);
|
||||
target.removeEventListener("dragover", this, true);
|
||||
target.removeEventListener("dragexit", this, true);
|
||||
target.removeEventListener("drop", this, true);
|
||||
target.removeEventListener("dragend", this, true);
|
||||
this._removeDragHandlers(target);
|
||||
}
|
||||
}.bind(this)).then(null, ERROR);
|
||||
},
|
||||
@ -1118,6 +1118,25 @@ CustomizeMode.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
onAreaNodeRegistered: function(aArea, aContainer) {
|
||||
if (aContainer.ownerDocument == this.document) {
|
||||
this._wrapItemsInArea(aContainer);
|
||||
this._addDragHandlers(aContainer);
|
||||
DragPositionManager.add(this.window, aArea, aContainer);
|
||||
this.areas.push(aContainer);
|
||||
}
|
||||
},
|
||||
|
||||
onAreaNodeUnregistered: function(aArea, aContainer, aReason) {
|
||||
if (aContainer.ownerDocument == this.document && aReason == CustomizableUI.REASON_AREA_UNREGISTERED) {
|
||||
this._unwrapItemsInArea(aContainer);
|
||||
this._removeDragHandlers(aContainer);
|
||||
DragPositionManager.remove(this.window, aArea, aContainer);
|
||||
let index = this.areas.indexOf(aContainer);
|
||||
this.areas.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
_onUIChange: function() {
|
||||
this._changed = true;
|
||||
if (!this.resetting) {
|
||||
|
@ -393,6 +393,22 @@ let DragPositionManager = {
|
||||
}
|
||||
},
|
||||
|
||||
add: function(aWindow, aArea, aContainer) {
|
||||
if (CustomizableUI.getAreaType(aArea) != "toolbar") {
|
||||
return;
|
||||
}
|
||||
|
||||
gManagers.set(aContainer, new AreaPositionManager(aContainer));
|
||||
},
|
||||
|
||||
remove: function(aWindow, aArea, aContainer) {
|
||||
if (CustomizableUI.getAreaType(aArea) != "toolbar") {
|
||||
return;
|
||||
}
|
||||
|
||||
gManagers.delete(aContainer);
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
gManagers.clear();
|
||||
},
|
||||
|
@ -104,5 +104,6 @@ skip-if = os == "linux"
|
||||
[browser_987492_window_api.js]
|
||||
[browser_992747_toggle_noncustomizable_toolbar.js]
|
||||
[browser_993322_widget_notoolbar.js]
|
||||
[browser_995164_registerArea_during_customize_mode.js]
|
||||
[browser_bootstrapped_custom_toolbar.js]
|
||||
[browser_panel_toggle.js]
|
||||
|
@ -31,4 +31,6 @@ add_task(function*() {
|
||||
|
||||
CustomizableUI.destroyWidget(BUTTONID);
|
||||
CustomizableUI.unregisterArea(TOOLBARID, true);
|
||||
toolbar.remove();
|
||||
gAddedToolbars.clear();
|
||||
});
|
||||
|
@ -0,0 +1,113 @@
|
||||
/* 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 TOOLBARID = "test-toolbar-added-during-customize-mode";
|
||||
|
||||
add_task(function*() {
|
||||
yield startCustomizing();
|
||||
let toolbar = createToolbarWithPlacements(TOOLBARID, []);
|
||||
CustomizableUI.addWidgetToArea("sync-button", TOOLBARID);
|
||||
let syncButton = document.getElementById("sync-button");
|
||||
ok(syncButton, "Sync button should exist.");
|
||||
is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should be a wrapper.");
|
||||
|
||||
simulateItemDrag(syncButton, gNavToolbox.palette);
|
||||
ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette");
|
||||
ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette.");
|
||||
|
||||
simulateItemDrag(syncButton, toolbar);
|
||||
ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
|
||||
is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
|
||||
ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
|
||||
|
||||
yield endCustomizing();
|
||||
isnot(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should not be a wrapper outside customize mode.");
|
||||
yield startCustomizing();
|
||||
|
||||
is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should be a wrapper back in customize mode.");
|
||||
|
||||
simulateItemDrag(syncButton, gNavToolbox.palette);
|
||||
ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette");
|
||||
ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette.");
|
||||
|
||||
ok(!CustomizableUI.inDefaultState, "Not in default state while toolbar is not collapsed yet.");
|
||||
setToolbarVisibility(toolbar, false);
|
||||
ok(CustomizableUI.inDefaultState, "In default state while toolbar is collapsed.");
|
||||
|
||||
setToolbarVisibility(toolbar, true);
|
||||
|
||||
info("Check that removing the area registration from within customize mode works");
|
||||
CustomizableUI.unregisterArea(TOOLBARID);
|
||||
ok(CustomizableUI.inDefaultState, "Now that the toolbar is no longer registered, should be in default state.");
|
||||
ok(!(new Set(gCustomizeMode.areas)).has(toolbar), "Toolbar shouldn't be known to customize mode.");
|
||||
|
||||
CustomizableUI.registerArea(TOOLBARID, {legacy: true, defaultPlacements: []});
|
||||
CustomizableUI.registerToolbarNode(toolbar, []);
|
||||
ok(!CustomizableUI.inDefaultState, "Now that the toolbar is registered again, should no longer be in default state.");
|
||||
ok((new Set(gCustomizeMode.areas)).has(toolbar), "Toolbar should be known to customize mode again.");
|
||||
|
||||
simulateItemDrag(syncButton, toolbar);
|
||||
ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
|
||||
is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
|
||||
ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
|
||||
|
||||
let otherWin = yield openAndLoadWindow({}, true);
|
||||
let otherTB = otherWin.document.createElementNS(kNSXUL, "toolbar");
|
||||
otherTB.id = TOOLBARID;
|
||||
otherTB.setAttribute("customizable", "true");
|
||||
otherWin.gNavToolbox.appendChild(otherTB);
|
||||
ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
|
||||
|
||||
simulateItemDrag(syncButton, gNavToolbox.palette);
|
||||
ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette");
|
||||
ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette.");
|
||||
ok(!otherTB.querySelector("#sync-button"), "Sync button is in palette in other window, too.");
|
||||
|
||||
simulateItemDrag(syncButton, toolbar);
|
||||
ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
|
||||
is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
|
||||
ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
|
||||
ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
|
||||
|
||||
let wasInformedCorrectlyOfAreaDisappearing = false;
|
||||
let listener = {
|
||||
onAreaNodeUnregistered: function(aArea, aNode, aReason) {
|
||||
if (aArea == TOOLBARID) {
|
||||
is(aNode, otherTB, "Should be informed about other toolbar");
|
||||
is(aReason, CustomizableUI.REASON_WINDOW_CLOSED, "Reason should be correct.");
|
||||
wasInformedCorrectlyOfAreaDisappearing = (aReason === CustomizableUI.REASON_WINDOW_CLOSED);
|
||||
}
|
||||
}
|
||||
};
|
||||
CustomizableUI.addListener(listener);
|
||||
yield promiseWindowClosed(otherWin);
|
||||
|
||||
ok(wasInformedCorrectlyOfAreaDisappearing, "Should be told about window closing.");
|
||||
CustomizableUI.removeListener(listener);
|
||||
// Closing the other window should not be counted against this window's customize mode:
|
||||
is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should still be a wrapper.");
|
||||
isnot(gCustomizeMode.areas.indexOf(toolbar), -1, "Toolbar should still be a customizable area for this customize mode instance.");
|
||||
|
||||
yield gCustomizeMode.reset();
|
||||
|
||||
yield endCustomizing();
|
||||
|
||||
wasInformedCorrectlyOfAreaDisappearing = false;
|
||||
listener = {
|
||||
onAreaNodeUnregistered: function(aArea, aNode, aReason) {
|
||||
if (aArea == TOOLBARID) {
|
||||
is(aNode, toolbar, "Should be informed about this window's toolbar");
|
||||
is(aReason, CustomizableUI.REASON_AREA_UNREGISTERED, "Reason for final removal should be correct.");
|
||||
wasInformedCorrectlyOfAreaDisappearing = (aReason === CustomizableUI.REASON_AREA_UNREGISTERED);
|
||||
}
|
||||
},
|
||||
}
|
||||
CustomizableUI.addListener(listener);
|
||||
removeCustomToolbars();
|
||||
ok(wasInformedCorrectlyOfAreaDisappearing, "Should be told about area being unregistered.");
|
||||
CustomizableUI.removeListener(listener);
|
||||
ok(CustomizableUI.inDefaultState, "Should be fine after exiting customize mode.");
|
||||
});
|
@ -145,6 +145,8 @@ skip-if = true
|
||||
[browser_590268.js]
|
||||
[browser_590563.js]
|
||||
[browser_595601-restore_hidden.js]
|
||||
[browser_597071.js]
|
||||
skip-if = true # Needs to be rewritten as Marionette test, bug 995916
|
||||
[browser_599909.js]
|
||||
[browser_600545.js]
|
||||
[browser_601955.js]
|
||||
@ -184,8 +186,6 @@ skip-if = true
|
||||
skip-if = true
|
||||
|
||||
# Disabled on OS X:
|
||||
[browser_597071.js]
|
||||
skip-if = os == "mac" || e10s
|
||||
[browser_625016.js]
|
||||
skip-if = os == "mac" || e10s
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* 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/. */
|
||||
|
||||
const stateBackup = ss.getBrowserState();
|
||||
const stateBackup = JSON.parse(ss.getBrowserState());
|
||||
const testState = {
|
||||
windows: [{
|
||||
tabs: [
|
||||
@ -76,8 +76,7 @@ function runNextTest() {
|
||||
});
|
||||
}
|
||||
else {
|
||||
ss.setBrowserState(stateBackup);
|
||||
finish();
|
||||
waitForBrowserState(stateBackup, finish);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,7 +203,6 @@
|
||||
@BINPATH@/components/dom_notification.xpt
|
||||
@BINPATH@/components/dom_html.xpt
|
||||
@BINPATH@/components/dom_indexeddb.xpt
|
||||
@BINPATH@/components/dom_inputmethod.xpt
|
||||
@BINPATH@/components/dom_offline.xpt
|
||||
@BINPATH@/components/dom_json.xpt
|
||||
@BINPATH@/components/dom_power.xpt
|
||||
@ -430,6 +429,8 @@
|
||||
@BINPATH@/components/nsTaggingService.js
|
||||
@BINPATH@/components/nsPlacesAutoComplete.manifest
|
||||
@BINPATH@/components/nsPlacesAutoComplete.js
|
||||
@BINPATH@/components/UnifiedComplete.manifest
|
||||
@BINPATH@/components/UnifiedComplete.js
|
||||
@BINPATH@/components/nsPlacesExpiration.js
|
||||
@BINPATH@/browser/components/PlacesProtocolHandler.js
|
||||
@BINPATH@/components/PlacesCategoriesStarter.js
|
||||
|
@ -88,7 +88,7 @@
|
||||
margin-top: @windowButtonMarginTop@;
|
||||
}
|
||||
|
||||
#main-window[customizing] > #titlebar {
|
||||
#main-window[customize-entered] > #titlebar {
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
@ -2847,6 +2847,16 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
padding: 6px 0 4px;
|
||||
}
|
||||
|
||||
/* Background tabs:
|
||||
*
|
||||
* Decrease the height of the hoverable region of background tabs whenever the tabs are at the top
|
||||
* of the window (e.g. no menubar, tabs in titlebar, etc.) to make it easier to drag the window by
|
||||
* the titlebar. We don't need this in fullscreen since window dragging is not an issue there.
|
||||
*/
|
||||
#main-window[tabsintitlebar]:not([inFullscreen]) .tab-background-middle:not([selected=true]) {
|
||||
clip-path: url(chrome://browser/content/browser.xul#tab-hover-clip-path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab Drag and Drop
|
||||
*/
|
||||
|
@ -226,20 +226,6 @@
|
||||
|
||||
/* End selected tab */
|
||||
|
||||
/* Background tabs */
|
||||
|
||||
/* Decrease the height of the hoverable region of background tabs whenever the tabs are at the top
|
||||
of the window (e.g. no menubar, tabs in titlebar, etc.) to make it easier to drag the window by
|
||||
the titlebar. We don't need this in fullscreen since window dragging is not an issue there. */
|
||||
%ifdef XP_MACOSX
|
||||
#main-window[tabsintitlebar][sizemode="maximized"] .tab-background-middle:not([selected=true]),
|
||||
%endif
|
||||
#main-window[tabsintitlebar]:not([sizemode="maximized"]):not([inFullscreen]) #toolbar-menubar:-moz-any([autohide="true"][inactive], :not([autohide])) + #TabsToolbar .tab-background-middle:not([selected=true]) {
|
||||
clip-path: url(chrome://browser/content/browser.xul#tab-hover-clip-path);
|
||||
}
|
||||
|
||||
/* End background tabs */
|
||||
|
||||
/* new tab button border and gradient on hover */
|
||||
.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
|
||||
.tabs-newtab-button:hover {
|
||||
|
@ -1902,6 +1902,16 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
||||
outline: 1px dotted;
|
||||
}
|
||||
|
||||
/* Background tabs:
|
||||
*
|
||||
* Decrease the height of the hoverable region of background tabs whenever the tabs are at the top
|
||||
* of the window (e.g. no menubar, tabs in titlebar, etc.) to make it easier to drag the window by
|
||||
* the titlebar. We don't need this in fullscreen since window dragging is not an issue there.
|
||||
*/
|
||||
#main-window[tabsintitlebar][sizemode=normal] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar .tab-background-middle:not([selected=true]) {
|
||||
clip-path: url(chrome://browser/content/browser.xul#tab-hover-clip-path);
|
||||
}
|
||||
|
||||
/* Tab DnD indicator */
|
||||
.tab-drop-indicator {
|
||||
list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png);
|
||||
|
@ -57,6 +57,25 @@ extern bool gBluetoothDebugFlag;
|
||||
#define BT_WARNING(msg, ...) printf("%s: " msg, __FUNCTION__, ##__VA_ARGS__))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Wrap literal name and value into a BluetoothNamedValue
|
||||
* and append it to the array.
|
||||
*/
|
||||
#define BT_APPEND_NAMED_VALUE(array, name, value) \
|
||||
array.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING(name), value))
|
||||
|
||||
/**
|
||||
* Ensure success of system message broadcast with void return.
|
||||
*/
|
||||
#define BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters) \
|
||||
do { \
|
||||
if (!BroadcastSystemMessage(type, parameters)) { \
|
||||
BT_WARNING("Failed to broadcast [%s]", \
|
||||
NS_ConvertUTF16toUTF8(type).get()); \
|
||||
return; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define BEGIN_BLUETOOTH_NAMESPACE \
|
||||
namespace mozilla { namespace dom { namespace bluetooth {
|
||||
#define END_BLUETOOTH_NAMESPACE \
|
||||
|
@ -241,18 +241,10 @@ BluetoothHidManager::NotifyStatusChanged()
|
||||
NS_NAMED_LITERAL_STRING(type, BLUETOOTH_HID_STATUS_CHANGED_ID);
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
|
||||
BluetoothValue v = mConnected;
|
||||
parameters.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("connected"), v));
|
||||
BT_APPEND_NAMED_VALUE(parameters, "connected", mConnected);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
|
||||
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("address"), v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to broadcast system message to settings");
|
||||
return;
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -266,8 +266,7 @@ A2dpConnectionStateCallback(btav_connection_state_t aState,
|
||||
AvStatusToSinkString(aState, a2dpState);
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> props;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("State"), a2dpState));
|
||||
BT_APPEND_NAMED_VALUE(props, "State", a2dpState);
|
||||
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("AudioSink"),
|
||||
remoteDeviceBdAddress, props);
|
||||
@ -296,8 +295,7 @@ A2dpAudioStateCallback(btav_audio_state_t aState,
|
||||
}
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> props;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("State"), a2dpState));
|
||||
BT_APPEND_NAMED_VALUE(props, "State", a2dpState);
|
||||
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("AudioSink"),
|
||||
remoteDeviceBdAddress, props);
|
||||
|
@ -1265,39 +1265,17 @@ BluetoothOppManager::FileTransferComplete()
|
||||
return;
|
||||
}
|
||||
|
||||
nsString type, name;
|
||||
BluetoothValue v;
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-opp-transfer-complete");
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
type.AssignLiteral("bluetooth-opp-transfer-complete");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "success", mSuccessFlag);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "received", mIsServer);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileName", mFileName);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileLength", mSentFileLength);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "contentType", mContentType);
|
||||
|
||||
name.AssignLiteral("success");
|
||||
v = mSuccessFlag;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("received");
|
||||
v = mIsServer;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileName");
|
||||
v = mFileName;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileLength");
|
||||
v = mSentFileLength;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("contentType");
|
||||
v = mContentType;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to broadcast [bluetooth-opp-transfer-complete]");
|
||||
return;
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
|
||||
mSendTransferCompleteFlag = true;
|
||||
}
|
||||
@ -1305,35 +1283,16 @@ BluetoothOppManager::FileTransferComplete()
|
||||
void
|
||||
BluetoothOppManager::StartFileTransfer()
|
||||
{
|
||||
nsString type, name;
|
||||
BluetoothValue v;
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-opp-transfer-start");
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
type.AssignLiteral("bluetooth-opp-transfer-start");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "received", mIsServer);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileName", mFileName);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileLength", mFileLength);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "contentType", mContentType);
|
||||
|
||||
name.AssignLiteral("received");
|
||||
v = mIsServer;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileName");
|
||||
v = mFileName;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileLength");
|
||||
v = mFileLength;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("contentType");
|
||||
v = mContentType;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to broadcast [bluetooth-opp-transfer-start]");
|
||||
return;
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
|
||||
mSendTransferCompleteFlag = false;
|
||||
}
|
||||
@ -1341,61 +1300,29 @@ BluetoothOppManager::StartFileTransfer()
|
||||
void
|
||||
BluetoothOppManager::UpdateProgress()
|
||||
{
|
||||
nsString type, name;
|
||||
BluetoothValue v;
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-opp-update-progress");
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
type.AssignLiteral("bluetooth-opp-update-progress");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "received", mIsServer);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "processedLength", mSentFileLength);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileLength", mFileLength);
|
||||
|
||||
name.AssignLiteral("received");
|
||||
v = mIsServer;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("processedLength");
|
||||
v = mSentFileLength;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileLength");
|
||||
v = mFileLength;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to broadcast [bluetooth-opp-update-progress]");
|
||||
return;
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::ReceivingFileConfirmation()
|
||||
{
|
||||
nsString type, name;
|
||||
BluetoothValue v;
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-opp-receiving-file-confirmation");
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
type.AssignLiteral("bluetooth-opp-receiving-file-confirmation");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileName", mFileName);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileLength", mFileLength);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "contentType", mContentType);
|
||||
|
||||
name.AssignLiteral("fileName");
|
||||
v = mFileName;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileLength");
|
||||
v = mFileLength;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("contentType");
|
||||
v = mContentType;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to send [bluetooth-opp-receiving-file-confirmation]");
|
||||
return;
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -294,15 +294,13 @@ AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
|
||||
if (p.type == BT_PROPERTY_BDADDR) {
|
||||
BdAddressTypeToString((bt_bdaddr_t*)p.val, sAdapterBdAddress);
|
||||
propertyValue = sAdapterBdAddress;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Address"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "Address", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_BDNAME) {
|
||||
// Construct nsCString here because Bd name returned from bluedroid
|
||||
// is missing a null terminated character after SetProperty.
|
||||
propertyValue = sAdapterBdName = NS_ConvertUTF8toUTF16(
|
||||
nsCString((char*)p.val, p.len));
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_ADAPTER_SCAN_MODE) {
|
||||
bt_scan_mode_t newMode = *(bt_scan_mode_t*)p.val;
|
||||
|
||||
@ -312,13 +310,10 @@ AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
|
||||
propertyValue = sAdapterDiscoverable = false;
|
||||
}
|
||||
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Discoverable"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "Discoverable", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) {
|
||||
propertyValue = sAdapterDiscoverableTimeout = *(uint32_t*)p.val;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("DiscoverableTimeout"),
|
||||
propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) {
|
||||
// We have to cache addresses of bonded devices. Unlike BlueZ,
|
||||
// bluedroid would not send an another BT_PROPERTY_ADAPTER_BONDED_DEVICES
|
||||
@ -337,8 +332,7 @@ AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
|
||||
}
|
||||
|
||||
propertyValue = sAdapterBondedAddressArray;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Devices"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "Devices", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_UUIDS) {
|
||||
//FIXME: This will be implemented in the later patchset
|
||||
continue;
|
||||
@ -389,25 +383,21 @@ RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress,
|
||||
|
||||
nsString remoteDeviceBdAddress;
|
||||
BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Address"), remoteDeviceBdAddress));
|
||||
BT_APPEND_NAMED_VALUE(props, "Address", remoteDeviceBdAddress);
|
||||
|
||||
for (int i = 0; i < aNumProperties; ++i) {
|
||||
bt_property_t p = aProperties[i];
|
||||
|
||||
if (p.type == BT_PROPERTY_BDNAME) {
|
||||
BluetoothValue propertyValue = NS_ConvertUTF8toUTF16((char*)p.val);
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
|
||||
uint32_t cod = *(uint32_t*)p.val;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Class"), BluetoothValue(cod)));
|
||||
BT_APPEND_NAMED_VALUE(props, "Class", cod);
|
||||
|
||||
nsString icon;
|
||||
ClassToIcon(cod, icon);
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Icon"), BluetoothValue(icon)));
|
||||
BT_APPEND_NAMED_VALUE(props, "Icon", icon);
|
||||
} else {
|
||||
BT_LOGD("Other non-handled device properties. Type: %d", p.type);
|
||||
}
|
||||
@ -460,22 +450,20 @@ DeviceFoundCallback(int aNumProperties, bt_property_t *aProperties)
|
||||
nsString remoteDeviceBdAddress;
|
||||
BdAddressTypeToString((bt_bdaddr_t*)p.val, remoteDeviceBdAddress);
|
||||
propertyValue = remoteDeviceBdAddress;
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Address"), propertyValue));
|
||||
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Address", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_BDNAME) {
|
||||
propertyValue = NS_ConvertUTF8toUTF16((char*)p.val);
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Name", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
|
||||
uint32_t cod = *(uint32_t*)p.val;
|
||||
propertyValue = cod;
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Class"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Class", propertyValue);
|
||||
|
||||
nsString icon;
|
||||
ClassToIcon(cod, icon);
|
||||
propertyValue = icon;
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Icon"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Icon", propertyValue);
|
||||
} else {
|
||||
BT_LOGD("Not handled remote device property: %d", p.type);
|
||||
}
|
||||
@ -515,15 +503,12 @@ PinRequestCallback(bt_bdaddr_t* aRemoteBdAddress,
|
||||
nsAutoString remoteAddress;
|
||||
BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
|
||||
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("address"), remoteAddress));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("method"),
|
||||
NS_LITERAL_STRING("pincode")));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("name"),
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "method",
|
||||
NS_LITERAL_STRING("pincode"));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "name",
|
||||
NS_ConvertUTF8toUTF16(
|
||||
(const char*)aRemoteBdName->name)));
|
||||
(const char*)aRemoteBdName->name));
|
||||
|
||||
BluetoothValue value = propertiesArray;
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("RequestPinCode"),
|
||||
@ -546,17 +531,13 @@ SspRequestCallback(bt_bdaddr_t* aRemoteBdAddress, bt_bdname_t* aRemoteBdName,
|
||||
nsAutoString remoteAddress;
|
||||
BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
|
||||
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("address"), remoteAddress));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("method"),
|
||||
NS_LITERAL_STRING("confirmation")));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("name"),
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "method",
|
||||
NS_LITERAL_STRING("confirmation"));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "name",
|
||||
NS_ConvertUTF8toUTF16(
|
||||
(const char*)aRemoteBdName->name)));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("passkey"), aPasskey));
|
||||
(const char*)aRemoteBdName->name));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", aPasskey);
|
||||
|
||||
BluetoothValue value = propertiesArray;
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("RequestConfirmation"),
|
||||
@ -592,9 +573,9 @@ BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
|
||||
|
||||
// Update bonded address list to BluetoothAdapter
|
||||
InfallibleTArray<BluetoothNamedValue> propertiesChangeArray;
|
||||
propertiesChangeArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Devices"),
|
||||
sAdapterBondedAddressArray));
|
||||
BT_APPEND_NAMED_VALUE(propertiesChangeArray, "Devices",
|
||||
sAdapterBondedAddressArray);
|
||||
|
||||
BluetoothValue value(propertiesChangeArray);
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
@ -603,10 +584,9 @@ BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
|
||||
|
||||
// Update bonding status to gaia
|
||||
InfallibleTArray<BluetoothNamedValue> propertiesArray;
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("address"), remoteAddress));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("status"), bonded));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded);
|
||||
|
||||
BluetoothSignal newSignal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
BluetoothValue(propertiesArray));
|
||||
@ -796,23 +776,20 @@ BluetoothServiceBluedroid::GetDefaultAdapterPathInternal(
|
||||
|
||||
BluetoothValue v = InfallibleTArray<BluetoothNamedValue>();
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue().AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Address"), sAdapterBdAddress));
|
||||
BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
|
||||
"Address", sAdapterBdAddress);
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue().AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Name"), sAdapterBdName));
|
||||
BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
|
||||
"Name", sAdapterBdName);
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue().AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Discoverable"),
|
||||
sAdapterDiscoverable));
|
||||
BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
|
||||
"Discoverable", sAdapterDiscoverable);
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue().AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("DiscoverableTimeout"),
|
||||
sAdapterDiscoverableTimeout));
|
||||
BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
|
||||
"DiscoverableTimeout", sAdapterDiscoverableTimeout);
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue().AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Devices"),
|
||||
sAdapterBondedAddressArray));
|
||||
BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
|
||||
"Devices", sAdapterBondedAddressArray);
|
||||
|
||||
nsAutoString replyError;
|
||||
DispatchBluetoothReply(runnable.get(), v, replyError);
|
||||
|
@ -176,10 +176,8 @@ DispatchStatusChangedEvent(const nsAString& aType,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> data;
|
||||
data.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("address"), nsString(aAddress)));
|
||||
data.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("status"), aStatus));
|
||||
BT_APPEND_NAMED_VALUE(data, "address", nsString(aAddress));
|
||||
BT_APPEND_NAMED_VALUE(data, "status", aStatus);
|
||||
|
||||
BluetoothSignal signal(nsString(aType), NS_LITERAL_STRING(KEY_ADAPTER), data);
|
||||
|
||||
|
@ -811,18 +811,12 @@ BluetoothHfpManager::NotifyConnectionStateChanged(const nsAString& aType)
|
||||
void
|
||||
BluetoothHfpManager::NotifyDialer(const nsAString& aCommand)
|
||||
{
|
||||
BluetoothValue v;
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-dialer-command");
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-dialer-command");
|
||||
NS_NAMED_LITERAL_STRING(name, "command");
|
||||
BT_APPEND_NAMED_VALUE(parameters, "command", nsString(aCommand));
|
||||
|
||||
v = nsString(aCommand);
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to broadcast system message to dialer");
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1,6 +1,2 @@
|
||||
component {397a7fdf-2254-47be-b74e-76625a1a66d5} MozKeyboard.js
|
||||
contract @mozilla.org/b2g-keyboard;1 {397a7fdf-2254-47be-b74e-76625a1a66d5}
|
||||
category JavaScript-navigator-property mozKeyboard @mozilla.org/b2g-keyboard;1
|
||||
|
||||
component {4607330d-e7d2-40a4-9eb8-43967eae0142} MozKeyboard.js
|
||||
contract @mozilla.org/b2g-inputmethod;1 {4607330d-e7d2-40a4-9eb8-43967eae0142}
|
||||
|
@ -27,7 +27,6 @@ this.Keyboard = {
|
||||
],
|
||||
|
||||
_messageNames: [
|
||||
'SetValue', 'RemoveFocus', 'SetSelectedOption', 'SetSelectedOptions',
|
||||
'SetSelectionRange', 'ReplaceSurroundingText', 'ShowInputMethodPicker',
|
||||
'SwitchToNextInputMethod', 'HideInputMethod',
|
||||
'GetText', 'SendKey', 'GetContext',
|
||||
@ -170,7 +169,6 @@ this.Keyboard = {
|
||||
this.forwardEvent(name, msg);
|
||||
break;
|
||||
|
||||
case 'Keyboard:SetValue':
|
||||
case 'System:SetValue':
|
||||
this.setValue(msg);
|
||||
break;
|
||||
@ -178,11 +176,9 @@ this.Keyboard = {
|
||||
case 'System:RemoveFocus':
|
||||
this.removeFocus();
|
||||
break;
|
||||
case 'Keyboard:SetSelectedOption':
|
||||
case 'System:SetSelectedOption':
|
||||
this.setSelectedOption(msg);
|
||||
break;
|
||||
case 'Keyboard:SetSelectedOptions':
|
||||
case 'System:SetSelectedOptions':
|
||||
this.setSelectedOption(msg);
|
||||
break;
|
||||
|
@ -18,187 +18,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "tm",
|
||||
"@mozilla.org/thread-manager;1", "nsIThreadManager");
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// MozKeyboard
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function MozKeyboard() { }
|
||||
|
||||
MozKeyboard.prototype = {
|
||||
classID: Components.ID("{397a7fdf-2254-47be-b74e-76625a1a66d5}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIB2GKeyboard, Ci.nsIDOMGlobalPropertyInitializer, Ci.nsIObserver
|
||||
]),
|
||||
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
"classID": Components.ID("{397a7fdf-2254-47be-b74e-76625a1a66d5}"),
|
||||
"contractID": "@mozilla.org/b2g-keyboard;1",
|
||||
"interfaces": [Ci.nsIB2GKeyboard],
|
||||
"flags": Ci.nsIClassInfo.DOM_OBJECT,
|
||||
"classDescription": "B2G Virtual Keyboard"
|
||||
}),
|
||||
|
||||
init: function mozKeyboardInit(win) {
|
||||
let principal = win.document.nodePrincipal;
|
||||
// Limited the deprecated mozKeyboard API to certified apps only
|
||||
let perm = Services.perms.testExactPermissionFromPrincipal(principal,
|
||||
"input-manage");
|
||||
if (perm != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
dump("No permission to use the keyboard API for " +
|
||||
principal.origin + "\n");
|
||||
return null;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
cpmm.addMessageListener('Keyboard:FocusChange', this);
|
||||
cpmm.addMessageListener('Keyboard:SelectionChange', this);
|
||||
|
||||
this._window = win;
|
||||
this._utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
this.innerWindowID = this._utils.currentInnerWindowID;
|
||||
this._focusHandler = null;
|
||||
this._selectionHandler = null;
|
||||
this._selectionStart = -1;
|
||||
this._selectionEnd = -1;
|
||||
},
|
||||
|
||||
uninit: function mozKeyboardUninit() {
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
cpmm.removeMessageListener('Keyboard:FocusChange', this);
|
||||
cpmm.removeMessageListener('Keyboard:SelectionChange', this);
|
||||
|
||||
this._window = null;
|
||||
this._utils = null;
|
||||
this._focusHandler = null;
|
||||
this._selectionHandler = null;
|
||||
},
|
||||
|
||||
sendKey: function mozKeyboardSendKey(keyCode, charCode) {
|
||||
charCode = (charCode == undefined) ? keyCode : charCode;
|
||||
|
||||
let mainThread = tm.mainThread;
|
||||
let utils = this._utils;
|
||||
|
||||
function send(type) {
|
||||
mainThread.dispatch(function() {
|
||||
utils.sendKeyEvent(type, keyCode, charCode, null);
|
||||
}, mainThread.DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
send("keydown");
|
||||
send("keypress");
|
||||
send("keyup");
|
||||
},
|
||||
|
||||
setSelectedOption: function mozKeyboardSetSelectedOption(index) {
|
||||
cpmm.sendAsyncMessage('Keyboard:SetSelectedOption', {
|
||||
'index': index
|
||||
});
|
||||
},
|
||||
|
||||
setValue: function mozKeyboardSetValue(value) {
|
||||
cpmm.sendAsyncMessage('Keyboard:SetValue', {
|
||||
'value': value
|
||||
});
|
||||
},
|
||||
|
||||
setSelectedOptions: function mozKeyboardSetSelectedOptions(indexes) {
|
||||
cpmm.sendAsyncMessage('Keyboard:SetSelectedOptions', {
|
||||
'indexes': indexes
|
||||
});
|
||||
},
|
||||
|
||||
set onselectionchange(val) {
|
||||
this._selectionHandler = val;
|
||||
},
|
||||
|
||||
get onselectionchange() {
|
||||
return this._selectionHandler;
|
||||
},
|
||||
|
||||
get selectionStart() {
|
||||
return this._selectionStart;
|
||||
},
|
||||
|
||||
get selectionEnd() {
|
||||
return this._selectionEnd;
|
||||
},
|
||||
|
||||
setSelectionRange: function mozKeyboardSetSelectionRange(start, end) {
|
||||
cpmm.sendAsyncMessage('Keyboard:SetSelectionRange', {
|
||||
'selectionStart': start,
|
||||
'selectionEnd': end
|
||||
});
|
||||
},
|
||||
|
||||
removeFocus: function mozKeyboardRemoveFocus() {
|
||||
cpmm.sendAsyncMessage('Keyboard:RemoveFocus', {});
|
||||
},
|
||||
|
||||
set onfocuschange(val) {
|
||||
this._focusHandler = val;
|
||||
},
|
||||
|
||||
get onfocuschange() {
|
||||
return this._focusHandler;
|
||||
},
|
||||
|
||||
replaceSurroundingText: function mozKeyboardReplaceSurroundingText(
|
||||
text, beforeLength, afterLength) {
|
||||
cpmm.sendAsyncMessage('Keyboard:ReplaceSurroundingText', {
|
||||
'text': text || '',
|
||||
'beforeLength': (typeof beforeLength === 'number' ? beforeLength : 0),
|
||||
'afterLength': (typeof afterLength === 'number' ? afterLength: 0)
|
||||
});
|
||||
},
|
||||
|
||||
receiveMessage: function mozKeyboardReceiveMessage(msg) {
|
||||
if (msg.name == "Keyboard:FocusChange") {
|
||||
let msgJson = msg.json;
|
||||
if (msgJson.type != "blur") {
|
||||
this._selectionStart = msgJson.selectionStart;
|
||||
this._selectionEnd = msgJson.selectionEnd;
|
||||
} else {
|
||||
this._selectionStart = 0;
|
||||
this._selectionEnd = 0;
|
||||
}
|
||||
|
||||
let handler = this._focusHandler;
|
||||
if (!handler || !(handler instanceof Ci.nsIDOMEventListener))
|
||||
return;
|
||||
|
||||
let detail = {
|
||||
"detail": msgJson
|
||||
};
|
||||
|
||||
let evt = new this._window.CustomEvent("focuschanged",
|
||||
Cu.cloneInto(detail, this._window));
|
||||
handler.handleEvent(evt);
|
||||
} else if (msg.name == "Keyboard:SelectionChange") {
|
||||
let msgJson = msg.json;
|
||||
|
||||
this._selectionStart = msgJson.selectionStart;
|
||||
this._selectionEnd = msgJson.selectionEnd;
|
||||
|
||||
let handler = this._selectionHandler;
|
||||
if (!handler || !(handler instanceof Ci.nsIDOMEventListener))
|
||||
return;
|
||||
|
||||
let evt = new this._window.CustomEvent("selectionchange",
|
||||
Cu.cloneInto({}, this._window));
|
||||
handler.handleEvent(evt);
|
||||
}
|
||||
},
|
||||
|
||||
observe: function mozKeyboardObserve(subject, topic, data) {
|
||||
let wId = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId == this.innerWindowID)
|
||||
this.uninit();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* A WeakMap to map input method iframe window to its active status.
|
||||
*/
|
||||
@ -288,6 +107,7 @@ MozInputMethod.prototype = {
|
||||
_layouts: {},
|
||||
_window: null,
|
||||
_isSystem: false,
|
||||
_isKeyboard: true,
|
||||
|
||||
classID: Components.ID("{4607330d-e7d2-40a4-9eb8-43967eae0142}"),
|
||||
|
||||
@ -304,6 +124,8 @@ MozInputMethod.prototype = {
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.currentInnerWindowID;
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
|
||||
let principal = win.document.nodePrincipal;
|
||||
let perm = Services.perms.testExactPermissionFromPrincipal(principal,
|
||||
"input-manage");
|
||||
@ -311,7 +133,18 @@ MozInputMethod.prototype = {
|
||||
this._isSystem = true;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
// Check if we can use keyboard related APIs.
|
||||
let testing = false;
|
||||
try {
|
||||
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
|
||||
} catch (e) {
|
||||
}
|
||||
perm = Services.perms.testExactPermissionFromPrincipal(principal, "input");
|
||||
if (!testing && perm !== Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
this._isKeyboard = false;
|
||||
return;
|
||||
}
|
||||
|
||||
cpmm.addWeakMessageListener('Keyboard:FocusChange', this);
|
||||
cpmm.addWeakMessageListener('Keyboard:SelectionChange', this);
|
||||
cpmm.addWeakMessageListener('Keyboard:GetContext:Result:OK', this);
|
||||
@ -319,15 +152,18 @@ MozInputMethod.prototype = {
|
||||
},
|
||||
|
||||
uninit: function mozInputMethodUninit() {
|
||||
this.setActive(false);
|
||||
this._window = null;
|
||||
this._mgmt = null;
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
if (!this._isKeyboard) {
|
||||
return;
|
||||
}
|
||||
|
||||
cpmm.removeWeakMessageListener('Keyboard:FocusChange', this);
|
||||
cpmm.removeWeakMessageListener('Keyboard:SelectionChange', this);
|
||||
cpmm.removeWeakMessageListener('Keyboard:GetContext:Result:OK', this);
|
||||
cpmm.removeWeakMessageListener('Keyboard:LayoutsChange', this);
|
||||
|
||||
this._window = null;
|
||||
this._mgmt = null;
|
||||
this.setActive(false);
|
||||
},
|
||||
|
||||
receiveMessage: function mozInputMethodReceiveMsg(msg) {
|
||||
@ -769,5 +605,4 @@ MozInputContext.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
|
||||
[MozKeyboard, MozInputMethod]);
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MozInputMethod]);
|
||||
|
@ -6,12 +6,6 @@
|
||||
|
||||
TEST_DIRS += ['mochitest']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIB2GKeyboard.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'dom_inputmethod'
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'InputMethod.manifest',
|
||||
'MozKeyboard.js',
|
||||
@ -21,4 +15,4 @@ EXTRA_JS_MODULES += [
|
||||
'Keyboard.jsm',
|
||||
]
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
@ -1,71 +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/. */
|
||||
|
||||
#include "domstubs.idl"
|
||||
|
||||
[scriptable, uuid(40ad96b2-9efa-41fb-84c7-fbcec9b153f0)]
|
||||
interface nsIB2GKeyboard : nsISupports
|
||||
{
|
||||
void sendKey(in long keyCode, in long charCode);
|
||||
|
||||
// Select the <select> option specified by index.
|
||||
// If this method is called on a <select> that support multiple
|
||||
// selection, then the option specified by index will be added to
|
||||
// the selection.
|
||||
// If this method is called for a select that does not support multiple
|
||||
// selection the previous element will be unselected.
|
||||
void setSelectedOption(in jsval index);
|
||||
|
||||
// Select the <select> options specified by indexes. All other options
|
||||
// will be deselected.
|
||||
// If this method is called for a <select> that does not support multiple
|
||||
// selection, then the last index specified in indexes will be selected.
|
||||
void setSelectedOptions(in jsval indexes);
|
||||
|
||||
// Set the value on the currently focused element. This has to be used
|
||||
// for special situations where the value had to be chosen amongst a
|
||||
// list (type=month) or a widget (type=date, time, etc.).
|
||||
// If the value passed in parameter isn't valid (in the term of HTML5
|
||||
// Forms Validation), the value will simply be ignored by the element.
|
||||
void setValue(in jsval value);
|
||||
|
||||
void removeFocus();
|
||||
|
||||
attribute nsIDOMEventListener onfocuschange;
|
||||
|
||||
// Fires when user moves the cursor, changes the selection, or alters the
|
||||
// composing text length
|
||||
attribute nsIDOMEventListener onselectionchange;
|
||||
|
||||
// The start position of the selection.
|
||||
readonly attribute long selectionStart;
|
||||
|
||||
// The stop position of the selection.
|
||||
readonly attribute long selectionEnd;
|
||||
|
||||
/*
|
||||
* Set the selection range of the the editable text.
|
||||
*
|
||||
* @param start The beginning of the selected text.
|
||||
* @param end The end of the selected text.
|
||||
*
|
||||
* Note that the start position should be less or equal to the end position.
|
||||
* To move the cursor, set the start and end position to the same value.
|
||||
*/
|
||||
void setSelectionRange(in long start, in long end);
|
||||
|
||||
/*
|
||||
* Replace text around the beginning of the current selection range of the
|
||||
* editable text.
|
||||
*
|
||||
* @param text The string to be replaced with.
|
||||
* @param beforeLength The number of characters to be deleted before the
|
||||
* beginning of the current selection range. Defaults to 0.
|
||||
* @param afterLength The number of characters to be deleted after the
|
||||
* beginning of the current selection range. Defaults to 0.
|
||||
*/
|
||||
void replaceSurroundingText(in DOMString text,
|
||||
[optional] in long beforeLength,
|
||||
[optional] in long afterLength);
|
||||
};
|
@ -166,8 +166,9 @@ mozNfc.prototype = {
|
||||
this._window = aWindow;
|
||||
},
|
||||
|
||||
// Only System Process can call the following interfaces
|
||||
// 'checkP2PRegistration' , 'notifyUserAcceptedP2P' , 'notifySendFileStatus'
|
||||
// Only apps which have nfc-manager permission can call the following interfaces
|
||||
// 'checkP2PRegistration' , 'notifyUserAcceptedP2P' , 'notifySendFileStatus',
|
||||
// 'startPoll', 'stopPoll', and 'powerOff'.
|
||||
checkP2PRegistration: function checkP2PRegistration(manifestUrl) {
|
||||
// Get the AppID and pass it to ContentHelper
|
||||
let appID = appsService.getAppLocalIdByManifestURL(manifestUrl);
|
||||
@ -185,6 +186,18 @@ mozNfc.prototype = {
|
||||
status, requestId);
|
||||
},
|
||||
|
||||
startPoll: function startPoll() {
|
||||
return this._nfcContentHelper.startPoll(this._window);
|
||||
},
|
||||
|
||||
stopPoll: function stopPoll() {
|
||||
return this._nfcContentHelper.stopPoll(this._window);
|
||||
},
|
||||
|
||||
powerOff: function powerOff() {
|
||||
return this._nfcContentHelper.powerOff(this._window);
|
||||
},
|
||||
|
||||
getNFCTag: function getNFCTag(sessionToken) {
|
||||
let obj = new MozNFCTag();
|
||||
let nfcTag = this._window.MozNFCTag._create(this._window, obj);
|
||||
|
@ -3,40 +3,35 @@
|
||||
|
||||
let pendingEmulatorCmdCount = 0;
|
||||
|
||||
SpecialPowers.addPermission("nfc-manager", true, document);
|
||||
|
||||
function toggleNFC(enabled, callback) {
|
||||
isnot(callback, null);
|
||||
var settings = window.navigator.mozSettings;
|
||||
isnot(settings, null);
|
||||
ok(settings instanceof SettingsManager,
|
||||
'settings instanceof ' + settings.constructor +
|
||||
', expected SettingsManager');
|
||||
|
||||
let req = settings.createLock().get('nfc.enabled');
|
||||
let nfc = window.navigator.mozNfc;
|
||||
let req;
|
||||
if (enabled) {
|
||||
req = nfc.startPoll();
|
||||
} else {
|
||||
req = nfc.powerOff();
|
||||
}
|
||||
|
||||
req.onsuccess = function() {
|
||||
if (req.result['nfc.enabled'] === enabled) {
|
||||
callback();
|
||||
} else {
|
||||
let req = settings.createLock().set({'nfc.enabled': enabled});
|
||||
req.onsuccess = function() {
|
||||
window.setTimeout(callback, 5000); // give emulator time to toggle NFC
|
||||
};
|
||||
req.onerror = function() {
|
||||
ok(false,
|
||||
'Setting \'nfc.enabled\' to \'' + enabled +
|
||||
'\' failed, error ' + req.error.name);
|
||||
finish();
|
||||
};
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
req.onerror = function() {
|
||||
ok(false, 'Getting \'nfc.enabled\' failed, error ' + req.error.name);
|
||||
ok(false, 'operation failed, error ' + req.error.name);
|
||||
finish();
|
||||
};
|
||||
}
|
||||
|
||||
function cleanUp() {
|
||||
log('Cleaning up');
|
||||
waitFor(finish(),
|
||||
waitFor(function() {
|
||||
SpecialPowers.removePermission("nfc-manager", document);
|
||||
finish()
|
||||
},
|
||||
function() {
|
||||
return pendingEmulatorCmdCount === 0;
|
||||
});
|
||||
|
@ -33,5 +33,4 @@ let tests = [
|
||||
testConstructNDEF
|
||||
];
|
||||
|
||||
SpecialPowers.pushPermissions(
|
||||
[{'type': 'settings', 'allow': true, 'context': document}], runTests);
|
||||
runTests();
|
||||
|
@ -4,20 +4,52 @@
|
||||
MARIONETTE_TIMEOUT = 30000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
let nfc = window.navigator.mozNfc;
|
||||
function testEnableNFC() {
|
||||
log('Running \'testEnableNFC\'');
|
||||
toggleNFC(true, runNextTest);
|
||||
let req = nfc.startPoll();
|
||||
req.onsuccess = function () {
|
||||
ok(true);
|
||||
runNextTest();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "startPoll failed");
|
||||
runNextTest();
|
||||
};
|
||||
}
|
||||
|
||||
function testDisableNFC() {
|
||||
log('Running \'testDisableNFC\'');
|
||||
toggleNFC(false, runNextTest);
|
||||
let req = nfc.powerOff();
|
||||
req.onsuccess = function () {
|
||||
ok(true);
|
||||
runNextTest();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "powerOff failed");
|
||||
runNextTest();
|
||||
};
|
||||
}
|
||||
|
||||
function testStopPollNFC() {
|
||||
log('Running \'testStopPollNFC\'');
|
||||
let req = nfc.stopPoll();
|
||||
req.onsuccess = function () {
|
||||
ok(true);
|
||||
runNextTest();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "stopPoll failed");
|
||||
runNextTest();
|
||||
};
|
||||
}
|
||||
|
||||
let tests = [
|
||||
testEnableNFC,
|
||||
testStopPollNFC,
|
||||
testDisableNFC
|
||||
];
|
||||
|
||||
SpecialPowers.pushPermissions(
|
||||
[{'type': 'settings', 'allow': true, 'context': document}], runTests);
|
||||
[{'type': 'nfc-manager', 'allow': true, 'context': document}],
|
||||
runTests);
|
||||
|
@ -33,5 +33,4 @@ let tests = [
|
||||
];
|
||||
|
||||
SpecialPowers.pushPermissions(
|
||||
[{'type': 'nfc-manager', 'allow': true, context: document},
|
||||
{'type': 'settings', 'allow': true, context: document}], runTests);
|
||||
[{'type': 'nfc-manager', 'allow': true, context: document}], runTests);
|
||||
|
@ -20,6 +20,8 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(https not working, bug
|
||||
[test_camera.html]
|
||||
disabled = disabled until bug 859593 is fixed
|
||||
[test_keyboard.html]
|
||||
skip-if = buildapp != 'b2g'
|
||||
skip-if = toolkit == 'android'
|
||||
[test_input-manage.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_wifi-manage.html]
|
||||
skip-if = (buildapp != 'b2g') || (buildapp == 'b2g' && toolkit != 'gonk') #b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
|
||||
|
68
dom/permission/tests/test_input-manage.html
Normal file
68
dom/permission/tests/test_input-manage.html
Normal file
@ -0,0 +1,68 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=920977
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 920977 </title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=920977">Mozilla Bug 920977 </a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
|
||||
<script type="application/javascript;version=1.8">
|
||||
function verifier(success, failure) {
|
||||
try {
|
||||
if (!this.getObj()) {
|
||||
failure("Did not receive proper object");
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
failure("Received exception!: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.getObj().removeFocus();
|
||||
} catch (e) {
|
||||
failure("Received exception!: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("mozbrowser", true);
|
||||
iframe.src = "http://example.org/";
|
||||
iframe.addEventListener("load", function() {
|
||||
iframe.removeEventListener("load", arguments.callee);
|
||||
if (iframe.setInputMethodActive &&
|
||||
typeof iframe.setInputMethodActive == "function") {
|
||||
success("Got setInputMethodActive");
|
||||
} else {
|
||||
failure("Didn't get setInputMethodActive") ;
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('content').appendChild(iframe);
|
||||
}
|
||||
|
||||
var gData = [
|
||||
{
|
||||
perm: ["input-manage", "browser"],
|
||||
needParentPerm: true,
|
||||
obj: "mozInputMethod",
|
||||
webidl: "MozInputMethod",
|
||||
settings: [["dom.mozInputMethod.enabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true]],
|
||||
verifier: verifier.toSource()
|
||||
}
|
||||
]
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -16,17 +16,32 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=920977
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
|
||||
<script type="application/javascript;version=1.8">
|
||||
function verifier(success, failure) {
|
||||
try {
|
||||
if (!this.getObj()) {
|
||||
failure("Did not receive proper object");
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
failure("Received exception!: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.getObj().removeFocus();
|
||||
failure("Should receive exception when accessing system only method.!");
|
||||
} catch (e) {
|
||||
success(this.perm);
|
||||
}
|
||||
}
|
||||
|
||||
var gData = [
|
||||
{
|
||||
perm: ["input"],
|
||||
obj: "mozInputMethod",
|
||||
webidl: "MozInputMethod",
|
||||
settings: [["dom.mozInputMethod.enabled", true]],
|
||||
},
|
||||
{
|
||||
perm: ["input-manage"],
|
||||
obj: "mozKeyboard",
|
||||
idl: "nsIB2GKeyboard",
|
||||
verifier: verifier.toSource()
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
@ -66,7 +66,10 @@ const NFC_IPC_WRITE_PERM_MSG_NAMES = [
|
||||
const NFC_IPC_MANAGER_PERM_MSG_NAMES = [
|
||||
"NFC:CheckP2PRegistration",
|
||||
"NFC:NotifyUserAcceptedP2P",
|
||||
"NFC:NotifySendFileStatus"
|
||||
"NFC:NotifySendFileStatus",
|
||||
"NFC:StartPoll",
|
||||
"NFC:StopPoll",
|
||||
"NFC:PowerOff"
|
||||
];
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
@ -420,6 +423,7 @@ function Nfc() {
|
||||
lock.get(NFC.SETTING_NFC_ENABLED, this);
|
||||
// Maps sessionId (that are generated from nfcd) with a unique guid : 'SessionToken'
|
||||
this.sessionTokenMap = {};
|
||||
this.targetsByRequestId = {};
|
||||
|
||||
gSystemWorkerManager.registerNfcWorker(this.worker);
|
||||
}
|
||||
@ -516,7 +520,14 @@ Nfc.prototype = {
|
||||
this.currentPeerAppId = null;
|
||||
break;
|
||||
case "ConfigResponse":
|
||||
gSystemMessenger.broadcastMessage("nfc-powerlevel-change", message);
|
||||
let target = this.targetsByRequestId[message.requestId];
|
||||
if (!target) {
|
||||
debug("No target for requestId: " + message.requestId);
|
||||
return;
|
||||
}
|
||||
delete this.targetsByRequestId[message.requestId];
|
||||
|
||||
target.sendAsyncMessage("NFC:ConfigResponse", message);
|
||||
break;
|
||||
case "ConnectResponse": // Fall through.
|
||||
case "CloseResponse":
|
||||
@ -539,12 +550,32 @@ Nfc.prototype = {
|
||||
|
||||
sessionTokenMap: null,
|
||||
|
||||
targetsByRequestId: null,
|
||||
|
||||
/**
|
||||
* Process a message from the content process.
|
||||
*/
|
||||
receiveMessage: function receiveMessage(message) {
|
||||
debug("Received '" + JSON.stringify(message) + "' message from content process");
|
||||
|
||||
// Handle messages without sessionToken.
|
||||
if (message.name == "NFC:StartPoll") {
|
||||
this.targetsByRequestId[message.json.requestId] = message.target;
|
||||
this.setConfig({powerLevel: NFC.NFC_POWER_LEVEL_ENABLED,
|
||||
requestId: message.json.requestId});
|
||||
return null;
|
||||
} else if (message.name == "NFC:StopPoll") {
|
||||
this.targetsByRequestId[message.json.requestId] = message.target;
|
||||
this.setConfig({powerLevel: NFC.NFC_POWER_LEVEL_LOW,
|
||||
requestId: message.json.requestId});
|
||||
return null;
|
||||
} else if (message.name == "NFC:PowerOff") {
|
||||
this.targetsByRequestId[message.json.requestId] = message.target;
|
||||
this.setConfig({powerLevel: NFC.NFC_POWER_LEVEL_DISABLED,
|
||||
requestId: message.json.requestId});
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!this._enabled) {
|
||||
debug("NFC is not enabled.");
|
||||
this.sendNfcErrorResponse(message);
|
||||
|
@ -54,7 +54,7 @@ const NFC_IPC_MSG_NAMES = [
|
||||
"NFC:CheckP2PRegistrationResponse",
|
||||
"NFC:PeerEvent",
|
||||
"NFC:NotifySendFileStatusResponse",
|
||||
"NFC:SendFileResponse"
|
||||
"NFC:ConfigResponse"
|
||||
];
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
@ -314,6 +314,51 @@ NfcContentHelper.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
startPoll: function startPoll(window) {
|
||||
if (window == null) {
|
||||
throw Components.Exception("Can't get window object",
|
||||
Cr.NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
let request = Services.DOMRequest.createRequest(window);
|
||||
let requestId = btoa(this.getRequestId(request));
|
||||
this._requestMap[requestId] = window;
|
||||
|
||||
cpmm.sendAsyncMessage("NFC:StartPoll",
|
||||
{requestId: requestId});
|
||||
return request;
|
||||
},
|
||||
|
||||
stopPoll: function stopPoll(window) {
|
||||
if (window == null) {
|
||||
throw Components.Exception("Can't get window object",
|
||||
Cr.NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
let request = Services.DOMRequest.createRequest(window);
|
||||
let requestId = btoa(this.getRequestId(request));
|
||||
this._requestMap[requestId] = window;
|
||||
|
||||
cpmm.sendAsyncMessage("NFC:StopPoll",
|
||||
{requestId: requestId});
|
||||
return request;
|
||||
},
|
||||
|
||||
powerOff: function powerOff(window) {
|
||||
if (window == null) {
|
||||
throw Components.Exception("Can't get window object",
|
||||
Cr.NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
let request = Services.DOMRequest.createRequest(window);
|
||||
let requestId = btoa(this.getRequestId(request));
|
||||
this._requestMap[requestId] = window;
|
||||
|
||||
cpmm.sendAsyncMessage("NFC:PowerOff",
|
||||
{requestId: requestId});
|
||||
return request;
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
observe: function observe(subject, topic, data) {
|
||||
if (topic == "xpcom-shutdown") {
|
||||
@ -368,6 +413,7 @@ NfcContentHelper.prototype = {
|
||||
case "NFC:MakeReadOnlyNDEFResponse":
|
||||
case "NFC:CheckP2PRegistrationResponse":
|
||||
case "NFC:NotifySendFileStatusResponse":
|
||||
case "NFC:ConfigResponse":
|
||||
if (result.status !== NFC.GECKO_NFC_ERROR_SUCCESS) {
|
||||
this.fireRequestError(atob(result.requestId), result.status);
|
||||
} else {
|
||||
|
@ -24,7 +24,7 @@ interface nsINfcPeerCallback : nsISupports
|
||||
in DOMString sessionToken);
|
||||
};
|
||||
|
||||
[scriptable, uuid(70cac000-7e3c-11e3-baa7-0800200c9a66)]
|
||||
[scriptable, uuid(10b2eb1b-3fe0-4c98-9c67-9e4c2274cd78)]
|
||||
interface nsINfcContentHelper : nsISupports
|
||||
{
|
||||
const long NFC_EVENT_PEER_READY = 0x01;
|
||||
@ -135,4 +135,19 @@ interface nsINfcContentHelper : nsISupports
|
||||
void notifySendFileStatus(in nsIDOMWindow window,
|
||||
in octet status,
|
||||
in DOMString requestId);
|
||||
|
||||
/**
|
||||
* Power on the NFC hardware and start polling for NFC tags or devices.
|
||||
*/
|
||||
nsIDOMDOMRequest startPoll(in nsIDOMWindow window);
|
||||
|
||||
/**
|
||||
* Stop polling for NFC tags or devices. i.e. enter low power mode.
|
||||
*/
|
||||
nsIDOMDOMRequest stopPoll(in nsIDOMWindow window);
|
||||
|
||||
/**
|
||||
* Power off the NFC hardware.
|
||||
*/
|
||||
nsIDOMDOMRequest powerOff(in nsIDOMWindow window);
|
||||
};
|
||||
|
@ -25,6 +25,21 @@ interface MozNfcManager {
|
||||
* Notify the status of sendFile operation
|
||||
*/
|
||||
void notifySendFileStatus(octet status, DOMString requestId);
|
||||
|
||||
/**
|
||||
* Power on the NFC hardware and start polling for NFC tags or devices.
|
||||
*/
|
||||
DOMRequest startPoll();
|
||||
|
||||
/**
|
||||
* Stop polling for NFC tags or devices. i.e. enter low power mode.
|
||||
*/
|
||||
DOMRequest stopPoll();
|
||||
|
||||
/**
|
||||
* Power off the NFC hardware.
|
||||
*/
|
||||
DOMRequest powerOff();
|
||||
};
|
||||
|
||||
[JSImplementation="@mozilla.org/navigatorNfc;1",
|
||||
|
@ -126,7 +126,7 @@ this.PriorityUrlProvider = Object.freeze({
|
||||
matches.delete(token);
|
||||
},
|
||||
|
||||
getMatchingSpec: function (searchToken) {
|
||||
getMatch: function (searchToken) {
|
||||
return Task.spawn(function* () {
|
||||
yield promiseInitialized();
|
||||
for (let [token, match] of matches.entries()) {
|
||||
|
1236
toolkit/components/places/UnifiedComplete.js
Normal file
1236
toolkit/components/places/UnifiedComplete.js
Normal file
File diff suppressed because it is too large
Load Diff
2
toolkit/components/places/UnifiedComplete.manifest
Normal file
2
toolkit/components/places/UnifiedComplete.manifest
Normal file
@ -0,0 +1,2 @@
|
||||
component {f964a319-397a-4d21-8be6-5cdd1ee3e3ae} UnifiedComplete.js
|
||||
contract @mozilla.org/autocomplete/search;1?name=unifiedcomplete {f964a319-397a-4d21-8be6-5cdd1ee3e3ae}
|
@ -87,6 +87,8 @@ if CONFIG['MOZ_PLACES']:
|
||||
EXTRA_COMPONENTS += [
|
||||
'nsPlacesAutoComplete.js',
|
||||
'nsPlacesAutoComplete.manifest',
|
||||
'UnifiedComplete.js',
|
||||
'UnifiedComplete.manifest',
|
||||
]
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
|
@ -11,7 +11,7 @@ function run_test() {
|
||||
add_task(function* search_engine_match() {
|
||||
let engine = yield promiseDefaultSearchEngine();
|
||||
let token = engine.getResultDomain();
|
||||
let match = yield PriorityUrlProvider.getMatchingSpec(token.substr(0, 1));
|
||||
let match = yield PriorityUrlProvider.getMatch(token.substr(0, 1));
|
||||
do_check_eq(match.url, engine.searchForm);
|
||||
do_check_eq(match.title, engine.name);
|
||||
do_check_eq(match.iconUrl, engine.iconURI ? engine.iconURI.spec : null);
|
||||
@ -19,7 +19,7 @@ add_task(function* search_engine_match() {
|
||||
});
|
||||
|
||||
add_task(function* no_match() {
|
||||
do_check_eq(null, yield PriorityUrlProvider.getMatchingSpec("test"));
|
||||
do_check_eq(null, yield PriorityUrlProvider.getMatch("test"));
|
||||
});
|
||||
|
||||
add_task(function* hide_search_engine_nomatch() {
|
||||
@ -29,16 +29,16 @@ add_task(function* hide_search_engine_nomatch() {
|
||||
Services.search.removeEngine(engine);
|
||||
yield promiseTopic;
|
||||
do_check_true(engine.hidden);
|
||||
do_check_eq(null, yield PriorityUrlProvider.getMatchingSpec(token.substr(0, 1)));
|
||||
do_check_eq(null, yield PriorityUrlProvider.getMatch(token.substr(0, 1)));
|
||||
});
|
||||
|
||||
add_task(function* add_search_engine_match() {
|
||||
let promiseTopic = promiseSearchTopic("engine-added");
|
||||
do_check_eq(null, yield PriorityUrlProvider.getMatchingSpec("bacon"));
|
||||
do_check_eq(null, yield PriorityUrlProvider.getMatch("bacon"));
|
||||
Services.search.addEngineWithDetails("bacon", "", "bacon", "Search Bacon",
|
||||
"GET", "http://www.bacon.moz/?search={searchTerms}");
|
||||
yield promiseSearchTopic;
|
||||
let match = yield PriorityUrlProvider.getMatchingSpec("bacon");
|
||||
let match = yield PriorityUrlProvider.getMatch("bacon");
|
||||
do_check_eq(match.url, "http://www.bacon.moz");
|
||||
do_check_eq(match.title, "bacon");
|
||||
do_check_eq(match.iconUrl, null);
|
||||
@ -50,7 +50,7 @@ add_task(function* remove_search_engine_nomatch() {
|
||||
let promiseTopic = promiseSearchTopic("engine-removed");
|
||||
Services.search.removeEngine(engine);
|
||||
yield promiseTopic;
|
||||
do_check_eq(null, yield PriorityUrlProvider.getMatchingSpec("bacon"));
|
||||
do_check_eq(null, yield PriorityUrlProvider.getMatch("bacon"));
|
||||
});
|
||||
|
||||
function promiseDefaultSearchEngine() {
|
||||
|
@ -45,6 +45,12 @@ const UNKNOWN_XPCOM_ABI = "unknownABI";
|
||||
const UPDATE_REQUEST_VERSION = 2;
|
||||
const CATEGORY_UPDATE_PARAMS = "extension-update-params";
|
||||
|
||||
const XMLURI_BLOCKLIST = "http://www.mozilla.org/2006/addons-blocklist";
|
||||
|
||||
const KEY_PROFILEDIR = "ProfD";
|
||||
const KEY_APPDIR = "XCurProcD";
|
||||
const FILE_BLOCKLIST = "blocklist.xml";
|
||||
|
||||
const BRANCH_REGEXP = /^([^\.]+\.[0-9]+[a-z]*).*/gi;
|
||||
const PREF_EM_CHECK_COMPATIBILITY_BASE = "extensions.checkCompatibility";
|
||||
#ifdef MOZ_COMPATIBILITY_NIGHTLY
|
||||
@ -65,6 +71,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
|
||||
"resource://gre/modules/addons/AddonRepository.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "CertUtils", function certUtilsLazyGetter() {
|
||||
let certUtils = {};
|
||||
@ -521,6 +529,88 @@ var AddonManagerInternal = {
|
||||
this.TelemetryTimestamps.add(name, value);
|
||||
},
|
||||
|
||||
validateBlocklist: function AMI_validateBlocklist() {
|
||||
let appBlocklist = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
|
||||
|
||||
// If there is no application shipped blocklist then there is nothing to do
|
||||
if (!appBlocklist.exists())
|
||||
return;
|
||||
|
||||
let profileBlocklist = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
|
||||
|
||||
// If there is no blocklist in the profile then copy the application shipped
|
||||
// one there
|
||||
if (!profileBlocklist.exists()) {
|
||||
try {
|
||||
appBlocklist.copyTo(profileBlocklist.parent, FILE_BLOCKLIST);
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("Failed to copy the application shipped blocklist to the profile", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
try {
|
||||
let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Ci.nsIConverterInputStream);
|
||||
fileStream.init(appBlocklist, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
|
||||
cstream.init(fileStream, "UTF-8", 0, 0);
|
||||
|
||||
let data = "";
|
||||
let str = {};
|
||||
let read = 0;
|
||||
do {
|
||||
read = cstream.readString(0xffffffff, str);
|
||||
data += str.value;
|
||||
} while (read != 0);
|
||||
|
||||
let parser = Cc["@mozilla.org/xmlextras/domparser;1"].
|
||||
createInstance(Ci.nsIDOMParser);
|
||||
var doc = parser.parseFromString(data, "text/xml");
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("Application shipped blocklist could not be loaded", e);
|
||||
return;
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
fileStream.close();
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("Unable to close blocklist file stream", e);
|
||||
}
|
||||
}
|
||||
|
||||
// If the namespace is incorrect then ignore the application shipped
|
||||
// blocklist
|
||||
if (doc.documentElement.namespaceURI != XMLURI_BLOCKLIST) {
|
||||
logger.warn("Application shipped blocklist has an unexpected namespace (" +
|
||||
doc.documentElement.namespaceURI + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
// If there is no lastupdate information then ignore the application shipped
|
||||
// blocklist
|
||||
if (!doc.documentElement.hasAttribute("lastupdate"))
|
||||
return;
|
||||
|
||||
// If the application shipped blocklist is older than the profile blocklist
|
||||
// then do nothing
|
||||
if (doc.documentElement.getAttribute("lastupdate") <=
|
||||
profileBlocklist.lastModifiedTime)
|
||||
return;
|
||||
|
||||
// Otherwise copy the application shipped blocklist to the profile
|
||||
try {
|
||||
appBlocklist.copyTo(profileBlocklist.parent, FILE_BLOCKLIST);
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("Failed to copy the application shipped blocklist to the profile", e);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes the AddonManager, loading any known providers and initializing
|
||||
* them.
|
||||
@ -559,6 +649,7 @@ var AddonManagerInternal = {
|
||||
Services.appinfo.platformVersion);
|
||||
Services.prefs.setIntPref(PREF_BLOCKLIST_PINGCOUNTVERSION,
|
||||
(appChanged === undefined ? 0 : -1));
|
||||
this.validateBlocklist();
|
||||
}
|
||||
|
||||
#ifndef MOZ_COMPATIBILITY_NIGHTLY
|
||||
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
||||
<emItems>
|
||||
<emItem blockID="i454" id="ancient@tests.mozilla.org">
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
</emItems>
|
||||
</blocklist>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1396046918000">
|
||||
<emItems>
|
||||
<emItem blockID="i454" id="new@tests.mozilla.org">
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
</emItems>
|
||||
</blocklist>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1296046918000">
|
||||
<emItems>
|
||||
<emItem blockID="i454" id="old@tests.mozilla.org">
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
</emItems>
|
||||
</blocklist>
|
@ -0,0 +1,200 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const KEY_PROFILEDIR = "ProfD";
|
||||
const KEY_APPDIR = "XCurProcD";
|
||||
const FILE_BLOCKLIST = "blocklist.xml";
|
||||
|
||||
const PREF_BLOCKLIST_ENABLED = "extensions.blocklist.enabled";
|
||||
|
||||
const OLD = do_get_file("data/test_overrideblocklist/old.xml");
|
||||
const NEW = do_get_file("data/test_overrideblocklist/new.xml");
|
||||
const ANCIENT = do_get_file("data/test_overrideblocklist/ancient.xml");
|
||||
const OLD_TSTAMP = 1296046918000;
|
||||
const NEW_TSTAMP = 1396046918000;
|
||||
|
||||
const gAppDir = FileUtils.getFile(KEY_APPDIR, []);
|
||||
|
||||
let oldAddon = {
|
||||
id: "old@tests.mozilla.org",
|
||||
version: 1
|
||||
}
|
||||
let newAddon = {
|
||||
id: "new@tests.mozilla.org",
|
||||
version: 1
|
||||
}
|
||||
let ancientAddon = {
|
||||
id: "ancient@tests.mozilla.org",
|
||||
version: 1
|
||||
}
|
||||
let invalidAddon = {
|
||||
id: "invalid@tests.mozilla.org",
|
||||
version: 1
|
||||
}
|
||||
|
||||
function incrementAppVersion() {
|
||||
gAppInfo.version = "" + (parseInt(gAppInfo.version) + 1);
|
||||
}
|
||||
|
||||
function clearBlocklists() {
|
||||
let blocklist = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
|
||||
if (blocklist.exists())
|
||||
blocklist.remove(true);
|
||||
|
||||
blocklist = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
|
||||
if (blocklist.exists())
|
||||
blocklist.remove(true);
|
||||
}
|
||||
|
||||
function reloadBlocklist() {
|
||||
Services.prefs.setBoolPref(PREF_BLOCKLIST_ENABLED, false);
|
||||
Services.prefs.setBoolPref(PREF_BLOCKLIST_ENABLED, true);
|
||||
}
|
||||
|
||||
function copyToApp(file) {
|
||||
file.clone().copyTo(gAppDir, FILE_BLOCKLIST);
|
||||
}
|
||||
|
||||
function copyToProfile(file, tstamp) {
|
||||
file = file.clone();
|
||||
file.copyTo(gProfD, FILE_BLOCKLIST);
|
||||
file = gProfD.clone();
|
||||
file.append(FILE_BLOCKLIST);
|
||||
file.lastModifiedTime = tstamp;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
|
||||
|
||||
let appBlocklist = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
|
||||
if (appBlocklist.exists()) {
|
||||
try {
|
||||
appBlocklist.moveTo(gAppDir, "blocklist.old");
|
||||
}
|
||||
catch (e) {
|
||||
todo(false, "Aborting test due to unmovable blocklist file: " + e);
|
||||
return;
|
||||
}
|
||||
do_register_cleanup(function() {
|
||||
clearBlocklists();
|
||||
appBlocklist.moveTo(gAppDir, FILE_BLOCKLIST);
|
||||
});
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// On first run whataver is in the app dir should get copied to the profile
|
||||
add_test(function test_copy() {
|
||||
clearBlocklists();
|
||||
copyToApp(OLD);
|
||||
|
||||
incrementAppVersion();
|
||||
startupManager();
|
||||
|
||||
reloadBlocklist();
|
||||
let blocklist = AM_Cc["@mozilla.org/extensions/blocklist;1"].
|
||||
getService(AM_Ci.nsIBlocklistService);
|
||||
do_check_false(blocklist.isAddonBlocklisted(invalidAddon));
|
||||
do_check_false(blocklist.isAddonBlocklisted(ancientAddon));
|
||||
do_check_true(blocklist.isAddonBlocklisted(oldAddon));
|
||||
do_check_false(blocklist.isAddonBlocklisted(newAddon));
|
||||
|
||||
shutdownManager();
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// An ancient blocklist should be ignored
|
||||
add_test(function test_ancient() {
|
||||
clearBlocklists();
|
||||
copyToApp(ANCIENT);
|
||||
copyToProfile(OLD, OLD_TSTAMP);
|
||||
|
||||
incrementAppVersion();
|
||||
startupManager();
|
||||
|
||||
reloadBlocklist();
|
||||
let blocklist = AM_Cc["@mozilla.org/extensions/blocklist;1"].
|
||||
getService(AM_Ci.nsIBlocklistService);
|
||||
do_check_false(blocklist.isAddonBlocklisted(invalidAddon));
|
||||
do_check_false(blocklist.isAddonBlocklisted(ancientAddon));
|
||||
do_check_true(blocklist.isAddonBlocklisted(oldAddon));
|
||||
do_check_false(blocklist.isAddonBlocklisted(newAddon));
|
||||
|
||||
shutdownManager();
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// A new blocklist should override an old blocklist
|
||||
add_test(function test_override() {
|
||||
clearBlocklists();
|
||||
copyToApp(NEW);
|
||||
copyToProfile(OLD, OLD_TSTAMP);
|
||||
|
||||
incrementAppVersion();
|
||||
startupManager();
|
||||
|
||||
reloadBlocklist();
|
||||
let blocklist = AM_Cc["@mozilla.org/extensions/blocklist;1"].
|
||||
getService(AM_Ci.nsIBlocklistService);
|
||||
do_check_false(blocklist.isAddonBlocklisted(invalidAddon));
|
||||
do_check_false(blocklist.isAddonBlocklisted(ancientAddon));
|
||||
do_check_false(blocklist.isAddonBlocklisted(oldAddon));
|
||||
do_check_true(blocklist.isAddonBlocklisted(newAddon));
|
||||
|
||||
shutdownManager();
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// An old blocklist shouldn't override a new blocklist
|
||||
add_test(function test_retain() {
|
||||
clearBlocklists();
|
||||
copyToApp(OLD);
|
||||
copyToProfile(NEW, NEW_TSTAMP);
|
||||
|
||||
incrementAppVersion();
|
||||
startupManager();
|
||||
|
||||
reloadBlocklist();
|
||||
let blocklist = AM_Cc["@mozilla.org/extensions/blocklist;1"].
|
||||
getService(AM_Ci.nsIBlocklistService);
|
||||
do_check_false(blocklist.isAddonBlocklisted(invalidAddon));
|
||||
do_check_false(blocklist.isAddonBlocklisted(ancientAddon));
|
||||
do_check_false(blocklist.isAddonBlocklisted(oldAddon));
|
||||
do_check_true(blocklist.isAddonBlocklisted(newAddon));
|
||||
|
||||
shutdownManager();
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// A missing blocklist in the profile should still load an app-shipped blocklist
|
||||
add_test(function test_missing() {
|
||||
clearBlocklists();
|
||||
copyToApp(OLD);
|
||||
copyToProfile(NEW, NEW_TSTAMP);
|
||||
|
||||
incrementAppVersion();
|
||||
startupManager();
|
||||
shutdownManager();
|
||||
|
||||
let blocklist = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
|
||||
blocklist.remove(true);
|
||||
startupManager(false);
|
||||
|
||||
reloadBlocklist();
|
||||
let blocklist = AM_Cc["@mozilla.org/extensions/blocklist;1"].
|
||||
getService(AM_Ci.nsIBlocklistService);
|
||||
do_check_false(blocklist.isAddonBlocklisted(invalidAddon));
|
||||
do_check_false(blocklist.isAddonBlocklisted(ancientAddon));
|
||||
do_check_true(blocklist.isAddonBlocklisted(oldAddon));
|
||||
do_check_false(blocklist.isAddonBlocklisted(newAddon));
|
||||
|
||||
shutdownManager();
|
||||
|
||||
run_next_test();
|
||||
});
|
@ -262,4 +262,6 @@ run-sequentially = Uses global XCurProcD dir.
|
||||
# Bug 676992: test consistently hangs on Android
|
||||
skip-if = os == "android"
|
||||
run-sequentially = Uses global XCurProcD dir.
|
||||
[test_overrideblocklist.js]
|
||||
run-sequentially = Uses global XCurProcD dir.
|
||||
[test_sourceURI.js]
|
||||
|
Loading…
Reference in New Issue
Block a user