mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to inbound. a=merge
This commit is contained in:
commit
7e3133c429
@ -1,9 +1,12 @@
|
||||
{
|
||||
"name": "toolbar-api",
|
||||
"title": "toolbar-api",
|
||||
"id": "toolbar-api",
|
||||
"title": "Toolbar API",
|
||||
"main": "./lib/main.js",
|
||||
"description": "a toolbar api example",
|
||||
"author": "",
|
||||
"license": "MPL 2.0",
|
||||
"version": "0.1"
|
||||
"version": "0.1",
|
||||
"engines": {
|
||||
"firefox": ">=27.0 <=30.0"
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,12 @@ const { once } = require('../system/events');
|
||||
const { exit, env, staticArgs } = require('../system');
|
||||
const { when: unload } = require('../system/unload');
|
||||
const { loadReason } = require('../self');
|
||||
const { rootURI, metadata: { preferences } } = require("@loader/options");
|
||||
const { rootURI, metadata } = require("@loader/options");
|
||||
const globals = require('../system/globals');
|
||||
const xulApp = require('../system/xul-app');
|
||||
const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
|
||||
getService(Ci.nsIAppShellService);
|
||||
const { preferences } = metadata;
|
||||
|
||||
const NAME2TOPIC = {
|
||||
'Firefox': 'sessionstore-windows-restored',
|
||||
@ -134,13 +135,13 @@ function run(options) {
|
||||
if (preferences && preferences.length > 0) {
|
||||
try {
|
||||
require('../preferences/native-options').enable(preferences);
|
||||
}
|
||||
catch (error) {
|
||||
console.exception(error);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.exception(error);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// keeping support for addons packaged with older SDK versions,
|
||||
// keeping support for addons packaged with older SDK versions,
|
||||
// when cfx didn't include the 'preferences' key in @loader/options
|
||||
|
||||
// Initialize inline options localization, without preventing addon to be
|
||||
@ -158,7 +159,7 @@ function run(options) {
|
||||
// Only set if `prefsURI` specified
|
||||
try {
|
||||
setDefaultPrefs(options.prefsURI);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
// cfx bootstrap always passes prefsURI, even in addons without prefs
|
||||
}
|
||||
|
@ -7,13 +7,26 @@ module.metadata = {
|
||||
"stability": "deprecated"
|
||||
};
|
||||
|
||||
const { deprecateFunction } = require('../util/deprecate');
|
||||
const { deprecateUsage } = require('../util/deprecate');
|
||||
|
||||
exports.Loader = deprecateFunction(require('./loader').Loader,
|
||||
'`sdk/content/content` is deprecated. Please use `sdk/content/loader` directly.');
|
||||
exports.Symbiont = deprecateFunction(require('../deprecated/symbiont').Symbiont,
|
||||
'Both `sdk/content/content` and `sdk/deprecated/symbiont` are deprecated. ' +
|
||||
'`sdk/core/heritage` supersedes Symbiont for inheritance.');
|
||||
exports.Worker = deprecateFunction(require('./worker').Worker,
|
||||
'`sdk/content/content` is deprecated. Please use `sdk/content/worker` directly.');
|
||||
Object.defineProperty(exports, "Loader", {
|
||||
get: function() {
|
||||
deprecateUsage('`sdk/content/content` is deprecated. Please use `sdk/content/loader` directly.');
|
||||
return require('./loader').Loader;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(exports, "Symbiont", {
|
||||
get: function() {
|
||||
deprecateUsage('Both `sdk/content/content` and `sdk/deprecated/symbiont` are deprecated. ' +
|
||||
'`sdk/core/heritage` supersedes Symbiont for inheritance.');
|
||||
return require('../deprecated/symbiont').Symbiont;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(exports, "Worker", {
|
||||
get: function() {
|
||||
deprecateUsage('`sdk/content/content` is deprecated. Please use `sdk/content/worker` directly.');
|
||||
return require('./worker').Worker;
|
||||
}
|
||||
});
|
||||
|
@ -44,6 +44,10 @@ const { validateOptions, validateSingleOption } = new OptionsValidator({
|
||||
overrideMimeType: {
|
||||
map: function(v) v || null,
|
||||
is: ["string", "null"],
|
||||
},
|
||||
anonymous: {
|
||||
map: function(v) v || false,
|
||||
is: ["boolean", "null"],
|
||||
}
|
||||
});
|
||||
|
||||
@ -54,7 +58,7 @@ const REUSE_ERROR = "This request object has been used already. You must " +
|
||||
// request types
|
||||
function runRequest(mode, target) {
|
||||
let source = request(target)
|
||||
let { xhr, url, content, contentType, headers, overrideMimeType } = source;
|
||||
let { xhr, url, content, contentType, headers, overrideMimeType, anonymous } = source;
|
||||
|
||||
let isGetOrHead = (mode == "GET" || mode == "HEAD");
|
||||
|
||||
@ -63,7 +67,9 @@ function runRequest(mode, target) {
|
||||
if (xhr)
|
||||
throw new Error(REUSE_ERROR);
|
||||
|
||||
xhr = source.xhr = new XMLHttpRequest();
|
||||
xhr = source.xhr = new XMLHttpRequest({
|
||||
mozAnon: anonymous
|
||||
});
|
||||
|
||||
// Build the data to be set. For GET or HEAD requests, we want to append that
|
||||
// to the URL before opening the request.
|
||||
@ -129,6 +135,7 @@ const Request = Class({
|
||||
set contentType(value) {
|
||||
request(this).contentType = validateSingleOption('contentType', value);
|
||||
},
|
||||
get anonymous() { return request(this).anonymous; },
|
||||
get response() { return request(this).response; },
|
||||
delete: function() {
|
||||
runRequest('DELETE', this);
|
||||
@ -202,7 +209,8 @@ const Response = Class({
|
||||
}
|
||||
});
|
||||
return headers;
|
||||
}
|
||||
},
|
||||
get anonymous() response(this).request.mozAnon
|
||||
});
|
||||
|
||||
// apiUtils.validateOptions doesn't give the ability to easily validate single
|
||||
|
@ -8,12 +8,24 @@ module.metadata = {
|
||||
};
|
||||
|
||||
const { CC } = require('chrome');
|
||||
const { id, name, prefixURI, rootURI, metadata,
|
||||
version, loadReason, preferencesBranch } = require('@loader/options');
|
||||
const options = require('@loader/options');
|
||||
|
||||
const { get } = require("./preferences/service");
|
||||
const { readURISync } = require('./net/url');
|
||||
|
||||
const addonDataURI = prefixURI + name + '/data/';
|
||||
const id = options.id;
|
||||
|
||||
const readPref = key => get("extensions." + id + ".sdk." + key);
|
||||
|
||||
const name = readPref("name") || options.name;
|
||||
const version = readPref("version") || options.version;
|
||||
const loadReason = readPref("load.reason") || options.loadReason;
|
||||
const rootURI = readPref("rootURI") || options.rootURI || "";
|
||||
const baseURI = readPref("baseURI") || options.prefixURI + name + "/";
|
||||
const addonDataURI = baseURI + "data/";
|
||||
const metadata = options.metadata || {};
|
||||
const permissions = metadata.permissions || {};
|
||||
const isPacked = rootURI && rootURI.indexOf("jar:") === 0;
|
||||
|
||||
const uri = (path="") =>
|
||||
path.contains(":") ? path : addonDataURI + path;
|
||||
@ -24,16 +36,15 @@ const uri = (path="") =>
|
||||
// associated unique URI string that can be used for that.
|
||||
exports.uri = 'addon:' + id;
|
||||
exports.id = id;
|
||||
exports.preferencesBranch = preferencesBranch || id;
|
||||
exports.preferencesBranch = options.preferencesBranch || id;
|
||||
exports.name = name;
|
||||
exports.loadReason = loadReason;
|
||||
exports.version = version;
|
||||
// If `rootURI` is jar:file://...!/ than add-on is packed.
|
||||
exports.packed = (rootURI || '').indexOf('jar:') === 0;
|
||||
exports.packed = isPacked;
|
||||
exports.data = Object.freeze({
|
||||
url: uri,
|
||||
load: function read(path) {
|
||||
return readURISync(uri(path));
|
||||
}
|
||||
});
|
||||
exports.isPrivateBrowsingSupported = ((metadata || {}).permissions || {})['private-browsing'] === true;
|
||||
exports.isPrivateBrowsingSupported = permissions['private-browsing'] === true;
|
||||
|
@ -61,7 +61,8 @@ function activateTab(tab, window) {
|
||||
exports.activateTab = activateTab;
|
||||
|
||||
function getTabBrowser(window) {
|
||||
return window.gBrowser;
|
||||
// bug 1009938 - may be null in SeaMonkey
|
||||
return window.gBrowser || window.getBrowser();
|
||||
}
|
||||
exports.getTabBrowser = getTabBrowser;
|
||||
|
||||
@ -240,63 +241,10 @@ exports.getAllTabContentWindows = getAllTabContentWindows;
|
||||
|
||||
// gets the tab containing the provided window
|
||||
function getTabForContentWindow(window) {
|
||||
// Retrieve the topmost frame container. It can be either <xul:browser>,
|
||||
// <xul:iframe/> or <html:iframe/>. But in our case, it should be xul:browser.
|
||||
let browser;
|
||||
try {
|
||||
browser = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler;
|
||||
} catch(e) {
|
||||
// Bug 699450: The tab may already have been detached so that `window` is
|
||||
// in a almost destroyed state and can't be queryinterfaced anymore.
|
||||
}
|
||||
|
||||
// Is null for toplevel documents
|
||||
if (!browser) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Retrieve the owner window, should be browser.xul one
|
||||
let chromeWindow = browser.ownerDocument.defaultView;
|
||||
|
||||
// Ensure that it is top-level browser window.
|
||||
// We need extra checks because of Mac hidden window that has a broken
|
||||
// `gBrowser` global attribute.
|
||||
if ('gBrowser' in chromeWindow && chromeWindow.gBrowser &&
|
||||
'browsers' in chromeWindow.gBrowser) {
|
||||
// Looks like we are on Firefox Desktop
|
||||
// Then search for the position in tabbrowser in order to get the tab object
|
||||
let browsers = chromeWindow.gBrowser.browsers;
|
||||
let i = browsers.indexOf(browser);
|
||||
if (i !== -1)
|
||||
return chromeWindow.gBrowser.tabs[i];
|
||||
return null;
|
||||
}
|
||||
// Fennec
|
||||
else if ('BrowserApp' in chromeWindow) {
|
||||
return getTabForWindow(window);
|
||||
}
|
||||
|
||||
return null;
|
||||
return getTabs().find(tab => getTabContentWindow(tab) === window.top) || null;
|
||||
}
|
||||
exports.getTabForContentWindow = getTabForContentWindow;
|
||||
|
||||
// used on fennec
|
||||
function getTabForWindow(window) {
|
||||
for each (let { BrowserApp } in getWindows()) {
|
||||
if (!BrowserApp)
|
||||
continue;
|
||||
|
||||
for each (let tab in BrowserApp.tabs) {
|
||||
if (tab.browser.contentWindow == window.top)
|
||||
return tab;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getTabURL(tab) {
|
||||
if (tab.browser) // fennec
|
||||
return String(tab.browser.currentURI.spec);
|
||||
|
@ -384,13 +384,12 @@ exports.resolve = resolve;
|
||||
// algorithm.
|
||||
// `id` should already be resolved relatively at this point.
|
||||
// http://nodejs.org/api/modules.html#modules_all_together
|
||||
const nodeResolve = iced(function nodeResolve(id, requirer, { manifest, rootURI }) {
|
||||
const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) {
|
||||
// Resolve again
|
||||
id = exports.resolve(id, requirer);
|
||||
|
||||
// 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);
|
||||
|
||||
let resolvedPath;
|
||||
@ -400,7 +399,7 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { manifest, rootURI
|
||||
return stripBase(rootURI, resolvedPath);
|
||||
// If manifest has dependencies, attempt to look up node modules
|
||||
// in the `dependencies` list
|
||||
else if (manifest.dependencies) {
|
||||
else {
|
||||
let dirs = getNodeModulePaths(dirname(join(rootURI, requirer))).map(dir => join(dir, id));
|
||||
for (let i = 0; i < dirs.length; i++) {
|
||||
if (resolvedPath = loadAsFile(dirs[i]))
|
||||
@ -533,7 +532,6 @@ const Require = iced(function Require(loader, requirer) {
|
||||
|
||||
// TODO should get native Firefox modules before doing node-style lookups
|
||||
// to save on loading time
|
||||
|
||||
if (isNative) {
|
||||
// If a requireMap is available from `generateMap`, use that to
|
||||
// immediately resolve the node-style mapping.
|
||||
@ -693,7 +691,8 @@ const Loader = iced(function Loader(options) {
|
||||
});
|
||||
|
||||
let {
|
||||
modules, globals, resolve, paths, rootURI, manifest, requireMap, isNative
|
||||
modules, globals, resolve, paths, rootURI,
|
||||
manifest, requireMap, isNative, metadata
|
||||
} = override({
|
||||
paths: {},
|
||||
modules: {},
|
||||
@ -748,6 +747,7 @@ const Loader = iced(function Loader(options) {
|
||||
mapping: { enumerable: false, value: mapping },
|
||||
// Map of module objects indexed by module URIs.
|
||||
modules: { enumerable: false, value: modules },
|
||||
metadata: { enumerable: false, value: metadata },
|
||||
// Map of module sandboxes indexed by module URIs.
|
||||
sandboxes: { enumerable: false, value: {} },
|
||||
resolve: { enumerable: false, value: resolve },
|
||||
|
@ -5,7 +5,6 @@
|
||||
import sys
|
||||
import os
|
||||
import optparse
|
||||
import webbrowser
|
||||
import time
|
||||
|
||||
from copy import copy
|
||||
|
@ -148,12 +148,12 @@ class SmallXPI(unittest.TestCase):
|
||||
os.path.join("sdk", "core", "promise.js"),
|
||||
os.path.join("sdk", "net", "url.js"),
|
||||
os.path.join("sdk", "util", "object.js"),
|
||||
os.path.join("sdk", "util", "array.js")
|
||||
os.path.join("sdk", "util", "array.js"),
|
||||
os.path.join("sdk", "preferences", "service.js")
|
||||
]])
|
||||
|
||||
missing = set(expected) - set(used_files)
|
||||
extra = set(used_files) - set(expected)
|
||||
|
||||
self.failUnlessEqual(list(missing), [])
|
||||
self.failUnlessEqual(list(extra), [])
|
||||
used_deps = m.get_used_packages()
|
||||
@ -190,6 +190,8 @@ class SmallXPI(unittest.TestCase):
|
||||
"resources/addon-sdk/lib/sdk/util/object.js",
|
||||
"resources/addon-sdk/lib/sdk/util/array.js",
|
||||
"resources/addon-sdk/lib/sdk/net/url.js",
|
||||
"resources/addon-sdk/lib/sdk/preferences/",
|
||||
"resources/addon-sdk/lib/sdk/preferences/service.js",
|
||||
"resources/three/",
|
||||
"resources/three/lib/",
|
||||
"resources/three/lib/main.js",
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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";
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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";
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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";
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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/. */
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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";
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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";
|
||||
|
@ -134,7 +134,7 @@ if (app.is('Firefox')) {
|
||||
});
|
||||
}
|
||||
|
||||
// run it again, to test against inline options document caching
|
||||
// run it again, to test against inline options document caching
|
||||
// and duplication of <setting> nodes upon re-entry to about:addons
|
||||
exports.testAgainstDocCaching = exports.testAOM;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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";
|
||||
|
@ -540,3 +540,6 @@ exports.testFork = function (assert) {
|
||||
after(exports, cleanUp);
|
||||
|
||||
require("test").run(exports);
|
||||
|
||||
// Test disabled because of bug 979675
|
||||
module.exports = {};
|
||||
|
@ -9,6 +9,10 @@ const self = require('sdk/self');
|
||||
const fixtures = require("./fixtures");
|
||||
const { close } = require('sdk/window/helpers');
|
||||
const app = require("sdk/system/xul-app");
|
||||
const { LoaderWithHookedConsole } = require('sdk/test/loader');
|
||||
const { set: setPref, get: getPref } = require("sdk/preferences/service");
|
||||
|
||||
const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
|
||||
|
||||
function makeWindow() {
|
||||
let content =
|
||||
@ -157,4 +161,25 @@ exports["test:document element present on 'start'"] = function(assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
exports["test:content/content deprecation"] = function(assert) {
|
||||
let pref = getPref(DEPRECATE_PREF, false);
|
||||
setPref(DEPRECATE_PREF, true);
|
||||
|
||||
const { loader, messages } = LoaderWithHookedConsole(module);
|
||||
const { Loader, Symbiont, Worker } = loader.require("sdk/content/content");
|
||||
|
||||
assert.equal(messages.length, 3, "Should see three warnings");
|
||||
|
||||
assert.strictEqual(Loader, loader.require('sdk/content/loader').Loader,
|
||||
"Loader from content/content is the exact same object as the one from content/loader");
|
||||
|
||||
assert.strictEqual(Symbiont, loader.require('sdk/deprecated/symbiont').Symbiont,
|
||||
"Symbiont from content/content is the exact same object as the one from deprecated/symbiont");
|
||||
|
||||
assert.strictEqual(Worker, loader.require('sdk/content/worker').Worker,
|
||||
"Worker from content/content is the exact same object as the one from content/worker");
|
||||
|
||||
setPref(DEPRECATE_PREF, pref);
|
||||
}
|
||||
|
||||
require("test").run(exports);
|
||||
|
@ -43,6 +43,23 @@ exports.testOptionsValidator = function(assert) {
|
||||
}, /The option "url" is invalid/);
|
||||
// The url shouldn't have changed, so check that
|
||||
assert.equal(req.url, "http://playground.zpao.com/jetpack/request/text.php");
|
||||
|
||||
// Test default anonymous parameter value
|
||||
assert.equal(req.anonymous, false);
|
||||
// Test set anonymous parameter value
|
||||
req = Request({
|
||||
url: "http://playground.zpao.com/jetpack/request/text.php",
|
||||
anonymous: true,
|
||||
onComplete: function () {}
|
||||
});
|
||||
assert.equal(req.anonymous, true);
|
||||
// Test wrong value as anonymous parameter value
|
||||
assert.throws(function() {
|
||||
Request({
|
||||
url: "http://playground.zpao.com/jetpack/request/text.php",
|
||||
anonymous: "invalidvalue"
|
||||
});
|
||||
}, /The option "anonymous" must be one of the following types/);
|
||||
};
|
||||
|
||||
exports.testContentValidator = function(assert, done) {
|
||||
@ -183,6 +200,60 @@ exports.test3rdPartyCookies = function (assert, done) {
|
||||
}).get();
|
||||
};
|
||||
|
||||
// Test anonymous request behavior
|
||||
exports.testAnonymousRequest = function(assert, done) {
|
||||
let srv = startServerAsync(port, basePath);
|
||||
let basename = "test-anonymous-request.sjs";
|
||||
let testUrl = "http://localhost:" + port + "/" + basename;
|
||||
// Function to handle the requests in the server
|
||||
let content = function handleRequest(request, response) {
|
||||
// Request to store cookie
|
||||
response.setHeader("Set-Cookie", "anonymousKey=anonymousValue;", "true");
|
||||
// Set response content type
|
||||
response.setHeader("Content-Type", "application/json");
|
||||
// Check if cookie was send during request
|
||||
var cookiePresent = request.hasHeader("Cookie");
|
||||
// Create server respone content
|
||||
response.write(JSON.stringify({ "hasCookie": cookiePresent }));
|
||||
}.toString();
|
||||
prepareFile(basename, content);
|
||||
// Create request callbacks
|
||||
var checkCookieCreated = function (response) {
|
||||
// Check that the server created the cookie
|
||||
assert.equal(response.headers['Set-Cookie'], 'anonymousKey=anonymousValue;');
|
||||
// Make an other request and check that the server this time got the cookie
|
||||
Request({
|
||||
url: testUrl,
|
||||
onComplete: checkCookieSend
|
||||
}).get();
|
||||
},
|
||||
checkCookieSend = function (response) {
|
||||
// Check the response sent headers and cookies
|
||||
assert.equal(response.anonymous, false);
|
||||
// Check the server got the created cookie
|
||||
assert.equal(response.json.hasCookie, true);
|
||||
// Make a anonymous request and check the server did not get the cookie
|
||||
Request({
|
||||
url: testUrl,
|
||||
anonymous: true,
|
||||
onComplete: checkCookieNotSend
|
||||
}).get();
|
||||
},
|
||||
checkCookieNotSend = function (response) {
|
||||
// Check the response is anonymous
|
||||
assert.equal(response.anonymous, true);
|
||||
// Check the server did not get the cookie
|
||||
assert.equal(response.json.hasCookie, false);
|
||||
// Stop the server
|
||||
srv.stop(done);
|
||||
};
|
||||
// Make the first request to create cookie
|
||||
Request({
|
||||
url: testUrl,
|
||||
onComplete: checkCookieCreated
|
||||
}).get();
|
||||
};
|
||||
|
||||
exports.testSimpleJSON = function (assert, done) {
|
||||
let srv = startServerAsync(port, basePath);
|
||||
let json = { foo: "bar" };
|
||||
|
@ -19,13 +19,13 @@
|
||||
<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="857129928b6e56a809cee9d5445effb8fa9f1c2c"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3f3963fe6e165c0a7afc6222e1137d0862c70b30"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="8e4420c0c5c8e8c8e58a000278a7129403769f96"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9100fa82fc355f5201e23e400fc6b40e875304ed"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="a819a94a572c7b32556435491ed8eaab841a95ff"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="89812422efe8df364ddf364b4740030496181277"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a68dde81fcbe3c6bbd45bafdeb94c3f269bdc20"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="857129928b6e56a809cee9d5445effb8fa9f1c2c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3f3963fe6e165c0a7afc6222e1137d0862c70b30"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="89812422efe8df364ddf364b4740030496181277"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a68dde81fcbe3c6bbd45bafdeb94c3f269bdc20"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
@ -126,11 +126,11 @@
|
||||
<!-- Emulator specific things -->
|
||||
<project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
|
||||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
|
||||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="c3ee0c875393607430086f942950d1b3f496ab0e"/>
|
||||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="0e31f35a2a77301e91baa8a237aa9e9fa4076084"/>
|
||||
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="0a2b7e94dce4989a3740fea6f6e3152978216c88"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="cba8ebe395652e62a911d885cd6ac1bb4ad3ed57"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="dd94b2e17a146cb782d71933d25dcaa9c060e6ce"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="832f4acaf481a19031e479a40b03d9ce5370ddee"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d0aa65b140a45016975ed0ecf35f280dd336e1d3"/>
|
||||
<project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
|
||||
</manifest>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="857129928b6e56a809cee9d5445effb8fa9f1c2c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3f3963fe6e165c0a7afc6222e1137d0862c70b30"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="89812422efe8df364ddf364b4740030496181277"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a68dde81fcbe3c6bbd45bafdeb94c3f269bdc20"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||
|
@ -19,13 +19,13 @@
|
||||
<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="857129928b6e56a809cee9d5445effb8fa9f1c2c"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3f3963fe6e165c0a7afc6222e1137d0862c70b30"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="8e4420c0c5c8e8c8e58a000278a7129403769f96"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9100fa82fc355f5201e23e400fc6b40e875304ed"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="a819a94a572c7b32556435491ed8eaab841a95ff"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="89812422efe8df364ddf364b4740030496181277"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a68dde81fcbe3c6bbd45bafdeb94c3f269bdc20"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="857129928b6e56a809cee9d5445effb8fa9f1c2c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3f3963fe6e165c0a7afc6222e1137d0862c70b30"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="89812422efe8df364ddf364b4740030496181277"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a68dde81fcbe3c6bbd45bafdeb94c3f269bdc20"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
@ -119,7 +119,7 @@
|
||||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="e8a318f7690092e639ba88891606f4183e846d3f"/>
|
||||
<project name="device/qcom/common" path="device/qcom/common" revision="34ed8345250bb97262d70a052217a92e83444ede"/>
|
||||
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="95423152b66d4a41032414fc3fb8c3d9a0636c7d"/>
|
||||
<project name="kernel/msm" path="kernel" revision="e3895712aa9ddb955f0fdac880aa553556e64c41"/>
|
||||
<project name="kernel/msm" path="kernel" revision="ccfff630163ca9a0530701fa93b501c34042d06c"/>
|
||||
<project name="platform/bootable/recovery" path="bootable/recovery" revision="f2914eacee9120680a41463708bb6ee8291749fc"/>
|
||||
<project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="81c4a859d75d413ad688067829d21b7ba9205f81"/>
|
||||
<project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="f0689ac1914cdbc59e53bdc9edd9013dc157c299"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "e32dee285e41ff8be7779ab4adb3db81a5b36570",
|
||||
"revision": "99abcedfe288d6d29352b2add96b5ace90543985",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,12 +17,12 @@
|
||||
<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="857129928b6e56a809cee9d5445effb8fa9f1c2c"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3f3963fe6e165c0a7afc6222e1137d0862c70b30"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="89812422efe8df364ddf364b4740030496181277"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a68dde81fcbe3c6bbd45bafdeb94c3f269bdc20"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="857129928b6e56a809cee9d5445effb8fa9f1c2c"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3f3963fe6e165c0a7afc6222e1137d0862c70b30"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="857129928b6e56a809cee9d5445effb8fa9f1c2c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3f3963fe6e165c0a7afc6222e1137d0862c70b30"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="89812422efe8df364ddf364b4740030496181277"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a68dde81fcbe3c6bbd45bafdeb94c3f269bdc20"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -17,12 +17,12 @@
|
||||
<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="857129928b6e56a809cee9d5445effb8fa9f1c2c"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3f3963fe6e165c0a7afc6222e1137d0862c70b30"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="89812422efe8df364ddf364b4740030496181277"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a68dde81fcbe3c6bbd45bafdeb94c3f269bdc20"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
|
@ -1237,12 +1237,8 @@ pref("devtools.appmanager.enabled", true);
|
||||
pref("devtools.appmanager.lastTab", "help");
|
||||
pref("devtools.appmanager.manifestEditor.enabled", true);
|
||||
|
||||
// Enable devtools webide
|
||||
#ifdef MOZ_DEVTOOLS_WEBIDE
|
||||
pref("devtools.webide.enabled", true);
|
||||
#else
|
||||
// Disable devtools webide until bug 1007059
|
||||
pref("devtools.webide.enabled", false);
|
||||
#endif
|
||||
|
||||
// Toolbox preferences
|
||||
pref("devtools.toolbox.footer.height", 250);
|
||||
|
@ -62,7 +62,11 @@
|
||||
<button class="launchButton" id="apps" hidden="true">&abouthome.appsButton.label;</button>
|
||||
<button class="launchButton" id="addons">&abouthome.addonsButton.label;</button>
|
||||
<button class="launchButton" id="sync">&abouthome.syncButton.label;</button>
|
||||
<button class="launchButton" id="settings">&abouthome.settingsButton.label;</button>
|
||||
#ifdef XP_WIN
|
||||
<button class="launchButton" id="settings">&abouthome.preferencesButtonWin.label;</button>
|
||||
#else
|
||||
<button class="launchButton" id="settings">&abouthome.preferencesButtonUnix.label;</button>
|
||||
#endif
|
||||
<div id="restorePreviousSessionSeparator"/>
|
||||
<button class="launchButton" id="restorePreviousSession">&historyRestoreLastSession.label;</button>
|
||||
</div>
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -38,25 +38,28 @@
|
||||
#endif
|
||||
/>
|
||||
|
||||
<checkbox label="&engine.tabs.label;"
|
||||
accesskey="&engine.tabs.accesskey;"
|
||||
preference="engine.tabs"/>
|
||||
<checkbox label="&engine.bookmarks.label;"
|
||||
accesskey="&engine.bookmarks.accesskey;"
|
||||
preference="engine.bookmarks"/>
|
||||
<checkbox id="fxa-pweng-chk"
|
||||
label="&engine.passwords.label;"
|
||||
accesskey="&engine.passwords.accesskey;"
|
||||
preference="engine.passwords"/>
|
||||
<checkbox label="&engine.history.label;"
|
||||
accesskey="&engine.history.accesskey;"
|
||||
preference="engine.history"/>
|
||||
<checkbox label="&engine.addons.label;"
|
||||
accesskey="&engine.addons.accesskey;"
|
||||
preference="engine.addons"/>
|
||||
<checkbox label="&engine.prefs.label;"
|
||||
accesskey="&engine.prefs.accesskey;"
|
||||
preference="engine.prefs"/>
|
||||
<vbox align="start">
|
||||
<checkbox label="&engine.tabs.label;"
|
||||
accesskey="&engine.tabs.accesskey;"
|
||||
preference="engine.tabs"/>
|
||||
<checkbox label="&engine.bookmarks.label;"
|
||||
accesskey="&engine.bookmarks.accesskey;"
|
||||
preference="engine.bookmarks"/>
|
||||
<checkbox id="fxa-pweng-chk"
|
||||
label="&engine.passwords.label;"
|
||||
accesskey="&engine.passwords.accesskey;"
|
||||
preference="engine.passwords"/>
|
||||
<checkbox label="&engine.history.label;"
|
||||
accesskey="&engine.history.accesskey;"
|
||||
preference="engine.history"/>
|
||||
<checkbox label="&engine.addons.label;"
|
||||
accesskey="&engine.addons.accesskey;"
|
||||
preference="engine.addons"/>
|
||||
<checkbox label="&engine.prefs.label;"
|
||||
accesskey="&engine.prefs.accesskey;"
|
||||
preference="engine.prefs"/>
|
||||
</vbox>
|
||||
|
||||
</prefpane>
|
||||
|
||||
<script type="application/javascript"
|
||||
|
@ -18,7 +18,7 @@ browser.jar:
|
||||
* content/browser/aboutDialog.js (content/aboutDialog.js)
|
||||
content/browser/aboutDialog.css (content/aboutDialog.css)
|
||||
content/browser/aboutRobots.xhtml (content/aboutRobots.xhtml)
|
||||
content/browser/abouthome/aboutHome.xhtml (content/abouthome/aboutHome.xhtml)
|
||||
* content/browser/abouthome/aboutHome.xhtml (content/abouthome/aboutHome.xhtml)
|
||||
content/browser/abouthome/aboutHome.js (content/abouthome/aboutHome.js)
|
||||
* content/browser/abouthome/aboutHome.css (content/abouthome/aboutHome.css)
|
||||
content/browser/abouthome/snippet1.png (content/abouthome/snippet1.png)
|
||||
@ -78,9 +78,6 @@ browser.jar:
|
||||
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
|
||||
* content/browser/chatWindow.xul (content/chatWindow.xul)
|
||||
content/browser/content.js (content/content.js)
|
||||
content/browser/fonts/ClearSans-Regular.woff (content/fonts/ClearSans-Regular.woff)
|
||||
content/browser/fonts/FiraSans-Regular.woff (content/fonts/FiraSans-Regular.woff)
|
||||
content/browser/fonts/FiraSans-Light.woff (content/fonts/FiraSans-Light.woff)
|
||||
content/browser/newtab/newTab.xul (content/newtab/newTab.xul)
|
||||
* content/browser/newtab/newTab.js (content/newtab/newTab.js)
|
||||
content/browser/newtab/newTab.css (content/newtab/newTab.css)
|
||||
|
@ -12,8 +12,8 @@ pref("app.update.interval", 28800); // 8 hours
|
||||
// The time interval between the downloading of mar file chunks in the
|
||||
// background (in seconds)
|
||||
pref("app.update.download.backgroundInterval", 60);
|
||||
// Give the user x seconds to react before showing the big UI. default=24 hours
|
||||
pref("app.update.promptWaitTime", 86400);
|
||||
// Give the user x seconds to react before showing the big UI. default=168 hours
|
||||
pref("app.update.promptWaitTime", 604800);
|
||||
// URL user can browse to manually if for some reason all update installation
|
||||
// attempts fail.
|
||||
pref("app.update.url.manual", "https://www.mozilla.org/firefox/aurora/");
|
||||
|
@ -185,18 +185,18 @@
|
||||
<spacer flex="1"/>
|
||||
</vbox>
|
||||
|
||||
<vbox id="noFxaAccount">
|
||||
<vbox id="noFxaAccount" align="start">
|
||||
<label>&welcome.description;</label>
|
||||
<label class="text-link"
|
||||
onclick="gSyncPane.signUp(); return false;"
|
||||
value="&welcome.createAccount.label;"/>
|
||||
<label class="text-link"
|
||||
onclick="gSyncPane.signIn(); return false;"
|
||||
value="&welcome.signIn.label;"/>
|
||||
<separator/>
|
||||
<label class="text-link"
|
||||
onclick="gSyncPane.openOldSyncSupportPage(); return false;"
|
||||
value="&welcome.useOldSync.label;"/>
|
||||
<label class="text-link"
|
||||
onclick="gSyncPane.signUp(); return false;"
|
||||
value="&welcome.createAccount.label;"/>
|
||||
<label class="text-link"
|
||||
onclick="gSyncPane.signIn(); return false;"
|
||||
value="&welcome.signIn.label;"/>
|
||||
<separator/>
|
||||
<label class="text-link"
|
||||
onclick="gSyncPane.openOldSyncSupportPage(); return false;"
|
||||
value="&welcome.useOldSync.label;"/>
|
||||
</vbox>
|
||||
|
||||
<vbox id="hasFxaAccount">
|
||||
@ -208,11 +208,12 @@
|
||||
<!-- logged in and verified and all is good -->
|
||||
<hbox>
|
||||
<label id="fxaEmailAddress1"/>
|
||||
<vbox flex="1">
|
||||
<vbox>
|
||||
<label class="text-link"
|
||||
onclick="gSyncPane.manageFirefoxAccount();"
|
||||
value="&manage.label;"/>
|
||||
</vbox>
|
||||
<spacer flex="1"/>
|
||||
<vbox>
|
||||
<button id="fxaUnlinkButton"
|
||||
oncommand="gSyncPane.unlinkFirefoxAccount(true);"
|
||||
|
@ -444,7 +444,6 @@ ThreadState.prototype = {
|
||||
this.activeThread.addListener("resumed", this._update);
|
||||
this.activeThread.pauseOnExceptions(Prefs.pauseOnExceptions,
|
||||
Prefs.ignoreCaughtExceptions);
|
||||
this.handleTabNavigation();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -28,11 +28,9 @@ DIRS += [
|
||||
'tilt',
|
||||
'webaudioeditor',
|
||||
'webconsole',
|
||||
'webide',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_DEVTOOLS_WEBIDE']:
|
||||
DIRS += ['webide']
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'devtools-clhandler.js',
|
||||
'devtools-clhandler.manifest',
|
||||
|
@ -7,9 +7,9 @@ const promise = require("projecteditor/helpers/promise");
|
||||
const ProjectEditor = require("projecteditor/projecteditor");
|
||||
|
||||
const SAMPLE_PATH = buildTempDirectoryStructure();
|
||||
const SAMPLE_NAME = "DevTools Content";
|
||||
const SAMPLE_NAME = "DevTools Content Application Name";
|
||||
const SAMPLE_PROJECT_URL = "http://mozilla.org";
|
||||
const SAMPLE_ICON = "chrome://browser/skin/devtools/tool-options.svg";
|
||||
const SAMPLE_ICON = "chrome://browser/skin/devtools/tool-debugger.svg";
|
||||
|
||||
/**
|
||||
* Create a workspace for working on projecteditor, available at
|
||||
@ -56,11 +56,13 @@ document.addEventListener("DOMContentLoaded", function onDOMReady(e) {
|
||||
projecteditor.setProjectToAppPath(SAMPLE_PATH, {
|
||||
name: SAMPLE_NAME,
|
||||
iconUrl: SAMPLE_ICON,
|
||||
projectOverviewURL: SAMPLE_PROJECT_URL
|
||||
projectOverviewURL: SAMPLE_PROJECT_URL,
|
||||
validationStatus: "valid"
|
||||
}).then(() => {
|
||||
let allResources = projecteditor.project.allResources();
|
||||
console.log("All resources have been loaded", allResources, allResources.map(r=>r.basename).join("|"));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}, false);
|
||||
|
@ -4,10 +4,8 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/light-theme.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/projecteditor/projecteditor.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/devtools/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/devtools/debugger.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/devtools/markup-view.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/markup-view.css" type="text/css"?>
|
||||
|
||||
|
@ -5,6 +5,7 @@ const { emit } = require("sdk/event/core");
|
||||
const promise = require("projecteditor/helpers/promise");
|
||||
var { registerPlugin, Plugin } = require("projecteditor/plugins/core");
|
||||
const { AppProjectEditor } = require("./app-project-editor");
|
||||
const OPTION_URL = "chrome://browser/skin/devtools/tool-options.svg";
|
||||
|
||||
var AppManagerRenderer = Class({
|
||||
extends: Plugin,
|
||||
@ -25,20 +26,32 @@ var AppManagerRenderer = Class({
|
||||
let {appManagerOpts} = this.host.project;
|
||||
let doc = elt.ownerDocument;
|
||||
let image = doc.createElement("image");
|
||||
let label = doc.createElement("label");
|
||||
let optionImage = doc.createElement("image");
|
||||
let flexElement = doc.createElement("div");
|
||||
let nameLabel = doc.createElement("span");
|
||||
let statusElement = doc.createElement("div");
|
||||
|
||||
label.className = "project-name-label";
|
||||
image.className = "project-image";
|
||||
optionImage.className = "project-options";
|
||||
nameLabel.className = "project-name-label";
|
||||
statusElement.className = "project-status";
|
||||
flexElement.className = "project-flex";
|
||||
|
||||
let name = appManagerOpts.name || resource.basename;
|
||||
let url = appManagerOpts.iconUrl || "icon-sample.png";
|
||||
let status = appManagerOpts.validationStatus || "unknown";
|
||||
|
||||
label.textContent = name;
|
||||
nameLabel.textContent = name;
|
||||
image.setAttribute("src", url);
|
||||
optionImage.setAttribute("src", OPTION_URL);
|
||||
statusElement.setAttribute("status", status)
|
||||
|
||||
elt.innerHTML = "";
|
||||
elt.appendChild(image);
|
||||
elt.appendChild(label);
|
||||
elt.appendChild(nameLabel);
|
||||
elt.appendChild(flexElement);
|
||||
elt.appendChild(statusElement);
|
||||
elt.appendChild(optionImage);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
@ -136,13 +136,11 @@ var Project = Class({
|
||||
/**
|
||||
* Get every file path used inside of the project.
|
||||
*
|
||||
* @returns generator-iterator<string>
|
||||
* @returns Array<string>
|
||||
* A list of all file paths
|
||||
*/
|
||||
allPaths: function*() {
|
||||
for (let [path, store] of this.localStores) {
|
||||
yield path;
|
||||
}
|
||||
allPaths: function() {
|
||||
return [path for (path of this.localStores.keys())];
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -264,14 +264,29 @@ var ProjectEditor = Class({
|
||||
* @param string path
|
||||
* The file path to set
|
||||
* @param Object opts
|
||||
* Custom options used by the project. See plugins/app-manager.
|
||||
* Custom options used by the project.
|
||||
* - name: display name for project
|
||||
* - iconUrl: path to icon for project
|
||||
* - validationStatus: one of 'unknown|error|warning|valid'
|
||||
* - projectOverviewURL: path to load for iframe when project
|
||||
* is selected in the tree.
|
||||
* @param Promise
|
||||
* Promise that is resolved once the project is ready to be used.
|
||||
*/
|
||||
setProjectToAppPath: function(path, opts = {}) {
|
||||
this.project.appManagerOpts = opts;
|
||||
this.project.removeAllStores();
|
||||
this.project.addPath(path);
|
||||
|
||||
let existingPaths = this.project.allPaths();
|
||||
if (existingPaths.length !== 1 || existingPaths[0] !== path) {
|
||||
// Only fully reset if this is a new path.
|
||||
this.project.removeAllStores();
|
||||
this.project.addPath(path);
|
||||
} else {
|
||||
// Otherwise, just ask for the root to be redrawn
|
||||
let rootResource = this.project.localStores.get(path).root;
|
||||
emit(rootResource, "label-change", rootResource);
|
||||
}
|
||||
|
||||
return this.project.refresh();
|
||||
},
|
||||
|
||||
|
@ -39,7 +39,7 @@ var ResourceContainer = Class({
|
||||
|
||||
this.line = doc.createElementNS(HTML_NS, "div");
|
||||
this.line.classList.add("child");
|
||||
this.line.classList.add("side-menu-widget-item");
|
||||
this.line.classList.add("entry");
|
||||
this.line.setAttribute("theme", "dark");
|
||||
this.line.setAttribute("tabindex", "0");
|
||||
|
||||
@ -223,15 +223,14 @@ var TreeView = Class({
|
||||
this.models = new Set();
|
||||
this.roots = new Set();
|
||||
this._containers = new Map();
|
||||
this.elt = document.createElement("vbox");
|
||||
this.elt = document.createElementNS(HTML_NS, "div");
|
||||
this.elt.tree = this;
|
||||
this.elt.className = "side-menu-widget-container sources-tree";
|
||||
this.elt.className = "sources-tree";
|
||||
this.elt.setAttribute("with-arrows", "true");
|
||||
this.elt.setAttribute("theme", "dark");
|
||||
this.elt.setAttribute("flex", "1");
|
||||
|
||||
this.children = document.createElementNS(HTML_NS, "ul");
|
||||
this.children.setAttribute("flex", "1");
|
||||
this.elt.appendChild(this.children);
|
||||
|
||||
this.resourceChildrenChanged = this.resourceChildrenChanged.bind(this);
|
||||
@ -315,7 +314,7 @@ var TreeView = Class({
|
||||
return;
|
||||
}
|
||||
let container = this.importResource(root);
|
||||
container.line.classList.add("side-menu-widget-group-title");
|
||||
container.line.classList.add("entry-group-title");
|
||||
container.line.setAttribute("theme", "dark");
|
||||
this.selectContainer(container);
|
||||
|
||||
|
@ -5,6 +5,7 @@ support-files =
|
||||
head.js
|
||||
helper_homepage.html
|
||||
|
||||
[browser_projecteditor_app_options.js]
|
||||
[browser_projecteditor_delete_file.js]
|
||||
[browser_projecteditor_editing_01.js]
|
||||
[browser_projecteditor_immediate_destroy.js]
|
||||
|
@ -0,0 +1,102 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that options can be changed without resetting the whole
|
||||
// editor.
|
||||
let test = asyncTest(function*() {
|
||||
|
||||
let TEMP_PATH = buildTempDirectoryStructure();
|
||||
let projecteditor = yield addProjectEditorTab();
|
||||
|
||||
let resourceBeenAdded = promise.defer();
|
||||
projecteditor.project.once("resource-added", () => {
|
||||
info ("A resource has been added");
|
||||
resourceBeenAdded.resolve();
|
||||
});
|
||||
|
||||
info ("About to set project to: " + TEMP_PATH);
|
||||
yield projecteditor.setProjectToAppPath(TEMP_PATH, {
|
||||
name: "Test",
|
||||
iconUrl: "chrome://browser/skin/devtools/tool-options.svg",
|
||||
projectOverviewURL: SAMPLE_WEBAPP_URL
|
||||
});
|
||||
|
||||
info ("Making sure a resource has been added before continuing");
|
||||
yield resourceBeenAdded.promise;
|
||||
|
||||
info ("From now on, if a resource is added it should fail");
|
||||
projecteditor.project.on("resource-added", failIfResourceAdded);
|
||||
|
||||
info ("Getting ahold and validating the project header DOM");
|
||||
let header = projecteditor.document.querySelector(".entry-group-title");
|
||||
let image = header.querySelector(".project-image");
|
||||
let nameLabel = header.querySelector(".project-name-label");
|
||||
let statusElement = header.querySelector(".project-status");
|
||||
is (statusElement.getAttribute("status"), "unknown", "The status starts out as unknown.");
|
||||
is (nameLabel.textContent, "Test", "The name label has been set correctly");
|
||||
is (image.getAttribute("src"), "chrome://browser/skin/devtools/tool-options.svg", "The icon has been set correctly");
|
||||
|
||||
info ("About to set project with new options.");
|
||||
yield projecteditor.setProjectToAppPath(TEMP_PATH, {
|
||||
name: "Test2",
|
||||
iconUrl: "chrome://browser/skin/devtools/tool-inspector.svg",
|
||||
projectOverviewURL: SAMPLE_WEBAPP_URL,
|
||||
validationStatus: "error"
|
||||
});
|
||||
|
||||
ok (!nameLabel.parentNode, "The old elements have been removed");
|
||||
|
||||
info ("Getting ahold of and validating the project header DOM");
|
||||
let image = header.querySelector(".project-image");
|
||||
let nameLabel = header.querySelector(".project-name-label");
|
||||
let statusElement = header.querySelector(".project-status");
|
||||
is (statusElement.getAttribute("status"), "error", "The status has been set correctly.");
|
||||
is (nameLabel.textContent, "Test2", "The name label has been set correctly");
|
||||
is (image.getAttribute("src"), "chrome://browser/skin/devtools/tool-inspector.svg", "The icon has been set correctly");
|
||||
|
||||
info ("About to set project with new options.");
|
||||
yield projecteditor.setProjectToAppPath(TEMP_PATH, {
|
||||
name: "Test3",
|
||||
iconUrl: "chrome://browser/skin/devtools/tool-webconsole.svg",
|
||||
projectOverviewURL: SAMPLE_WEBAPP_URL,
|
||||
validationStatus: "warning"
|
||||
});
|
||||
|
||||
ok (!nameLabel.parentNode, "The old elements have been removed");
|
||||
|
||||
info ("Getting ahold of and validating the project header DOM");
|
||||
let image = header.querySelector(".project-image");
|
||||
let nameLabel = header.querySelector(".project-name-label");
|
||||
let statusElement = header.querySelector(".project-status");
|
||||
is (statusElement.getAttribute("status"), "warning", "The status has been set correctly.");
|
||||
is (nameLabel.textContent, "Test3", "The name label has been set correctly");
|
||||
is (image.getAttribute("src"), "chrome://browser/skin/devtools/tool-webconsole.svg", "The icon has been set correctly");
|
||||
|
||||
info ("About to set project with new options.");
|
||||
yield projecteditor.setProjectToAppPath(TEMP_PATH, {
|
||||
name: "Test4",
|
||||
iconUrl: "chrome://browser/skin/devtools/tool-debugger.svg",
|
||||
projectOverviewURL: SAMPLE_WEBAPP_URL,
|
||||
validationStatus: "valid"
|
||||
});
|
||||
|
||||
ok (!nameLabel.parentNode, "The old elements have been removed");
|
||||
|
||||
info ("Getting ahold of and validating the project header DOM");
|
||||
let image = header.querySelector(".project-image");
|
||||
let nameLabel = header.querySelector(".project-name-label");
|
||||
let statusElement = header.querySelector(".project-status");
|
||||
is (statusElement.getAttribute("status"), "valid", "The status has been set correctly.");
|
||||
is (nameLabel.textContent, "Test4", "The name label has been set correctly");
|
||||
is (image.getAttribute("src"), "chrome://browser/skin/devtools/tool-debugger.svg", "The icon has been set correctly");
|
||||
|
||||
info ("Test finished, cleaning up");
|
||||
projecteditor.project.off("resource-added", failIfResourceAdded);
|
||||
});
|
||||
|
||||
function failIfResourceAdded() {
|
||||
ok (false, "A resource has been added, but it shouldn't have been");
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
// Test ProjectEditor basic functionality
|
||||
let test = asyncTest(function*() {
|
||||
let projecteditor = yield addProjectEditorTabForTempDirectory();
|
||||
let TEMP_PATH = [...projecteditor.project.allPaths()][0];
|
||||
let TEMP_PATH = projecteditor.project.allPaths()[0];
|
||||
|
||||
is (getTempFile("").path, TEMP_PATH, "Temp path is set correctly.");
|
||||
|
||||
|
@ -7,10 +7,10 @@
|
||||
// Test ProjectEditor basic functionality
|
||||
let test = asyncTest(function*() {
|
||||
let projecteditor = yield addProjectEditorTabForTempDirectory();
|
||||
let TEMP_PATH = [...projecteditor.project.allPaths()][0];
|
||||
let TEMP_PATH = projecteditor.project.allPaths()[0];
|
||||
is (getTempFile("").path, TEMP_PATH, "Temp path is set correctly.");
|
||||
|
||||
is ([...projecteditor.project.allPaths()].length, 1, "1 path is set");
|
||||
is (projecteditor.project.allPaths().length, 1, "1 path is set");
|
||||
projecteditor.project.removeAllStores();
|
||||
is ([...projecteditor.project.allPaths()].length, 0, "No paths are remaining");
|
||||
is (projecteditor.project.allPaths().length, 0, "No paths are remaining");
|
||||
});
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
let projecteditor = yield addProjectEditorTabForTempDirectory();
|
||||
let TEMP_PATH = [...projecteditor.project.allPaths()][0];
|
||||
let TEMP_PATH = projecteditor.project.allPaths()[0];
|
||||
|
||||
is (getTempFile("").path, TEMP_PATH, "Temp path is set correctly.");
|
||||
|
||||
|
@ -454,26 +454,23 @@ StyleEditorUI.prototype = {
|
||||
}
|
||||
}, false);
|
||||
|
||||
Task.spawn(function* () {
|
||||
// autofocus if it's a new user-created stylesheet
|
||||
if (editor.isNew) {
|
||||
yield this._selectEditor(editor);
|
||||
}
|
||||
// autofocus if it's a new user-created stylesheet
|
||||
if (editor.isNew) {
|
||||
this._selectEditor(editor);
|
||||
}
|
||||
|
||||
if (this._styleSheetToSelect
|
||||
&& this._styleSheetToSelect.stylesheet == editor.styleSheet.href) {
|
||||
yield this.switchToSelectedSheet();
|
||||
}
|
||||
if (this._styleSheetToSelect
|
||||
&& this._styleSheetToSelect.stylesheet == editor.styleSheet.href) {
|
||||
this.switchToSelectedSheet();
|
||||
}
|
||||
|
||||
// If this is the first stylesheet and there is no pending request to
|
||||
// select a particular style sheet, select this sheet.
|
||||
if (!this.selectedEditor && !this._styleSheetBoundToSelect
|
||||
&& editor.styleSheet.styleSheetIndex == 0) {
|
||||
yield this._selectEditor(editor);
|
||||
}
|
||||
|
||||
this.emit("editor-added", editor);
|
||||
}.bind(this)).then(null, Cu.reportError);
|
||||
// If this is the first stylesheet and there is no pending request to
|
||||
// select a particular style sheet, select this sheet.
|
||||
if (!this.selectedEditor && !this._styleSheetBoundToSelect
|
||||
&& editor.styleSheet.styleSheetIndex == 0) {
|
||||
this._selectEditor(editor);
|
||||
}
|
||||
this.emit("editor-added", editor);
|
||||
}.bind(this),
|
||||
|
||||
onShow: function(summary, details, data) {
|
||||
@ -712,7 +709,8 @@ StyleEditorUI.prototype = {
|
||||
* Editor to update @media sidebar of
|
||||
*/
|
||||
_updateMediaList: function(editor) {
|
||||
this.getEditorDetails(editor).then((details) => {
|
||||
Task.spawn(function* () {
|
||||
let details = yield this.getEditorDetails(editor);
|
||||
let list = details.querySelector(".stylesheet-media-list");
|
||||
|
||||
while (list.firstChild) {
|
||||
@ -722,12 +720,31 @@ StyleEditorUI.prototype = {
|
||||
let rules = editor.mediaRules;
|
||||
let showSidebar = Services.prefs.getBoolPref(PREF_MEDIA_SIDEBAR);
|
||||
let sidebar = details.querySelector(".stylesheet-sidebar");
|
||||
sidebar.hidden = !showSidebar || !rules.length;
|
||||
|
||||
let inSource = false;
|
||||
|
||||
for (let rule of rules) {
|
||||
let {line, column, parentStyleSheet} = rule;
|
||||
|
||||
let location = {
|
||||
line: line,
|
||||
column: column,
|
||||
source: editor.styleSheet.href,
|
||||
styleSheet: parentStyleSheet
|
||||
};
|
||||
if (editor.styleSheet.isOriginalSource) {
|
||||
location = yield editor.cssSheet.getOriginalLocation(line, column);
|
||||
}
|
||||
|
||||
// this @media rule is from a different original source
|
||||
if (location.source != editor.styleSheet.href) {
|
||||
continue;
|
||||
}
|
||||
inSource = true;
|
||||
|
||||
let div = this._panelDoc.createElement("div");
|
||||
div.className = "media-rule-label";
|
||||
div.addEventListener("click", this._jumpToMediaRule.bind(this, rule));
|
||||
div.addEventListener("click", this._jumpToLocation.bind(this, location));
|
||||
|
||||
let cond = this._panelDoc.createElement("div");
|
||||
cond.textContent = rule.conditionText;
|
||||
@ -737,25 +754,29 @@ StyleEditorUI.prototype = {
|
||||
}
|
||||
div.appendChild(cond);
|
||||
|
||||
let line = this._panelDoc.createElement("div");
|
||||
line.className = "media-rule-line theme-link";
|
||||
line.textContent = ":" + rule.line;
|
||||
div.appendChild(line);
|
||||
let link = this._panelDoc.createElement("div");
|
||||
link.className = "media-rule-line theme-link";
|
||||
link.textContent = ":" + location.line;
|
||||
div.appendChild(link);
|
||||
|
||||
list.appendChild(div);
|
||||
}
|
||||
|
||||
sidebar.hidden = !showSidebar || !inSource;
|
||||
|
||||
this.emit("media-list-changed", editor);
|
||||
});
|
||||
}.bind(this)).then(null, Cu.reportError);
|
||||
},
|
||||
|
||||
/**
|
||||
* Jump cursor to the editor for a stylesheet and line number for a rule.
|
||||
*
|
||||
* @param {MediaRuleFront} rule
|
||||
* Rule to jump to.
|
||||
* @param {object} location
|
||||
* Location object with 'line', 'column', and 'source' properties.
|
||||
*/
|
||||
_jumpToMediaRule: function(rule) {
|
||||
this.selectStyleSheet(rule.parentStyleSheet, rule.line - 1, rule.column - 1);
|
||||
_jumpToLocation: function(location) {
|
||||
let source = location.styleSheet || location.source;
|
||||
this.selectStyleSheet(source, location.line - 1, location.column - 1);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
|
@ -96,21 +96,14 @@ function StyleSheetEditor(styleSheet, win, file, isNew, walker) {
|
||||
this.checkLinkedFileForChanges = this.checkLinkedFileForChanges.bind(this);
|
||||
this.markLinkedFileBroken = this.markLinkedFileBroken.bind(this);
|
||||
|
||||
this.mediaRules = [];
|
||||
if (this.styleSheet.getMediaRules) {
|
||||
this.styleSheet.getMediaRules().then(this._onMediaRulesChanged);
|
||||
}
|
||||
this.styleSheet.on("media-rules-changed", this._onMediaRulesChanged);
|
||||
|
||||
this._focusOnSourceEditorReady = false;
|
||||
|
||||
let relatedSheet = this.styleSheet.relatedStyleSheet;
|
||||
if (relatedSheet) {
|
||||
relatedSheet.on("property-change", this._onPropertyChange);
|
||||
}
|
||||
this.styleSheet.on("property-change", this._onPropertyChange);
|
||||
this.cssSheet.on("property-change", this._onPropertyChange);
|
||||
this.styleSheet.on("error", this._onError);
|
||||
|
||||
this.mediaRules = [];
|
||||
if (this.cssSheet.getMediaRules) {
|
||||
this.cssSheet.getMediaRules().then(this._onMediaRulesChanged);
|
||||
}
|
||||
this.cssSheet.on("media-rules-changed", this._onMediaRulesChanged);
|
||||
this.savedFile = file;
|
||||
this.linkCSSFile();
|
||||
}
|
||||
@ -131,6 +124,17 @@ StyleSheetEditor.prototype = {
|
||||
return this._isNew;
|
||||
},
|
||||
|
||||
/**
|
||||
* The style sheet or the generated style sheet for this source if it's an
|
||||
* original source.
|
||||
*/
|
||||
get cssSheet() {
|
||||
if (this.styleSheet.isOriginalSource) {
|
||||
return this.styleSheet.relatedStyleSheet;
|
||||
}
|
||||
return this.styleSheet;
|
||||
},
|
||||
|
||||
get savedFile() {
|
||||
return this._savedFile;
|
||||
},
|
||||
@ -530,7 +534,9 @@ StyleSheetEditor.prototype = {
|
||||
this._friendlyName = null;
|
||||
this.savedFile = returnFile;
|
||||
|
||||
this.sourceEditor.setClean();
|
||||
if (this.sourceEditor) {
|
||||
this.sourceEditor.setClean();
|
||||
}
|
||||
|
||||
this.emit("property-change");
|
||||
|
||||
@ -628,8 +634,8 @@ StyleSheetEditor.prototype = {
|
||||
if (this.sourceEditor) {
|
||||
this.sourceEditor.destroy();
|
||||
}
|
||||
this.styleSheet.off("media-rules-changed", this._onMediaRulesChanged);
|
||||
this.styleSheet.off("property-change", this._onPropertyChange);
|
||||
this.cssSheet.off("property-change", this._onPropertyChange);
|
||||
this.cssSheet.off("media-rules-changed", this._onMediaRulesChanged);
|
||||
this.styleSheet.off("error", this._onError);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ support-files =
|
||||
media.html
|
||||
media-rules.html
|
||||
media-rules.css
|
||||
media-rules-sourcemaps.html
|
||||
minified.html
|
||||
nostyle.html
|
||||
pretty.css
|
||||
@ -30,7 +31,10 @@ support-files =
|
||||
sourcemap-css/contained.css
|
||||
sourcemap-css/sourcemaps.css
|
||||
sourcemap-css/sourcemaps.css.map
|
||||
sourcemap-css/media-rules.css
|
||||
sourcemap-css/media-rules.css.map
|
||||
sourcemap-sass/sourcemaps.scss
|
||||
sourcemap-sass/media-rules.scss
|
||||
sourcemaps.html
|
||||
test_private.css
|
||||
test_private.html
|
||||
@ -49,6 +53,7 @@ skip-if = os == "linux" || "mac" # bug 949355
|
||||
[browser_styleeditor_inline_friendly_names.js]
|
||||
[browser_styleeditor_loading.js]
|
||||
[browser_styleeditor_media_sidebar.js]
|
||||
[browser_styleeditor_media_sidebar_sourcemaps.js]
|
||||
[browser_styleeditor_new.js]
|
||||
[browser_styleeditor_nostyle.js]
|
||||
[browser_styleeditor_pretty.js]
|
||||
|
@ -20,7 +20,7 @@ function testEditorAdded(aEditor)
|
||||
{
|
||||
if (aEditor.styleSheet.styleSheetIndex == 0) {
|
||||
gEditorAddedCount++;
|
||||
testFirstStyleSheetEditor(aEditor);
|
||||
gUI.editors[0].getSourceEditor().then(testFirstStyleSheetEditor);
|
||||
}
|
||||
if (aEditor.styleSheet.styleSheetIndex == 1) {
|
||||
gEditorAddedCount++;
|
||||
|
@ -0,0 +1,72 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// https rather than chrome to improve coverage
|
||||
const TESTCASE_URI = TEST_BASE_HTTPS + "media-rules-sourcemaps.html";
|
||||
const MEDIA_PREF = "devtools.styleeditor.showMediaSidebar";
|
||||
const MAP_PREF = "devtools.styleeditor.source-maps-enabled";
|
||||
|
||||
const LABELS = ["screen and (max-width: 320px)",
|
||||
"screen and (min-width: 1200px)"];
|
||||
const LINE_NOS = [4, 4];
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
Services.prefs.setBoolPref(MEDIA_PREF, true);
|
||||
Services.prefs.setBoolPref(MAP_PREF, true);
|
||||
|
||||
let {UI} = yield addTabAndOpenStyleEditors(2, null, TESTCASE_URI);
|
||||
|
||||
yield listenForMediaChange(UI);
|
||||
|
||||
is(UI.editors.length, 1, "correct number of editors");
|
||||
|
||||
// Test editor with @media rules
|
||||
let mediaEditor = UI.editors[0];
|
||||
yield openEditor(mediaEditor);
|
||||
testMediaEditor(mediaEditor);
|
||||
|
||||
Services.prefs.clearUserPref(MEDIA_PREF);
|
||||
Services.prefs.clearUserPref(MAP_PREF);
|
||||
});
|
||||
|
||||
function testMediaEditor(editor) {
|
||||
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
|
||||
is(sidebar.hidden, false, "sidebar is showing on editor with @media");
|
||||
|
||||
let entries = [...sidebar.querySelectorAll(".media-rule-label")];
|
||||
is(entries.length, 2, "two @media rules displayed in sidebar");
|
||||
|
||||
testRule(entries[0], LABELS[0], LINE_NOS[0]);
|
||||
testRule(entries[1], LABELS[1], LINE_NOS[1]);
|
||||
}
|
||||
|
||||
function testRule(rule, text, lineno) {
|
||||
let cond = rule.querySelector(".media-rule-condition");
|
||||
is(cond.textContent, text, "media label is correct for " + text);
|
||||
|
||||
let line = rule.querySelector(".media-rule-line");
|
||||
is(line.textContent, ":" + lineno, "correct line number shown");
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
|
||||
function openEditor(editor) {
|
||||
getLinkFor(editor).click();
|
||||
|
||||
return editor.getSourceEditor();
|
||||
}
|
||||
|
||||
function listenForMediaChange(UI) {
|
||||
let deferred = promise.defer();
|
||||
UI.once("media-list-changed", () => {
|
||||
deferred.resolve();
|
||||
})
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getLinkFor(editor) {
|
||||
return editor.summary.querySelector(".stylesheet-name");
|
||||
}
|
@ -27,7 +27,11 @@ function test()
|
||||
function runTests()
|
||||
{
|
||||
let count = 0;
|
||||
gUI.once("editor-selected", (event, editor) => {
|
||||
gUI.on("editor-selected", function editorSelected(event, editor) {
|
||||
if (editor.styleSheet != gUI.editors[1].styleSheet) {
|
||||
return;
|
||||
}
|
||||
gUI.off("editor-selected", editorSelected);
|
||||
editor.getSourceEditor().then(() => {
|
||||
info("selected second editor, about to reload page");
|
||||
reloadPage();
|
||||
@ -41,7 +45,7 @@ function runTests()
|
||||
})
|
||||
});
|
||||
});
|
||||
gUI.selectStyleSheet(gUI.editors[1].styleSheet.href, LINE_NO, COL_NO);
|
||||
gUI.selectStyleSheet(gUI.editors[1].styleSheet, LINE_NO, COL_NO);
|
||||
}
|
||||
|
||||
function testRemembered()
|
||||
|
@ -30,7 +30,12 @@ function runTests()
|
||||
|
||||
// Make sure Editor doesn't go into an infinite loop when
|
||||
// column isn't passed. See bug 941018.
|
||||
gUI.once("editor-selected", (event, editor) => {
|
||||
gUI.on("editor-selected", function editorSelected(event, editor) {
|
||||
if (editor.styleSheet != gUI.editors[1].styleSheet) {
|
||||
return;
|
||||
}
|
||||
gUI.off("editor-selected", editorSelected);
|
||||
|
||||
editor.getSourceEditor().then(() => {
|
||||
is(gUI.selectedEditor, gUI.editors[1], "second editor is selected");
|
||||
let {line, ch} = gUI.selectedEditor.sourceEditor.getCursor();
|
||||
|
@ -104,9 +104,13 @@ function togglePref(UI) {
|
||||
deferred.resolve();
|
||||
}
|
||||
})
|
||||
let editorsPromise = deferred.promise;
|
||||
|
||||
let selectedPromise = UI.once("editor-selected");
|
||||
|
||||
Services.prefs.setBoolPref(PREF, false);
|
||||
return deferred.promise;
|
||||
|
||||
return promise.all([editorsPromise, selectedPromise]);
|
||||
}
|
||||
|
||||
function openEditor(editor) {
|
||||
|
@ -45,9 +45,10 @@ function addTabAndOpenStyleEditors(count, callback, uri) {
|
||||
let deferred = promise.defer();
|
||||
let currentCount = 0;
|
||||
let panel;
|
||||
addTabAndCheckOnStyleEditorAdded(p => panel = p, function () {
|
||||
addTabAndCheckOnStyleEditorAdded(p => panel = p, function (editor) {
|
||||
currentCount++;
|
||||
info(currentCount + " of " + count + " editors opened");
|
||||
info(currentCount + " of " + count + " editors opened: "
|
||||
+ editor.styleSheet.href);
|
||||
if (currentCount == count) {
|
||||
if (callback) {
|
||||
callback(panel);
|
||||
|
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" type="text/css" href="sourcemap-css/media-rules.css"
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Testing style editor media sidebar with source maps
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,8 @@
|
||||
@media screen and (max-width: 320px) {
|
||||
div {
|
||||
width: 100px; } }
|
||||
@media screen and (min-width: 1200px) {
|
||||
div {
|
||||
width: 400px; } }
|
||||
|
||||
/*# sourceMappingURL=media-rules.css.map */
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": 3,
|
||||
"mappings": "AAIE,oCAA4C;EAD9C,GAAI;IAEA,KAAK,EAAE,KAAK;AAEd,qCAA4C;EAJ9C,GAAI;IAKA,KAAK,EAAE,KAAK",
|
||||
"sources": ["../sourcemap-sass/media-rules.scss"],
|
||||
"file": "media-rules.css"
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
$break-small: 320px;
|
||||
$break-large: 1200px;
|
||||
|
||||
div {
|
||||
@media screen and (max-width: $break-small) {
|
||||
width: 100px;
|
||||
}
|
||||
@media screen and (min-width: $break-large) {
|
||||
width: 400px;
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.j
|
||||
loader.lazyImporter(this, "Task","resource://gre/modules/Task.jsm");
|
||||
|
||||
const Heritage = require("sdk/core/heritage");
|
||||
const URI = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
|
||||
@ -1081,6 +1082,11 @@ Messages.Extended.prototype = Heritage.extend(Messages.Simple.prototype,
|
||||
|
||||
let result = this.document.createElementNS(XHTML_NS, "span");
|
||||
if (isPrimitive) {
|
||||
if (Widgets.URLString.prototype.containsURL.call(Widgets.URLString.prototype, grip)) {
|
||||
let widget = new Widgets.URLString(this, grip, options).render();
|
||||
return widget.element;
|
||||
}
|
||||
|
||||
let className = this.getClassNameForValueGrip(grip);
|
||||
if (className) {
|
||||
result.className = className;
|
||||
@ -1757,6 +1763,125 @@ Widgets.MessageTimestamp.prototype = Heritage.extend(Widgets.BaseWidget.prototyp
|
||||
}); // Widgets.MessageTimestamp.prototype
|
||||
|
||||
|
||||
/**
|
||||
* The URLString widget, for rendering strings where at least one token is a
|
||||
* URL.
|
||||
*
|
||||
* @constructor
|
||||
* @param object message
|
||||
* The owning message.
|
||||
* @param string str
|
||||
* The string, which contains at least one valid URL.
|
||||
*/
|
||||
Widgets.URLString = function(message, str)
|
||||
{
|
||||
Widgets.BaseWidget.call(this, message);
|
||||
this.str = str;
|
||||
};
|
||||
|
||||
Widgets.URLString.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
|
||||
{
|
||||
/**
|
||||
* The string to format, which contains at least one valid URL.
|
||||
* @type string
|
||||
*/
|
||||
str: "",
|
||||
|
||||
render: function()
|
||||
{
|
||||
if (this.element) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// The rendered URLString will be a <span> containing a number of text
|
||||
// <spans> for non-URL tokens and <a>'s for URL tokens.
|
||||
this.element = this.el("span", {
|
||||
class: "console-string"
|
||||
});
|
||||
this.element.appendChild(this._renderText("\""));
|
||||
|
||||
// As we walk through the tokens of the source string, we make sure to preserve
|
||||
// the original whitespace that seperated the tokens.
|
||||
let tokens = this.str.split(/\s+/);
|
||||
let textStart = 0;
|
||||
let tokenStart;
|
||||
for (let token of tokens) {
|
||||
tokenStart = this.str.indexOf(token, textStart);
|
||||
if (this._isURL(token)) {
|
||||
this.element.appendChild(this._renderText(this.str.slice(textStart, tokenStart)));
|
||||
textStart = tokenStart + token.length;
|
||||
this.element.appendChild(this._renderURL(token));
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up any non-URL text at the end of the source string.
|
||||
this.element.appendChild(this._renderText(this.str.slice(textStart, this.str.length)));
|
||||
this.element.appendChild(this._renderText("\""));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether a grip is a string containing a URL.
|
||||
*
|
||||
* @param string grip
|
||||
* The grip, which may contain a URL.
|
||||
* @return boolean
|
||||
* Whether the grip is a string containing a URL.
|
||||
*/
|
||||
containsURL: function(grip)
|
||||
{
|
||||
if (typeof grip != "string") {
|
||||
return false;
|
||||
}
|
||||
|
||||
let tokens = grip.split(/\s+/);
|
||||
return tokens.some(this._isURL);
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether a string token is a valid URL.
|
||||
*
|
||||
* @param string token
|
||||
* The token.
|
||||
* @return boolean
|
||||
* Whenther the token is a URL.
|
||||
*/
|
||||
_isURL: function(token) {
|
||||
try {
|
||||
let uri = URI.newURI(token, null, null);
|
||||
let url = uri.QueryInterface(Ci.nsIURL);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders a string as a URL.
|
||||
*
|
||||
* @param string url
|
||||
* The string to be rendered as a url.
|
||||
* @return DOMElement
|
||||
* An element containing the rendered string.
|
||||
*/
|
||||
_renderURL: function(url)
|
||||
{
|
||||
let result = this.el("a", {
|
||||
class: "url",
|
||||
title: url,
|
||||
href: url,
|
||||
draggable: false
|
||||
}, url);
|
||||
this.message._addLinkCallback(result);
|
||||
return result;
|
||||
},
|
||||
|
||||
_renderText: function(text) {
|
||||
return this.el("span", text);
|
||||
},
|
||||
}); // Widgets.URLString.prototype
|
||||
|
||||
/**
|
||||
* Widget used for displaying ObjectActors that have no specialised renderers.
|
||||
*
|
||||
|
@ -245,6 +245,7 @@ run-if = os == "mac"
|
||||
[browser_webconsole_cached_autocomplete.js]
|
||||
[browser_webconsole_change_font_size.js]
|
||||
[browser_webconsole_chrome.js]
|
||||
[browser_webconsole_clickable_urls.js]
|
||||
[browser_webconsole_closure_inspection.js]
|
||||
[browser_webconsole_completion.js]
|
||||
[browser_webconsole_console_extras.js]
|
||||
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// When strings containing URLs are entered into the webconsole,
|
||||
// check its output and ensure that the output can be clicked to open those URLs.
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,Bug 1005909 - Clickable URLS";
|
||||
|
||||
let inputTests = [
|
||||
|
||||
// 0: URL opens page when clicked.
|
||||
{
|
||||
input: "'http://example.com'",
|
||||
output: "http://example.com",
|
||||
expectedTab: "http://example.com/",
|
||||
},
|
||||
|
||||
// 1: URL opens page using https when clicked.
|
||||
{
|
||||
input: "'https://example.com'",
|
||||
output: "https://example.com",
|
||||
expectedTab: "https://example.com/",
|
||||
},
|
||||
|
||||
// 2: URL with port opens page when clicked.
|
||||
{
|
||||
input: "'https://example.com:443'",
|
||||
output: "https://example.com:443",
|
||||
expectedTab: "https://example.com/",
|
||||
},
|
||||
|
||||
// 3: URL containing non-empty path opens page when clicked.
|
||||
{
|
||||
input: "'http://example.com/foo'",
|
||||
output: "http://example.com/foo",
|
||||
expectedTab: "http://example.com/foo",
|
||||
},
|
||||
|
||||
// 4: URL opens page when clicked, even when surrounded by non-URL tokens.
|
||||
{
|
||||
input: "'foo http://example.com bar'",
|
||||
output: "foo http://example.com bar",
|
||||
expectedTab: "http://example.com/",
|
||||
},
|
||||
|
||||
// 5: URL opens page when clicked, and whitespace is be preserved.
|
||||
{
|
||||
input: "'foo\\nhttp://example.com\\nbar'",
|
||||
output: "foo\nhttp://example.com\nbar",
|
||||
expectedTab: "http://example.com/",
|
||||
},
|
||||
|
||||
// 6: URL opens page when clicked when multiple links are present.
|
||||
{
|
||||
input: "'http://example.com http://example.com'",
|
||||
output: "http://example.com http://example.com",
|
||||
expectedTab: "http://example.com/",
|
||||
},
|
||||
|
||||
// 7: URL without scheme does not open page when clicked.
|
||||
{
|
||||
input: "'example.com'",
|
||||
output: "example.com",
|
||||
},
|
||||
|
||||
// 8: URL with invalid scheme does not open page when clicked.
|
||||
{
|
||||
input: "'foo://example.com'",
|
||||
output: "foo://example.com",
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
function test() {
|
||||
Task.spawn(function*() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole(tab);
|
||||
yield checkOutputForInputs(hud, inputTests);
|
||||
inputTests = null;
|
||||
}).then(finishTest);
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-03.html";
|
||||
|
||||
let inputTests = [
|
||||
|
||||
// 0
|
||||
{
|
||||
input: "document",
|
||||
@ -57,6 +58,7 @@ let inputTests = [
|
||||
{
|
||||
input: "window.location.href",
|
||||
output: '"' + TEST_URI + '"',
|
||||
noClick: true,
|
||||
},
|
||||
|
||||
// 6
|
||||
|
@ -110,11 +110,10 @@ let inputTests = [
|
||||
];
|
||||
|
||||
function test() {
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
openConsole().then((hud) => {
|
||||
return checkOutputForInputs(hud, inputTests);
|
||||
}).then(finishTest);
|
||||
}, true);
|
||||
Task.spawn(function*() {
|
||||
const {tab} = yield loadTab(TEST_URI);
|
||||
const hud = yield openConsole(tab);
|
||||
yield checkOutputForInputs(hud, inputTests);
|
||||
inputTests = null;
|
||||
}).then(finishTest);
|
||||
}
|
||||
|
@ -84,6 +84,32 @@ function loadTab(url) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function loadBrowser(browser) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
deferred.resolve(null)
|
||||
}, true);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function closeTab(tab) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
let container = gBrowser.tabContainer;
|
||||
|
||||
container.addEventListener("TabClose", function onTabClose() {
|
||||
container.removeEventListener("TabClose", onTabClose, true);
|
||||
deferred.resolve(null);
|
||||
}, true);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function afterAllTabsLoaded(callback, win) {
|
||||
win = win || window;
|
||||
|
||||
@ -1382,10 +1408,14 @@ function whenDelayedStartupFinished(aWindow, aCallback)
|
||||
* - inspectorIcon: boolean, when true, the test runner expects the
|
||||
* result widget to contain an inspectorIcon element (className
|
||||
* open-inspector).
|
||||
*
|
||||
* - expectedTab: string, optional, the full URL of the new tab which must
|
||||
* open. If this is not provided, any new tabs that open will cause a test
|
||||
* failure.
|
||||
*/
|
||||
function checkOutputForInputs(hud, inputTests)
|
||||
{
|
||||
let eventHandlers = new Set();
|
||||
let container = gBrowser.tabContainer;
|
||||
|
||||
function* runner()
|
||||
{
|
||||
@ -1393,10 +1423,7 @@ function checkOutputForInputs(hud, inputTests)
|
||||
info("checkInput(" + i + "): " + entry.input);
|
||||
yield checkInput(entry);
|
||||
}
|
||||
|
||||
for (let fn of eventHandlers) {
|
||||
hud.jsterm.off("variablesview-open", fn);
|
||||
}
|
||||
container = null;
|
||||
}
|
||||
|
||||
function* checkInput(entry)
|
||||
@ -1467,27 +1494,39 @@ function checkOutputForInputs(hud, inputTests)
|
||||
}
|
||||
}
|
||||
|
||||
function checkObjectClick(entry, msg)
|
||||
function* checkObjectClick(entry, msg)
|
||||
{
|
||||
let body = msg.querySelector(".message-body a") ||
|
||||
msg.querySelector(".message-body");
|
||||
ok(body, "the message body");
|
||||
|
||||
let deferred = promise.defer();
|
||||
|
||||
entry._onVariablesViewOpen = onVariablesViewOpen.bind(null, entry, deferred);
|
||||
let deferredVariablesView = promise.defer();
|
||||
entry._onVariablesViewOpen = onVariablesViewOpen.bind(null, entry, deferredVariablesView);
|
||||
hud.jsterm.on("variablesview-open", entry._onVariablesViewOpen);
|
||||
eventHandlers.add(entry._onVariablesViewOpen);
|
||||
|
||||
let deferredTab = promise.defer();
|
||||
entry._onTabOpen = onTabOpen.bind(null, entry, deferredTab);
|
||||
container.addEventListener("TabOpen", entry._onTabOpen, true);
|
||||
|
||||
body.scrollIntoView();
|
||||
EventUtils.synthesizeMouse(body, 2, 2, {}, hud.iframeWindow);
|
||||
|
||||
if (entry.inspectable) {
|
||||
info("message body tagName '" + body.tagName + "' className '" + body.className + "'");
|
||||
return deferred.promise; // wait for the panel to open if we need to.
|
||||
yield deferredVariablesView.promise;
|
||||
} else {
|
||||
hud.jsterm.off("variablesview-open", entry._onVariablesView);
|
||||
entry._onVariablesView = null;
|
||||
}
|
||||
|
||||
return promise.resolve(null);
|
||||
if (entry.expectedTab) {
|
||||
yield deferredTab.promise;
|
||||
} else {
|
||||
container.removeEventListener("TabOpen", entry._onTabOpen, true);
|
||||
entry._onTabOpen = null;
|
||||
}
|
||||
|
||||
yield promise.resolve(null);
|
||||
}
|
||||
|
||||
function checkLinkToInspector(entry, msg)
|
||||
@ -1513,7 +1552,7 @@ function checkOutputForInputs(hud, inputTests)
|
||||
});
|
||||
}
|
||||
|
||||
function onVariablesViewOpen(entry, deferred, event, view, options)
|
||||
function onVariablesViewOpen(entry, {resolve, reject}, event, view, options)
|
||||
{
|
||||
let label = entry.variablesViewLabel || entry.output;
|
||||
if (typeof label == "string" && options.label != label) {
|
||||
@ -1524,12 +1563,25 @@ function checkOutputForInputs(hud, inputTests)
|
||||
}
|
||||
|
||||
hud.jsterm.off("variablesview-open", entry._onVariablesViewOpen);
|
||||
eventHandlers.delete(entry._onVariablesViewOpen);
|
||||
entry._onVariablesViewOpen = null;
|
||||
|
||||
ok(entry.inspectable, "variables view was shown");
|
||||
|
||||
deferred.resolve(null);
|
||||
resolve(null);
|
||||
}
|
||||
|
||||
function onTabOpen(entry, {resolve, reject}, event)
|
||||
{
|
||||
container.removeEventListener("TabOpen", entry._onTabOpen, true);
|
||||
entry._onTabOpen = null;
|
||||
|
||||
let tab = event.target;
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
loadBrowser(browser).then(() => {
|
||||
let uri = content.location.href;
|
||||
ok(entry.expectedTab && entry.expectedTab == uri,
|
||||
"opened tab '" + uri + "', expected tab '" + entry.expectedTab + "'");
|
||||
return closeTab(tab);
|
||||
}).then(resolve, reject);
|
||||
}
|
||||
|
||||
return Task.spawn(runner);
|
||||
|
@ -157,12 +157,14 @@ let UI = {
|
||||
unbusy: function() {
|
||||
document.querySelector("window").classList.remove("busy")
|
||||
this.updateCommands();
|
||||
this._busyPromise = null;
|
||||
},
|
||||
|
||||
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.
|
||||
this._busyPromise = promise;
|
||||
let timeout = setTimeout(() => {
|
||||
this.unbusy();
|
||||
UI.reportError("error_operationTimeout", operationDescription);
|
||||
@ -616,11 +618,10 @@ let Cmds = {
|
||||
projectsNode.appendChild(panelItemNode);
|
||||
panelItemNode.setAttribute("label", project.name || AppManager.DEFAULT_PROJECT_NAME);
|
||||
panelItemNode.setAttribute("image", project.icon || AppManager.DEFAULT_PROJECT_ICON);
|
||||
if (!project.validationStatus) {
|
||||
// The result of the validation process (storing names, icons, …) has never been
|
||||
// stored in the IndexedDB database. This happens when the project has been created
|
||||
// from the old app manager. We need to run the validation again and update the name
|
||||
// and icon of the app
|
||||
if (!project.name || !project.icon) {
|
||||
// The result of the validation process (storing names, icons, …) is not stored in
|
||||
// the IndexedDB database when App Manager v1 is used.
|
||||
// We need to run the validation again and update the name and icon of the app.
|
||||
AppManager.validateProject(project).then(() => {
|
||||
panelItemNode.setAttribute("label", project.name);
|
||||
panelItemNode.setAttribute("image", project.icon);
|
||||
|
@ -62,17 +62,15 @@ function closeWebIDE(win) {
|
||||
}
|
||||
|
||||
function removeAllProjects() {
|
||||
let deferred = promise.defer();
|
||||
AppProjects.load().then(() => {
|
||||
return Task.spawn(function* () {
|
||||
yield AppProjects.load();
|
||||
let projects = AppProjects.store.object.projects;
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
AppProjects.remove(projects[i].location);
|
||||
yield AppProjects.remove(projects[i].location);
|
||||
}
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function nextTick() {
|
||||
let deferred = promise.defer();
|
||||
SimpleTest.executeSoon(() => {
|
||||
|
@ -19,15 +19,12 @@
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
Task.spawn(function* () {
|
||||
let clClass = Components.classes["@mozilla.org/toolkit/command-line;1"].createInstance();
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
||||
DebuggerServer.init(function () { return true; });
|
||||
DebuggerServer.addBrowserActors();
|
||||
|
||||
let win = yield openWebIDE();
|
||||
|
||||
|
||||
let packagedAppLocation = getTestFilePath("app");
|
||||
|
||||
let cli = "actions=addPackagedApp&location=" + packagedAppLocation;
|
||||
|
@ -22,6 +22,9 @@
|
||||
let win = yield openWebIDE();
|
||||
let packagedAppLocation = getTestFilePath("app");
|
||||
|
||||
yield win.AppProjects.load();
|
||||
is(win.AppProjects.store.object.projects.length, 0, "IDB is empty");
|
||||
|
||||
yield win.Cmds.importPackagedApp(packagedAppLocation);
|
||||
|
||||
let project = win.AppManager.selectedProject;
|
||||
|
@ -49,10 +49,9 @@
|
||||
|
||||
win.AppManager.update("runtimelist");
|
||||
|
||||
let hostedAppManifest = TEST_BASE + "hosted_app.manifest";
|
||||
yield win.Cmds.importHostedApp(hostedAppManifest);
|
||||
let packagedAppLocation = getTestFilePath("app");
|
||||
|
||||
yield win.Cmds.showRuntimePanel();
|
||||
yield win.Cmds.importPackagedApp(packagedAppLocation);
|
||||
|
||||
let panelNode = win.document.querySelector("#runtime-panel");
|
||||
let items = panelNode.querySelectorAll(".runtime-panel-item-usb");
|
||||
@ -65,36 +64,27 @@
|
||||
|
||||
items[0].click();
|
||||
|
||||
yield deferred.promise;
|
||||
ok(win.document.querySelector("window").className, "busy", "UI is busy");
|
||||
yield win.UI._busyPromise;
|
||||
|
||||
is(Object.keys(DebuggerServer._connections).length, 1, "Connected");
|
||||
|
||||
ok(isPlayActive(), "play button is enabled 1");
|
||||
ok(!isStopActive(), "stop button is disabled 1");
|
||||
let oldProject = win.AppManager.selectedProject;
|
||||
win.AppManager.selectedProject = null;
|
||||
|
||||
yield nextTick();
|
||||
|
||||
ok(!isPlayActive(), "play button is disabled 2");
|
||||
ok(!isStopActive(), "stop button is disabled 2");
|
||||
|
||||
win.AppManager.selectedProject.errorsCount = 0;
|
||||
win.AppManager._selectedProject = oldProject;
|
||||
win.UI.updateCommands();
|
||||
|
||||
yield nextTick();
|
||||
|
||||
ok(isPlayActive(), "play button is enabled 3");
|
||||
ok(!isStopActive(), "stop button is disabled 3");
|
||||
let oldProject = win.AppManager.selectedProject;
|
||||
win.AppManager.selectedProject = null;
|
||||
|
||||
yield nextTick();
|
||||
|
||||
ok(!isPlayActive(), "play button is disabled 4");
|
||||
ok(!isStopActive(), "stop button is disabled 4");
|
||||
win.AppManager._selectedProject = oldProject;
|
||||
win.UI.updateCommands();
|
||||
|
||||
yield nextTick();
|
||||
|
||||
ok(isPlayActive(), "play button is enabled 5");
|
||||
ok(!isStopActive(), "stop button is disabled 5");
|
||||
|
||||
|
||||
yield win.Cmds.disconnectRuntime();
|
||||
@ -102,8 +92,8 @@
|
||||
is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
|
||||
|
||||
ok(win.AppManager.selectedProject, "A project is still selected");
|
||||
ok(!isPlayActive(), "play button is disabled 6");
|
||||
ok(!isStopActive(), "stop button is disabled 6");
|
||||
ok(!isPlayActive(), "play button is disabled 4");
|
||||
ok(!isStopActive(), "stop button is disabled 4");
|
||||
|
||||
deferred = promise.defer();
|
||||
win.AppManager.connection.once(
|
||||
@ -122,6 +112,8 @@
|
||||
|
||||
DebuggerServer.destroy();
|
||||
|
||||
yield removeAllProjects();
|
||||
|
||||
SimpleTest.finish();
|
||||
|
||||
});
|
||||
|
@ -4,6 +4,6 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
pref("devtools.webide.showProjectEditor", true);
|
||||
pref("devtools.webide.templatesURL", "http://fixme/");
|
||||
pref("devtools.webide.templatesURL", "http://people.mozilla.org/~prouget/webidetemplates/template.json"); // See bug 1021504
|
||||
pref("devtools.webide.lastprojectlocation", "");
|
||||
pref("devtools.webide.enableLocalRuntime", false);
|
||||
|
@ -638,11 +638,9 @@
|
||||
#endif
|
||||
|
||||
; [Webide Files]
|
||||
#ifdef MOZ_DEVTOOLS_WEBIDE
|
||||
@BINPATH@/browser/chrome/webide@JAREXT@
|
||||
@BINPATH@/browser/chrome/webide.manifest
|
||||
@BINPATH@/browser/@PREF_DIR@/webide-prefs.js
|
||||
#endif
|
||||
|
||||
; shell icons
|
||||
#ifdef XP_UNIX
|
||||
|
@ -26,7 +26,12 @@
|
||||
|
||||
<!ENTITY abouthome.bookmarksButton.label "Bookmarks">
|
||||
<!ENTITY abouthome.historyButton.label "History">
|
||||
<!ENTITY abouthome.settingsButton.label "Settings">
|
||||
<!-- LOCALIZATION NOTE (abouthome.preferencesButtonWin.label): The label for the
|
||||
preferences/options item on about:home on Windows -->
|
||||
<!ENTITY abouthome.preferencesButtonWin.label "Options">
|
||||
<!-- LOCALIZATION NOTE (abouthome.preferencesButtonUnix.label): The label for the
|
||||
preferences/options item on about:home on Linux and OS X -->
|
||||
<!ENTITY abouthome.preferencesButtonUnix.label "Preferences">
|
||||
<!ENTITY abouthome.addonsButton.label "Add-ons">
|
||||
<!ENTITY abouthome.appsButton.label "Marketplace">
|
||||
<!ENTITY abouthome.downloadsButton.label "Downloads">
|
||||
|
@ -6,14 +6,14 @@ def test(mod, path, entity = None):
|
||||
import re
|
||||
# ignore anything but Firefox
|
||||
if mod not in ("netwerk", "dom", "toolkit", "security/manager",
|
||||
"browser", "browser/metro", "webapprt",
|
||||
"browser", "webapprt",
|
||||
"extensions/reporter", "extensions/spellcheck",
|
||||
"other-licenses/branding/firefox",
|
||||
"browser/branding/official",
|
||||
"services/sync"):
|
||||
return "ignore"
|
||||
if mod not in ("browser", "browser/metro", "extensions/spellcheck"):
|
||||
# we only have exceptions for browser, metro and extensions/spellcheck
|
||||
if mod not in ("browser", "extensions/spellcheck"):
|
||||
# we only have exceptions for browser and extensions/spellcheck
|
||||
return "error"
|
||||
if not entity:
|
||||
# the only files to ignore are spell checkers and search
|
||||
@ -35,8 +35,4 @@ def test(mod, path, entity = None):
|
||||
re.match(r"gecko\.handlerService\.schemes\.", entity) or
|
||||
re.match(r"gecko\.handlerService\.defaultHandlersVersion", entity))
|
||||
else "error")
|
||||
if mod == "browser/metro" and path == "chrome/region.properties":
|
||||
return ("ignore"
|
||||
if re.match(r"browser\.search\.order\.[1-9]", entity)
|
||||
else "error")
|
||||
return "error"
|
||||
|
@ -8,7 +8,6 @@ all = browser/locales/all-locales
|
||||
|
||||
[compare]
|
||||
dirs = browser
|
||||
browser/metro
|
||||
extensions/reporter
|
||||
other-licenses/branding/firefox
|
||||
browser/branding/official
|
||||
|
@ -109,12 +109,6 @@ toolbarseparator {
|
||||
background: url(chrome://browser/skin/Toolbar-background-noise.png) hsl(0,0%,83%);
|
||||
}
|
||||
|
||||
#TabsToolbar:not([collapsed="true"]) + #nav-bar {
|
||||
/* Position the toolbar above the bottom of background tabs */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#nav-bar {
|
||||
-moz-appearance: none;
|
||||
background: url(chrome://browser/skin/Toolbar-background-noise.png),
|
||||
@ -138,6 +132,19 @@ toolbarseparator {
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw the bottom border of the tabs toolbar when it's not using
|
||||
-moz-appearance: toolbar. */
|
||||
#main-window:-moz-any([sizemode="fullscreen"],[customize-entered]) #TabsToolbar:not([collapsed="true"]) + #nav-bar,
|
||||
#main-window:not([tabsintitlebar]) #TabsToolbar:not([collapsed="true"]) + #nav-bar,
|
||||
#TabsToolbar:not([collapsed="true"]) + #nav-bar:-moz-lwtheme {
|
||||
border-top: 1px solid hsla(0,0%,0%,.3);
|
||||
background-clip: padding-box;
|
||||
margin-top: -@tabToolbarNavbarOverlap@;
|
||||
/* Position the toolbar above the bottom of background tabs */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#nav-bar-customization-target {
|
||||
padding: 4px;
|
||||
}
|
||||
@ -2770,33 +2777,14 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
box-shadow: @focusRingShadow@;
|
||||
}
|
||||
|
||||
/* We want the titlebar to be unified, but we still want to be able
|
||||
* to give #TabsToolbar a background. So we can't set -moz-appearance:
|
||||
* toolbar on #TabsToolbar itself. Instead, we set it on a box of the
|
||||
* right size which is put underneath #TabsToolbar.
|
||||
*
|
||||
* Because of Bug 941309, we make sure this pseudoelement always exists,
|
||||
* but we only make it visible when we need it.
|
||||
*/
|
||||
#navigator-toolbox::before {
|
||||
content: '';
|
||||
display: block;
|
||||
-moz-appearance: toolbar;
|
||||
height: @tabMinHeight@;
|
||||
margin-bottom: -@tabMinHeight@;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#main-window:not([customizing]) #navigator-toolbox[inFullscreen]:not(:-moz-lwtheme)::before,
|
||||
#main-window:not(:-moz-any([customizing],[tabsintitlebar])) #navigator-toolbox:not(:-moz-lwtheme)::before {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#TabsToolbar {
|
||||
position: relative;
|
||||
-moz-appearance: none;
|
||||
background-repeat: repeat-x;
|
||||
margin-bottom: -@tabToolbarNavbarOverlap@;
|
||||
margin-bottom: -1px; /* Overlap the inner highlight at the top of the nav-bar */
|
||||
}
|
||||
|
||||
#main-window:not([customizing]) #navigator-toolbox[inFullscreen] > #TabsToolbar:not(:-moz-lwtheme),
|
||||
#main-window:not(:-moz-any([customizing],[tabsintitlebar])) #navigator-toolbox > #TabsToolbar:not(:-moz-lwtheme) {
|
||||
-moz-appearance: toolbar;
|
||||
}
|
||||
|
||||
#TabsToolbar:not(:-moz-lwtheme) {
|
||||
@ -2804,32 +2792,10 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
text-shadow: @loweredShadow@;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw the bottom border of the tabstrip when core doesn't do it for us.
|
||||
* Because of Bug 941309, we make sure this pseudoelement always exists,
|
||||
* but we only make it visible when we need it.
|
||||
*/
|
||||
#TabsToolbar::after {
|
||||
content: '';
|
||||
/* Because we use placeholders for window controls etc. in the tabstrip,
|
||||
* and position those with ordinal attributes, and because our layout code
|
||||
* expects :before/:after nodes to come first/last in the frame list,
|
||||
* we have to reorder this element to come last, hence the
|
||||
* ordinal group value (see bug 853415). */
|
||||
-moz-box-ordinal-group: 1001;
|
||||
position: absolute;
|
||||
bottom: @tabToolbarNavbarOverlap@;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 0;
|
||||
border-bottom: 1px solid hsla(0,0%,0%,.3);
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#main-window:-moz-any([sizemode="fullscreen"],[customize-entered]) #TabsToolbar::after,
|
||||
#main-window:not([tabsintitlebar]) #TabsToolbar::after,
|
||||
#TabsToolbar:-moz-lwtheme::after {
|
||||
visibility: visible;
|
||||
@media (-moz-mac-lion-theme) {
|
||||
#navigator-toolbox[inFullscreen] > #TabsToolbar {
|
||||
padding-top: @spaceAboveTabbar@;
|
||||
}
|
||||
}
|
||||
|
||||
#tabbrowser-tabs {
|
||||
@ -4058,17 +4024,6 @@ menulist.translate-infobar-element > .menulist-dropmarker {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
/* Lion Fullscreen window styling */
|
||||
@media (-moz-mac-lion-theme) {
|
||||
#navigator-toolbox[inFullscreen]::before {
|
||||
/* Adjust by the full element height of #titlebar, since that element is
|
||||
* not displayed in native full-screen.
|
||||
* Also add the height of the tabs, since we're calculating the
|
||||
* total height of this pseudo-element, not just the top-padding. */
|
||||
height: calc(@tabMinHeight@ + @spaceAboveTabbar@) !important;
|
||||
}
|
||||
}
|
||||
|
||||
#full-screen-warning-message {
|
||||
background-image: url("chrome://browser/skin/fullscreen-darknoise.png");
|
||||
color: white;
|
||||
@ -4421,6 +4376,11 @@ window > chatbox {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
#main-window[customize-entered] #nav-bar {
|
||||
border-top-left-radius: 2.5px;
|
||||
border-top-right-radius: 2.5px;
|
||||
}
|
||||
|
||||
/* Compensate for the border set above for this horizontal line. */
|
||||
#main-window[customize-entered] #navigator-toolbox::after {
|
||||
margin-left: 3px;
|
||||
|
@ -11,6 +11,20 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
-moz-appearance: treetwisty;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.arrow[open] {
|
||||
-moz-appearance: treetwistyopen;
|
||||
}
|
||||
|
||||
.arrow[invisible] {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#projecteditor-menubar {
|
||||
/* XXX: Hide menu bar until we have option to add menu items
|
||||
to an existing one. */
|
||||
@ -27,7 +41,13 @@
|
||||
|
||||
.sources-tree {
|
||||
overflow:auto;
|
||||
overflow-x: hidden;
|
||||
-moz-user-focus: normal;
|
||||
|
||||
/* Allows this to expand inside of parent xul element, while
|
||||
still supporting child flexbox elements, including ellipses. */
|
||||
-moz-box-flex: 1;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sources-tree input {
|
||||
@ -37,94 +57,95 @@
|
||||
|
||||
#main-deck .sources-tree {
|
||||
background: rgb(225, 225, 225);
|
||||
min-width: 50px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item {
|
||||
.entry {
|
||||
color: #18191A;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item .file-label {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
.entry .file-label {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item .file-icon {
|
||||
.entry .file-icon {
|
||||
display: inline-block;
|
||||
background: url(file-icons-sheet@2x.png);
|
||||
background-size: 140px 15px;
|
||||
background-repeat: no-repeat;
|
||||
width: 20px;
|
||||
height: 15px;
|
||||
vertical-align: middle;
|
||||
background-position: -40px 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item .file-icon.icon-none {
|
||||
.entry .file-icon.icon-none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item .icon-css {
|
||||
.entry .icon-css {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item .icon-js {
|
||||
.entry .icon-js {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item .icon-html {
|
||||
.entry .icon-html {
|
||||
background-position: -40px 0;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item .icon-file {
|
||||
.entry .icon-file {
|
||||
background-position: -60px 0;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item .icon-folder {
|
||||
.entry .icon-folder {
|
||||
background-position: -80px 0;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item .icon-img {
|
||||
.entry .icon-img {
|
||||
background-position: -100px 0;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item .icon-manifest {
|
||||
.entry .icon-manifest {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item:hover {
|
||||
background: rgba(0, 0, 0, .05);
|
||||
.entry {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
line-height: 20px;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
.entry:hover:not(.entry-group-title):not(.selected) {
|
||||
background: rgba(0, 0, 0, .05);
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-item.selected {
|
||||
background: #3875D7;
|
||||
.entry.selected {
|
||||
background: rgba(56, 117, 215, 1);
|
||||
color: #F5F7FA;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree .side-menu-widget-group-title,
|
||||
#main-deck .sources-tree .side-menu-widget-group-title:hover:not(.selected) {
|
||||
background: #B4D7EB;
|
||||
color: #222;
|
||||
.entry-group-title {
|
||||
background: rgba(56, 117, 215, 0.8);
|
||||
color: #F5F7FA;
|
||||
font-weight: bold;
|
||||
font-size: 1.05em;
|
||||
cursor: default;
|
||||
line-height: 35px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
#main-deck .sources-tree li.child:only-child .side-menu-widget-group-title .expander {
|
||||
.sources-tree .entry-group-title .expander {
|
||||
display: none;
|
||||
}
|
||||
#main-deck .sources-tree .side-menu-widget-item .expander {
|
||||
|
||||
.entry .expander {
|
||||
width: 16px;
|
||||
padding: 0;
|
||||
}
|
||||
@ -143,30 +164,62 @@
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
||||
/* App Manager */
|
||||
.project-name-label {
|
||||
font-weight: bold;
|
||||
padding-left: 10px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.project-version-label {
|
||||
color: #666;
|
||||
padding-left: 5px;
|
||||
font-size: .9em;
|
||||
.project-flex {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.project-image {
|
||||
max-height: 28px;
|
||||
margin-left: -.5em;
|
||||
vertical-align: middle;
|
||||
max-height: 25px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.editor-image {
|
||||
padding: 10px;
|
||||
.project-image,
|
||||
.project-status,
|
||||
.project-options {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.project-status {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
border: solid 1px rgba(255, 255, 255, .5);
|
||||
margin-right: 10px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.project-status[status=valid] {
|
||||
background: #70bf53;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.project-status[status=warning] {
|
||||
background: #d99b28;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.project-status[status=error] {
|
||||
background: #ed2655;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* Status Bar */
|
||||
.projecteditor-file-label {
|
||||
font-weight: bold;
|
||||
padding-left: 29px;
|
||||
vertical-align: middle;
|
||||
padding-right: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Image View */
|
||||
.editor-image {
|
||||
padding: 10px;
|
||||
}
|
||||
|
@ -5,11 +5,6 @@
|
||||
%endif
|
||||
@namespace html "http://www.w3.org/1999/xhtml";
|
||||
|
||||
@font-face {
|
||||
font-family: "Clear Sans";
|
||||
src: url("chrome://browser/content/fonts/ClearSans-Regular.woff") format('woff');
|
||||
}
|
||||
|
||||
page {
|
||||
-moz-appearance: none;
|
||||
background-color: white;
|
||||
@ -39,7 +34,7 @@ caption > label {
|
||||
prefpane {
|
||||
max-width: 800px;
|
||||
padding: 0;
|
||||
font-family: "Clear Sans", sans-serif;
|
||||
font: message-box;
|
||||
font-size: 1.25rem;
|
||||
line-height: 22px;
|
||||
color: #424E5A;
|
||||
@ -292,7 +287,6 @@ menulist > menupopup menuitem,
|
||||
button[type="menu"] > menupopup menu,
|
||||
button[type="menu"] > menupopup menuitem {
|
||||
-moz-appearance: none;
|
||||
font-family: "Clear Sans", sans-serif;
|
||||
font-size: 1.25rem;
|
||||
line-height: 22px;
|
||||
height: 40px;
|
||||
@ -488,7 +482,6 @@ radio[disabled="true"] > .radio-check {
|
||||
|
||||
.category-name {
|
||||
line-height: 22px;
|
||||
font-family: "Clear Sans", sans-serif;
|
||||
font-size: 1.25rem;
|
||||
padding-bottom: 2px;
|
||||
-moz-padding-start: 9px;
|
||||
@ -694,7 +687,6 @@ filefield {
|
||||
#typeColumn,
|
||||
#actionColumn {
|
||||
-moz-appearance: none;
|
||||
font-family: "Clear Sans", sans-serif;
|
||||
line-height: 20px;
|
||||
color: #333333;
|
||||
height: 36px;
|
||||
|
@ -440,11 +440,13 @@ browser.jar:
|
||||
skin/classic/aero/browser/livemark-folder.png (livemark-folder-aero.png)
|
||||
skin/classic/aero/browser/menu-back.png (menu-back-aero.png)
|
||||
skin/classic/aero/browser/menu-forward.png (menu-forward-aero.png)
|
||||
skin/classic/aero/browser/menuPanel.png (menuPanel-aero.png)
|
||||
skin/classic/aero/browser/menuPanel.png
|
||||
skin/classic/aero/browser/menuPanel-aero.png
|
||||
skin/classic/aero/browser/menuPanel-customize.png
|
||||
skin/classic/aero/browser/menuPanel-exit.png
|
||||
skin/classic/aero/browser/menuPanel-help.png
|
||||
skin/classic/aero/browser/menuPanel-small.png (menuPanel-small-aero.png)
|
||||
skin/classic/aero/browser/menuPanel-small.png
|
||||
skin/classic/aero/browser/menuPanel-small-aero.png
|
||||
skin/classic/aero/browser/Metro_Glyph.png (Metro_Glyph-aero.png)
|
||||
skin/classic/aero/browser/Metro_Glyph-inverted.png
|
||||
skin/classic/aero/browser/Metro_Glyph-menuPanel.png
|
||||
@ -806,5 +808,11 @@ browser.jar:
|
||||
% override chrome://browser/skin/Toolbar.png chrome://browser/skin/Toolbar-aero.png os=WINNT osversion=6
|
||||
% override chrome://browser/skin/Toolbar.png chrome://browser/skin/Toolbar-aero.png os=WINNT osversion=6.1
|
||||
|
||||
% override chrome://browser/skin/menuPanel.png chrome://browser/skin/menuPanel-aero.png os=WINNT osversion=6
|
||||
% override chrome://browser/skin/menuPanel.png chrome://browser/skin/menuPanel-aero.png os=WINNT osversion=6.1
|
||||
|
||||
% override chrome://browser/skin/menuPanel-small.png chrome://browser/skin/menuPanel-small-aero.png os=WINNT osversion=6
|
||||
% override chrome://browser/skin/menuPanel-small.png chrome://browser/skin/menuPanel-small-aero.png os=WINNT osversion=6.1
|
||||
|
||||
% override chrome://browser/skin/sync-horizontalbar.png chrome://browser/skin/sync-horizontalbar-XPVista7.png os=WINNT osversion<6.2
|
||||
% override chrome://browser/skin/syncProgress-horizontalbar.png chrome://browser/skin/syncProgress-horizontalbar-XPVista7.png os=WINNT osversion<6.2
|
||||
|
13
configure.in
13
configure.in
@ -7680,19 +7680,6 @@ if test "$MOZ_CHROME_FILE_FORMAT" != "jar" &&
|
||||
AC_MSG_ERROR([--enable-chrome-format must be set to either jar, flat, or omni])
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Support for devtools webide
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(devtools-webide,
|
||||
[ --enable-devtools-webide Set compile flags necessary for compiling devtools webide ],
|
||||
MOZ_DEVTOOLS_WEBIDE=1,
|
||||
MOZ_DEVTOOLS_WEBIDE= )
|
||||
|
||||
if test -n "$MOZ_DEVTOOLS_WEBIDE"; then
|
||||
AC_DEFINE(MOZ_DEVTOOLS_WEBIDE)
|
||||
fi
|
||||
AC_SUBST(MOZ_DEVTOOLS_WEBIDE)
|
||||
|
||||
dnl =========================================================
|
||||
dnl Omnijar packaging (bug 552121)
|
||||
dnl =========================================================
|
||||
|
@ -3436,14 +3436,13 @@ BluetoothDBusService::ToggleCalls(BluetoothReplyRunnable* aRunnable)
|
||||
class OnUpdateSdpRecordsRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
OnUpdateSdpRecordsRunnable(const nsAString& aObjectPath,
|
||||
OnUpdateSdpRecordsRunnable(const nsAString& aDeviceAddress,
|
||||
BluetoothProfileManagerBase* aManager)
|
||||
: mManager(aManager)
|
||||
: mDeviceAddress(aDeviceAddress)
|
||||
, mManager(aManager)
|
||||
{
|
||||
MOZ_ASSERT(!aObjectPath.IsEmpty());
|
||||
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
mDeviceAddress = GetAddressFromObjectPath(aObjectPath);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -3456,6 +3455,12 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GetDeviceAddress(nsAString& aRetDeviceAddress)
|
||||
{
|
||||
aRetDeviceAddress = mDeviceAddress;
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mDeviceAddress;
|
||||
BluetoothProfileManagerBase* mManager;
|
||||
@ -3641,31 +3646,74 @@ public:
|
||||
MOZ_ASSERT(sDBusConnection);
|
||||
MOZ_ASSERT(!sAdapterPath.IsEmpty());
|
||||
|
||||
const nsString objectPath =
|
||||
GetObjectPathFromAddress(sAdapterPath, mDeviceAddress);
|
||||
// We first guess that the device doesn't exist at all. So we use BlueZ
|
||||
// API "CreateDevice" to create an object path for the BluetoothDevice
|
||||
// object. "CreateDevice" will connect to the remote device and retrieve
|
||||
// SDP records of the target.
|
||||
NS_ConvertUTF16toUTF8 address(mDeviceAddress);
|
||||
const char* cAddress = address.get();
|
||||
|
||||
// I choose to use raw pointer here because this is going to be passed as an
|
||||
// argument into SendWithReply() at once.
|
||||
OnUpdateSdpRecordsRunnable* callbackRunnable =
|
||||
new OnUpdateSdpRecordsRunnable(objectPath, mBluetoothProfileManager);
|
||||
new OnUpdateSdpRecordsRunnable(mDeviceAddress, mBluetoothProfileManager);
|
||||
|
||||
sDBusConnection->SendWithReply(DiscoverServicesCallback,
|
||||
(void*)callbackRunnable, -1,
|
||||
BLUEZ_DBUS_BASE_IFC,
|
||||
NS_ConvertUTF16toUTF8(objectPath).get(),
|
||||
DBUS_DEVICE_IFACE,
|
||||
"DiscoverServices",
|
||||
DBUS_TYPE_STRING, &EmptyCString(),
|
||||
DBUS_TYPE_INVALID);
|
||||
sDBusConnection->SendWithReply(
|
||||
CreateDeviceCallback, callbackRunnable, -1,
|
||||
BLUEZ_DBUS_BASE_IFC,
|
||||
NS_ConvertUTF16toUTF8(sAdapterPath).get(),
|
||||
DBUS_ADAPTER_IFACE,
|
||||
"CreateDevice",
|
||||
DBUS_TYPE_STRING, &cAddress,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
protected:
|
||||
static void CreateDeviceCallback(DBusMessage* aMsg, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
|
||||
|
||||
nsAutoString errorString;
|
||||
OnUpdateSdpRecordsRunnable* r =
|
||||
static_cast<OnUpdateSdpRecordsRunnable*>(aData);
|
||||
|
||||
if (IsDBusMessageError(aMsg, nullptr, errorString)) {
|
||||
// If the device already exists it comes here. If we want to refresh its
|
||||
// SDP records then we have to do "DiscoverServices"
|
||||
BT_LOGR("%s", NS_ConvertUTF16toUTF8(errorString).get());
|
||||
|
||||
nsString deviceAddress;
|
||||
r->GetDeviceAddress(deviceAddress);
|
||||
|
||||
const nsString objectPath =
|
||||
GetObjectPathFromAddress(sAdapterPath, deviceAddress);
|
||||
|
||||
sDBusConnection->SendWithReply(DiscoverServicesCallback,
|
||||
aData, -1,
|
||||
BLUEZ_DBUS_BASE_IFC,
|
||||
NS_ConvertUTF16toUTF8(objectPath).get(),
|
||||
DBUS_DEVICE_IFACE,
|
||||
"DiscoverServices",
|
||||
DBUS_TYPE_STRING, &EmptyCString(),
|
||||
DBUS_TYPE_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
static void DiscoverServicesCallback(DBusMessage* aMsg, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
|
||||
|
||||
nsRefPtr<OnUpdateSdpRecordsRunnable> r(
|
||||
static_cast<OnUpdateSdpRecordsRunnable*>(aData));
|
||||
nsAutoString errorStr;
|
||||
|
||||
if (IsDBusMessageError(aMsg, nullptr, errorStr)) {
|
||||
BT_LOGR("%s", NS_ConvertUTF16toUTF8(errorStr).get());
|
||||
}
|
||||
|
||||
OnUpdateSdpRecordsRunnable* r =
|
||||
static_cast<OnUpdateSdpRecordsRunnable*>(aData);
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
@ -3680,8 +3728,7 @@ BluetoothDBusService::UpdateSdpRecords(const nsAString& aDeviceAddress,
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
Task* task = new UpdateSdpRecordsTask(aDeviceAddress, aManager);
|
||||
DispatchToDBusThread(task);
|
||||
DispatchToDBusThread(new UpdateSdpRecordsTask(aDeviceAddress, aManager));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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/. */
|
||||
|
||||
@ -36,7 +34,14 @@ const BDADDR_ALL = "ff:ff:ff:ff:ff:ff";
|
||||
const BDADDR_LOCAL = "ff:ff:ff:00:00:00";
|
||||
|
||||
// A user friendly name for remote BT device.
|
||||
const REMOTE_DEVICE_NAME = "Remote BT Device";
|
||||
const REMOTE_DEVICE_NAME = "Remote_BT_Device";
|
||||
|
||||
// A system message signature of pairing request event
|
||||
const BT_PAIRING_REQ = "bluetooth-pairing-request";
|
||||
|
||||
// Passkey and pincode used to reply pairing requst
|
||||
const BT_PAIRING_PASSKEY = 123456;
|
||||
const BT_PAIRING_PINCODE = "ABCDEFG";
|
||||
|
||||
let Promise =
|
||||
SpecialPowers.Cu.import("resource://gre/modules/Promise.jsm").Promise;
|
||||
@ -80,6 +85,33 @@ function runEmulatorCmdSafe(aCommand) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap DOMRequest onsuccess/onerror events to Promise resolve/reject.
|
||||
*
|
||||
* Fulfill params: A DOMEvent.
|
||||
* Reject params: A DOMEvent.
|
||||
*
|
||||
* @param aRequest
|
||||
* A DOMRequest instance.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function wrapDomRequestAsPromise(aRequest) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
ok(aRequest instanceof DOMRequest,
|
||||
"aRequest is instanceof " + aRequest.constructor);
|
||||
|
||||
aRequest.onsuccess = function(aEvent) {
|
||||
deferred.resolve(aEvent);
|
||||
};
|
||||
aRequest.onerror = function(aEvent) {
|
||||
deferred.reject(aEvent);
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Bluetooth remote device to scatternet and set its properties.
|
||||
*
|
||||
@ -188,13 +220,11 @@ function setEmulatorDeviceProperty(aAddress, aPropertyName, aValue) {
|
||||
function getEmulatorDeviceProperty(aAddress, aPropertyName) {
|
||||
let cmd = "bt property " + aAddress + " " + aPropertyName;
|
||||
return runEmulatorCmdSafe(cmd)
|
||||
.then(function(aResults) {
|
||||
return aResults[0];
|
||||
});
|
||||
.then(aResults => aResults[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start dicovering Bluetooth devices.
|
||||
* Start discovering Bluetooth devices.
|
||||
*
|
||||
* Allows the device's adapter to start seeking for remote devices.
|
||||
*
|
||||
@ -202,32 +232,28 @@ function getEmulatorDeviceProperty(aAddress, aPropertyName) {
|
||||
* Reject params: a DOMError
|
||||
*
|
||||
* @param aAdapter
|
||||
* A BluetoothAdapter which is used to interact with local BT dev
|
||||
* A BluetoothAdapter which is used to interact with local BT device.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function startDiscovery(aAdapter) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = aAdapter.startDiscovery();
|
||||
request.onsuccess = function () {
|
||||
log(" Start discovery - Success");
|
||||
// TODO (bug 892207): Make Bluetooth APIs available for 3rd party apps.
|
||||
// Currently, discovering state wouldn't change immediately here.
|
||||
// We would turn on this check when the redesigned API are landed.
|
||||
// is(aAdapter.discovering, true, "BluetoothAdapter.discovering");
|
||||
deferred.resolve();
|
||||
}
|
||||
request.onerror = function (aEvent) {
|
||||
ok(false, "Start discovery - Fail");
|
||||
deferred.reject(aEvent.target.error);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return wrapDomRequestAsPromise(request)
|
||||
.then(function resolve() {
|
||||
// TODO (bug 892207): Make Bluetooth APIs available for 3rd party apps.
|
||||
// Currently, discovering state wouldn't change immediately here.
|
||||
// We would turn on this check when the redesigned API are landed.
|
||||
// is(aAdapter.discovering, false, "BluetoothAdapter.discovering");
|
||||
log(" Start discovery - Success");
|
||||
}, function reject(aEvent) {
|
||||
ok(false, "Start discovery - Fail");
|
||||
throw aEvent.target.error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop dicovering Bluetooth devices.
|
||||
* Stop discovering Bluetooth devices.
|
||||
*
|
||||
* Allows the device's adapter to stop seeking for remote devices.
|
||||
*
|
||||
@ -240,24 +266,184 @@ function startDiscovery(aAdapter) {
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function stopDiscovery(aAdapter) {
|
||||
let request = aAdapter.stopDiscovery();
|
||||
|
||||
return wrapDomRequestAsPromise(request)
|
||||
.then(function resolve() {
|
||||
// TODO (bug 892207): Make Bluetooth APIs available for 3rd party apps.
|
||||
// Currently, discovering state wouldn't change immediately here.
|
||||
// We would turn on this check when the redesigned API are landed.
|
||||
// is(aAdapter.discovering, false, "BluetoothAdapter.discovering");
|
||||
log(" Stop discovery - Success");
|
||||
}, function reject(aEvent) {
|
||||
ok(false, "Stop discovery - Fail");
|
||||
throw aEvent.target.error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for 'devicefound' event of specified devices.
|
||||
*
|
||||
* Resolve if that every specified devices has been found. Never reject.
|
||||
*
|
||||
* Fulfill params: an array which contains addresses of remote devices.
|
||||
*
|
||||
* @param aAdapter
|
||||
* A BluetoothAdapter which is used to interact with local BT device.
|
||||
* @param aRemoteAddresses
|
||||
* An array which contains addresses of remote devices.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function waitForDevicesFound(aAdapter, aRemoteAddresses) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = aAdapter.stopDiscovery();
|
||||
request.onsuccess = function () {
|
||||
log(" Stop discovery - Success");
|
||||
// TODO (bug 892207): Make Bluetooth APIs available for 3rd party apps.
|
||||
// Currently, discovering state wouldn't change immediately here.
|
||||
// We would turn on this check when the redesigned API are landed.
|
||||
// is(aAdapter.discovering, false, "BluetoothAdapter.discovering");
|
||||
deferred.resolve();
|
||||
}
|
||||
request.onerror = function (aEvent) {
|
||||
ok(false, "Stop discovery - Fail");
|
||||
deferred.reject(aEvent.target.error);
|
||||
}
|
||||
var addrArray = [];
|
||||
aAdapter.addEventListener("devicefound", function onevent(aEvent) {
|
||||
if(aRemoteAddresses.indexOf(aEvent.device.address) != -1) {
|
||||
addrArray.push(aEvent.device.address);
|
||||
}
|
||||
if(addrArray.length == aRemoteAddresses.length) {
|
||||
aAdapter.removeEventListener("devicefound", onevent);
|
||||
ok(true, "BluetoothAdapter has found all remote devices.");
|
||||
|
||||
deferred.resolve(addrArray);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start discovering Bluetooth devices and wait for 'devicefound' events.
|
||||
*
|
||||
* Allows the device's adapter to start seeking for remote devices and wait for
|
||||
* the 'devicefound' events of specified devices.
|
||||
*
|
||||
* Fulfill params: an array of addresses of found devices.
|
||||
*
|
||||
* @param aAdapter
|
||||
* A BluetoothAdapter which is used to interact with local BT device.
|
||||
* @param aRemoteAddresses
|
||||
* An array which contains addresses of remote devices.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function startDiscoveryAndWaitDevicesFound(aAdapter, aRemoteAddresses) {
|
||||
let promises = [];
|
||||
|
||||
promises.push(waitForDevicesFound(aAdapter, aRemoteAddresses));
|
||||
promises.push(startDiscovery(aAdapter));
|
||||
return Promise.all(promises)
|
||||
.then(aResults => aResults[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start pairing a remote device.
|
||||
*
|
||||
* Start pairing a remote device with the device's adapter.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: a DOMError
|
||||
*
|
||||
* @param aAdapter
|
||||
* A BluetoothAdapter which is used to interact with local BT device.
|
||||
* @param aDeviceAddress
|
||||
* The string of remote Bluetooth address with format xx:xx:xx:xx:xx:xx.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function pair(aAdapter, aDeviceAddress) {
|
||||
let request = aAdapter.pair(aDeviceAddress);
|
||||
|
||||
return wrapDomRequestAsPromise(request)
|
||||
.then(function resolve() {
|
||||
log(" Pair - Success");
|
||||
}, function reject(aEvent) {
|
||||
ok(false, "Pair - Fail");
|
||||
throw aEvent.target.error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the paired device from the paired device list.
|
||||
*
|
||||
* Remove the paired device from the paired device list of the device's adapter.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: a DOMError
|
||||
*
|
||||
* @param aAdapter
|
||||
* A BluetoothAdapter which is used to interact with local BT device.
|
||||
* @param aDeviceAddress
|
||||
* The string of remote Bluetooth address with format xx:xx:xx:xx:xx:xx.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function unpair(aAdapter, aDeviceAddress) {
|
||||
let request = aAdapter.unpair(aDeviceAddress);
|
||||
|
||||
return wrapDomRequestAsPromise(request)
|
||||
.then(function resolve() {
|
||||
log(" Unpair - Success");
|
||||
}, function reject(aEvent) {
|
||||
ok(false, "Unpair - Fail");
|
||||
throw aEvent.target.error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start pairing a remote device and wait for "pairedstatuschanged" event.
|
||||
*
|
||||
* Start pairing a remote device with the device's adapter and wait for
|
||||
* "pairedstatuschanged" event.
|
||||
*
|
||||
* Fulfill params: an array of promise results contains the fulfilled params of
|
||||
* 'waitForAdapterEvent' and 'pair'.
|
||||
*
|
||||
* @param aAdapter
|
||||
* A BluetoothAdapter which is used to interact with local BT device.
|
||||
* @param aDeviceAddress
|
||||
* The string of remote Bluetooth address with format xx:xx:xx:xx:xx:xx.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function pairDeviceAndWait(aAdapter, aDeviceAddress) {
|
||||
let promises = [];
|
||||
promises.push(waitForAdapterEvent(aAdapter, "pairedstatuschanged"));
|
||||
promises.push(pair(aAdapter, aDeviceAddress));
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get paried Bluetooth devices.
|
||||
*
|
||||
* The getPairedDevices method is used to retrieve the full list of all devices
|
||||
* paired with the device's adapter.
|
||||
*
|
||||
* Fulfill params: a shallow copy of the Array of paired BluetoothDevice
|
||||
* objects.
|
||||
* Reject params: a DOMError
|
||||
*
|
||||
* @param aAdapter
|
||||
* A BluetoothAdapter which is used to interact with local BT device.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getPairedDevices(aAdapter) {
|
||||
let request = aAdapter.getPairedDevices();
|
||||
|
||||
return wrapDomRequestAsPromise(request)
|
||||
.then(function resolve() {
|
||||
log(" getPairedDevices - Success");
|
||||
let pairedDevices = request.result.slice();
|
||||
return pairedDevices;
|
||||
}, function reject(aEvent) {
|
||||
ok(false, "getPairedDevices - Fail");
|
||||
throw aEvent.target.error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mozSettings value specified by @aKey.
|
||||
*
|
||||
@ -274,19 +460,16 @@ function stopDiscovery(aAdapter) {
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getSettings(aKey) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = navigator.mozSettings.createLock().get(aKey);
|
||||
request.addEventListener("success", function(aEvent) {
|
||||
ok(true, "getSettings(" + aKey + ")");
|
||||
deferred.resolve(aEvent.target.result[aKey]);
|
||||
});
|
||||
request.addEventListener("error", function() {
|
||||
ok(false, "getSettings(" + aKey + ")");
|
||||
deferred.reject();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
return wrapDomRequestAsPromise(request)
|
||||
.then(function resolve(aEvent) {
|
||||
ok(true, "getSettings(" + aKey + ")");
|
||||
return aEvent.target.result[aKey];
|
||||
}, function reject(aEvent) {
|
||||
ok(false, "getSettings(" + aKey + ")");
|
||||
throw aEvent.target.error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -303,19 +486,15 @@ function getSettings(aKey) {
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function setSettings(aSettings) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = navigator.mozSettings.createLock().set(aSettings);
|
||||
request.addEventListener("success", function() {
|
||||
ok(true, "setSettings(" + JSON.stringify(aSettings) + ")");
|
||||
deferred.resolve();
|
||||
});
|
||||
request.addEventListener("error", function() {
|
||||
ok(false, "setSettings(" + JSON.stringify(aSettings) + ")");
|
||||
deferred.reject();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
return wrapDomRequestAsPromise(request)
|
||||
.then(function resolve() {
|
||||
ok(true, "setSettings(" + JSON.stringify(aSettings) + ")");
|
||||
}, function reject(aEvent) {
|
||||
ok(false, "setSettings(" + JSON.stringify(aSettings) + ")");
|
||||
throw aEvent.target.error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -438,7 +617,7 @@ function waitForManagerEvent(aEventName) {
|
||||
* Fulfill params: the DOMEvent passed.
|
||||
*
|
||||
* @param aAdapter
|
||||
* The BluetoothAdapter you want to use.
|
||||
* A BluetoothAdapter which is used to interact with local BT device.
|
||||
* @param aEventName
|
||||
* The name of the EventHandler.
|
||||
*
|
||||
@ -463,7 +642,8 @@ function waitForAdapterEvent(aAdapter, aEventName) {
|
||||
*
|
||||
* Resolve if that named event occurs. Reject if we can't set settings.
|
||||
*
|
||||
* Fulfill params: the DOMEvent passed.
|
||||
* Fulfill params: an array of promise results contains the fulfill params of
|
||||
* 'waitForManagerEvent' and 'setBluetoothEnabled'.
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @return A deferred promise.
|
||||
|
@ -3,8 +3,10 @@ b2g = true
|
||||
browser = false
|
||||
qemu = true
|
||||
|
||||
[test_navigate_to_default_url.py]
|
||||
[test_dom_BluetoothManager_enabled.js]
|
||||
[test_dom_BluetoothManager_adapteradded.js]
|
||||
[test_dom_BluetoothAdapter_setters.js]
|
||||
[test_dom_BluetoothAdapter_getters.js]
|
||||
[test_dom_BluetoothAdapter_discovery.js]
|
||||
[test_dom_BluetoothAdapter_pair.js]
|
||||
|
@ -1,13 +1,11 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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/. */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Test Purpose:
|
||||
// To verify that discovery process of BluetoothAdapter is correct.
|
||||
// Use B2G emulator commands to add/remote remote devices to simulate
|
||||
// Use B2G emulator commands to add/remove remote devices to simulate
|
||||
// discovering behavior.
|
||||
//
|
||||
// Test Coverage:
|
||||
@ -24,15 +22,9 @@ MARIONETTE_HEAD_JS = 'head.js';
|
||||
startBluetoothTest(true, function testCaseMain(aAdapter) {
|
||||
log("Testing the discovery process of BluetoothAdapter ...");
|
||||
|
||||
// The properties of remote device.
|
||||
let theProperties = {
|
||||
"name": REMOTE_DEVICE_NAME,
|
||||
"discoverable": true
|
||||
};
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => removeEmulatorRemoteDevice(BDADDR_ALL))
|
||||
.then(() => addEmulatorRemoteDevice(/*theProperties*/ null))
|
||||
.then(() => addEmulatorRemoteDevice(null))
|
||||
.then(function(aRemoteAddress) {
|
||||
let promises = [];
|
||||
promises.push(waitForAdapterEvent(aAdapter, "devicefound"));
|
||||
|
@ -1,6 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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/. */
|
||||
|
||||
|
@ -0,0 +1,66 @@
|
||||
/* 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/. */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Test Purpose:
|
||||
// To verify that pairing process of BluetoothAdapter is correct.
|
||||
// Use B2G emulator commands to add/remove remote devices to simulate
|
||||
// discovering behavior. With current emulator implemation, the pair method
|
||||
// between adapter and remote device would be 'confirmation'.
|
||||
//
|
||||
// Test Coverage:
|
||||
// - BluetoothAdapter.startDiscovery()
|
||||
// - BluetoothAdapter.stopDiscovery()
|
||||
// - BluetoothAdapter.pair()
|
||||
// - BluetoothAdapter.unpair()
|
||||
// - BluetoothAdapter.onpairedstatuschanged()
|
||||
// - BluetoothAdapter.setPairingConfirmation()
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
function replyPairingReq(aAdapter, aPairingEvent) {
|
||||
switch (aPairingEvent.method) {
|
||||
case 'confirmation':
|
||||
log("The pairing passkey is " + aPairingEvent.passkey);
|
||||
aAdapter.setPairingConfirmation(aPairingEvent.address, true);
|
||||
break;
|
||||
case 'pincode':
|
||||
let pincode = BT_PAIRING_PINCODE;
|
||||
aAdapter.setPinCode(aPairingEvent.address, pincode);
|
||||
break;
|
||||
case 'passkey':
|
||||
let passkey = BT_PAIRING_PASSKEY;
|
||||
aAdapter.setPasskey(aPairingEvent.address, passkey);
|
||||
break;
|
||||
default:
|
||||
ok(false, "Unsupported pairing method. [" + aPairingEvent.method + "]");
|
||||
}
|
||||
}
|
||||
|
||||
startBluetoothTest(true, function testCaseMain(aAdapter) {
|
||||
log("Testing the pairing process of BluetoothAdapter ...");
|
||||
|
||||
// listens to the system message BT_PAIRING_REQ
|
||||
navigator.mozSetMessageHandler(BT_PAIRING_REQ,
|
||||
(evt) => replyPairingReq(aAdapter, evt));
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => removeEmulatorRemoteDevice(BDADDR_ALL))
|
||||
.then(() => addEmulatorRemoteDevice())
|
||||
.then((aRemoteAddress) =>
|
||||
startDiscoveryAndWaitDevicesFound(aAdapter, [aRemoteAddress]))
|
||||
.then((aRemoteAddresses) =>
|
||||
stopDiscovery(aAdapter).then(() => aRemoteAddresses))
|
||||
// 'aRemoteAddresses' is an arrary which contains addresses of discovered
|
||||
// remote devices.
|
||||
// Pairs with the first device in 'aRemoteAddresses' to test the functionality
|
||||
// of BluetoothAdapter.pair and BluetoothAdapter.onpairedstatuschanged.
|
||||
.then((aRemoteAddresses) => pairDeviceAndWait(aAdapter, aRemoteAddresses.pop()))
|
||||
.then(() => getPairedDevices(aAdapter))
|
||||
.then((aPairedDevices) => unpair(aAdapter, aPairedDevices.pop().address))
|
||||
.then(() => removeEmulatorRemoteDevice(BDADDR_ALL));
|
||||
});
|
@ -1,6 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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/. */
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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/. */
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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/. */
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
# 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/.
|
||||
|
||||
from marionette_test import MarionetteTestCase
|
||||
|
||||
class testNavigateToDefault(MarionetteTestCase):
|
||||
def test_navigate_to_default_url(self):
|
||||
try:
|
||||
self.marionette.navigate("app://system.gaiamobile.org/index.html")
|
||||
except:
|
||||
self.assertTrue(Flase, "Can not navigate to system app.")
|
@ -1,15 +0,0 @@
|
||||
[DEFAULT]
|
||||
; true if the test requires an emulator, otherwise false
|
||||
qemu = false
|
||||
|
||||
; true if the test is compatible with the browser, otherwise false
|
||||
browser = true
|
||||
|
||||
; true if the test is compatible with b2g, otherwise false
|
||||
b2g = true
|
||||
|
||||
; true if the test should be skipped
|
||||
skip = false
|
||||
|
||||
[test_touchcaret.py]
|
||||
b2g = false ; Bug 1020261
|
@ -1,339 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 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/.
|
||||
|
||||
import string
|
||||
|
||||
from by import By
|
||||
from marionette import Actions
|
||||
from marionette_test import MarionetteTestCase
|
||||
|
||||
|
||||
class TouchCaretTest(MarionetteTestCase):
|
||||
_input_selector = (By.ID, 'input')
|
||||
_textarea_selector = (By.ID, 'textarea')
|
||||
_contenteditable_selector = (By.ID, 'contenteditable')
|
||||
|
||||
def setUp(self):
|
||||
# Code to execute before a tests are run.
|
||||
MarionetteTestCase.setUp(self)
|
||||
self.actions = Actions(self.marionette)
|
||||
|
||||
def openTestHtml(self, enabled=True):
|
||||
'''Open html for testing and locate elements, and enable/disable touch
|
||||
caret.'''
|
||||
self.marionette.execute_script(
|
||||
'SpecialPowers.setBoolPref("touchcaret.enabled", %s);' %
|
||||
('true' if enabled else 'false'))
|
||||
|
||||
test_html = self.marionette.absolute_url('test_touchcaret.html')
|
||||
self.marionette.navigate(test_html)
|
||||
|
||||
self._input = self.marionette.find_element(*self._input_selector)
|
||||
self._textarea = self.marionette.find_element(*self._textarea_selector)
|
||||
self._contenteditable = self.marionette.find_element(*self._contenteditable_selector)
|
||||
|
||||
def is_input_or_textarea(self, element):
|
||||
'''Return True if element is either <input> or <textarea>'''
|
||||
return element.tag_name in ('input', 'textarea')
|
||||
|
||||
def get_js_selection_cmd(self, element):
|
||||
'''Return a command snippet to get selection object.
|
||||
|
||||
If the element is <input> or <textarea>, return the selection object
|
||||
associated with it. Otherwise, return the current selection object.
|
||||
|
||||
Note: "element" must be provided as the first argument to
|
||||
execute_script().
|
||||
|
||||
'''
|
||||
if self.is_input_or_textarea(element):
|
||||
# We must unwrap sel so that DOMRect could be returned to Python
|
||||
# side.
|
||||
return '''var sel = SpecialPowers.wrap(arguments[0]).editor.selection;
|
||||
sel = SpecialPowers.unwrap(sel);'''
|
||||
else:
|
||||
return '''var sel = window.getSelection();'''
|
||||
|
||||
def caret_rect(self, element):
|
||||
'''Return the caret's DOMRect object.
|
||||
|
||||
If the element is either <input> or <textarea>, return the caret's
|
||||
DOMRect within the element. Otherwise, return the DOMRect of the
|
||||
current selected caret.
|
||||
|
||||
'''
|
||||
cmd = self.get_js_selection_cmd(element) +\
|
||||
'''return sel.getRangeAt(0).getClientRects()[0];'''
|
||||
return self.marionette.execute_script(cmd, script_args=[element])
|
||||
|
||||
def caret_location(self, element):
|
||||
'''Return caret's center location by the number of characters offset
|
||||
within the given element.
|
||||
|
||||
Return (x, y) coordinates of the caret's center by the number of
|
||||
characters offset relative to the top left-hand corner of the given
|
||||
element.
|
||||
|
||||
'''
|
||||
rect = self.caret_rect(element)
|
||||
x = rect['left'] + rect['width'] / 2.0 - element.location['x']
|
||||
y = rect['top'] + rect['height'] / 2.0 - element.location['y']
|
||||
return x, y
|
||||
|
||||
def touch_caret_location(self, element):
|
||||
'''Return touch caret's location (based on current caret location).
|
||||
|
||||
Return (x, y) coordinates of the touch caret's tip relative to the top
|
||||
left-hand corner of the given element.
|
||||
|
||||
'''
|
||||
rect = self.caret_rect(element)
|
||||
x = rect['left'] - element.location['x']
|
||||
|
||||
# Touch caret's tip is below the bottom of the caret. Add 5px to y
|
||||
# should be sufficient to locate it.
|
||||
y = rect['bottom'] + 5 - element.location['y']
|
||||
|
||||
return x, y
|
||||
|
||||
def move_caret_by_offset(self, element, offset, backward=False):
|
||||
'''Move caret in the element by offset.'''
|
||||
cmd = self.get_js_selection_cmd(element) +\
|
||||
'''sel.modify("move", arguments[1], "character");'''
|
||||
direction = 'backward' if backward else 'forward'
|
||||
|
||||
for i in range(offset):
|
||||
self.marionette.execute_script(
|
||||
cmd, script_args=[element, direction])
|
||||
|
||||
def move_caret_to_front(self, element):
|
||||
if self.is_input_or_textarea(element):
|
||||
cmd = '''arguments[0].setSelectionRange(0, 0);'''
|
||||
else:
|
||||
cmd = '''var sel = window.getSelection();
|
||||
sel.collapse(arguments[0].firstChild, 0);'''
|
||||
|
||||
self.marionette.execute_script(cmd, script_args=[element])
|
||||
|
||||
def move_caret_to_end(self, element):
|
||||
if self.is_input_or_textarea(element):
|
||||
cmd = '''var len = arguments[0].value.length;
|
||||
arguments[0].setSelectionRange(len, len);'''
|
||||
else:
|
||||
cmd = '''var sel = window.getSelection();
|
||||
sel.collapse(arguments[0].lastChild, arguments[0].lastChild.length);'''
|
||||
|
||||
self.marionette.execute_script(cmd, script_args=[element])
|
||||
|
||||
def get_content(self, element):
|
||||
'''Return the content of the element.'''
|
||||
if self.is_input_or_textarea(element):
|
||||
return element.get_attribute('value')
|
||||
else:
|
||||
return element.text
|
||||
|
||||
def _test_move_caret_to_the_right_by_one_character(self, el, assertFunc):
|
||||
content_to_add = '!'
|
||||
target_content = self.get_content(el)
|
||||
target_content = target_content[:1] + content_to_add + target_content[1:]
|
||||
|
||||
# Get touch caret (x, y) at position 1 and 2.
|
||||
self.move_caret_to_front(el)
|
||||
caret0_x, caret0_y = self.caret_location(el)
|
||||
touch_caret0_x, touch_caret0_y = self.touch_caret_location(el)
|
||||
self.move_caret_by_offset(el, 1)
|
||||
touch_caret1_x, touch_caret1_y = self.touch_caret_location(el)
|
||||
|
||||
# Tap the front of the input to make touch caret appear.
|
||||
el.tap(caret0_x, caret0_y)
|
||||
|
||||
# Move touch caret
|
||||
self.actions.flick(el, touch_caret0_x, touch_caret0_y,
|
||||
touch_caret1_x, touch_caret1_y).perform()
|
||||
|
||||
el.send_keys(content_to_add)
|
||||
assertFunc(target_content, self.get_content(el))
|
||||
|
||||
def _test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self, el, assertFunc):
|
||||
content_to_add = '!'
|
||||
target_content = self.get_content(el) + content_to_add
|
||||
|
||||
# Tap the front of the input to make touch caret appear.
|
||||
self.move_caret_to_front(el)
|
||||
el.tap(*self.caret_location(el))
|
||||
|
||||
# Move touch caret to the bottom-right corner of the element.
|
||||
src_x, src_y = self.touch_caret_location(el)
|
||||
dest_x, dest_y = el.size['width'], el.size['height']
|
||||
self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()
|
||||
|
||||
el.send_keys(content_to_add)
|
||||
assertFunc(target_content, self.get_content(el))
|
||||
|
||||
def _test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self, el, assertFunc):
|
||||
content_to_add = '!'
|
||||
target_content = content_to_add + self.get_content(el)
|
||||
|
||||
# Tap to make touch caret appear. Note: it's strange that when the caret
|
||||
# is at the end, the rect of the caret in <textarea> cannot be obtained.
|
||||
# A bug perhaps.
|
||||
self.move_caret_to_end(el)
|
||||
self.move_caret_by_offset(el, 1, backward=True)
|
||||
el.tap(*self.caret_location(el))
|
||||
|
||||
# Move touch caret to the top-left corner of the input box.
|
||||
src_x, src_y = self.touch_caret_location(el)
|
||||
dest_x, dest_y = 0, 0
|
||||
self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()
|
||||
|
||||
el.send_keys(content_to_add)
|
||||
assertFunc(target_content, self.get_content(el))
|
||||
|
||||
def _test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(self, el, assertFunc):
|
||||
content_to_add = '!'
|
||||
non_target_content = content_to_add + self.get_content(el)
|
||||
|
||||
# Get touch caret timeout in millisecond, and convert it to second.
|
||||
timeout = self.marionette.execute_script(
|
||||
'return SpecialPowers.getIntPref("touchcaret.expiration.time");')
|
||||
timeout /= 1000.0
|
||||
|
||||
# Tap to make touch caret appear. Note: it's strange that when the caret
|
||||
# is at the end, the rect of the caret in <textarea> cannot be obtained.
|
||||
# A bug perhaps.
|
||||
self.move_caret_to_end(el)
|
||||
self.move_caret_by_offset(el, 1, backward=True)
|
||||
el.tap(*self.caret_location(el))
|
||||
|
||||
# Wait until touch caret disappears, then pretend to move it to the
|
||||
# top-left corner of the input box.
|
||||
src_x, src_y = self.touch_caret_location(el)
|
||||
dest_x, dest_y = 0, 0
|
||||
self.actions.wait(timeout).flick(el, src_x, src_y, dest_x, dest_y).perform()
|
||||
|
||||
el.send_keys(content_to_add)
|
||||
assertFunc(non_target_content, self.get_content(el))
|
||||
|
||||
def _test_scroll_by_dragging_touch_caret_to_bottom_right_corner(self, el, assertFunc):
|
||||
content_to_add = '!'
|
||||
target_content = string.ascii_letters + content_to_add
|
||||
|
||||
# Insert a long string to test horizontal scrolling.
|
||||
el.clear()
|
||||
el.send_keys(string.ascii_letters)
|
||||
|
||||
# Tap to make touch caret appear.
|
||||
el.tap()
|
||||
|
||||
# Move touch caret to 100px right to the bottom-right corner of the input
|
||||
# box so that it could scroll faster.
|
||||
src_x, src_y = self.touch_caret_location(el)
|
||||
dest_x, dest_y = el.size['width'] + 100, el.size['height']
|
||||
self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()
|
||||
|
||||
el.send_keys(content_to_add)
|
||||
assertFunc(target_content, self.get_content(el))
|
||||
|
||||
########################################################################
|
||||
# <input> test cases with touch caret enabled
|
||||
########################################################################
|
||||
def test_input_move_caret_to_the_right_by_one_character(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_move_caret_to_the_right_by_one_character(self._input, self.assertEqual)
|
||||
|
||||
def test_input_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self._input, self.assertEqual)
|
||||
|
||||
def test_input_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._input, self.assertEqual)
|
||||
|
||||
def test_input_touch_caret_timeout(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(self._input, self.assertNotEqual)
|
||||
|
||||
def test_input_scroll_by_dragging_touch_caret_to_bottom_right_corner(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_scroll_by_dragging_touch_caret_to_bottom_right_corner(self._input, self.assertEqual)
|
||||
|
||||
########################################################################
|
||||
# <input> test cases with touch caret disabled
|
||||
########################################################################
|
||||
def test_input_move_caret_to_the_right_by_one_character_disabled(self):
|
||||
self.openTestHtml(enabled=False)
|
||||
self._test_move_caret_to_the_right_by_one_character(self._input, self.assertNotEqual)
|
||||
|
||||
def test_input_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner_disabled(self):
|
||||
self.openTestHtml(enabled=False)
|
||||
self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._input, self.assertNotEqual)
|
||||
|
||||
########################################################################
|
||||
# <textarea> test cases with touch caret enabled
|
||||
########################################################################
|
||||
def test_textarea_move_caret_to_the_right_by_one_character(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_move_caret_to_the_right_by_one_character(self._textarea, self.assertEqual)
|
||||
|
||||
def test_textarea_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self._textarea, self.assertEqual)
|
||||
|
||||
def test_textarea_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._textarea, self.assertEqual)
|
||||
|
||||
def test_textarea_touch_caret_timeout(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(self._textarea, self.assertNotEqual)
|
||||
|
||||
def test_textarea_scroll_by_dragging_touch_caret_to_bottom_right_corner(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_scroll_by_dragging_touch_caret_to_bottom_right_corner(self._textarea, self.assertEqual)
|
||||
|
||||
########################################################################
|
||||
# <textarea> test cases with touch caret disabled
|
||||
########################################################################
|
||||
def test_textarea_move_caret_to_the_right_by_one_character_disabled(self):
|
||||
self.openTestHtml(enabled=False)
|
||||
self._test_move_caret_to_the_right_by_one_character(self._textarea, self.assertNotEqual)
|
||||
|
||||
def test_textarea_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner_disabled(self):
|
||||
self.openTestHtml(enabled=False)
|
||||
self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._textarea, self.assertNotEqual)
|
||||
|
||||
########################################################################
|
||||
# <div> contenteditable test cases with touch caret enabled
|
||||
########################################################################
|
||||
def test_contenteditable_move_caret_to_the_right_by_one_character(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_move_caret_to_the_right_by_one_character(self._contenteditable, self.assertEqual)
|
||||
|
||||
def test_contenteditable_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_move_caret_to_end_by_dragging_touch_caret_to_bottom_right_corner(self._contenteditable, self.assertEqual)
|
||||
|
||||
def test_contenteditable_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._contenteditable, self.assertEqual)
|
||||
|
||||
def test_contenteditable_touch_caret_timeout(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_touch_caret_timeout_by_dragging_it_to_top_left_corner_after_timout(self._contenteditable, self.assertNotEqual)
|
||||
|
||||
def test_contenteditable_scroll_by_dragging_touch_caret_to_bottom_right_corner(self):
|
||||
self.openTestHtml(enabled=True)
|
||||
self._test_scroll_by_dragging_touch_caret_to_bottom_right_corner(self._contenteditable, self.assertEqual)
|
||||
|
||||
########################################################################
|
||||
# <div> contenteditable test cases with touch caret disabled
|
||||
########################################################################
|
||||
def test_contenteditable_move_caret_to_the_right_by_one_character_disabled(self):
|
||||
self.openTestHtml(enabled=False)
|
||||
self._test_move_caret_to_the_right_by_one_character(self._contenteditable, self.assertNotEqual)
|
||||
|
||||
def test_contenteditable_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner_disabled(self):
|
||||
self.openTestHtml(enabled=False)
|
||||
self._test_move_caret_to_front_by_dragging_touch_caret_to_top_left_corner(self._contenteditable, self.assertNotEqual)
|
@ -525,16 +525,17 @@ public class BrowserHealthRecorder implements HealthRecorder, GeckoEventListener
|
||||
|
||||
// Because the distribution lookup can take some time, do it at the end of
|
||||
// our background startup work, along with the Gecko snapshot fetch.
|
||||
final GeckoEventListener self = this;
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
final Distribution distribution = Distribution.getInstance(context);
|
||||
distribution.addOnDistributionReadyCallback(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final DistributionDescriptor desc = new Distribution(context).getDescriptor();
|
||||
Log.d(LOG_TAG, "Running post-distribution task: health recorder.");
|
||||
final DistributionDescriptor desc = distribution.getDescriptor();
|
||||
if (desc != null && desc.valid) {
|
||||
profileCache.setDistributionString(desc.id, desc.version);
|
||||
}
|
||||
Log.d(LOG_TAG, "Requesting all add-ons and FHR prefs from Gecko.");
|
||||
dispatcher.registerGeckoThreadListener(self, EVENT_SNAPSHOT);
|
||||
dispatcher.registerGeckoThreadListener(BrowserHealthRecorder.this, EVENT_SNAPSHOT);
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("HealthReport:RequestSnapshot", null));
|
||||
}
|
||||
});
|
||||
|
@ -93,10 +93,15 @@
|
||||
|
||||
<color name="panel_image_item_background">#D1D9E1</color>
|
||||
|
||||
<!-- Swipe to refresh colors -->
|
||||
<!-- Swipe to refresh colors for dynamic panel -->
|
||||
<color name="swipe_refresh_orange">#FFFFC26C</color>
|
||||
<color name="swipe_refresh_white">#FFFFFFFF</color>
|
||||
<color name="swipe_refresh_orange_dark">#FF9500</color>
|
||||
|
||||
<!-- Swipe to refresh colors for remote tabs -->
|
||||
<color name="swipe_refresh_orange1">#EE6700</color>
|
||||
<color name="swipe_refresh_orange2">#FF9400</color>
|
||||
<color name="swipe_refresh_orange3">#F57900</color>
|
||||
<color name="swipe_refresh_orange4">#FFB44C</color>
|
||||
|
||||
<!-- Remote tabs setup -->
|
||||
<color name="remote_tabs_setup_button_background">#E66000</color>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user