зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound a=merge CLOSED TREE
This commit is contained in:
Коммит
af7c4c6606
|
@ -354,7 +354,6 @@ function nukeModules() {
|
|||
// the addon is unload.
|
||||
|
||||
unloadSandbox(cuddlefishSandbox.loaderSandbox);
|
||||
unloadSandbox(cuddlefishSandbox.xulappSandbox);
|
||||
|
||||
// Bug 764840: We need to unload cuddlefish otherwise it will stay alive
|
||||
// and keep a reference to this compartment.
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var readParam = require("./node-scripts/utils").readParam;
|
||||
var path = require("path");
|
||||
var Promise = require("promise");
|
||||
var Mocha = require("mocha");
|
||||
var mocha = new Mocha({
|
||||
ui: "bdd",
|
||||
|
@ -12,16 +11,19 @@ var mocha = new Mocha({
|
|||
timeout: 900000
|
||||
});
|
||||
|
||||
var type = readParam("type");
|
||||
exports.run = function(type) {
|
||||
return new Promise(function(resolve) {
|
||||
type = type || "";
|
||||
[
|
||||
(/^(modules)?$/.test(type)) && require.resolve("../bin/node-scripts/test.modules"),
|
||||
(/^(addons)?$/.test(type)) && require.resolve("../bin/node-scripts/test.addons"),
|
||||
(/^(examples)?$/.test(type)) && require.resolve("../bin/node-scripts/test.examples"),
|
||||
].sort().forEach(function(filepath) {
|
||||
filepath && mocha.addFile(filepath);
|
||||
})
|
||||
|
||||
[
|
||||
(!type || type == "modules") && require.resolve("../bin/node-scripts/test.modules"),
|
||||
(!type || type == "addons") && require.resolve("../bin/node-scripts/test.addons"),
|
||||
(!type || type == "examples") && require.resolve("../bin/node-scripts/test.examples"),
|
||||
].sort().forEach(function(filepath) {
|
||||
filepath && mocha.addFile(filepath);
|
||||
})
|
||||
|
||||
mocha.run(function (failures) {
|
||||
process.exit(failures);
|
||||
});
|
||||
mocha.run(function(failures) {
|
||||
resolve(failures);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ var Connection = Class({
|
|||
},
|
||||
poolFor: function(id) {
|
||||
for (let pool of this.pools.values()) {
|
||||
if (pool.has(id))
|
||||
if pool.has(id)
|
||||
return pool;
|
||||
}
|
||||
},
|
||||
|
@ -797,7 +797,7 @@ var Tab = Client.from({
|
|||
"storageActor": "storage",
|
||||
"gcliActor": "gcli",
|
||||
"memoryActor": "memory",
|
||||
"eventLoopLag": "eventLoopLag",
|
||||
"eventLoopLag": "eventLoopLag"
|
||||
|
||||
"trace": "trace", // missing
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* 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 gulp = require('gulp');
|
||||
|
||||
gulp.task('test', function(done) {
|
||||
require("./bin/jpm-test").run().then(done);
|
||||
});
|
||||
|
||||
gulp.task('test:addons', function(done) {
|
||||
require("./bin/jpm-test").run("addons").then(done);
|
||||
});
|
||||
|
||||
gulp.task('test:examples', function(done) {
|
||||
require("./bin/jpm-test").run("examples").then(done);
|
||||
});
|
||||
|
||||
gulp.task('test:modules', function(done) {
|
||||
require("./bin/jpm-test").run("modules").then(done);
|
||||
});
|
||||
|
|
@ -16,6 +16,31 @@ const assetsURI = require('../self').data.url();
|
|||
|
||||
const hideSheetUri = "data:text/css,:root {visibility: hidden !important;}";
|
||||
|
||||
function translateElementAttributes(element) {
|
||||
// Translateable attributes
|
||||
const attrList = ['title', 'accesskey', 'alt', 'label', 'placeholder'];
|
||||
const ariaAttrMap = {
|
||||
'ariaLabel': 'aria-label',
|
||||
'ariaValueText': 'aria-valuetext',
|
||||
'ariaMozHint': 'aria-moz-hint'
|
||||
};
|
||||
const attrSeparator = '.';
|
||||
|
||||
// Try to translate each of the attributes
|
||||
for (let attribute of attrList) {
|
||||
const data = core.get(element.dataset.l10nId + attrSeparator + attribute);
|
||||
if (data)
|
||||
element.setAttribute(attribute, data);
|
||||
}
|
||||
|
||||
// Look for the aria attribute translations that match fxOS's aliases
|
||||
for (let attrAlias in ariaAttrMap) {
|
||||
const data = core.get(element.dataset.l10nId + attrSeparator + attrAlias);
|
||||
if (data)
|
||||
element.setAttribute(ariaAttrMap[attrAlias], data);
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from Gaia:
|
||||
// https://github.com/andreasgal/gaia/blob/04fde2640a7f40314643016a5a6c98bf3755f5fd/webapi.js#L1470
|
||||
function translateElement(element) {
|
||||
|
@ -32,6 +57,8 @@ function translateElement(element) {
|
|||
var data = core.get(key);
|
||||
if (data)
|
||||
child.textContent = data;
|
||||
|
||||
translateElementAttributes(child);
|
||||
}
|
||||
}
|
||||
exports.translateElement = translateElement;
|
||||
|
|
|
@ -320,6 +320,8 @@ TestRunner.prototype = {
|
|||
});
|
||||
|
||||
PromiseDebugging.flushUncaughtErrors();
|
||||
PromiseDebugging.removeUncaughtErrorObserver(this._uncaughtErrorObserver);
|
||||
|
||||
|
||||
return all(winPromises).then(() => {
|
||||
let browserWins = wins.filter(isBrowser);
|
||||
|
@ -537,7 +539,8 @@ TestRunner.prototype = {
|
|||
this.test.errors = {};
|
||||
this.test.last = 'START';
|
||||
PromiseDebugging.clearUncaughtErrorObservers();
|
||||
PromiseDebugging.addUncaughtErrorObserver(this._uncaughtErrorObserver.bind(this));
|
||||
this._uncaughtErrorObserver = this._uncaughtErrorObserver.bind(this);
|
||||
PromiseDebugging.addUncaughtErrorObserver(this._uncaughtErrorObserver);
|
||||
|
||||
this.isDone = false;
|
||||
this.onDone = function(self) {
|
||||
|
|
|
@ -21,6 +21,10 @@ let getWindowFrom = x =>
|
|||
null;
|
||||
|
||||
function removeFromListeners() {
|
||||
this.removeEventListener("DOMWindowClose", removeFromListeners);
|
||||
for (let cleaner of listeners.get(this))
|
||||
cleaner();
|
||||
|
||||
listeners.delete(this);
|
||||
}
|
||||
|
||||
|
@ -45,26 +49,25 @@ function open(target, type, options) {
|
|||
if (!window)
|
||||
throw new Error("Unable to obtain the owner window from the target given.");
|
||||
|
||||
let cleaners = listeners.get(window) || [];
|
||||
let cleaners = listeners.get(window);
|
||||
if (!cleaners) {
|
||||
cleaners = [];
|
||||
listeners.set(window, cleaners);
|
||||
|
||||
// We need to remove from our map the `window` once is closed, to prevent
|
||||
// memory leak
|
||||
window.addEventListener("DOMWindowClose", removeFromListeners);
|
||||
}
|
||||
|
||||
cleaners.push(() => target.removeEventListener(type, listener, capture));
|
||||
|
||||
listeners.set(window, cleaners);
|
||||
|
||||
// We need to remove from our map the `window` once is closed, to prevent
|
||||
// memory leak
|
||||
window.addEventListener("DOMWindowClose", removeFromListeners);
|
||||
|
||||
target.addEventListener(type, listener, capture);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
unload(() => {
|
||||
for (let [window, cleaners] of listeners) {
|
||||
cleaners.forEach(callback => callback())
|
||||
}
|
||||
|
||||
listeners.clear();
|
||||
for (let window of listeners.keys())
|
||||
removeFromListeners.call(window);
|
||||
});
|
||||
|
||||
exports.open = open;
|
||||
|
|
|
@ -692,8 +692,6 @@ function writeSync(fd, buffer, offset, length, position) {
|
|||
else if (length + offset !== buffer.length) {
|
||||
buffer = buffer.slice(offset, offset + length);
|
||||
}
|
||||
let writeStream = new WriteStream(fd, { position: position,
|
||||
length: length });
|
||||
|
||||
let output = BinaryOutputStream(nsIFileOutputStream(fd));
|
||||
nsIBinaryOutputStream(fd, output);
|
||||
|
|
|
@ -23,6 +23,7 @@ const historyService = Cc['@mozilla.org/browser/nav-history-service;1']
|
|||
const { mapBookmarkItemType } = require('./utils');
|
||||
const { EventTarget } = require('../event/target');
|
||||
const { emit } = require('../event/core');
|
||||
const { when } = require('../system/unload');
|
||||
|
||||
const emitter = EventTarget();
|
||||
|
||||
|
@ -119,4 +120,9 @@ historyService.addObserver(historyObserver, false);
|
|||
let bookmarkObserver = createObserverInstance(BOOKMARK_EVENTS, BOOKMARK_ARGS);
|
||||
bookmarkService.addObserver(bookmarkObserver, false);
|
||||
|
||||
when(() => {
|
||||
historyService.removeObserver(historyObserver);
|
||||
bookmarkService.removeObserver(bookmarkObserver);
|
||||
});
|
||||
|
||||
exports.events = emitter;
|
||||
|
|
|
@ -169,6 +169,15 @@ function serializeStack(frames) {
|
|||
Loader.serializeStack = serializeStack;
|
||||
|
||||
function readURI(uri) {
|
||||
let nsURI = NetUtil.newURI(uri);
|
||||
if (nsURI.scheme == "resource") {
|
||||
// Resolve to a real URI, this will catch any obvious bad paths without
|
||||
// logging assertions in debug builds, see bug 1135219
|
||||
let proto = Cc["@mozilla.org/network/protocol;1?name=resource"].
|
||||
getService(Ci.nsIResProtocolHandler);
|
||||
uri = proto.resolveURI(nsURI);
|
||||
}
|
||||
|
||||
let stream = NetUtil.newChannel2(uri,
|
||||
'UTF-8',
|
||||
null,
|
||||
|
@ -420,6 +429,10 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) {
|
|||
// Resolve again
|
||||
id = Loader.resolve(id, requirer);
|
||||
|
||||
// If this is already an absolute URI then there is no resolution to do
|
||||
if (isAbsoluteURI(id))
|
||||
return void 0;
|
||||
|
||||
// we assume that extensions are correct, i.e., a directory doesnt't have '.js'
|
||||
// and a js file isn't named 'file.json.js'
|
||||
let fullId = join(rootURI, id);
|
||||
|
@ -431,9 +444,14 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) {
|
|||
if ((resolvedPath = loadAsDirectory(fullId)))
|
||||
return stripBase(rootURI, resolvedPath);
|
||||
|
||||
// If the requirer is an absolute URI then the node module resolution below
|
||||
// won't work correctly as we prefix everything with rootURI
|
||||
if (isAbsoluteURI(requirer))
|
||||
return void 0;
|
||||
|
||||
// If manifest has dependencies, attempt to look up node modules
|
||||
// in the `dependencies` list
|
||||
let dirs = getNodeModulePaths(dirname(join(rootURI, requirer))).map(dir => join(dir, id));
|
||||
let dirs = getNodeModulePaths(dirname(requirer)).map(dir => join(rootURI, dir, id));
|
||||
for (let i = 0; i < dirs.length; i++) {
|
||||
if ((resolvedPath = loadAsFile(dirs[i])))
|
||||
return stripBase(rootURI, resolvedPath);
|
||||
|
@ -509,6 +527,7 @@ function getNodeModulePaths (start) {
|
|||
let dir = join(parts.slice(0, i + 1).join('/'), moduleDir);
|
||||
dirs.push(dir);
|
||||
}
|
||||
dirs.push(moduleDir);
|
||||
return dirs;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,10 +8,7 @@
|
|||
"license": "MPL 2.0",
|
||||
"unpack": true,
|
||||
"scripts": {
|
||||
"test": "node ./bin/jpm-test.js",
|
||||
"modules": "node ./bin/jpm-test.js --type modules",
|
||||
"addons": "node ./bin/jpm-test.js --type addons",
|
||||
"examples": "node ./bin/jpm-test.js --type examples"
|
||||
"test": "gulp test"
|
||||
},
|
||||
"homepage": "https://github.com/mozilla/addon-sdk",
|
||||
"repository": {
|
||||
|
@ -25,6 +22,7 @@
|
|||
"async": "0.9.0",
|
||||
"chai": "2.1.1",
|
||||
"glob": "4.4.2",
|
||||
"gulp": "3.8.11",
|
||||
"jpm": "0.0.29",
|
||||
"lodash": "3.3.1",
|
||||
"mocha": "2.1.0",
|
||||
|
|
|
@ -56,6 +56,7 @@ DEFAULT_NO_CONNECTIONS_PREFS = {
|
|||
'browser.aboutHomeSnippets.updateUrl': 'https://localhost/snippet-dummy',
|
||||
'browser.newtab.url' : 'about:blank',
|
||||
'browser.search.update': False,
|
||||
'browser.search.suggest.enabled' : False,
|
||||
'browser.safebrowsing.enabled' : False,
|
||||
'browser.safebrowsing.updateURL': 'http://localhost/safebrowsing-dummy/update',
|
||||
'browser.safebrowsing.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
|
||||
|
|
|
@ -20,5 +20,10 @@
|
|||
<div data-l10n-id="Translated">
|
||||
A data-l10n-id value can be used in multiple elements
|
||||
</div>
|
||||
<a data-l10n-id="link-attributes" title="Certain whitelisted attributes get translated too" alt="No" accesskey="A"></a>
|
||||
<input data-l10n-id="input" type="text" placeholder="Form placeholders are translateable">
|
||||
<menu>
|
||||
<menuitem data-l10n-id="contextitem" label="Labels of select options and context menus are translateable">
|
||||
</menu>
|
||||
</body>
|
||||
</html
|
||||
|
|
|
@ -26,3 +26,13 @@ first_identifier[one]=first entry is %s and the second one is %s.
|
|||
first_identifier=the entries are %s and %s.
|
||||
second_identifier[other]=first entry is %s and the second one is %s.
|
||||
third_identifier=first entry is %s and the second one is %s.
|
||||
|
||||
# bug 824489 allow translation of element attributes
|
||||
link-attributes.title=Yes
|
||||
link-attributes.alt=Yes
|
||||
link-attributes.accesskey=B
|
||||
input.placeholder=Yes
|
||||
contextitem.label=Yes
|
||||
link-attributes.ariaLabel=Yes
|
||||
link-attributes.ariaValueText=Value
|
||||
link-attributes.ariaMozHint=Hint
|
||||
|
|
|
@ -105,7 +105,15 @@ exports.testHtmlLocalizationPageWorker = createTest("en-GB", function(assert, lo
|
|||
self.postMessage([nodes[0].innerHTML,
|
||||
nodes[1].innerHTML,
|
||||
nodes[2].innerHTML,
|
||||
nodes[3].innerHTML]);
|
||||
nodes[3].innerHTML,
|
||||
nodes[4].title,
|
||||
nodes[4].getAttribute("alt"),
|
||||
nodes[4].getAttribute("accesskey"),
|
||||
nodes[4].getAttribute("aria-label"),
|
||||
nodes[4].getAttribute("aria-valuetext"),
|
||||
nodes[4].getAttribute("aria-moz-hint"),
|
||||
nodes[5].placeholder,
|
||||
nodes[6].label]);
|
||||
},
|
||||
onMessage: function (data) {
|
||||
assert.equal(
|
||||
|
@ -121,6 +129,19 @@ exports.testHtmlLocalizationPageWorker = createTest("en-GB", function(assert, lo
|
|||
);
|
||||
assert.equal(data[3], "Yes", "Multiple elements with same data-l10n-id are accepted.");
|
||||
|
||||
// Attribute translation tests
|
||||
assert.equal(data[4], "Yes", "Title attributes gets translated.");
|
||||
assert.equal(data[5], "Yes", "Alt attributes gets translated.");
|
||||
assert.equal(data[6], "B", "Accesskey gets translated.");
|
||||
|
||||
assert.equal(data[7], "Yes", "Aria-Label gets translated.");
|
||||
assert.equal(data[8], "Value", "Aria-valuetext gets translated.");
|
||||
assert.equal(data[9], "Hint", "Aria-moz-hint gets translated.");
|
||||
|
||||
assert.equal(data[10], "Yes", "Form placeholders are translateable.");
|
||||
|
||||
assert.equal(data[11], "Yes", "Labels of select options and context menus are translateable.");
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
@ -144,7 +165,15 @@ exports.testHtmlLocalization = createTest("en-GB", function(assert, loader, done
|
|||
self.postMessage([nodes[0].innerHTML,
|
||||
nodes[1].innerHTML,
|
||||
nodes[2].innerHTML,
|
||||
nodes[3].innerHTML]);
|
||||
nodes[3].innerHTML,
|
||||
nodes[4].title,
|
||||
nodes[4].getAttribute("alt"),
|
||||
nodes[4].getAttribute("accesskey"),
|
||||
nodes[4].getAttribute("aria-label"),
|
||||
nodes[4].getAttribute("aria-valuetext"),
|
||||
nodes[4].getAttribute("aria-moz-hint"),
|
||||
nodes[5].placeholder,
|
||||
nodes[6].label]);
|
||||
},
|
||||
onMessage: function (data) {
|
||||
assert.equal(
|
||||
|
@ -160,6 +189,19 @@ exports.testHtmlLocalization = createTest("en-GB", function(assert, loader, done
|
|||
);
|
||||
assert.equal(data[3], "Yes", "Multiple elements with same data-l10n-id are accepted.");
|
||||
|
||||
// Attribute translation tests
|
||||
assert.equal(data[4], "Yes", "Title attributes gets translated.");
|
||||
assert.equal(data[5], "Yes", "Alt attributes gets translated.");
|
||||
assert.equal(data[6], "B", "Accesskey gets translated.");
|
||||
|
||||
assert.equal(data[7], "Yes", "Aria-Label gets translated.");
|
||||
assert.equal(data[8], "Value", "Aria-valuetext gets translated.");
|
||||
assert.equal(data[9], "Hint", "Aria-moz-hint gets translated.");
|
||||
|
||||
assert.equal(data[10], "Yes", "Form placeholders are translateable.");
|
||||
|
||||
assert.equal(data[11], "Yes", "Labels of select options and context menus are translateable.");
|
||||
|
||||
tab.close(done);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"use strict";
|
||||
|
||||
const LOCAL_URI = "about:robots";
|
||||
const REMOTE_URI = "about:home";
|
||||
const REMOTE_URI = "data:text/html;charset=utf-8,remote";
|
||||
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const { getTabs, openTab, closeTab, setTabURL, getBrowserForTab, getURI } = require('sdk/tabs/utils');
|
||||
|
@ -21,6 +21,19 @@ const { set } = require('sdk/preferences/service');
|
|||
// The hidden preload browser messes up our frame counts
|
||||
set('browser.newtab.preload', false);
|
||||
|
||||
function promiseTabFrameAttach(frames) {
|
||||
return new Promise(resolve => {
|
||||
let listener = function(frame, ...args) {
|
||||
if (!frame.isTab)
|
||||
return;
|
||||
frames.off("attach", listener);
|
||||
resolve([frame, ...args]);
|
||||
}
|
||||
|
||||
frames.on("attach", listener);
|
||||
});
|
||||
}
|
||||
|
||||
// Check that we see a process stop and start
|
||||
exports["test process restart"] = function*(assert) {
|
||||
if (!isE10S) {
|
||||
|
@ -44,7 +57,7 @@ exports["test process restart"] = function*(assert) {
|
|||
// Switch the remote tab to a local URI which should kill the remote process
|
||||
|
||||
let frameDetach = promiseEventOnItemAndContainer(assert, remoteFrame, frames, 'detach');
|
||||
let frameAttach = promiseEvent(frames, 'attach');
|
||||
let frameAttach = promiseTabFrameAttach(frames);
|
||||
let processDetach = promiseEventOnItemAndContainer(assert, remoteProcess, processes, 'detach');
|
||||
setTabURL(tab, LOCAL_URI);
|
||||
// The load should kill the remote frame
|
||||
|
@ -57,7 +70,7 @@ exports["test process restart"] = function*(assert) {
|
|||
|
||||
frameDetach = promiseEventOnItemAndContainer(assert, newFrame, frames, 'detach');
|
||||
let processAttach = promiseEvent(processes, 'attach');
|
||||
frameAttach = promiseEvent(frames, 'attach');
|
||||
frameAttach = promiseTabFrameAttach(frames);
|
||||
setTabURL(tab, REMOTE_URI);
|
||||
// The load should kill the remote frame
|
||||
yield frameDetach;
|
||||
|
@ -149,7 +162,7 @@ exports["test frame list"] = function*(assert) {
|
|||
assert.equal(browserFrames(frames), getTabs(window).length, "Should be the right number of browser frames.");
|
||||
assert.equal((yield getChildFrameCount(processes)), frames.length, "Child processes should have the right number of frames");
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let tab1 = openTab(window, LOCAL_URI);
|
||||
let [frame1] = yield promise;
|
||||
assert.ok(!!frame1, "Should have seen the new frame");
|
||||
|
@ -158,7 +171,7 @@ exports["test frame list"] = function*(assert) {
|
|||
assert.equal(browserFrames(frames), getTabs(window).length, "Should be the right number of browser frames.");
|
||||
assert.equal((yield getChildFrameCount(processes)), frames.length, "Child processes should have the right number of frames");
|
||||
|
||||
promise = promiseEvent(frames, 'attach');
|
||||
promise = promiseTabFrameAttach(frames);
|
||||
let tab2 = openTab(window, REMOTE_URI);
|
||||
let [frame2] = yield promise;
|
||||
assert.ok(!!frame2, "Should have seen the new frame");
|
||||
|
@ -256,7 +269,7 @@ exports["test unload"] = function*(assert) {
|
|||
let loader = new Loader(module);
|
||||
let { frames } = yield waitForProcesses(loader);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let tab = openTab(window, "data:,<html/>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
@ -280,7 +293,7 @@ exports["test frame detach on unload"] = function*(assert) {
|
|||
let loader = new Loader(module);
|
||||
let { frames } = yield waitForProcesses(loader);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let tab = openTab(window, "data:,<html/>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
@ -304,7 +317,7 @@ exports["test frame event listeners"] = function*(assert) {
|
|||
let loader = new Loader(module);
|
||||
let { frames } = yield waitForProcesses(loader);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let tab = openTab(window, "data:text/html,<html></html>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
@ -339,7 +352,7 @@ exports["test frames event listeners"] = function*(assert) {
|
|||
let loader = new Loader(module);
|
||||
let { frames } = yield waitForProcesses(loader);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let tab = openTab(window, "data:text/html,<html></html>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
@ -377,8 +390,8 @@ exports["test unload removes frame event listeners"] = function*(assert) {
|
|||
let loader2 = new Loader(module);
|
||||
let { frames: frames2 } = yield waitForProcesses(loader2);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise2 = promiseEvent(frames2, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let promise2 = promiseTabFrameAttach(frames2);
|
||||
let tab = openTab(window, "data:text/html,<html></html>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
@ -418,8 +431,8 @@ exports["test unload removes frames event listeners"] = function*(assert) {
|
|||
let loader2 = new Loader(module);
|
||||
let { frames: frames2 } = yield waitForProcesses(loader2);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise2 = promiseEvent(frames2, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let promise2 = promiseTabFrameAttach(frames2);
|
||||
let tab = openTab(window, "data:text/html,<html></html>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
|
|
@ -20,5 +20,10 @@
|
|||
<div data-l10n-id="Translated">
|
||||
A data-l10n-id value can be used in multiple elements
|
||||
</div>
|
||||
<a data-l10n-id="link-attributes" title="Certain whitelisted attributes get translated too" alt="No" accesskey="A"></a>
|
||||
<input data-l10n-id="input" type="text" placeholder="Form placeholders are translateable">
|
||||
<menu>
|
||||
<menuitem data-l10n-id="contextitem" label="Labels of select options and context menus are translateable">
|
||||
</menu>
|
||||
</body>
|
||||
</html
|
||||
|
|
|
@ -26,3 +26,13 @@ first_identifier[one]=first entry is %s and the second one is %s.
|
|||
first_identifier=the entries are %s and %s.
|
||||
second_identifier[other]=first entry is %s and the second one is %s.
|
||||
third_identifier=first entry is %s and the second one is %s.
|
||||
|
||||
# bug 824489 allow translation of element attributes
|
||||
link-attributes.title=Yes
|
||||
link-attributes.alt=Yes
|
||||
link-attributes.accesskey=B
|
||||
input.placeholder=Yes
|
||||
contextitem.label=Yes
|
||||
link-attributes.ariaLabel=Yes
|
||||
link-attributes.ariaValueText=Value
|
||||
link-attributes.ariaMozHint=Hint
|
||||
|
|
|
@ -105,7 +105,15 @@ exports.testHtmlLocalizationPageWorker = createTest("en-GB", function(assert, lo
|
|||
self.postMessage([nodes[0].innerHTML,
|
||||
nodes[1].innerHTML,
|
||||
nodes[2].innerHTML,
|
||||
nodes[3].innerHTML]);
|
||||
nodes[3].innerHTML,
|
||||
nodes[4].title,
|
||||
nodes[4].getAttribute("alt"),
|
||||
nodes[4].getAttribute("accesskey"),
|
||||
nodes[4].getAttribute("aria-label"),
|
||||
nodes[4].getAttribute("aria-valuetext"),
|
||||
nodes[4].getAttribute("aria-moz-hint"),
|
||||
nodes[5].placeholder,
|
||||
nodes[6].label]);
|
||||
},
|
||||
onMessage: function (data) {
|
||||
assert.equal(
|
||||
|
@ -120,6 +128,19 @@ exports.testHtmlLocalizationPageWorker = createTest("en-GB", function(assert, lo
|
|||
"Content from .properties is text content; HTML can't be injected."
|
||||
);
|
||||
assert.equal(data[3], "Yes", "Multiple elements with same data-l10n-id are accepted.");
|
||||
|
||||
// Attribute translation tests
|
||||
assert.equal(data[4], "Yes", "Title attributes gets translated.");
|
||||
assert.equal(data[5], "Yes", "Alt attributes gets translated.");
|
||||
assert.equal(data[6], "B", "Accesskey gets translated.");
|
||||
|
||||
assert.equal(data[7], "Yes", "Aria-Label gets translated.");
|
||||
assert.equal(data[8], "Value", "Aria-valuetext gets translated.");
|
||||
assert.equal(data[9], "Hint", "Aria-moz-hint gets translated.");
|
||||
|
||||
assert.equal(data[10], "Yes", "Form placeholders are translateable.");
|
||||
|
||||
assert.equal(data[11], "Yes", "Labels of select options and context menus are translateable.");
|
||||
|
||||
done();
|
||||
}
|
||||
|
@ -144,7 +165,15 @@ exports.testHtmlLocalization = createTest("en-GB", function(assert, loader, done
|
|||
self.postMessage([nodes[0].innerHTML,
|
||||
nodes[1].innerHTML,
|
||||
nodes[2].innerHTML,
|
||||
nodes[3].innerHTML]);
|
||||
nodes[3].innerHTML,
|
||||
nodes[4].title,
|
||||
nodes[4].getAttribute("alt"),
|
||||
nodes[4].getAttribute("accesskey"),
|
||||
nodes[4].getAttribute("aria-label"),
|
||||
nodes[4].getAttribute("aria-valuetext"),
|
||||
nodes[4].getAttribute("aria-moz-hint"),
|
||||
nodes[5].placeholder,
|
||||
nodes[6].label]);
|
||||
},
|
||||
onMessage: function (data) {
|
||||
assert.equal(
|
||||
|
@ -160,6 +189,19 @@ exports.testHtmlLocalization = createTest("en-GB", function(assert, loader, done
|
|||
);
|
||||
assert.equal(data[3], "Yes", "Multiple elements with same data-l10n-id are accepted.");
|
||||
|
||||
// Attribute translation tests
|
||||
assert.equal(data[4], "Yes", "Title attributes gets translated.");
|
||||
assert.equal(data[5], "Yes", "Alt attributes gets translated.");
|
||||
assert.equal(data[6], "B", "Accesskey gets translated.");
|
||||
|
||||
assert.equal(data[7], "Yes", "Aria-Label gets translated.");
|
||||
assert.equal(data[8], "Value", "Aria-valuetext gets translated.");
|
||||
assert.equal(data[9], "Hint", "Aria-moz-hint gets translated.");
|
||||
|
||||
assert.equal(data[10], "Yes", "Form placeholders are translateable.");
|
||||
|
||||
assert.equal(data[11], "Yes", "Labels of select options and context menus are translateable.");
|
||||
|
||||
tab.close(done);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"use strict";
|
||||
|
||||
const LOCAL_URI = "about:robots";
|
||||
const REMOTE_URI = "about:home";
|
||||
const REMOTE_URI = "data:text/html;charset=utf-8,remote";
|
||||
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const { getTabs, openTab, closeTab, setTabURL, getBrowserForTab, getURI } = require('sdk/tabs/utils');
|
||||
|
@ -21,6 +21,19 @@ const { set } = require('sdk/preferences/service');
|
|||
// The hidden preload browser messes up our frame counts
|
||||
set('browser.newtab.preload', false);
|
||||
|
||||
function promiseTabFrameAttach(frames) {
|
||||
return new Promise(resolve => {
|
||||
let listener = function(frame, ...args) {
|
||||
if (!frame.isTab)
|
||||
return;
|
||||
frames.off("attach", listener);
|
||||
resolve([frame, ...args]);
|
||||
}
|
||||
|
||||
frames.on("attach", listener);
|
||||
});
|
||||
}
|
||||
|
||||
// Check that we see a process stop and start
|
||||
exports["test process restart"] = function*(assert) {
|
||||
if (!isE10S) {
|
||||
|
@ -44,7 +57,7 @@ exports["test process restart"] = function*(assert) {
|
|||
// Switch the remote tab to a local URI which should kill the remote process
|
||||
|
||||
let frameDetach = promiseEventOnItemAndContainer(assert, remoteFrame, frames, 'detach');
|
||||
let frameAttach = promiseEvent(frames, 'attach');
|
||||
let frameAttach = promiseTabFrameAttach(frames);
|
||||
let processDetach = promiseEventOnItemAndContainer(assert, remoteProcess, processes, 'detach');
|
||||
setTabURL(tab, LOCAL_URI);
|
||||
// The load should kill the remote frame
|
||||
|
@ -57,7 +70,7 @@ exports["test process restart"] = function*(assert) {
|
|||
|
||||
frameDetach = promiseEventOnItemAndContainer(assert, newFrame, frames, 'detach');
|
||||
let processAttach = promiseEvent(processes, 'attach');
|
||||
frameAttach = promiseEvent(frames, 'attach');
|
||||
frameAttach = promiseTabFrameAttach(frames);
|
||||
setTabURL(tab, REMOTE_URI);
|
||||
// The load should kill the remote frame
|
||||
yield frameDetach;
|
||||
|
@ -149,7 +162,7 @@ exports["test frame list"] = function*(assert) {
|
|||
assert.equal(browserFrames(frames), getTabs(window).length, "Should be the right number of browser frames.");
|
||||
assert.equal((yield getChildFrameCount(processes)), frames.length, "Child processes should have the right number of frames");
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let tab1 = openTab(window, LOCAL_URI);
|
||||
let [frame1] = yield promise;
|
||||
assert.ok(!!frame1, "Should have seen the new frame");
|
||||
|
@ -158,7 +171,7 @@ exports["test frame list"] = function*(assert) {
|
|||
assert.equal(browserFrames(frames), getTabs(window).length, "Should be the right number of browser frames.");
|
||||
assert.equal((yield getChildFrameCount(processes)), frames.length, "Child processes should have the right number of frames");
|
||||
|
||||
promise = promiseEvent(frames, 'attach');
|
||||
promise = promiseTabFrameAttach(frames);
|
||||
let tab2 = openTab(window, REMOTE_URI);
|
||||
let [frame2] = yield promise;
|
||||
assert.ok(!!frame2, "Should have seen the new frame");
|
||||
|
@ -256,7 +269,7 @@ exports["test unload"] = function*(assert) {
|
|||
let loader = new Loader(module);
|
||||
let { frames } = yield waitForProcesses(loader);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let tab = openTab(window, "data:,<html/>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
@ -280,7 +293,7 @@ exports["test frame detach on unload"] = function*(assert) {
|
|||
let loader = new Loader(module);
|
||||
let { frames } = yield waitForProcesses(loader);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let tab = openTab(window, "data:,<html/>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
@ -304,7 +317,7 @@ exports["test frame event listeners"] = function*(assert) {
|
|||
let loader = new Loader(module);
|
||||
let { frames } = yield waitForProcesses(loader);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let tab = openTab(window, "data:text/html,<html></html>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
@ -339,7 +352,7 @@ exports["test frames event listeners"] = function*(assert) {
|
|||
let loader = new Loader(module);
|
||||
let { frames } = yield waitForProcesses(loader);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let tab = openTab(window, "data:text/html,<html></html>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
@ -377,8 +390,8 @@ exports["test unload removes frame event listeners"] = function*(assert) {
|
|||
let loader2 = new Loader(module);
|
||||
let { frames: frames2 } = yield waitForProcesses(loader2);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise2 = promiseEvent(frames2, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let promise2 = promiseTabFrameAttach(frames2);
|
||||
let tab = openTab(window, "data:text/html,<html></html>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
@ -418,8 +431,8 @@ exports["test unload removes frames event listeners"] = function*(assert) {
|
|||
let loader2 = new Loader(module);
|
||||
let { frames: frames2 } = yield waitForProcesses(loader2);
|
||||
|
||||
let promise = promiseEvent(frames, 'attach');
|
||||
let promise2 = promiseEvent(frames2, 'attach');
|
||||
let promise = promiseTabFrameAttach(frames);
|
||||
let promise2 = promiseTabFrameAttach(frames2);
|
||||
let tab = openTab(window, "data:text/html,<html></html>");
|
||||
let browser = getBrowserForTab(tab);
|
||||
yield promiseDOMEvent(browser, "load", true);
|
||||
|
|
|
@ -62,6 +62,7 @@ skip-if = true
|
|||
[test-environment.js]
|
||||
[test-errors.js]
|
||||
[test-event-core.js]
|
||||
[test-event-dom.js]
|
||||
[test-event-target.js]
|
||||
[test-event-utils.js]
|
||||
[test-events.js]
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"browser.aboutHomeSnippets.updateUrl": "https://localhost/snippet-dummy",
|
||||
"browser.newtab.url": "about:blank",
|
||||
"browser.search.update": false,
|
||||
"browser.search.suggest.enabled": false,
|
||||
"browser.safebrowsing.enabled": false,
|
||||
"browser.safebrowsing.updateURL": "http://localhost/safebrowsing-dummy/update",
|
||||
"browser.safebrowsing.gethashURL": "http://localhost/safebrowsing-dummy/gethash",
|
||||
|
|
|
@ -10,6 +10,7 @@ const { getMode } = require('sdk/private-browsing/utils');
|
|||
const { browserWindows: windows } = require('sdk/windows');
|
||||
const { defer } = require('sdk/core/promise');
|
||||
const tabs = require('sdk/tabs');
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
|
||||
// test openDialog() from window/utils with private option
|
||||
// test isActive state in pwpb case
|
||||
|
@ -80,27 +81,22 @@ exports.testIsPrivateOnWindowOpenFromPrivate = function(assert, done) {
|
|||
};
|
||||
|
||||
exports.testOpenTabWithPrivateWindow = function*(assert) {
|
||||
let { promise, resolve } = defer();
|
||||
let window = getMostRecentBrowserWindow().OpenBrowserWindow({ private: true });
|
||||
|
||||
let window = yield openPromise(null, {
|
||||
features: {
|
||||
private: true,
|
||||
toolbar: true
|
||||
}
|
||||
});
|
||||
yield focus(window);
|
||||
assert.pass("loading new private window");
|
||||
|
||||
yield promise(window, 'load').then(focus);
|
||||
|
||||
assert.equal(isPrivate(window), true, 'the focused window is private');
|
||||
|
||||
tabs.open({
|
||||
yield new Promise(resolve => tabs.open({
|
||||
url: 'about:blank',
|
||||
onOpen: (tab) => {
|
||||
assert.equal(isPrivate(tab), false, 'the opened tab is not private');
|
||||
tab.close(resolve);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
yield promise;
|
||||
yield close(window);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { openTab: makeTab, getTabContentWindow } = require("sdk/tabs/utils");
|
||||
|
||||
function openTab(rawWindow, url) {
|
||||
return new Promise(resolve => {
|
||||
let tab = makeTab(rawWindow, url);
|
||||
let window = getTabContentWindow(tab);
|
||||
if (window.document.readyState == "complete") {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
window.addEventListener("load", function onLoad() {
|
||||
window.removeEventListener("load", onLoad, true);
|
||||
resolve();
|
||||
}, true);
|
||||
|
||||
return null;
|
||||
})
|
||||
}
|
||||
exports.openTab = openTab;
|
|
@ -0,0 +1,92 @@
|
|||
/* 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 { openWindow, closeWindow } = require('./util');
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { Cc, Ci } = require('chrome');
|
||||
const els = Cc["@mozilla.org/eventlistenerservice;1"].
|
||||
getService(Ci.nsIEventListenerService);
|
||||
|
||||
function countListeners(target, type) {
|
||||
let listeners = els.getListenerInfoFor(target, {});
|
||||
return listeners.filter(listener => listener.type == type).length;
|
||||
}
|
||||
|
||||
exports['test window close clears listeners'] = function(assert) {
|
||||
let window = yield openWindow();
|
||||
let loader = Loader(module);
|
||||
|
||||
// Any element will do here
|
||||
let gBrowser = window.gBrowser;
|
||||
|
||||
// Other parts of the app may be listening for this
|
||||
let windowListeners = countListeners(window, "DOMWindowClose");
|
||||
|
||||
// We can assume we're the only ones using the test events
|
||||
assert.equal(countListeners(gBrowser, "TestEvent1"), 0, "Should be no listener for test event 1");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2");
|
||||
|
||||
let { open } = loader.require('sdk/event/dom');
|
||||
|
||||
open(gBrowser, "TestEvent1");
|
||||
assert.equal(countListeners(window, "DOMWindowClose"), windowListeners + 1,
|
||||
"Should have added a DOMWindowClose listener");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent1"), 1, "Should be a listener for test event 1");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2");
|
||||
|
||||
open(gBrowser, "TestEvent2");
|
||||
assert.equal(countListeners(window, "DOMWindowClose"), windowListeners + 1,
|
||||
"Should not have added another DOMWindowClose listener");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent1"), 1, "Should be a listener for test event 1");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent2"), 1, "Should be a listener for test event 2");
|
||||
|
||||
window = yield closeWindow(window);
|
||||
|
||||
assert.equal(countListeners(window, "DOMWindowClose"), windowListeners,
|
||||
"Should have removed a DOMWindowClose listener");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent1"), 0, "Should be no listener for test event 1");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2");
|
||||
|
||||
loader.unload();
|
||||
};
|
||||
|
||||
exports['test unload clears listeners'] = function(assert) {
|
||||
let window = getMostRecentBrowserWindow();
|
||||
let loader = Loader(module);
|
||||
|
||||
// Any element will do here
|
||||
let gBrowser = window.gBrowser;
|
||||
|
||||
// Other parts of the app may be listening for this
|
||||
let windowListeners = countListeners(window, "DOMWindowClose");
|
||||
|
||||
// We can assume we're the only ones using the test events
|
||||
assert.equal(countListeners(gBrowser, "TestEvent1"), 0, "Should be no listener for test event 1");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2");
|
||||
|
||||
let { open } = loader.require('sdk/event/dom');
|
||||
|
||||
open(gBrowser, "TestEvent1");
|
||||
assert.equal(countListeners(window, "DOMWindowClose"), windowListeners + 1,
|
||||
"Should have added a DOMWindowClose listener");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent1"), 1, "Should be a listener for test event 1");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2");
|
||||
|
||||
open(gBrowser, "TestEvent2");
|
||||
assert.equal(countListeners(window, "DOMWindowClose"), windowListeners + 1,
|
||||
"Should not have added another DOMWindowClose listener");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent1"), 1, "Should be a listener for test event 1");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent2"), 1, "Should be a listener for test event 2");
|
||||
|
||||
loader.unload();
|
||||
|
||||
assert.equal(countListeners(window, "DOMWindowClose"), windowListeners,
|
||||
"Should have removed a DOMWindowClose listener");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent1"), 0, "Should be no listener for test event 1");
|
||||
assert.equal(countListeners(gBrowser, "TestEvent2"), 0, "Should be no listener for test event 2");
|
||||
};
|
||||
|
||||
require('sdk/test').run(exports);
|
|
@ -48,6 +48,14 @@ exports['test nodeResolve'] = function (assert) {
|
|||
'./node_modules/test-math/node_modules/test-add/index.js',
|
||||
'Dependencies\' dependencies can be found');
|
||||
|
||||
resolveTest('resource://gre/modules/commonjs/sdk/tabs.js', './index.js', undefined,
|
||||
'correctly ignores absolute URIs.');
|
||||
|
||||
resolveTest('../tabs', 'resource://gre/modules/commonjs/sdk/addon/bootstrap.js', undefined,
|
||||
'correctly ignores attempts to resolve from a module at an absolute URI.');
|
||||
|
||||
resolveTest('sdk/tabs', 'resource://gre/modules/commonjs/sdk/addon/bootstrap.js', undefined,
|
||||
'correctly ignores attempts to resolve from a module at an absolute URI.');
|
||||
|
||||
function resolveTest (id, requirer, expected, msg) {
|
||||
let result = nodeResolve(id, requirer, { manifest: manifest, rootURI: rootURI });
|
||||
|
|
|
@ -1491,12 +1491,17 @@ exports.testShowHideRawWindowArg = function*(assert) {
|
|||
const { Sidebar } = require('sdk/ui/sidebar');
|
||||
|
||||
let testName = 'testShowHideRawWindowArg';
|
||||
|
||||
assert.pass("Creating sidebar");
|
||||
|
||||
let sidebar = Sidebar({
|
||||
id: testName,
|
||||
title: testName,
|
||||
url: 'data:text/html;charset=utf-8,' + testName
|
||||
});
|
||||
|
||||
assert.pass("Created sidebar");
|
||||
|
||||
let mainWindow = getMostRecentBrowserWindow();
|
||||
let newWindow = yield windowPromise(mainWindow.OpenBrowserWindow(), 'load');
|
||||
assert.pass("Created the new window");
|
||||
|
@ -1504,21 +1509,26 @@ exports.testShowHideRawWindowArg = function*(assert) {
|
|||
yield focus(newWindow);
|
||||
assert.pass("Focused the new window");
|
||||
|
||||
yield focus(mainWindow);
|
||||
assert.pass("Focused the old window");
|
||||
let newWindow2 = yield windowPromise(mainWindow.OpenBrowserWindow(), 'load');
|
||||
assert.pass("Created the second new window");
|
||||
|
||||
yield focus(newWindow2);
|
||||
assert.pass("Focused the second new window");
|
||||
|
||||
yield sidebar.show(newWindow);
|
||||
|
||||
assert.pass('the sidebar was shown');
|
||||
assert.equal(isSidebarShowing(mainWindow), false, 'sidebar is not showing in main window');
|
||||
assert.equal(isSidebarShowing(newWindow2), false, 'sidebar is not showing in second window');
|
||||
assert.equal(isSidebarShowing(newWindow), true, 'sidebar is showing in new window');
|
||||
|
||||
assert.ok(isFocused(mainWindow), 'main window is still focused');
|
||||
assert.ok(isFocused(newWindow2), 'main window is still focused');
|
||||
|
||||
yield sidebar.hide(newWindow);
|
||||
|
||||
assert.equal(isFocused(mainWindow), true, 'main window is still focused');
|
||||
assert.equal(isFocused(newWindow2), true, 'second window is still focused');
|
||||
assert.equal(isSidebarShowing(mainWindow), false, 'sidebar is not showing in main window');
|
||||
assert.equal(isSidebarShowing(newWindow2), false, 'sidebar is not showing in second window');
|
||||
assert.equal(isSidebarShowing(newWindow), false, 'sidebar is not showing in new window');
|
||||
|
||||
sidebar.destroy();
|
||||
|
|
|
@ -31,7 +31,7 @@ const openWindow = () => {
|
|||
exports.openWindow = openWindow;
|
||||
|
||||
const closeWindow = (window) => {
|
||||
const closed = when(window, "unload", true).then(_target);
|
||||
const closed = when(window, "unload", true).then(_ => window);
|
||||
window.close();
|
||||
return closed;
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ const { Cc, Ci } = require('chrome');
|
|||
const { setTimeout } = require('sdk/timers');
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const { onFocus, getMostRecentWindow, windows, isBrowser, getWindowTitle, isFocused } = require('sdk/window/utils');
|
||||
const { open, close, focus } = require('sdk/window/helpers');
|
||||
const { open, close, focus, promise: windowPromise } = require('sdk/window/helpers');
|
||||
const { browserWindows } = require("sdk/windows");
|
||||
const tabs = require("sdk/tabs");
|
||||
const winUtils = require("sdk/deprecated/window-utils");
|
||||
|
@ -17,6 +17,9 @@ const { viewFor } = require("sdk/view/core");
|
|||
const { defer } = require("sdk/lang/functional");
|
||||
const { cleanUI } = require("sdk/test/utils");
|
||||
const { after } = require("sdk/test/utils");
|
||||
const { merge } = require("sdk/util/object");
|
||||
const self = require("sdk/self");
|
||||
const { openTab } = require("../tabs/utils");
|
||||
|
||||
// TEST: open & close window
|
||||
exports.testOpenAndCloseWindow = function(assert, done) {
|
||||
|
@ -59,12 +62,9 @@ exports.testNeWindowIsFocused = function(assert, done) {
|
|||
});
|
||||
}
|
||||
|
||||
exports.testOpenRelativePathWindow = function(assert, done) {
|
||||
exports.testOpenRelativePathWindow = function*(assert) {
|
||||
assert.equal(browserWindows.length, 1, "Only one window open");
|
||||
|
||||
const { merge } = require("sdk/util/object");
|
||||
const self = require("sdk/self");
|
||||
|
||||
let loader = Loader(module, null, null, {
|
||||
modules: {
|
||||
"sdk/self": merge({}, self, {
|
||||
|
@ -72,17 +72,31 @@ exports.testOpenRelativePathWindow = function(assert, done) {
|
|||
})
|
||||
}
|
||||
});
|
||||
assert.pass("Created a new loader");
|
||||
|
||||
loader.require("sdk/windows").browserWindows.open({
|
||||
url: "./test.html",
|
||||
onOpen: (window) => {
|
||||
window.tabs.activeTab.once("ready", (tab) => {
|
||||
assert.equal(tab.title, "foo",
|
||||
"tab opened a document with relative path");
|
||||
done();
|
||||
});
|
||||
}
|
||||
})
|
||||
let tabReady = new Promise(resolve => {
|
||||
loader.require("sdk/tabs").on("ready", (tab) => {
|
||||
if (!/test\.html$/.test(tab.url))
|
||||
return;
|
||||
assert.equal(tab.title, "foo",
|
||||
"tab opened a document with relative path");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
yield new Promise(resolve => {
|
||||
loader.require("sdk/windows").browserWindows.open({
|
||||
url: "./test.html",
|
||||
onOpen: (window) => {
|
||||
assert.pass("Created a new window");
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
yield tabReady;
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
exports.testAutomaticDestroy = function(assert, done) {
|
||||
|
@ -218,52 +232,26 @@ exports.testOnOpenOnCloseListeners = function(assert, done) {
|
|||
|
||||
exports.testActiveWindow = function*(assert) {
|
||||
let windows = browserWindows;
|
||||
|
||||
// API window objects
|
||||
let window2, window3;
|
||||
let window = getMostRecentWindow();
|
||||
|
||||
// Raw window objects
|
||||
let rawWindow2, rawWindow3;
|
||||
let rawWindow2 = yield windowPromise(window.OpenBrowserWindow(), "load").then(focus);
|
||||
assert.pass("Window 2 was created");
|
||||
|
||||
yield new Promise(resolve => {
|
||||
windows.open({
|
||||
url: "data:text/html;charset=utf-8,<title>window 2</title>",
|
||||
onOpen: (window) => {
|
||||
assert.pass('window 2 open');
|
||||
// open a tab in window 2
|
||||
yield openTab(rawWindow2, "data:text/html;charset=utf-8,<title>window 2</title>");
|
||||
|
||||
window.tabs.activeTab.once('ready', () => {
|
||||
assert.pass('window 2 tab activated');
|
||||
assert.equal(rawWindow2.content.document.title, "window 2", "Got correct raw window 2");
|
||||
assert.equal(rawWindow2.document.title, windows[1].title, "Saw correct title on window 2");
|
||||
|
||||
window2 = window;
|
||||
rawWindow2 = viewFor(window);
|
||||
let rawWindow3 = yield windowPromise(window.OpenBrowserWindow(), "load").then(focus);;
|
||||
assert.pass("Window 3 was created");
|
||||
|
||||
assert.equal(rawWindow2.content.document.title, "window 2", "Got correct raw window 2");
|
||||
assert.equal(rawWindow2.document.title, window2.title, "Saw correct title on window 2");
|
||||
// open a tab in window 3
|
||||
yield openTab(rawWindow3, "data:text/html;charset=utf-8,<title>window 3</title>");
|
||||
|
||||
windows.open({
|
||||
url: "data:text/html;charset=utf-8,<title>window 3</title>",
|
||||
onOpen: (window) => {
|
||||
assert.pass('window 3 open');
|
||||
|
||||
window.tabs.activeTab.once('ready', () => {
|
||||
assert.pass('window 3 tab activated');
|
||||
|
||||
window3 = window;
|
||||
rawWindow3 = viewFor(window);
|
||||
|
||||
assert.equal(rawWindow3.content.document.title, "window 3", "Got correct raw window 3");
|
||||
assert.equal(rawWindow3.document.title, window3.title, "Saw correct title on window 3");
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
yield focus(rawWindow3);
|
||||
assert.equal(rawWindow3.content.document.title, "window 3", "Got correct raw window 3");
|
||||
assert.equal(rawWindow3.document.title, windows[2].title, "Saw correct title on window 3");
|
||||
|
||||
assert.equal(windows.length, 3, "Correct number of browser windows");
|
||||
|
||||
|
@ -272,11 +260,13 @@ exports.testActiveWindow = function*(assert) {
|
|||
count++;
|
||||
}
|
||||
assert.equal(count, 3, "Correct number of windows returned by iterator");
|
||||
assert.equal(windows.activeWindow.title, window3.title, "Correct active window title - 3");
|
||||
assert.equal(windows.activeWindow.title, windows[2].title, "Correct active window title - 3");
|
||||
let window3 = windows[2];
|
||||
|
||||
yield focus(rawWindow2);
|
||||
|
||||
assert.equal(windows.activeWindow.title, window2.title, "Correct active window title - 2");
|
||||
assert.equal(windows.activeWindow.title, windows[1].title, "Correct active window title - 2");
|
||||
let window2 = windows[1];
|
||||
|
||||
yield new Promise(resolve => {
|
||||
onFocus(rawWindow2).then(resolve);
|
||||
|
@ -284,7 +274,7 @@ exports.testActiveWindow = function*(assert) {
|
|||
assert.pass("activating window2");
|
||||
});
|
||||
|
||||
assert.equal(windows.activeWindow.title, window2.title, "Correct active window - 2");
|
||||
assert.equal(windows.activeWindow.title, windows[1].title, "Correct active window - 2");
|
||||
|
||||
yield new Promise(resolve => {
|
||||
onFocus(rawWindow3).then(resolve);
|
||||
|
@ -391,21 +381,32 @@ exports.testTrackWindows = function(assert, done) {
|
|||
}
|
||||
|
||||
// test that it is not possible to open a private window by default
|
||||
exports.testWindowOpenPrivateDefault = function(assert, done) {
|
||||
browserWindows.open({
|
||||
url: 'about:mozilla',
|
||||
exports.testWindowOpenPrivateDefault = function*(assert) {
|
||||
const TITLE = "yo";
|
||||
const URL = "data:text/html,<title>" + TITLE + "</title>";
|
||||
|
||||
let tabReady = new Promise(resolve => {
|
||||
tabs.on('ready', function onTabReady(tab) {
|
||||
if (tab.url != URL)
|
||||
return;
|
||||
|
||||
tabs.removeListener('ready', onTabReady);
|
||||
assert.equal(tab.title, TITLE, 'opened correct tab');
|
||||
assert.equal(isPrivate(tab), false, 'tab is not private');
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
|
||||
yield new Promise(resolve => browserWindows.open({
|
||||
url: URL,
|
||||
isPrivate: true,
|
||||
onOpen: function(window) {
|
||||
let tab = window.tabs[0];
|
||||
|
||||
tab.once('ready', function() {
|
||||
assert.equal(tab.url, 'about:mozilla', 'opened correct tab');
|
||||
assert.equal(isPrivate(tab), false, 'tab is not private');
|
||||
|
||||
done();
|
||||
});
|
||||
assert.pass("the new window was opened");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
yield tabReady;
|
||||
}
|
||||
|
||||
// test that it is not possible to find a private window in
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="00d50b78a7a99de5b0b55309a467807c677e2a66"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="aebfbd998041e960cea0468533c0b5041b504850"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -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="00d50b78a7a99de5b0b55309a467807c677e2a66"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="aebfbd998041e960cea0468533c0b5041b504850"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="00d50b78a7a99de5b0b55309a467807c677e2a66"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="aebfbd998041e960cea0468533c0b5041b504850"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="00d50b78a7a99de5b0b55309a467807c677e2a66"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="aebfbd998041e960cea0468533c0b5041b504850"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="00d50b78a7a99de5b0b55309a467807c677e2a66"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="aebfbd998041e960cea0468533c0b5041b504850"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -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="00d50b78a7a99de5b0b55309a467807c677e2a66"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="aebfbd998041e960cea0468533c0b5041b504850"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="00d50b78a7a99de5b0b55309a467807c677e2a66"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="aebfbd998041e960cea0468533c0b5041b504850"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="00d50b78a7a99de5b0b55309a467807c677e2a66"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="aebfbd998041e960cea0468533c0b5041b504850"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "00d50b78a7a99de5b0b55309a467807c677e2a66",
|
||||
"git_revision": "aebfbd998041e960cea0468533c0b5041b504850",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "c1db04cf683e85135ca587f1f414d4456b20cfa0",
|
||||
"revision": "26282fe3ad19972a8d84cdc7eee85f73b6cfcc4e",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="00d50b78a7a99de5b0b55309a467807c677e2a66"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="aebfbd998041e960cea0468533c0b5041b504850"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="00d50b78a7a99de5b0b55309a467807c677e2a66"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="aebfbd998041e960cea0468533c0b5041b504850"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -490,7 +490,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", "resource:///modules/Panel
|
|||
|
||||
let wasVisible = false;
|
||||
// Hide the infobar from the previous tab.
|
||||
if (event.detail.previousTabfromTab) {
|
||||
if (event.detail.previousTab) {
|
||||
wasVisible = this._hideBrowserSharingInfoBar(false, event.detail.previousTab.linkedBrowser);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
<popupnotification id="password-notification" hidden="true">
|
||||
<popupnotificationcontent orient="vertical">
|
||||
<textbox id="password-notification-username" disabled="true"/>
|
||||
<textbox id="password-notification-username"/>
|
||||
<textbox id="password-notification-password" type="password"
|
||||
disabled="true"/>
|
||||
</popupnotificationcontent>
|
||||
|
|
|
@ -14,6 +14,6 @@ function startMiddleClickTestCase(aTestNumber) {
|
|||
}
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(5); // slowwww shutdown on e10s
|
||||
requestLongerTimeout(10); // slowwww shutdown on e10s
|
||||
startReferrerTest(startMiddleClickTestCase);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,6 @@ function startNewPrivateWindowTestCase(aTestNumber) {
|
|||
}
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(5); // slowwww shutdown on e10s
|
||||
requestLongerTimeout(10); // slowwww shutdown on e10s
|
||||
startReferrerTest(startNewPrivateWindowTestCase);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,6 @@ function startNewTabTestCase(aTestNumber) {
|
|||
}
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(5); // slowwww shutdown on e10s
|
||||
requestLongerTimeout(10); // slowwww shutdown on e10s
|
||||
startReferrerTest(startNewTabTestCase);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,6 @@ function startNewWindowTestCase(aTestNumber) {
|
|||
}
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(5); // slowwww shutdown on e10s
|
||||
requestLongerTimeout(10); // slowwww shutdown on e10s
|
||||
startReferrerTest(startNewWindowTestCase);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,6 @@ function startSimpleClickTestCase(aTestNumber) {
|
|||
};
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(5); // slowwww shutdown on e10s
|
||||
requestLongerTimeout(10); // slowwww shutdown on e10s
|
||||
startReferrerTest(startSimpleClickTestCase);
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
<hbox align="center">
|
||||
<label control="defaultFont" accesskey="&defaultFont.accesskey;">&defaultFont.label;</label>
|
||||
<menulist id="defaultFont" flex="1"/>
|
||||
<label control="defaultFontSize" accesskey="&defaultSize.accesskey;">&defaultSize.label;</label>
|
||||
<label id="defaultFontSizeLabel" control="defaultFontSize" accesskey="&defaultSize.accesskey;">&defaultSize.label;</label>
|
||||
<menulist id="defaultFontSize">
|
||||
<menupopup>
|
||||
<menuitem value="9" label="9"/>
|
||||
|
|
|
@ -72,14 +72,9 @@ let SessionMigrationInternal = {
|
|||
win._closedTabs = [];
|
||||
return win;
|
||||
});
|
||||
let wrappedState = {
|
||||
url: "about:welcomeback",
|
||||
formdata: {
|
||||
id: {"sessionData": state},
|
||||
xpath: {}
|
||||
}
|
||||
};
|
||||
return {windows: [{tabs: [{entries: [wrappedState]}]}]};
|
||||
let url = "about:welcomeback";
|
||||
let formdata = {id: {sessionData: state}, url};
|
||||
return {windows: [{tabs: [{entries: [{url}], formdata}]}]};
|
||||
},
|
||||
/**
|
||||
* Asynchronously read session restore state (JSON) from a path
|
||||
|
|
|
@ -470,14 +470,9 @@ let SessionStoreInternal = {
|
|||
|
||||
if (this._needsRestorePage(state, this._recentCrashes)) {
|
||||
// replace the crashed session with a restore-page-only session
|
||||
let pageData = {
|
||||
url: "about:sessionrestore",
|
||||
formdata: {
|
||||
id: { "sessionData": state },
|
||||
xpath: {}
|
||||
}
|
||||
};
|
||||
state = { windows: [{ tabs: [{ entries: [pageData] }] }] };
|
||||
let url = "about:sessionrestore";
|
||||
let formdata = {id: {sessionData: state}, url};
|
||||
state = { windows: [{ tabs: [{ entries: [{url}], formdata }] }] };
|
||||
} else if (this._hasSingleTabWithURL(state.windows,
|
||||
"about:welcomeback")) {
|
||||
// On a single about:welcomeback URL that crashed, replace about:welcomeback
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
let HiddenFrame = Cu.import("resource:///modules/HiddenFrame.jsm", {}).HiddenFrame;
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
|
@ -14,33 +16,25 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|||
* The URL to open in the browser.
|
||||
**/
|
||||
function createHiddenBrowser(aURL) {
|
||||
let deferred = Promise.defer();
|
||||
let hiddenDoc = Services.appShell.hiddenDOMWindow.document;
|
||||
let frame = new HiddenFrame();
|
||||
return new Promise(resolve =>
|
||||
frame.get().then(aFrame => {
|
||||
let doc = aFrame.document;
|
||||
let browser = doc.createElementNS(XUL_NS, "browser");
|
||||
browser.setAttribute("type", "content");
|
||||
browser.setAttribute("disableglobalhistory", "true");
|
||||
browser.setAttribute("src", aURL);
|
||||
|
||||
// Create a HTML iframe with a chrome URL, then this can host the browser.
|
||||
let iframe = hiddenDoc.createElementNS(HTML_NS, "iframe");
|
||||
iframe.setAttribute("src", "chrome://global/content/mozilla.xhtml");
|
||||
iframe.addEventListener("load", function onLoad() {
|
||||
iframe.removeEventListener("load", onLoad, true);
|
||||
|
||||
let browser = iframe.contentDocument.createElementNS(XUL_NS, "browser");
|
||||
browser.setAttribute("type", "content");
|
||||
browser.setAttribute("disableglobalhistory", "true");
|
||||
browser.setAttribute("src", aURL);
|
||||
|
||||
iframe.contentDocument.documentElement.appendChild(browser);
|
||||
deferred.resolve({frame: iframe, browser: browser});
|
||||
}, true);
|
||||
|
||||
hiddenDoc.documentElement.appendChild(iframe);
|
||||
return deferred.promise;
|
||||
};
|
||||
doc.documentElement.appendChild(browser);
|
||||
resolve({frame: frame, browser: browser});
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the browser and the iframe.
|
||||
* Remove the browser and the HiddenFrame.
|
||||
*
|
||||
* @param aFrame
|
||||
* The iframe to dismiss.
|
||||
* The HiddenFrame to dismiss.
|
||||
* @param aBrowser
|
||||
* The browser to dismiss.
|
||||
*/
|
||||
|
@ -49,9 +43,7 @@ function destroyHiddenBrowser(aFrame, aBrowser) {
|
|||
aBrowser.remove();
|
||||
|
||||
// Take care of the frame holding our invisible browser.
|
||||
if (!Cu.isDeadWrapper(aFrame)) {
|
||||
aFrame.remove();
|
||||
}
|
||||
aFrame.destroy();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -496,10 +496,22 @@ ThreadState.prototype = {
|
|||
// Ignore "interrupted" events, to avoid UI flicker. These are generated
|
||||
// by the slow script dialog and internal events such as setting
|
||||
// breakpoints. Pressing the resume button does need to be shown, though.
|
||||
if (aEvent == "paused" &&
|
||||
aPacket.why.type == "interrupted" &&
|
||||
!this.interruptedByResumeButton) {
|
||||
return;
|
||||
if (aEvent == "paused") {
|
||||
if (aPacket.why.type == "interrupted" &&
|
||||
!this.interruptedByResumeButton) {
|
||||
return;
|
||||
} else if (aPacket.why.type == "breakpointConditionThrown" && aPacket.why.message) {
|
||||
let where = aPacket.frame.where;
|
||||
let aLocation = {
|
||||
line: where.line,
|
||||
column: where.column,
|
||||
actor: where.source ? where.source.actor : null
|
||||
};
|
||||
DebuggerView.Sources.showBreakpointConditionThrownMessage(
|
||||
aLocation,
|
||||
aPacket.why.message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.interruptedByResumeButton = false;
|
||||
|
@ -590,6 +602,10 @@ StackFrames.prototype = {
|
|||
case "breakpoint":
|
||||
this._currentBreakpointLocation = aPacket.frame.where;
|
||||
break;
|
||||
case "breakpointConditionThrown":
|
||||
this._currentBreakpointLocation = aPacket.frame.where;
|
||||
this._conditionThrowMessage = aPacket.why.message;
|
||||
break;
|
||||
// If paused by a client evaluation, store the evaluated value.
|
||||
case "clientEvaluated":
|
||||
this._currentEvaluation = aPacket.why.frameFinished;
|
||||
|
|
|
@ -450,6 +450,19 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
this._unselectBreakpoint();
|
||||
},
|
||||
|
||||
/**
|
||||
* Display the message thrown on breakpoint condition
|
||||
*/
|
||||
showBreakpointConditionThrownMessage: function(aLocation, aMessage = "") {
|
||||
let breakpointItem = this.getBreakpoint(aLocation);
|
||||
if (!breakpointItem) {
|
||||
return;
|
||||
}
|
||||
let attachment = breakpointItem.attachment;
|
||||
attachment.view.container.classList.add("dbg-breakpoint-condition-thrown");
|
||||
attachment.view.message.setAttribute("value", aMessage);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the checked/unchecked and enabled/disabled states of the buttons in
|
||||
* the sources toolbar based on the currently selected source's state.
|
||||
|
@ -689,12 +702,13 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
* - location: the breakpoint's source location and line number
|
||||
* - disabled: the breakpoint's disabled state, boolean
|
||||
* - text: the breakpoint's line text to be displayed
|
||||
* - message: thrown string when the breakpoint condition throws,
|
||||
* @return object
|
||||
* An object containing the breakpoint container, checkbox,
|
||||
* line number and line text nodes.
|
||||
*/
|
||||
_createBreakpointView: function(aOptions) {
|
||||
let { location, disabled, text } = aOptions;
|
||||
let { location, disabled, text, message } = aOptions;
|
||||
let identifier = DebuggerController.Breakpoints.getIdentifier(location);
|
||||
|
||||
let checkbox = document.createElement("checkbox");
|
||||
|
@ -714,6 +728,26 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
let tooltip = text ? text.substr(0, BREAKPOINT_LINE_TOOLTIP_MAX_LENGTH) : "";
|
||||
lineTextNode.setAttribute("tooltiptext", tooltip);
|
||||
|
||||
let thrownNode = document.createElement("label");
|
||||
thrownNode.className = "plain dbg-breakpoint-condition-thrown-message dbg-breakpoint-text";
|
||||
thrownNode.setAttribute("value", message);
|
||||
thrownNode.setAttribute("crop", "end");
|
||||
thrownNode.setAttribute("flex", "1");
|
||||
|
||||
let bpLineContainer = document.createElement("hbox");
|
||||
bpLineContainer.className = "plain dbg-breakpoint-line-container";
|
||||
bpLineContainer.setAttribute("flex", "1");
|
||||
|
||||
bpLineContainer.appendChild(lineNumberNode);
|
||||
bpLineContainer.appendChild(lineTextNode);
|
||||
|
||||
let bpDetailContainer = document.createElement("vbox");
|
||||
bpDetailContainer.className = "plain dbg-breakpoint-detail-container";
|
||||
bpDetailContainer.setAttribute("flex", "1");
|
||||
|
||||
bpDetailContainer.appendChild(bpLineContainer);
|
||||
bpDetailContainer.appendChild(thrownNode);
|
||||
|
||||
let container = document.createElement("hbox");
|
||||
container.id = "breakpoint-" + identifier;
|
||||
container.className = "dbg-breakpoint side-menu-widget-item-other";
|
||||
|
@ -725,14 +759,14 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
checkbox.addEventListener("click", this._onBreakpointCheckboxClick, false);
|
||||
|
||||
container.appendChild(checkbox);
|
||||
container.appendChild(lineNumberNode);
|
||||
container.appendChild(lineTextNode);
|
||||
container.appendChild(bpDetailContainer);
|
||||
|
||||
return {
|
||||
container: container,
|
||||
checkbox: checkbox,
|
||||
lineNumber: lineNumberNode,
|
||||
lineText: lineTextNode
|
||||
lineText: lineTextNode,
|
||||
message: thrownNode
|
||||
};
|
||||
},
|
||||
|
||||
|
|
|
@ -48,3 +48,13 @@
|
|||
#body[layout=vertical] #stackframes {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#source-progress-container {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#source-progress {
|
||||
flex: none;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
macanimationtype="document"
|
||||
fullscreenbutton="true"
|
||||
screenX="4" screenY="4"
|
||||
|
@ -421,12 +422,12 @@
|
|||
label="&debuggerUI.blackBoxMessage.unBlackBoxButton;"
|
||||
command="unBlackBoxCommand"/>
|
||||
</vbox>
|
||||
<vbox id="source-progress-container"
|
||||
align="center"
|
||||
pack="center">
|
||||
<progressmeter id="source-progress"
|
||||
mode="undetermined"/>
|
||||
</vbox>
|
||||
<html:div id="source-progress-container"
|
||||
align="center">
|
||||
<html:div id="hbox">
|
||||
<html:progress id="source-progress"></html:progress>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</deck>
|
||||
<splitter id="editor-and-instruments-splitter"
|
||||
class="devtools-side-splitter"/>
|
||||
|
|
|
@ -143,6 +143,8 @@ skip-if = e10s # TODO
|
|||
skip-if = e10s # Bug 1093535
|
||||
[browser_dbg_breakpoints-button-01.js]
|
||||
[browser_dbg_breakpoints-button-02.js]
|
||||
[browser_dbg_breakpoints-condition-thrown-message.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_breakpoints-contextmenu-add.js]
|
||||
[browser_dbg_breakpoints-contextmenu.js]
|
||||
[browser_dbg_breakpoints-disabled-reload.js]
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure that the message which breakpoint condition throws
|
||||
* could be displayed on UI correctly
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
|
||||
|
||||
function test() {
|
||||
let gTab, gPanel, gDebugger, gEditor;
|
||||
let gSources, gLocation;
|
||||
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
gSources = gDebugger.DebuggerView.Sources;
|
||||
|
||||
waitForSourceAndCaretAndScopes(gPanel, ".html", 17)
|
||||
.then(addBreakpoints)
|
||||
.then(() => resumeAndTestThrownMessage(18))
|
||||
.then(() => resumeAndTestNoThrownMessage(19))
|
||||
.then(() => resumeAndTestThrownMessage(22))
|
||||
.then(() => resumeAndFinishTest())
|
||||
.then(() => closeDebuggerAndFinish(gPanel))
|
||||
.then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
|
||||
callInTab(gTab, "ermahgerd");
|
||||
});
|
||||
|
||||
function resumeAndTestThrownMessage(aLine) {
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
gDebugger.document.getElementById("resume"),
|
||||
gDebugger);
|
||||
|
||||
let finished = waitForCaretUpdated(gPanel, aLine).then(() => {
|
||||
//test that the thrown message is correctly shown
|
||||
let attachment = gSources.getBreakpoint({ actor: gSources.values[0], line: aLine}).attachment;
|
||||
ok(attachment.view.container.classList.contains('dbg-breakpoint-condition-thrown'),
|
||||
"Message on line " + aLine + " should be shown when condition throws.");
|
||||
});
|
||||
|
||||
return finished;
|
||||
}
|
||||
|
||||
function resumeAndTestNoThrownMessage(aLine) {
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
gDebugger.document.getElementById("resume"),
|
||||
gDebugger);
|
||||
|
||||
let finished = waitForCaretUpdated(gPanel, aLine).then(() => {
|
||||
//test that the thrown message is correctly shown
|
||||
let attachment = gSources.getBreakpoint({ actor: gSources.values[0], line: aLine}).attachment;
|
||||
ok(!attachment.view.container.classList.contains("dbg-breakpoint-condition-thrown"),
|
||||
"Message on line " + aLine + " should be hidden if condition doesn't throw.");
|
||||
});
|
||||
return finished;
|
||||
}
|
||||
|
||||
function resumeAndFinishTest() {
|
||||
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED)
|
||||
|
||||
gDebugger.gThreadClient.resume();
|
||||
|
||||
return finished;
|
||||
}
|
||||
|
||||
function addBreakpoints() {
|
||||
return promise.resolve(null)
|
||||
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue,
|
||||
line: 18,
|
||||
condition: " 1a"}))
|
||||
.then(() => initialCheck(18))
|
||||
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue,
|
||||
line: 19,
|
||||
condition: "true"}))
|
||||
.then(() => initialCheck(19))
|
||||
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue,
|
||||
line: 20,
|
||||
condition: "false"}))
|
||||
.then(() => initialCheck(20))
|
||||
.then(() => gPanel.addBreakpoint({ actor: gSources.selectedValue,
|
||||
line: 22,
|
||||
condition: "randomVar"}))
|
||||
.then(() => initialCheck(22));
|
||||
}
|
||||
|
||||
function initialCheck(aCaretLine) {
|
||||
let bp = gSources.getBreakpoint({ actor: gSources.values[0], line: aCaretLine})
|
||||
let attachment = bp.attachment;
|
||||
ok(attachment,
|
||||
"There should be an item for line " + aCaretLine + " in the sources pane.");
|
||||
|
||||
let thrownNode = attachment.view.container.querySelector(".dbg-breakpoint-condition-thrown-message");
|
||||
ok(thrownNode,
|
||||
"The breakpoint item should contain a thrown message node.")
|
||||
|
||||
ok(!attachment.view.container.classList.contains("dbg-breakpoint-condition-thrown"),
|
||||
"The thrown message on line " + aCaretLine + " should be hidden when condition has not been evaluated.")
|
||||
}
|
||||
}
|
|
@ -435,11 +435,8 @@ function Rule(aElementStyle, aOptions) {
|
|||
this.keyframes = aOptions.keyframes || null;
|
||||
this._modificationDepth = 0;
|
||||
|
||||
if (this.domRule) {
|
||||
let parentRule = this.domRule.parentRule;
|
||||
if (parentRule && parentRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE) {
|
||||
this.mediaText = parentRule.mediaText;
|
||||
}
|
||||
if (this.domRule && this.domRule.mediaText) {
|
||||
this.mediaText = this.domRule.mediaText;
|
||||
}
|
||||
|
||||
// Populate the text properties with the style's current cssText
|
||||
|
@ -507,7 +504,7 @@ Rule.prototype = {
|
|||
* The rule's line within a stylesheet
|
||||
*/
|
||||
get ruleLine() {
|
||||
return this.domRule ? this.domRule.line : null;
|
||||
return this.domRule ? this.domRule.line : "";
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -529,10 +526,12 @@ Rule.prototype = {
|
|||
if (this._originalSourceStrings) {
|
||||
return promise.resolve(this._originalSourceStrings);
|
||||
}
|
||||
return this.domRule.getOriginalLocation().then(({href, line}) => {
|
||||
return this.domRule.getOriginalLocation().then(({href, line, mediaText}) => {
|
||||
let mediaString = mediaText ? " @" + mediaText : "";
|
||||
|
||||
let sourceStrings = {
|
||||
full: href + ":" + line,
|
||||
short: CssLogic.shortSource({href: href}) + ":" + line
|
||||
full: (href || CssLogic.l10n("rule.sourceInline")) + ":" + line + mediaString,
|
||||
short: CssLogic.shortSource({href: href}) + ":" + line + mediaString
|
||||
};
|
||||
|
||||
this._originalSourceStrings = sourceStrings;
|
||||
|
|
|
@ -12,8 +12,10 @@ add_task(function*() {
|
|||
|
||||
info("Creating the test document");
|
||||
let style = "" +
|
||||
"#testid {" +
|
||||
" background-color: blue;" +
|
||||
"@media screen and (min-width: 10px) {" +
|
||||
" #testid {" +
|
||||
" background-color: blue;" +
|
||||
" }" +
|
||||
"}" +
|
||||
".testclass, .unmatched {" +
|
||||
" background-color: green;" +
|
||||
|
@ -35,6 +37,15 @@ function* testContentAfterNodeSelection(inspector, ruleView) {
|
|||
"After highlighting null, has a no-results element again.");
|
||||
|
||||
yield selectNode("#testid", inspector);
|
||||
|
||||
let linkText = getRuleViewLinkTextByIndex(ruleView, 1);
|
||||
is(linkText, "inline:1 @screen and (min-width: 10px)",
|
||||
"link text at index 1 contains media query text.");
|
||||
|
||||
linkText = getRuleViewLinkTextByIndex(ruleView, 2);
|
||||
is(linkText, "inline:1",
|
||||
"link text at index 2 contains no media query text.");
|
||||
|
||||
let classEditor = getRuleViewRuleEditor(ruleView, 2);
|
||||
is(classEditor.selectorText.querySelector(".ruleview-selector-matched").textContent,
|
||||
".testclass", ".textclass should be matched.");
|
||||
|
|
|
@ -693,6 +693,17 @@ function getRuleViewLinkByIndex(view, index) {
|
|||
return links[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rule-link text from the rule-view given its index
|
||||
* @param {CssRuleView} view The instance of the rule-view panel
|
||||
* @param {Number} index The index of the link to get
|
||||
* @return {String} The string at this index
|
||||
*/
|
||||
function getRuleViewLinkTextByIndex(view, index) {
|
||||
let link = getRuleViewLinkByIndex(view, index);
|
||||
return link.querySelector(".source-link-label").value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rule editor from the rule-view given its index
|
||||
* @param {CssRuleView} view The instance of the rule-view panel
|
||||
|
|
|
@ -302,9 +302,8 @@ let UI = {
|
|||
},
|
||||
|
||||
busyUntil: function(promise, operationDescription) {
|
||||
// Freeze the UI until the promise is resolved. A 30s timeout
|
||||
// will unfreeze the UI, just in case the promise never gets
|
||||
// resolved.
|
||||
// Freeze the UI until the promise is resolved. A timeout will unfreeze the
|
||||
// UI, just in case the promise never gets resolved.
|
||||
this._busyPromise = promise;
|
||||
this._busyOperationDescription = operationDescription;
|
||||
this.setupBusyTimeout();
|
||||
|
@ -469,7 +468,13 @@ let UI = {
|
|||
// |busyUntil| will listen for rejections.
|
||||
// Bug 1121100 may find a better way to silence these.
|
||||
});
|
||||
return this.busyUntil(promise, "Connecting to " + name);
|
||||
promise = this.busyUntil(promise, "Connecting to " + name);
|
||||
// Stop busy timeout for runtimes that take unknown or long amounts of time
|
||||
// to connect.
|
||||
if (runtime.prolongedConnection) {
|
||||
this.cancelBusyTimeout();
|
||||
}
|
||||
return promise;
|
||||
},
|
||||
|
||||
updateRuntimeButton: function() {
|
||||
|
|
|
@ -66,6 +66,10 @@ const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/
|
|||
* |name| field
|
||||
* A user-visible label to identify the runtime that will be displayed in a
|
||||
* runtime list.
|
||||
* |prolongedConnection| field
|
||||
* A boolean value which should be |true| if the connection process is
|
||||
* expected to take a unknown or large amount of time. A UI may use this as a
|
||||
* hint to skip timeouts or other time-based code paths.
|
||||
* connect()
|
||||
* Configure the passed |connection| object with any settings need to
|
||||
* successfully connect to the runtime, and call the |connection|'s connect()
|
||||
|
@ -446,6 +450,8 @@ function WiFiRuntime(deviceName) {
|
|||
|
||||
WiFiRuntime.prototype = {
|
||||
type: RuntimeTypes.WIFI,
|
||||
// Mark runtime as taking a long time to connect
|
||||
prolongedConnection: true,
|
||||
connect: function(connection) {
|
||||
let service = discovery.getRemoteService("devtools", this.deviceName);
|
||||
if (!service) {
|
||||
|
|
|
@ -37,6 +37,7 @@ SimpleTest.registerCleanupFunction(() => {
|
|||
Services.prefs.clearUserPref("devtools.webide.autoinstallADBHelper");
|
||||
Services.prefs.clearUserPref("devtools.webide.autoinstallFxdtAdapters");
|
||||
Services.prefs.clearUserPref("devtools.webide.sidebars");
|
||||
Services.prefs.clearUserPref("devtools.webide.busyTimeout");
|
||||
});
|
||||
|
||||
function openWebIDE(autoInstallAddons) {
|
||||
|
|
|
@ -62,6 +62,30 @@
|
|||
}
|
||||
});
|
||||
|
||||
win.AppManager.runtimeList.usb.push({
|
||||
connect: function(connection) {
|
||||
let deferred = promise.defer();
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
get name() {
|
||||
return "infiniteRuntime";
|
||||
}
|
||||
});
|
||||
|
||||
win.AppManager.runtimeList.usb.push({
|
||||
connect: function(connection) {
|
||||
let deferred = promise.defer();
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
prolongedConnection: true,
|
||||
|
||||
get name() {
|
||||
return "prolongedRuntime";
|
||||
}
|
||||
});
|
||||
|
||||
win.AppManager.update("runtimelist");
|
||||
|
||||
let packagedAppLocation = getTestFilePath("app");
|
||||
|
@ -71,7 +95,7 @@
|
|||
|
||||
let panelNode = win.document.querySelector("#runtime-panel");
|
||||
let items = panelNode.querySelectorAll(".runtime-panel-item-usb");
|
||||
is(items.length, 1, "Found one runtime button");
|
||||
is(items.length, 3, "Found 3 runtime buttons");
|
||||
|
||||
let deferred = promise.defer();
|
||||
win.AppManager.connection.once(
|
||||
|
@ -104,7 +128,6 @@
|
|||
ok(isPlayActive(), "play button is enabled 3");
|
||||
ok(!isStopActive(), "stop button is disabled 3");
|
||||
|
||||
|
||||
yield win.Cmds.disconnectRuntime();
|
||||
|
||||
is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
|
||||
|
@ -137,6 +160,39 @@
|
|||
|
||||
yield win.Cmds.disconnectRuntime();
|
||||
|
||||
Services.prefs.setIntPref("devtools.webide.busyTimeout", 100);
|
||||
|
||||
// Wait for error message since connection never completes
|
||||
let errorDeferred = promise.defer();
|
||||
win.UI.reportError = errorName => {
|
||||
if (errorName === "error_operationTimeout") {
|
||||
errorDeferred.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
// Click the infinite runtime
|
||||
items[1].click();
|
||||
ok(win.document.querySelector("window").className, "busy", "UI is busy");
|
||||
yield errorDeferred.promise;
|
||||
|
||||
// Check for unexpected error message since this is prolonged
|
||||
let noErrorDeferred = promise.defer();
|
||||
win.UI.reportError = errorName => {
|
||||
if (errorName === "error_operationTimeout") {
|
||||
noErrorDeferred.reject();
|
||||
}
|
||||
};
|
||||
|
||||
// Click the prolonged runtime
|
||||
items[2].click();
|
||||
ok(win.document.querySelector("window").className, "busy", "UI is busy");
|
||||
|
||||
setTimeout(() => {
|
||||
noErrorDeferred.resolve();
|
||||
}, 1000);
|
||||
|
||||
yield noErrorDeferred.promise;
|
||||
|
||||
SimpleTest.finish();
|
||||
|
||||
});
|
||||
|
|
|
@ -13,7 +13,7 @@ pref("devtools.webide.enableLocalRuntime", false);
|
|||
pref("devtools.webide.addonsURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/fxos-simulator/index.json");
|
||||
pref("devtools.webide.simulatorAddonsURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/fxos-simulator/#VERSION#/#OS#/fxos_#SLASHED_VERSION#_simulator-#OS#-latest.xpi");
|
||||
pref("devtools.webide.simulatorAddonID", "fxos_#SLASHED_VERSION#_simulator@mozilla.org");
|
||||
pref("devtools.webide.simulatorAddonRegExp", "fxos_(.*)_simulator@mozilla\.org$");
|
||||
pref("devtools.webide.simulatorAddonRegExp", "fxos_(.*)_simulator@mozilla\\.org$");
|
||||
pref("devtools.webide.adbAddonURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/fxos-simulator/adb-helper/#OS#/adbhelper-#OS#-latest.xpi");
|
||||
pref("devtools.webide.adbAddonID", "adbhelper@mozilla.org");
|
||||
pref("devtools.webide.adaptersAddonURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/fxdt-adapters/#OS#/fxdt-adapters-#OS#-latest.xpi");
|
||||
|
|
|
@ -45,6 +45,16 @@
|
|||
margin: 2px;
|
||||
}
|
||||
|
||||
.dbg-breakpoint-condition-thrown-message {
|
||||
display: none;
|
||||
color: var(--theme-highlight-red);
|
||||
}
|
||||
|
||||
.dbg-breakpoint.dbg-breakpoint-condition-thrown .dbg-breakpoint-condition-thrown-message {
|
||||
display: block;
|
||||
-moz-padding-start: 0;
|
||||
}
|
||||
|
||||
/* Sources toolbar */
|
||||
|
||||
#sources-toolbar > .devtools-toolbarbutton,
|
||||
|
|
|
@ -151,6 +151,11 @@ treecol {
|
|||
margin-right: 4px !important;
|
||||
}
|
||||
|
||||
#defaultFontSizeLabel {
|
||||
/* !important needed to override common !important rule */
|
||||
-moz-margin-start: 4px !important;
|
||||
}
|
||||
|
||||
/* Applications Pane Styles */
|
||||
|
||||
#applicationsContent {
|
||||
|
|
|
@ -164,7 +164,8 @@ public:
|
|||
return GetOwner();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual void DisconnectFromOwner() override;
|
||||
|
||||
/**
|
||||
|
|
|
@ -95,7 +95,8 @@ BluetoothClassOfDevice::Create(nsPIDOMWindow* aOwner)
|
|||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothClassOfDevice::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
BluetoothClassOfDevice::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return BluetoothClassOfDeviceBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ struct JSContext;
|
|||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothClassOfDevice final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
class BluetoothClassOfDevice final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
@ -69,7 +69,8 @@ public:
|
|||
{
|
||||
return mOwnerWindow;
|
||||
}
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
BluetoothClassOfDevice(nsPIDOMWindow* aOwner);
|
||||
|
|
|
@ -320,7 +320,8 @@ BluetoothDevice::GetGatt()
|
|||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothDevice::WrapObject(JSContext* aContext, JS::Handle<JSObject*> aGivenProto)
|
||||
BluetoothDevice::WrapObject(JSContext* aContext,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return BluetoothDeviceBinding::Wrap(aContext, this, aGivenProto);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ class BluetoothSignal;
|
|||
class BluetoothSocket;
|
||||
|
||||
class BluetoothDevice final : public DOMEventTargetHelper
|
||||
, public BluetoothSignalObserver
|
||||
, public BluetoothSignalObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -94,7 +94,8 @@ public:
|
|||
return GetOwner();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual void DisconnectFromOwner() override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -58,7 +58,8 @@ BluetoothDiscoveryHandle::DispatchDeviceEvent(BluetoothDevice* aDevice)
|
|||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothDiscoveryHandle::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
BluetoothDiscoveryHandle::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return BluetoothDiscoveryHandleBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ public:
|
|||
|
||||
IMPL_EVENT_HANDLER(devicefound);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
BluetoothDiscoveryHandle(nsPIDOMWindow* aWindow);
|
||||
|
|
|
@ -314,7 +314,8 @@ BluetoothGatt::Notify(const BluetoothSignal& aData)
|
|||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothGatt::WrapObject(JSContext* aContext, JS::Handle<JSObject*> aGivenProto)
|
||||
BluetoothGatt::WrapObject(JSContext* aContext,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return BluetoothGattBinding::Wrap(aContext, this, aGivenProto);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ class BluetoothSignal;
|
|||
class BluetoothValue;
|
||||
|
||||
class BluetoothGatt final : public DOMEventTargetHelper
|
||||
, public BluetoothSignalObserver
|
||||
, public BluetoothSignalObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -70,7 +70,8 @@ public:
|
|||
return GetOwner();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual void DisconnectFromOwner() override;
|
||||
|
||||
BluetoothGatt(nsPIDOMWindow* aOwner,
|
||||
|
|
|
@ -20,8 +20,8 @@ BEGIN_BLUETOOTH_NAMESPACE
|
|||
class BluetoothAdapter;
|
||||
class BluetoothValue;
|
||||
|
||||
class BluetoothManager : public DOMEventTargetHelper
|
||||
, public BluetoothSignalObserver
|
||||
class BluetoothManager final : public DOMEventTargetHelper
|
||||
, public BluetoothSignalObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -63,7 +63,8 @@ public:
|
|||
return GetOwner();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual void DisconnectFromOwner() override;
|
||||
|
||||
/**
|
||||
|
|
|
@ -121,7 +121,8 @@ BluetoothPairingHandle::SetPairingConfirmation(bool aConfirm, ErrorResult& aRv)
|
|||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothPairingHandle::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
BluetoothPairingHandle::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return BluetoothPairingHandleBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ BEGIN_BLUETOOTH_NAMESPACE
|
|||
|
||||
class BluetoothDevice;
|
||||
|
||||
class BluetoothPairingHandle final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
class BluetoothPairingHandle final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
@ -39,7 +39,8 @@ public:
|
|||
return mOwner;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void GetPasskey(nsString& aPasskey) const
|
||||
{
|
||||
|
|
|
@ -108,7 +108,8 @@ BluetoothPairingListener::Notify(const BluetoothSignal& aData)
|
|||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothPairingListener::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
BluetoothPairingListener::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return BluetoothPairingListenerBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class BluetoothDevice;
|
|||
class BluetoothSignal;
|
||||
|
||||
class BluetoothPairingListener final : public DOMEventTargetHelper
|
||||
, public BluetoothSignalObserver
|
||||
, public BluetoothSignalObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -37,7 +37,8 @@ public:
|
|||
return GetOwner();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
virtual void DisconnectFromOwner() override;
|
||||
virtual void EventListenerAdded(nsIAtom* aType) override;
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class BluetoothGattClient;
|
|||
class BluetoothReplyRunnable;
|
||||
|
||||
class BluetoothGattManager final : public nsIObserver
|
||||
, public BluetoothGattNotificationHandler
|
||||
, public BluetoothGattNotificationHandler
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "nsIRadioVisitor.h"
|
||||
#include "nsIPhonetic.h"
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsIControllers.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsFocusManager.h"
|
||||
|
@ -4497,6 +4498,12 @@ HTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
// And now make sure our state is up to date
|
||||
UpdateState(false);
|
||||
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
if (mType == NS_FORM_INPUT_PASSWORD) {
|
||||
Telemetry::Accumulate(Telemetry::PWMGR_PASSWORD_INPUT_IN_FORM, !!mForm);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
@ -115,6 +115,11 @@ this.Keyboard = {
|
|||
// The application has been closed unexpectingly. Let's tell the
|
||||
// keyboard app that the focus has been lost.
|
||||
this.sendToKeyboard('Keyboard:FocusChange', { 'type': 'blur' });
|
||||
// Notify system app to hide keyboard.
|
||||
SystemAppProxy.dispatchEvent({
|
||||
type: 'inputmethod-contextchange',
|
||||
inputType: 'blur'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Ignore notifications that aren't from a BrowserOrApp
|
||||
|
|
|
@ -2988,6 +2988,7 @@ public class BrowserApp extends GeckoApp
|
|||
bookmark.setCheckable(true);
|
||||
bookmark.setChecked(tab.isBookmark());
|
||||
bookmark.setIcon(resolveBookmarkIconID(tab.isBookmark()));
|
||||
bookmark.setTitle(resolveBookmarkTitleID(tab.isBookmark()));
|
||||
|
||||
reader.setEnabled(isAboutReader || !AboutPages.isAboutPage(tab.getURL()));
|
||||
reader.setVisible(!inGuestMode);
|
||||
|
@ -3116,6 +3117,10 @@ public class BrowserApp extends GeckoApp
|
|||
}
|
||||
}
|
||||
|
||||
private int resolveBookmarkTitleID(final boolean isBookmark) {
|
||||
return (isBookmark ? R.string.bookmark_remove : R.string.bookmark);
|
||||
}
|
||||
|
||||
private int resolveReadingListIconID(final boolean isInReadingList) {
|
||||
return (isInReadingList ? R.drawable.ic_menu_reader_remove : R.drawable.ic_menu_reader_add);
|
||||
}
|
||||
|
@ -3146,10 +3151,12 @@ public class BrowserApp extends GeckoApp
|
|||
Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.MENU, "bookmark");
|
||||
tab.removeBookmark();
|
||||
item.setIcon(resolveBookmarkIconID(false));
|
||||
item.setTitle(resolveBookmarkTitleID(false));
|
||||
} else {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SAVE, TelemetryContract.Method.MENU, "bookmark");
|
||||
tab.addBookmark();
|
||||
item.setIcon(resolveBookmarkIconID(true));
|
||||
item.setTitle(resolveBookmarkTitleID(true));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<!ENTITY url_bar_default_text2 "Search or enter address">
|
||||
|
||||
<!ENTITY bookmark "Bookmark">
|
||||
<!ENTITY bookmark_remove "Remove bookmark">
|
||||
<!ENTITY bookmark_added "Bookmark added">
|
||||
<!ENTITY bookmark_removed "Bookmark removed">
|
||||
<!ENTITY bookmark_updated "Bookmark updated">
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
<string name="quit">&quit;</string>
|
||||
<string name="bookmark">&bookmark;</string>
|
||||
<string name="bookmark_remove">&bookmark_remove;</string>
|
||||
<string name="bookmark_added">&bookmark_added;</string>
|
||||
<string name="bookmark_removed">&bookmark_removed;</string>
|
||||
<string name="bookmark_updated">&bookmark_updated;</string>
|
||||
|
|
|
@ -33,10 +33,9 @@ public class ToolbarComponent extends BaseComponent {
|
|||
|
||||
private static final String URL_HTTP_PREFIX = "http://";
|
||||
|
||||
// We are waiting up to 60 seconds instead of the default waiting time
|
||||
// because reader mode parsing can take quite some time on slower devices
|
||||
// See Bug 1142699
|
||||
private static final int READER_MODE_WAIT_MS = 60000;
|
||||
// We are waiting up to 30 seconds instead of the default waiting time because reader mode
|
||||
// parsing can take quite some time on slower devices (Bug 1142699)
|
||||
private static final int READER_MODE_WAIT_MS = 30000;
|
||||
|
||||
public ToolbarComponent(final UITestContext testContext) {
|
||||
super(testContext);
|
||||
|
|
|
@ -25,6 +25,14 @@ function getSelectionHandler() {
|
|||
this._selectionHandler;
|
||||
}
|
||||
|
||||
function getClipboard() {
|
||||
return Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
|
||||
}
|
||||
|
||||
function getTextValue(aElement) {
|
||||
return aElement.value || aElement.textContent;
|
||||
}
|
||||
|
||||
function todo(result, msg) {
|
||||
return Messaging.sendRequestForResult({
|
||||
type: TYPE_NAME,
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
|
||||
const DIV_POINT_TEXT = "Under";
|
||||
const INPUT_TEXT = "Text for select all in an <input>";
|
||||
const TEXTAREA_TEXT = "Text for select all in a <textarea>";
|
||||
const PASTE_TEXT = "Text for testing paste";
|
||||
const READONLY_INPUT_TEXT = "readOnly text";
|
||||
const TEXTAREA_TEXT = "Text for select all in a <textarea>";
|
||||
|
||||
/* =================================================================================
|
||||
*
|
||||
|
@ -25,6 +26,7 @@ function startTests() {
|
|||
then(testReadonlyInput).
|
||||
then(testCloseSelection).
|
||||
then(testStartSelectionFail).
|
||||
then(testPaste).
|
||||
|
||||
then(testAttachCaret).
|
||||
then(testAttachCaretFail).
|
||||
|
@ -351,6 +353,44 @@ function testAttachCaretFail() {
|
|||
});
|
||||
}
|
||||
|
||||
/* =================================================================================
|
||||
*
|
||||
* Tests to ensure we can paste text inside editable elements
|
||||
*
|
||||
*/
|
||||
function testPaste() {
|
||||
let sh = getSelectionHandler();
|
||||
let clipboard = getClipboard();
|
||||
clipboard.copyString(PASTE_TEXT, document);
|
||||
|
||||
// Add a contentEditable element to the document.
|
||||
let div = document.createElement("div");
|
||||
div.contentEditable = true;
|
||||
div.dataset.editable = true;
|
||||
document.body.appendChild(div);
|
||||
|
||||
let elements = document.querySelectorAll("div, input, textarea");
|
||||
let promises = [];
|
||||
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
sh.startSelection(elements[i]);
|
||||
if (sh.isElementEditableText(elements[i]) && !elements[i].disabled) {
|
||||
sh.actions.PASTE.action(elements[i]);
|
||||
}
|
||||
if (elements[i].dataset.editable) {
|
||||
promises.push(is(getTextValue(elements[i]), PASTE_TEXT, "Pasted correctly"));
|
||||
promises.push(ok(sh.isElementEditableText(elements[i]), "Element is editable"));
|
||||
} else {
|
||||
promises.push(isNot(getTextValue(elements[i]), PASTE_TEXT, "Paste failed correctly"));
|
||||
}
|
||||
}
|
||||
|
||||
document.body.removeChild(div);
|
||||
div = null;
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
@ -381,9 +421,9 @@ function testAttachCaretFail() {
|
|||
nunc vel, fringilla turpis. Nulla lacinia, leo ut egestas hendrerit, risus
|
||||
ligula interdum enim, vel varius libero sem ut ligula.</div><br>
|
||||
|
||||
<input id="inputNode" type="text"><br>
|
||||
<input data-editable="true" id="inputNode" type="text"><br>
|
||||
|
||||
<textarea id="textareaNode"></textarea><br>
|
||||
<textarea data-editable="true" id="textareaNode"></textarea><br>
|
||||
|
||||
<input id="readOnlyTextInput" type="text" readonly><br>
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.mozilla.gecko.tests;
|
||||
|
||||
import org.mozilla.gecko.tests.helpers.GeckoHelper;
|
||||
import org.mozilla.gecko.tests.helpers.NavigationHelper;
|
||||
|
||||
/**
|
||||
|
@ -7,6 +8,8 @@ import org.mozilla.gecko.tests.helpers.NavigationHelper;
|
|||
*/
|
||||
public class testReaderModeTitle extends UITest {
|
||||
public void testReaderModeTitle() {
|
||||
GeckoHelper.blockForReady();
|
||||
|
||||
NavigationHelper.enterAndLoadUrl(StringHelper.ROBOCOP_READER_MODE_BASIC_ARTICLE);
|
||||
|
||||
mToolbar.pressReaderModeButton();
|
||||
|
|
|
@ -679,7 +679,8 @@ var SelectionHandler = {
|
|||
order: 4,
|
||||
selector: {
|
||||
matches: function(aElement) {
|
||||
return SelectionHandler.isElementEditableText(aElement) ?
|
||||
// Disallow cut for contentEditable elements (until Bug 1112276 is fixed).
|
||||
return !aElement.isContentEditable && SelectionHandler.isElementEditableText(aElement) ?
|
||||
SelectionHandler.isSelectionActive() : false;
|
||||
}
|
||||
}
|
||||
|
@ -711,10 +712,10 @@ var SelectionHandler = {
|
|||
id: "paste_action",
|
||||
icon: "drawable://ab_paste",
|
||||
action: function(aElement) {
|
||||
if (aElement && (aElement instanceof Ci.nsIDOMNSEditableElement)) {
|
||||
let target = aElement.QueryInterface(Ci.nsIDOMNSEditableElement);
|
||||
target.editor.paste(Ci.nsIClipboard.kGlobalClipboard);
|
||||
target.focus();
|
||||
if (aElement) {
|
||||
let target = SelectionHandler._getEditor();
|
||||
aElement.focus();
|
||||
target.paste(Ci.nsIClipboard.kGlobalClipboard);
|
||||
SelectionHandler._closeSelection();
|
||||
UITelemetry.addEvent("action.1", "actionbar", null, "paste");
|
||||
}
|
||||
|
@ -895,7 +896,8 @@ var SelectionHandler = {
|
|||
|
||||
isElementEditableText: function (aElement) {
|
||||
return (((aElement instanceof HTMLInputElement && aElement.mozIsTextField(false)) ||
|
||||
(aElement instanceof HTMLTextAreaElement)) && !aElement.readOnly);
|
||||
(aElement instanceof HTMLTextAreaElement)) && !aElement.readOnly) ||
|
||||
aElement.isContentEditable;
|
||||
},
|
||||
|
||||
_isNonTextInputElement: function(aElement) {
|
||||
|
@ -963,7 +965,7 @@ var SelectionHandler = {
|
|||
_moveCaret: function sh_moveCaret(aX, aY) {
|
||||
// Get rect of text inside element
|
||||
let range = document.createRange();
|
||||
range.selectNodeContents(this._targetElement.QueryInterface(Ci.nsIDOMNSEditableElement).editor.rootElement);
|
||||
range.selectNodeContents(this._getEditor().rootElement);
|
||||
let textBounds = range.getBoundingClientRect();
|
||||
|
||||
// Get rect of editor
|
||||
|
|
|
@ -10,6 +10,10 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
Cu.import("resource://gre/modules/SharedPromptUtils.jsm");
|
||||
|
||||
const LoginInfo =
|
||||
Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
|
||||
"nsILoginInfo", "init");
|
||||
|
||||
/* Constants for password prompt telemetry.
|
||||
* Mirrored in mobile/android/components/LoginManagerPrompter.js */
|
||||
const PROMPT_DISPLAYED = 0;
|
||||
|
@ -792,11 +796,13 @@ LoginManagerPrompter.prototype = {
|
|||
_showLoginCaptureDoorhanger(login, type) {
|
||||
let { browser } = this._getNotifyWindow();
|
||||
|
||||
let msgNames = type == "password-save" ? {
|
||||
let saveMsgNames = {
|
||||
prompt: "rememberPasswordMsgNoUsername",
|
||||
buttonLabel: "notifyBarRememberPasswordButtonText",
|
||||
buttonAccessKey: "notifyBarRememberPasswordButtonAccessKey",
|
||||
} : {
|
||||
};
|
||||
|
||||
let changeMsgNames = {
|
||||
// We reuse the existing message, even if it expects a username, until we
|
||||
// switch to the final terminology in bug 1144856.
|
||||
prompt: "updatePasswordMsg",
|
||||
|
@ -804,28 +810,94 @@ LoginManagerPrompter.prototype = {
|
|||
buttonAccessKey: "notifyBarUpdateButtonAccessKey",
|
||||
};
|
||||
|
||||
let initialMsgNames = type == "password-save" ? saveMsgNames
|
||||
: changeMsgNames;
|
||||
|
||||
let histogramName = type == "password-save" ? "PWMGR_PROMPT_REMEMBER_ACTION"
|
||||
: "PWMGR_PROMPT_UPDATE_ACTION";
|
||||
let histogram = Services.telemetry.getHistogramById(histogramName);
|
||||
histogram.add(PROMPT_DISPLAYED);
|
||||
|
||||
let chromeDoc = browser.ownerDocument;
|
||||
|
||||
let currentNotification;
|
||||
|
||||
let updateButtonLabel = () => {
|
||||
let foundLogins = Services.logins.findLogins({}, login.hostname,
|
||||
login.formSubmitURL,
|
||||
login.httpRealm);
|
||||
let logins = foundLogins.filter(l => l.username == login.username);
|
||||
let msgNames = (logins.length == 0) ? saveMsgNames : changeMsgNames;
|
||||
|
||||
// Update the label based on whether this will be a new login or not.
|
||||
let label = this._getLocalizedString(msgNames.buttonLabel);
|
||||
let accessKey = this._getLocalizedString(msgNames.buttonAccessKey);
|
||||
|
||||
// Update the labels for the next time the panel is opened.
|
||||
currentNotification.mainAction.label = label;
|
||||
currentNotification.mainAction.accessKey = accessKey;
|
||||
|
||||
// Update the labels in real time if the notification is displayed.
|
||||
let element = [...currentNotification.owner.panel.childNodes]
|
||||
.find(n => n.notification == currentNotification);
|
||||
if (element) {
|
||||
element.setAttribute("buttonlabel", label);
|
||||
element.setAttribute("buttonaccesskey", accessKey);
|
||||
}
|
||||
};
|
||||
|
||||
let writeDataToUI = () => {
|
||||
chromeDoc.getElementById("password-notification-username")
|
||||
.setAttribute("placeholder", usernamePlaceholder);
|
||||
chromeDoc.getElementById("password-notification-username")
|
||||
.setAttribute("value", login.username);
|
||||
chromeDoc.getElementById("password-notification-password")
|
||||
.setAttribute("value", login.password);
|
||||
updateButtonLabel();
|
||||
};
|
||||
|
||||
let readDataFromUI = () => {
|
||||
login.username =
|
||||
chromeDoc.getElementById("password-notification-username").value;
|
||||
login.password =
|
||||
chromeDoc.getElementById("password-notification-password").value;
|
||||
};
|
||||
|
||||
let onUsernameInput = () => {
|
||||
readDataFromUI();
|
||||
updateButtonLabel();
|
||||
};
|
||||
|
||||
let persistData = () => {
|
||||
let foundLogins = Services.logins.findLogins({}, login.hostname,
|
||||
login.formSubmitURL,
|
||||
login.httpRealm);
|
||||
let logins = foundLogins.filter(l => l.username == login.username);
|
||||
if (logins.length == 0) {
|
||||
// The original login we have been provided with might have its own
|
||||
// metadata, but we don't want it propagated to the newly created one.
|
||||
Services.logins.addLogin(new LoginInfo(login.hostname,
|
||||
login.formSubmitURL,
|
||||
login.httpRealm,
|
||||
login.username,
|
||||
login.password,
|
||||
login.usernameField,
|
||||
login.passwordField));
|
||||
} else if (logins.length == 1) {
|
||||
this._updateLogin(logins[0], login.password);
|
||||
} else {
|
||||
Cu.reportError("Unexpected match of multiple logins.");
|
||||
}
|
||||
};
|
||||
|
||||
// The main action is the "Remember" or "Update" button.
|
||||
let mainAction = {
|
||||
label: this._getLocalizedString(msgNames.buttonLabel),
|
||||
accessKey: this._getLocalizedString(msgNames.buttonAccessKey),
|
||||
label: this._getLocalizedString(initialMsgNames.buttonLabel),
|
||||
accessKey: this._getLocalizedString(initialMsgNames.buttonAccessKey),
|
||||
callback: () => {
|
||||
histogram.add(PROMPT_ADD_OR_UPDATE);
|
||||
let foundLogins = Services.logins.findLogins({}, login.hostname,
|
||||
login.formSubmitURL,
|
||||
login.httpRealm);
|
||||
let logins = foundLogins.filter(l => l.username == login.username);
|
||||
if (logins.length == 0) {
|
||||
Services.logins.addLogin(login);
|
||||
} else if (logins.length == 1) {
|
||||
this._updateLogin(logins[0], login.password);
|
||||
} else {
|
||||
Cu.reportError("Unexpected match of multiple logins.");
|
||||
}
|
||||
readDataFromUI();
|
||||
persistData();
|
||||
browser.focus();
|
||||
}
|
||||
};
|
||||
|
@ -847,7 +919,7 @@ LoginManagerPrompter.prototype = {
|
|||
this._getPopupNote().show(
|
||||
browser,
|
||||
"password",
|
||||
this._getLocalizedString(msgNames.prompt, [displayHost]),
|
||||
this._getLocalizedString(initialMsgNames.prompt, [displayHost]),
|
||||
"password-notification-icon",
|
||||
mainAction,
|
||||
secondaryActions,
|
||||
|
@ -856,18 +928,23 @@ LoginManagerPrompter.prototype = {
|
|||
persistWhileVisible: true,
|
||||
passwordNotificationType: type,
|
||||
eventCallback: function (topic) {
|
||||
if (topic != "showing") {
|
||||
return false;
|
||||
switch (topic) {
|
||||
case "showing":
|
||||
currentNotification = this;
|
||||
writeDataToUI();
|
||||
chromeDoc.getElementById("password-notification-username")
|
||||
.addEventListener("input", onUsernameInput);
|
||||
break;
|
||||
case "dismissed":
|
||||
readDataFromUI();
|
||||
// Fall through.
|
||||
case "removed":
|
||||
currentNotification = null;
|
||||
chromeDoc.getElementById("password-notification-username")
|
||||
.removeEventListener("input", onUsernameInput);
|
||||
break;
|
||||
}
|
||||
|
||||
let chromeDoc = this.browser.ownerDocument;
|
||||
|
||||
chromeDoc.getElementById("password-notification-username")
|
||||
.setAttribute("placeholder", usernamePlaceholder);
|
||||
chromeDoc.getElementById("password-notification-username")
|
||||
.setAttribute("value", login.username);
|
||||
chromeDoc.getElementById("password-notification-password")
|
||||
.setAttribute("value", login.password);
|
||||
return false;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
|
|
@ -81,3 +81,119 @@ add_task(function* test_save_change() {
|
|||
Services.logins.removeAllLogins();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Test changing the username inside the doorhanger notification for passwords.
|
||||
*
|
||||
* We have to test combination of existing and non-existing logins both for
|
||||
* the original one from the webpage and the final one used by the dialog.
|
||||
*
|
||||
* We also check switching to and from empty usernames.
|
||||
*/
|
||||
add_task(function* test_edit_username() {
|
||||
let testCases = [{
|
||||
usernameInPage: "username",
|
||||
usernameChangedTo: "newUsername",
|
||||
}, {
|
||||
usernameInPage: "username",
|
||||
usernameInPageExists: true,
|
||||
usernameChangedTo: "newUsername",
|
||||
}, {
|
||||
usernameInPage: "username",
|
||||
usernameChangedTo: "newUsername",
|
||||
usernameChangedToExists: true,
|
||||
}, {
|
||||
usernameInPage: "username",
|
||||
usernameInPageExists: true,
|
||||
usernameChangedTo: "newUsername",
|
||||
usernameChangedToExists: true,
|
||||
}, {
|
||||
usernameInPage: "",
|
||||
usernameChangedTo: "newUsername",
|
||||
}, {
|
||||
usernameInPage: "newUsername",
|
||||
usernameChangedTo: "",
|
||||
}, {
|
||||
usernameInPage: "",
|
||||
usernameChangedTo: "newUsername",
|
||||
usernameChangedToExists: true,
|
||||
}, {
|
||||
usernameInPage: "newUsername",
|
||||
usernameChangedTo: "",
|
||||
usernameChangedToExists: true,
|
||||
}];
|
||||
|
||||
for (let testCase of testCases) {
|
||||
info("Test case: " + JSON.stringify(testCase));
|
||||
|
||||
// Create the pre-existing logins when needed.
|
||||
if (testCase.usernameInPageExists) {
|
||||
Services.logins.addLogin(LoginTestUtils.testData.formLogin({
|
||||
hostname: "https://example.com",
|
||||
formSubmitURL: "https://example.com",
|
||||
username: testCase.usernameInPage,
|
||||
password: "old password",
|
||||
}));
|
||||
}
|
||||
if (testCase.usernameChangedToExists) {
|
||||
Services.logins.addLogin(LoginTestUtils.testData.formLogin({
|
||||
hostname: "https://example.com",
|
||||
formSubmitURL: "https://example.com",
|
||||
username: testCase.usernameChangedTo,
|
||||
password: "old password",
|
||||
}));
|
||||
}
|
||||
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: "https://example.com/browser/toolkit/components/" +
|
||||
"passwordmgr/test/browser/form_basic.html",
|
||||
}, function* (browser) {
|
||||
// Submit the form in the content page with the credentials from the test
|
||||
// case. This will cause the doorhanger notification to be displayed.
|
||||
let promiseShown = BrowserTestUtils.waitForEvent(PopupNotifications.panel,
|
||||
"Shown");
|
||||
yield ContentTask.spawn(browser, testCase.usernameInPage,
|
||||
function* (usernameInPage) {
|
||||
let doc = content.document;
|
||||
doc.getElementById("form-basic-username").value = usernameInPage;
|
||||
doc.getElementById("form-basic-password").value = "password";
|
||||
doc.getElementById("form-basic").submit();
|
||||
});
|
||||
yield promiseShown;
|
||||
|
||||
// Modify the username in the dialog if requested.
|
||||
if (testCase.usernameChangedTo) {
|
||||
document.getElementById("password-notification-username")
|
||||
.setAttribute("value", testCase.usernameChangedTo);
|
||||
}
|
||||
|
||||
// We expect a modifyLogin notification if the final username used by the
|
||||
// dialog exists in the logins database, otherwise an addLogin one.
|
||||
let expectModifyLogin = testCase.usernameChangedTo
|
||||
? testCase.usernameChangedToExists
|
||||
: testCase.usernameInPageExists;
|
||||
|
||||
// Simulate the action on the notification to request the login to be
|
||||
// saved, and wait for the data to be updated or saved based on the type
|
||||
// of operation we expect.
|
||||
let expectedNotification = expectModifyLogin ? "modifyLogin" : "addLogin";
|
||||
let promiseLogin = TestUtils.topicObserved("passwordmgr-storage-changed",
|
||||
(_, data) => data == expectedNotification);
|
||||
let notificationElement = PopupNotifications.panel.childNodes[0];
|
||||
notificationElement.button.doCommand();
|
||||
let [result] = yield promiseLogin;
|
||||
|
||||
// Check that the values in the database match the expected values.
|
||||
let login = expectModifyLogin ? result.QueryInterface(Ci.nsIArray)
|
||||
.queryElementAt(1, Ci.nsILoginInfo)
|
||||
: result.QueryInterface(Ci.nsILoginInfo);
|
||||
Assert.equal(login.username, testCase.usernameChangedTo ||
|
||||
testCase.usernameInPage);
|
||||
Assert.equal(login.password, "password");
|
||||
});
|
||||
|
||||
// Clean up the database before the next test case is executed.
|
||||
Services.logins.removeAllLogins();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -740,7 +740,12 @@ Database::InitSchema(bool* aDatabaseMigrated)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Firefox 38 uses schema version 27.
|
||||
if (currentSchemaVersion < 28) {
|
||||
rv = MigrateV28Up();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Firefox 39 uses schema version 28.
|
||||
|
||||
// Schema Upgrades must add migration code here.
|
||||
|
||||
|
@ -1536,8 +1541,8 @@ Database::MigrateV27Up() {
|
|||
"JOIN moz_bookmarks b ON b.fk = h.id "
|
||||
"JOIN moz_keywords k ON k.id = b.keyword_id "
|
||||
"LEFT JOIN moz_items_annos a ON a.item_id = b.id "
|
||||
"LEFT JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
|
||||
"AND n.name = 'bookmarkProperties/POSTData'"
|
||||
"AND a.anno_attribute_id = (SELECT id FROM moz_anno_attributes "
|
||||
"WHERE name = 'bookmarkProperties/POSTData') "
|
||||
"WHERE k.place_id ISNULL "
|
||||
"GROUP BY keyword"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1563,6 +1568,38 @@ Database::MigrateV27Up() {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Database::MigrateV28Up() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// v27 migration was bogus and set some unrelated annotations as post_data for
|
||||
// keywords having an annotated bookmark.
|
||||
// The current v27 migration function is fixed, but we still need to handle
|
||||
// users that hit the bogus version. Since we can't distinguish, we'll just
|
||||
// set again all of the post data.
|
||||
DebugOnly<nsresult> rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_keywords "
|
||||
"SET post_data = ( "
|
||||
"SELECT content FROM moz_items_annos a "
|
||||
"JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
|
||||
"JOIN moz_bookmarks b on b.id = a.item_id "
|
||||
"WHERE n.name = 'bookmarkProperties/POSTData' "
|
||||
"AND b.keyword_id = moz_keywords.id "
|
||||
"ORDER BY b.lastModified DESC "
|
||||
"LIMIT 1 "
|
||||
") "
|
||||
"WHERE EXISTS(SELECT 1 FROM moz_bookmarks WHERE keyword_id = moz_keywords.id) "
|
||||
));
|
||||
// In case the update fails a constraint, we don't want to throw away the
|
||||
// whole database for just a few keywords. In rare cases the user might have
|
||||
// to recreate them. Though, at this point, there shouldn't be 2 keywords
|
||||
// pointing to the same url and post data, cause the previous migration step
|
||||
// removed them.
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
Database::Shutdown()
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
// This is the schema version. Update it at any schema change and add a
|
||||
// corresponding migrateVxx method below.
|
||||
#define DATABASE_SCHEMA_VERSION 27
|
||||
#define DATABASE_SCHEMA_VERSION 28
|
||||
|
||||
// Fired after Places inited.
|
||||
#define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
|
||||
|
@ -275,6 +275,7 @@ protected:
|
|||
nsresult MigrateV25Up();
|
||||
nsresult MigrateV26Up();
|
||||
nsresult MigrateV27Up();
|
||||
nsresult MigrateV28Up();
|
||||
|
||||
nsresult UpdateBookmarkRootTitles();
|
||||
|
||||
|
|
|
@ -3,7 +3,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 CURRENT_SCHEMA_VERSION = 27;
|
||||
const CURRENT_SCHEMA_VERSION = 28;
|
||||
const FIRST_UPGRADABLE_SCHEMA_VERSION = 11;
|
||||
|
||||
const NS_APP_USER_PROFILE_50_DIR = "ProfD";
|
||||
|
|
Двоичный файл не отображается.
|
@ -10,12 +10,15 @@ add_task(function* setup() {
|
|||
yield db.execute(`INSERT INTO moz_places (url, guid)
|
||||
VALUES ("http://test1.com/", "test1_______")
|
||||
, ("http://test2.com/", "test2_______")
|
||||
, ("http://test3.com/", "test3_______")
|
||||
`);
|
||||
// Add keywords.
|
||||
yield db.execute(`INSERT INTO moz_keywords (keyword)
|
||||
VALUES ("kw1")
|
||||
, ("kw2")
|
||||
, ("kw3")
|
||||
, ("kw4")
|
||||
, ("kw5")
|
||||
`);
|
||||
// Add bookmarks.
|
||||
let now = Date.now() * 1000;
|
||||
|
@ -38,15 +41,28 @@ add_task(function* setup() {
|
|||
/* different uri, same keyword as 1 */
|
||||
, (1, (SELECT id FROM moz_places WHERE guid = 'test1_______'), 3, ${index++}, ${now}, ${now},
|
||||
(SELECT id FROM moz_keywords WHERE keyword = 'kw3'), "bookmark6___")
|
||||
, (1, (SELECT id FROM moz_places WHERE guid = 'test3_______'), 3, ${index++}, ${now}, ${now},
|
||||
(SELECT id FROM moz_keywords WHERE keyword = 'kw4'), "bookmark7___")
|
||||
/* same uri and post_data as bookmark7, different keyword */
|
||||
, (1, (SELECT id FROM moz_places WHERE guid = 'test3_______'), 3, ${index++}, ${now}, ${now},
|
||||
(SELECT id FROM moz_keywords WHERE keyword = 'kw5'), "bookmark8___")
|
||||
`);
|
||||
// Add postData.
|
||||
yield db.execute(`INSERT INTO moz_anno_attributes (name)
|
||||
VALUES ("bookmarkProperties/POSTData")`);
|
||||
VALUES ("bookmarkProperties/POSTData")
|
||||
, ("someOtherAnno")`);
|
||||
yield db.execute(`INSERT INTO moz_items_annos(anno_attribute_id, item_id, content)
|
||||
VALUES ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
|
||||
(SELECT id FROM moz_bookmarks WHERE guid = "bookmark3___"), "postData1")
|
||||
, ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
|
||||
(SELECT id FROM moz_bookmarks WHERE guid = "bookmark5___"), "postData2")`);
|
||||
(SELECT id FROM moz_bookmarks WHERE guid = "bookmark5___"), "postData2")
|
||||
, ((SELECT id FROM moz_anno_attributes where name = "someOtherAnno"),
|
||||
(SELECT id FROM moz_bookmarks WHERE guid = "bookmark5___"), "zzzzzzzzzz")
|
||||
, ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
|
||||
(SELECT id FROM moz_bookmarks WHERE guid = "bookmark7___"), "postData3")
|
||||
, ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
|
||||
(SELECT id FROM moz_bookmarks WHERE guid = "bookmark8___"), "postData3")
|
||||
`);
|
||||
yield db.close();
|
||||
});
|
||||
|
||||
|
@ -69,7 +85,15 @@ add_task(function* test_keywords() {
|
|||
Assert.equal(postData2, "postData2");
|
||||
let [ url3, postData3 ] = PlacesUtils.getURLAndPostDataForKeyword("kw3");
|
||||
Assert.equal(url3, "http://test1.com/");
|
||||
Assert.equal(postData3, null);
|
||||
let [ url4, postData4 ] = PlacesUtils.getURLAndPostDataForKeyword("kw4");
|
||||
Assert.equal(url4, null);
|
||||
Assert.equal(postData4, null);
|
||||
let [ url5, postData5 ] = PlacesUtils.getURLAndPostDataForKeyword("kw5");
|
||||
Assert.equal(url5, "http://test3.com/");
|
||||
Assert.equal(postData5, "postData3");
|
||||
|
||||
Assert.equal((yield foreign_count("http://test1.com/")), 5); // 4 bookmark2 + 1 keywords
|
||||
Assert.equal((yield foreign_count("http://test2.com/")), 4); // 2 bookmark2 + 2 keywords
|
||||
Assert.equal((yield foreign_count("http://test3.com/")), 3); // 2 bookmark2 + 1 keywords
|
||||
});
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(function* setup() {
|
||||
yield setupPlacesDatabase("places_v27.sqlite");
|
||||
// Setup database contents to be migrated.
|
||||
let path = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME);
|
||||
let db = yield Sqlite.openConnection({ path });
|
||||
// Add pages.
|
||||
yield db.execute(`INSERT INTO moz_places (url, guid)
|
||||
VALUES ("http://test1.com/", "test1_______")
|
||||
, ("http://test2.com/", "test2_______")
|
||||
`);
|
||||
// Add keywords.
|
||||
yield db.execute(`INSERT INTO moz_keywords (keyword, place_id, post_data)
|
||||
VALUES ("kw1", (SELECT id FROM moz_places WHERE guid = "test2_______"), "broken data")
|
||||
, ("kw2", (SELECT id FROM moz_places WHERE guid = "test2_______"), NULL)
|
||||
, ("kw3", (SELECT id FROM moz_places WHERE guid = "test1_______"), "zzzzzzzzzz")
|
||||
`);
|
||||
// Add bookmarks.
|
||||
let now = Date.now() * 1000;
|
||||
let index = 0;
|
||||
yield db.execute(`INSERT INTO moz_bookmarks (type, fk, parent, position, dateAdded, lastModified, keyword_id, guid)
|
||||
VALUES (1, (SELECT id FROM moz_places WHERE guid = "test1_______"), 3, ${index++}, ${now}, ${now},
|
||||
(SELECT id FROM moz_keywords WHERE keyword = "kw1"), "bookmark1___")
|
||||
/* same uri, different keyword */
|
||||
, (1, (SELECT id FROM moz_places WHERE guid = "test1_______"), 3, ${index++}, ${now}, ${now},
|
||||
(SELECT id FROM moz_keywords WHERE keyword = "kw2"), "bookmark2___")
|
||||
/* different uri, same keyword as 1 */
|
||||
, (1, (SELECT id FROM moz_places WHERE guid = "test2_______"), 3, ${index++}, ${now}, ${now},
|
||||
(SELECT id FROM moz_keywords WHERE keyword = "kw1"), "bookmark3___")
|
||||
/* same uri, same keyword as 1 */
|
||||
, (1, (SELECT id FROM moz_places WHERE guid = "test1_______"), 3, ${index++}, ${now}, ${now},
|
||||
(SELECT id FROM moz_keywords WHERE keyword = "kw1"), "bookmark4___")
|
||||
/* same uri, same keyword as 2 */
|
||||
, (1, (SELECT id FROM moz_places WHERE guid = "test2_______"), 3, ${index++}, ${now}, ${now},
|
||||
(SELECT id FROM moz_keywords WHERE keyword = "kw2"), "bookmark5___")
|
||||
/* different uri, same keyword as 1 */
|
||||
, (1, (SELECT id FROM moz_places WHERE guid = "test1_______"), 3, ${index++}, ${now}, ${now},
|
||||
(SELECT id FROM moz_keywords WHERE keyword = "kw3"), "bookmark6___")
|
||||
`);
|
||||
// Add postData.
|
||||
yield db.execute(`INSERT INTO moz_anno_attributes (name)
|
||||
VALUES ("bookmarkProperties/POSTData")
|
||||
, ("someOtherAnno")`);
|
||||
yield db.execute(`INSERT INTO moz_items_annos(anno_attribute_id, item_id, content)
|
||||
VALUES ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
|
||||
(SELECT id FROM moz_bookmarks WHERE guid = "bookmark3___"), "postData1")
|
||||
, ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
|
||||
(SELECT id FROM moz_bookmarks WHERE guid = "bookmark5___"), "postData2")
|
||||
, ((SELECT id FROM moz_anno_attributes where name = "someOtherAnno"),
|
||||
(SELECT id FROM moz_bookmarks WHERE guid = "bookmark5___"), "zzzzzzzzzz")
|
||||
`);
|
||||
yield db.close();
|
||||
});
|
||||
|
||||
add_task(function* database_is_valid() {
|
||||
Assert.equal(PlacesUtils.history.databaseStatus,
|
||||
PlacesUtils.history.DATABASE_STATUS_UPGRADED);
|
||||
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
Assert.equal((yield db.getSchemaVersion()), CURRENT_SCHEMA_VERSION);
|
||||
});
|
||||
|
||||
add_task(function* test_keywords() {
|
||||
// When 2 urls have the same keyword, if one has postData it will be
|
||||
// preferred.
|
||||
let [ url1, postData1 ] = PlacesUtils.getURLAndPostDataForKeyword("kw1");
|
||||
Assert.equal(url1, "http://test2.com/");
|
||||
Assert.equal(postData1, "postData1");
|
||||
let [ url2, postData2 ] = PlacesUtils.getURLAndPostDataForKeyword("kw2");
|
||||
Assert.equal(url2, "http://test2.com/");
|
||||
Assert.equal(postData2, "postData2");
|
||||
let [ url3, postData3 ] = PlacesUtils.getURLAndPostDataForKeyword("kw3");
|
||||
Assert.equal(url3, "http://test1.com/");
|
||||
Assert.equal(postData3, null);
|
||||
});
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче