Merge m-c to inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-06-06 17:34:13 -04:00
commit 7e3133c429
109 changed files with 1663 additions and 1102 deletions

View File

@ -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"
}
}

View File

@ -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
}

View File

@ -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;
}
});

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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 },

View File

@ -5,7 +5,6 @@
import sys
import os
import optparse
import webbrowser
import time
from copy import copy

View File

@ -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",

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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/. */

View File

@ -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";

View File

@ -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";

View File

@ -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;

View File

@ -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";

View File

@ -540,3 +540,6 @@ exports.testFork = function (assert) {
after(exports, cleanUp);
require("test").run(exports);
// Test disabled because of bug 979675
module.exports = {};

View File

@ -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);

View File

@ -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" };

View File

@ -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"/>

View File

@ -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>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "e32dee285e41ff8be7779ab4adb3db81a5b36570",
"revision": "99abcedfe288d6d29352b2add96b5ace90543985",
"repo_path": "/integration/gaia-central"
}

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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 -->

View File

@ -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"/>

View File

@ -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);

View File

@ -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>

View File

@ -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"

View File

@ -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)

View File

@ -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/");

View File

@ -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);"

View File

@ -444,7 +444,6 @@ ThreadState.prototype = {
this.activeThread.addListener("resumed", this._update);
this.activeThread.pauseOnExceptions(Prefs.pauseOnExceptions,
Prefs.ignoreCaughtExceptions);
this.handleTabNavigation();
},
/**

View File

@ -28,11 +28,9 @@ DIRS += [
'tilt',
'webaudioeditor',
'webconsole',
'webide',
]
if CONFIG['MOZ_DEVTOOLS_WEBIDE']:
DIRS += ['webide']
EXTRA_COMPONENTS += [
'devtools-clhandler.js',
'devtools-clhandler.manifest',

View File

@ -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);

View File

@ -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"?>

View File

@ -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;
}
});

View File

@ -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())];
},
/**

View File

@ -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();
},

View File

@ -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);

View File

@ -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]

View File

@ -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");
}

View File

@ -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.");

View File

@ -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");
});

View File

@ -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.");

View File

@ -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() {

View File

@ -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);
}
}

View File

@ -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]

View File

@ -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++;

View File

@ -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");
}

View File

@ -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()

View File

@ -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();

View File

@ -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) {

View File

@ -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);

View File

@ -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>

View File

@ -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 */

View File

@ -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"
}

View File

@ -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;
}
}

View File

@ -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.
*

View File

@ -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]

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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(() => {

View File

@ -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;

View File

@ -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;

View File

@ -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();
});

View File

@ -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);

View File

@ -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

View File

@ -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">

View File

@ -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"

View File

@ -8,7 +8,6 @@ all = browser/locales/all-locales
[compare]
dirs = browser
browser/metro
extensions/reporter
other-licenses/branding/firefox
browser/branding/official

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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 =========================================================

View File

@ -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;
}

View File

@ -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.

View File

@ -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]

View File

@ -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"));

View File

@ -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/. */

View File

@ -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));
});

View File

@ -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/. */

View File

@ -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/. */

View File

@ -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/. */

View File

@ -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.")

View File

@ -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

View File

@ -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)

View File

@ -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));
}
});

View File

@ -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