Merge latest green b2g-inbound changeset and mozilla-central

This commit is contained in:
Ed Morley 2014-01-29 10:33:43 +00:00
Родитель 0b1757d3a5 2a9e32f301
Коммит 65824f4564
114 изменённых файлов: 1979 добавлений и 930 удалений

Просмотреть файл

@ -108,7 +108,7 @@ AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) :
return;
roles::Role parentRole = parent->Role();
if (IsConceptualParent(aRole, parentRole))
if (ShouldReportRelations(aRole, parentRole))
mParent = parent;
// ARIA tree and list can be arranged by using ARIA groups to organize levels.
@ -171,9 +171,9 @@ AccGroupInfo::FirstItemOf(Accessible* aContainer)
}
}
// Otherwise it can be a direct child.
// Otherwise, it can be a direct child if the container is a list or tree.
item = aContainer->FirstChild();
if (IsConceptualParent(BaseRole(item->Role()), containerRole))
if (ShouldReportRelations(item->Role(), containerRole))
return item;
return nullptr;
@ -201,29 +201,21 @@ AccGroupInfo::NextItemTo(Accessible* aItem)
}
}
NS_NOTREACHED("Item in the midle of the group but there's no next item!");
NS_NOTREACHED("Item in the middle of the group but there's no next item!");
return nullptr;
}
bool
AccGroupInfo::IsConceptualParent(role aRole, role aParentRole)
AccGroupInfo::ShouldReportRelations(role aRole, role aParentRole)
{
// We only want to report hierarchy-based node relations for items in tree or
// list form. ARIA level/owns relations are always reported.
if (aParentRole == roles::OUTLINE && aRole == roles::OUTLINEITEM)
return true;
if ((aParentRole == roles::TABLE || aParentRole == roles::TREE_TABLE) &&
aRole == roles::ROW)
if (aParentRole == roles::TREE_TABLE && aRole == roles::ROW)
return true;
if (aParentRole == roles::LIST && aRole == roles::LISTITEM)
return true;
if (aParentRole == roles::COMBOBOX_LIST && aRole == roles::COMBOBOX_OPTION)
return true;
if (aParentRole == roles::LISTBOX && aRole == roles::OPTION)
return true;
if (aParentRole == roles::PAGETABLIST && aRole == roles::PAGETAB)
return true;
if ((aParentRole == roles::POPUP_MENU || aParentRole == roles::MENUPOPUP) &&
aRole == roles::MENUITEM)
return true;
return false;
}

Просмотреть файл

@ -91,10 +91,10 @@ private:
}
/**
* Return true if the given parent role is conceptual parent of the given
* role.
* Return true if the given parent and child roles should have their node
* relations reported.
*/
static bool IsConceptualParent(a11y::role aRole, a11y::role aParentRole);
static bool ShouldReportRelations(a11y::role aRole, a11y::role aParentRole);
uint32_t mPosInSet;
uint32_t mSetSize;

Просмотреть файл

@ -96,6 +96,61 @@ function testRelation(aIdentifier, aRelType, aRelatedIdentifiers)
}
}
/**
* Test that the given accessible relations don't exist.
*
* @param aIdentifier [in] identifier to get an accessible, may be ID
* attribute or DOM element or accessible object
* @param aRelType [in] relation type (see constants above)
* @param aUnrelatedIdentifiers [in] identifier or array of identifiers of
* accessibles that shouldn't exist for this
* relation.
*/
function testAbsentRelation(aIdentifier, aRelType, aUnrelatedIdentifiers)
{
var relation = getRelationByType(aIdentifier, aRelType);
var relDescr = getRelationErrorMsg(aIdentifier, aRelType);
var relDescrStart = getRelationErrorMsg(aIdentifier, aRelType, true);
if (!aUnrelatedIdentifiers) {
ok(false, "No identifiers given for unrelated accessibles.");
return;
}
if (!relation || !relation.targetsCount) {
ok(true, "No relations exist.");
return;
}
var relatedIds = (aUnrelatedIdentifiers instanceof Array) ?
aUnrelatedIdentifiers : [aUnrelatedIdentifiers];
var targets = [];
for (var idx = 0; idx < relatedIds.length; idx++)
targets.push(getAccessible(relatedIds[idx]));
if (targets.length != relatedIds.length)
return;
var actualTargets = relation.getTargets();
// Any found targets that match given accessibles should be called out.
for (var idx = 0; idx < targets.length; idx++) {
var notFound = true;
var enumerate = actualTargets.enumerate();
while (enumerate.hasMoreElements()) {
var relatedAcc = enumerate.getNext().QueryInterface(nsIAccessible);
if (targets[idx] == relatedAcc) {
notFound = false;
break;
}
}
ok(notFound, prettyName(relatedIds[idx]) + " is a target of " + relDescr);
}
}
/**
* Return related accessible for the given relation type.
*

Просмотреть файл

@ -84,6 +84,18 @@
testRelation("tree2_ti1a", RELATION_NODE_CHILD_OF, "tree2_ti1");
testRelation("tree2_ti1b", RELATION_NODE_CHILD_OF, "tree2_ti1");
// 'node child of' relation for row role in grid.
// Relation for row associated using aria-owns should exist.
testRelation("simplegrid-ownrow", RELATION_NODE_CHILD_OF, "simplegrid");
// Relation for row associated using aria-level should exist.
testRelation("simplegrid-row3", RELATION_NODE_CHILD_OF,
"simplegrid-row2");
// Relations for hierarchical children elements shouldn't exist.
testAbsentRelation("simplegrid-row1", RELATION_NODE_CHILD_OF,
"simplegrid");
testAbsentRelation("simplegrid-row2", RELATION_NODE_CHILD_OF,
"simplegrid");
// 'node child of' relation for row role of treegrid
testRelation("treegridrow1", RELATION_NODE_CHILD_OF, "treegrid");
testRelation("treegridrow2", RELATION_NODE_CHILD_OF, "treegrid");
@ -118,6 +130,14 @@
testRelation("treegrid", RELATION_NODE_PARENT_OF,
["treegridrow1", "treegridrow2"]);
// 'node parent of' relation on ARIA grid.
// Should only have relation to child added through aria-owns.
testRelation("simplegrid", RELATION_NODE_PARENT_OF, "simplegrid-ownrow");
// 'node parent of' relation on ARIA grid's row.
// Should only have relation to child through aria-level.
testRelation("simplegrid-row2", RELATION_NODE_PARENT_OF,
"simplegrid-row3");
// 'node parent of' relation on ARIA list structured by groups
testRelation("list", RELATION_NODE_PARENT_OF,
"listitem1");
@ -290,6 +310,22 @@
</div>
</div>
<div aria-owns="simplegrid-ownrow" role="grid" id="simplegrid">
<div role="row" id="simplegrid-row1" aria-level="1">
<div role="gridcell">cell 1,1</div>
<div role="gridcell">cell 1,2</div>
</div>
<div role="row" id="simplegrid-row2" aria-level="1">
<div role="gridcell">cell 2,1</div>
<div role="gridcell">cell 2,2</div>
</div>
<div role="row" id="simplegrid-row3" aria-level="2">
<div role="gridcell">cell 3,1</div>
<div role="gridcell">cell 3,2</div>
</div>
</div>
<div role="row" id="simplegrid-ownrow"></div>
<ul role="tree" id="tree2">
<li role="treeitem" id="tree2_ti1">Item 1
<ul role="group">

Просмотреть файл

@ -4,3 +4,4 @@
# 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/.
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']

11
addon-sdk/test/Math.jsm Normal file
Просмотреть файл

@ -0,0 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["Math"];
this.Math = {
square: function (x) { return x * x; }
};

Просмотреть файл

@ -0,0 +1,14 @@
[DEFAULT]
support-files =
head.js
Math.jsm
math.js
data.json
invalid.json
[browser_sdk_loader_sdk_modules.js]
[browser_sdk_loader_sdk_gui_modules.js]
[browser_sdk_loader_jsm_modules.js]
[browser_sdk_loader_js_modules.js]
[browser_sdk_loader_json.js]
[browser_sdk_loader_chrome.js]
[browser_sdk_loader_chrome_in_sdk.js]

Просмотреть файл

@ -0,0 +1,24 @@
function test () {
let loader = makeLoader();
let module = Module("./main", gTestPath);
let require = Require(loader, module);
const { Ci, Cc, Cu, components } = require("chrome");
let { generateUUID } = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator);
ok(isUUID(generateUUID()), "chrome.Cc and chrome.Ci works");
let { ID: parseUUID } = components;
let uuidString = "00001111-2222-3333-4444-555566667777";
let parsed = parseUUID(uuidString);
is(parsed, "{" + uuidString + "}", "chrome.components works");
const { defer } = Cu.import("resource://gre/modules/Promise.jsm").Promise;
let { promise, resolve } = defer();
resolve(5);
promise.then(val => {
is(val, 5, "chrome.Cu works");
finish();
});
}

Просмотреть файл

@ -0,0 +1,19 @@
function test () {
let loader = makeLoader();
let module = Module("./main", gTestPath);
let require = Require(loader, module);
// sdk/util/uuid uses Cc, Ci, components
const { uuid } = require("sdk/util/uuid");
ok(isUUID(uuid()), "chrome.Cc and chrome.Ci works in SDK includes");
let uuidString = '00001111-2222-3333-4444-555566667777';
let parsed = uuid(uuidString);
is(parsed, '{' + uuidString + '}', "chrome.components works in SDK includes");
// sdk/base64 uses Cu
const { encode } = require("sdk/base64");
is(encode("hello"), "aGVsbG8=", "chrome.Cu works in SDK includes");
finish();
}

Просмотреть файл

@ -0,0 +1,33 @@
function test () {
let loader = makeLoader();
let module = Module("./main", gTestPath);
let require = Require(loader, module);
try {
let Model = require("./cant-find-me");
ok(false, "requiring a JS module that doesn't exist should throw");
}
catch (e) {
ok(e, "requiring a JS module that doesn't exist should throw");
}
/*
* Relative resource:// URI of JS
*/
let { square } = require("./math");
is(square(5), 25, "loads relative URI of JS");
/*
* Absolute resource:// URI of JS
*/
let { has } = require("resource://gre/modules/commonjs/sdk/util/array");
let testArray = ['rock', 'paper', 'scissors'];
ok(has(testArray, 'rock'), "loads absolute resource:// URI of JS");
ok(!has(testArray, 'dragon'), "loads absolute resource:// URI of JS");
finish();
}

Просмотреть файл

@ -0,0 +1,31 @@
function test () {
let loader = makeLoader();
let module = Module("./main", gTestPath);
let require = Require(loader, module);
try {
let Model = require("resource://gre/modules/BlinkTag.jsm");
ok(false, "requiring a JS module that doesn't exist should throw");
}
catch (e) {
ok(e, "requiring a JS module that doesn't exist should throw");
}
/*
* Relative resource:// URI of JSM
*/
let { square } = require("./Math.jsm").Math;
is(square(5), 25, "loads relative URI of JSM");
/*
* Absolute resource:// URI of JSM
*/
let { defer } = require("resource://gre/modules/Promise.jsm").Promise;
let { resolve, promise } = defer();
resolve(5);
promise.then(val => {
is(val, 5, "loads absolute resource:// URI of JSM");
}).then(finish);
}

Просмотреть файл

@ -0,0 +1,23 @@
function test () {
let loader = makeLoader();
let module = Module("./main", gTestPath);
let require = Require(loader, module);
/*
* Relative resource:// URI of json
*/
let data = require("./data.json");
is(data.title, "jetpack mochitests", "loads relative JSON");
is(data.dependencies.underscore, "1.0.0", "loads relative JSON");
try {
let data = require("./invalid.json");
ok(false, "parsing an invalid JSON should throw");
}
catch (e) {
ok(e, "parsing an invalid JSON should throw");
}
finish();
}

Просмотреть файл

@ -0,0 +1,18 @@
function test () {
// Load `constructor` as global since tabs uses `traits`
// that use this module
let loader = makeLoader({ globals: constructor });
let module = Module("./main", "scratchpad://");
let require = Require(loader, module);
let tabs = require("sdk/tabs");
tabs.open({
url: "about:blank",
onReady: function (tab) {
is(tab.url, "about:blank", "correct uri for tab");
is(tabs.activeTab, tab, "correctly active tab");
tab.close(finish);
}
});
}

Просмотреть файл

@ -0,0 +1,22 @@
function test () {
let loader = makeLoader();
let module = Module("./main", "scratchpad://");
let require = Require(loader, module);
let { has } = require("sdk/util/array");
let { extend } = require("sdk/util/object");
let testArray = [1, 'hello', 2, 'hi'];
ok(has(testArray, 1), 'loader loading simple array utils');
ok(has(testArray, 'hello'), 'loader loading simple array utils');
ok(!has(testArray, 4), 'loader loading simple array utils');
let testObj1 = { strings: 6, prop: [] };
let testObj2 = { name: 'Tosin Abasi', strings: 8 };
let extended = extend(testObj1, testObj2);
is(extended.name, 'Tosin Abasi', 'loader loading simple object utils');
is(extended.strings, 8, 'loader loading simple object utils');
is(extended.prop, testObj1.prop, 'loader loading simple object utils');
finish();
}

6
addon-sdk/test/data.json Normal file
Просмотреть файл

@ -0,0 +1,6 @@
{
"title": "jetpack mochitests",
"dependencies": {
"underscore": "1.0.0"
}
}

79
addon-sdk/test/head.js Normal file
Просмотреть файл

@ -0,0 +1,79 @@
/* 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/. */
const { utils: Cu } = Components;
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
const LoaderModule = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {}).Loader;
const { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
let {
Loader, main, Module, Require, unload
} = LoaderModule;
let CURRENT_DIR = gTestPath.replace(/\/[^\/]*\.js$/,'/');
let loaders = [];
// All tests are asynchronous.
waitForExplicitFinish();
let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
Services.prefs.setBoolPref("devtools.debugger.log", true);
registerCleanupFunction(() => {
info("finish() was called, cleaning up...");
loaders.forEach(unload);
Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
});
function makePaths (root) {
return {
'./': CURRENT_DIR,
'': 'resource://gre/modules/commonjs/'
};
}
function makeLoader (options) {
let { paths, globals } = options || {};
// We have to have `console` as a global, otherwise
// many SDK modules will fail
// bug 961252
let globalDefaults = {
console: console
};
let loader = Loader({
paths: paths || makePaths(),
globals: extend({}, globalDefaults, globals) || null,
modules: {
// Needed because sdk/ modules reference utilities in
// `toolkit/loader`, until Bug 961194 is completed
'toolkit/loader': LoaderModule
},
// We need rootURI due to `sdk/self` (or are using native loader)
// which overloads with pseudo modules
// bug 961245
rootURI: CURRENT_DIR,
// We also need metadata dummy object
// bug 961245
metadata: {}
});
loaders.push(loader);
return loader;
}
function isUUID (string) {
return /^\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}$/.test(string);
}
function extend (...objs) {
if (objs.length === 0 || objs.length === 1)
return objs[0] || {};
for (let i = objs.length; i > 1; i--) {
for (var prop in objs[i - 1])
objs[0][prop] = objs[i - 1][prop];
}
return objs[0];
}

Просмотреть файл

@ -0,0 +1 @@
this isnt json

7
addon-sdk/test/math.js Normal file
Просмотреть файл

@ -0,0 +1,7 @@
/* 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";
exports.square = function square (x) { return x * x; }

Просмотреть файл

@ -21,6 +21,16 @@ let wrapper = {
iframe: null,
init: function () {
let weave = Cc["@mozilla.org/weave/service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject;
// Don't show about:accounts with FxA disabled.
if (!weave.fxAccountsEnabled) {
document.body.remove();
return;
}
let iframe = document.getElementById("remote");
this.iframe = iframe;
iframe.addEventListener("load", this);
@ -53,6 +63,11 @@ let wrapper = {
onLogin: function (accountData) {
log("Received: 'login'. Data:" + JSON.stringify(accountData));
if (accountData.customizeSync) {
Services.prefs.setBoolPref("services.sync.needsCustomization", true);
delete accountData.customizeSync;
}
fxAccounts.setSignedInUser(accountData).then(
() => {
this.injectData("message", { status: "login" });
@ -133,7 +148,7 @@ let wrapper = {
// Button onclick handlers
function handleOldSync() {
// we just want to navigate the current tab to the new location...
window.location = "https://services.mozilla.com/legacysync";
window.location = Services.urlFormatter.formatURLPref("app.support.baseURL") + "old-sync";
}
function getStarted() {

Просмотреть файл

@ -9,14 +9,38 @@ XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () {
let gFxAccounts = {
_initialized: false,
_originalLabel: null,
_inCustomizationMode: false,
get weave() {
delete this.weave;
return this.weave = Cc["@mozilla.org/weave/service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject;
},
get topics() {
delete this.topics;
return this.topics = [
FxAccountsCommon.ONVERIFIED_NOTIFICATION
FxAccountsCommon.ONLOGIN_NOTIFICATION,
FxAccountsCommon.ONVERIFIED_NOTIFICATION,
FxAccountsCommon.ONLOGOUT_NOTIFICATION
];
},
get button() {
delete this.button;
return this.button = document.getElementById("PanelUI-fxa-status");
},
get syncNeedsCustomization() {
try {
return Services.prefs.getBoolPref("services.sync.needsCustomization");
} catch (e) {
return false;
}
},
init: function () {
if (this._initialized) {
return;
@ -26,7 +50,15 @@ let gFxAccounts = {
Services.obs.addObserver(this, topic, false);
}
gNavToolbox.addEventListener("customizationstarting", this);
gNavToolbox.addEventListener("customizationending", this);
// Save the button's original label so that
// we can restore it if overridden later.
this._originalLabel = this.button.getAttribute("label");
this._initialized = true;
this.updateUI();
},
uninit: function () {
@ -42,11 +74,20 @@ let gFxAccounts = {
},
observe: function (subject, topic) {
this.showDoorhanger();
if (topic != FxAccountsCommon.ONVERIFIED_NOTIFICATION) {
this.updateUI();
} else if (!this.syncNeedsCustomization) {
this.showSyncStartedDoorhanger();
}
},
showDoorhanger: function () {
let panel = document.getElementById("sync-popup");
handleEvent: function (event) {
this._inCustomizationMode = event.type == "customizationstarting";
this.updateUI();
},
showDoorhanger: function (id) {
let panel = document.getElementById(id);
let anchor = document.getElementById("PanelUI-menu-button");
let iconAnchor =
@ -55,5 +96,62 @@ let gFxAccounts = {
panel.hidden = false;
panel.openPopup(iconAnchor || anchor, "bottomcenter topright");
},
showSyncStartedDoorhanger: function () {
this.showDoorhanger("sync-start-panel");
},
showSyncFailedDoorhanger: function () {
this.showDoorhanger("sync-error-panel");
},
updateUI: function () {
// Bail out if FxA is disabled.
if (!this.weave.fxAccountsEnabled) {
return;
}
// FxA is enabled, show the widget.
this.button.removeAttribute("hidden");
// Make sure the button is disabled in customization mode.
if (this._inCustomizationMode) {
this.button.setAttribute("disabled", "true");
} else {
this.button.removeAttribute("disabled");
}
// If the user is signed into their Firefox account and we are not
// currently in customization mode, show their email address.
fxAccounts.getSignedInUser().then(userData => {
if (userData && !this._inCustomizationMode) {
this.button.setAttribute("signedin", "true");
this.button.setAttribute("label", userData.email);
this.button.setAttribute("tooltiptext", userData.email);
} else {
this.button.removeAttribute("signedin");
this.button.setAttribute("label", this._originalLabel);
this.button.removeAttribute("tooltiptext");
}
});
},
toggle: function (event) {
if (event.originalTarget.hasAttribute("signedin")) {
this.openPreferences();
} else {
this.openSignInPage();
}
PanelUI.hide();
},
openPreferences: function () {
openPreferences("paneSync");
},
openSignInPage: function () {
switchToTabHavingURI("about:accounts", true);
}
};

Просмотреть файл

@ -383,13 +383,50 @@
</panel>
<!-- Sync Panel -->
<panel id="sync-popup" type="arrow" hidden="true" noautofocus="true"
level="top" onclick="this.hidePopup();">
<hbox id="sync-popup-outer">
<image id="sync-popup-icon"/>
<vbox id="sync-popup-inner">
<description id="sync-popup-desc-syncing" value="&syncPanel.descriptionSyncing;"/>
<description id="sync-popup-desc-prefs">&syncPanel.descriptionPrefs;</description>
<panel id="sync-start-panel" class="sync-panel" type="arrow" hidden="true"
noautofocus="true" level="top" onclick="this.hidePopup();">
<hbox class="sync-panel-outer">
<image class="sync-panel-icon"/>
<vbox class="sync-panel-inner">
<description id="sync-start-panel-title"
value="&syncStartPanel.title;"/>
<description id="sync-start-panel-subtitle">
#ifdef XP_UNIX
&syncStartPanel.subTitleUnix;
#else
&syncStartPanel.subTitle;
#endif
</description>
</vbox>
</hbox>
</panel>
<!-- Sync Error Panel -->
<panel id="sync-error-panel" class="sync-panel" type="arrow" hidden="true"
noautofocus="true" level="top" onclick="this.hidePopup();">
<hbox class="sync-panel-outer">
<image class="sync-panel-icon"/>
<vbox class="sync-panel-inner">
<description id="sync-error-panel-title"
value="&syncErrorPanel.title;"/>
<description id="sync-error-panel-subtitle"
value="&syncErrorPanel.subTitle;"/>
<hbox class="sync-panel-button-box">
<button class="sync-panel-button"
#ifdef XP_UNIX
label="&syncErrorPanel.prefButtonUnix.label;"
accesskey="&syncErrorPanel.prefButtonUnix.accesskey;"
#else
label="&syncErrorPanel.prefButton.label;"
accesskey="&syncErrorPanel.prefButton.accesskey;"
#endif
onclick="gFxAccounts.openPreferences();"/>
<spacer flex="1"/>
<button class="sync-panel-button"
label="&syncErrorPanel.signInButton.label;"
accesskey="&syncErrorPanel.signInButton.accesskey;"
onclick="gFxAccounts.openSignInPage();"/>
</hbox>
</vbox>
</hbox>
</panel>

Просмотреть файл

@ -0,0 +1,28 @@
/* 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/. */
:root {
font-size: 80%;
}
#sync-customize-pane {
-moz-padding-start: 74px;
background: top left url(chrome://browser/skin/sync-128.png) no-repeat;
background-size: 64px;
}
#sync-customize-title {
-moz-margin-start: 0;
padding-bottom: 0.5em;
font-weight: bold;
}
#sync-customize-subtitle {
font-size: 90%;
}
checkbox {
margin: 0;
padding: 0.5em 0 0;
}

Просмотреть файл

@ -0,0 +1,9 @@
/* 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";
addEventListener("dialogaccept", function () {
window.arguments[0].accepted = true;
});

Просмотреть файл

@ -0,0 +1,64 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/sync/customize.css" type="text/css"?>
<!DOCTYPE dialog [
<!ENTITY % syncCustomizeDTD SYSTEM "chrome://browser/locale/syncCustomize.dtd">
%syncCustomizeDTD;
]>
<dialog id="sync-customize"
windowtype="Sync:Customize"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
title="&syncCustomize.dialog.title;"
buttonlabelaccept="&syncCustomize.acceptButton.label;"
buttons="accept">
<prefpane id="sync-customize-pane">
<preferences>
<preference id="engine.bookmarks" name="services.sync.engine.bookmarks" type="bool"/>
<preference id="engine.history" name="services.sync.engine.history" type="bool"/>
<preference id="engine.tabs" name="services.sync.engine.tabs" type="bool"/>
<preference id="engine.passwords" name="services.sync.engine.passwords" type="bool"/>
<preference id="engine.addons" name="services.sync.engine.addons" type="bool"/>
<preference id="engine.prefs" name="services.sync.engine.prefs" type="bool"/>
</preferences>
<label id="sync-customize-title" value="&syncCustomize.title;"/>
<description id="sync-customize-subtitle"
#ifdef XP_UNIX
value="&syncCustomize.subTitleUnix;"
#else
value="&syncCustomize.subTitle;"
#endif
/>
<checkbox label="&engine.bookmarks.label;"
accesskey="&engine.bookmarks.accesskey;"
preference="engine.bookmarks"/>
<checkbox label="&engine.history.label;"
accesskey="&engine.history.accesskey;"
preference="engine.history"/>
<checkbox label="&engine.tabs.label;"
accesskey="&engine.tabs.accesskey;"
preference="engine.tabs"/>
<checkbox label="&engine.passwords.label;"
accesskey="&engine.passwords.accesskey;"
preference="engine.passwords"/>
<checkbox label="&engine.addons.label;"
accesskey="&engine.addons.accesskey;"
preference="engine.addons"/>
<checkbox label="&engine.prefs.label;"
accesskey="&engine.prefs.accesskey;"
preference="engine.prefs"/>
</prefpane>
<script type="application/javascript"
src="chrome://browser/content/sync/customize.js" />
</dialog>

Просмотреть файл

@ -14,6 +14,13 @@ let gSyncUtils = {
return this.bundle = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties");
},
get fxAccountsEnabled() {
let service = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
return service.fxAccountsEnabled;
},
// opens in a new window if we're in a modal prefwindow world, in a new tab otherwise
_openLink: function (url) {
let thisDocEl = document.documentElement,
@ -71,11 +78,13 @@ let gSyncUtils = {
},
openToS: function () {
this._openLink(Weave.Svc.Prefs.get("termsURL"));
let root = this.fxAccountsEnabled ? "fxa." : "";
this._openLink(Weave.Svc.Prefs.get(root + "termsURL"));
},
openPrivacyPolicy: function () {
this._openLink(Weave.Svc.Prefs.get("privacyURL"));
let root = this.fxAccountsEnabled ? "fxa." : "";
this._openLink(Weave.Svc.Prefs.get(root + "privacyURL"));
},
openFirstSyncProgressPage: function () {

Просмотреть файл

@ -9,6 +9,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
registerCleanupFunction(function() {
// Ensure we don't pollute prefs for next tests.
Services.prefs.clearUserPref("identity.fxaccounts.enabled");
Services.prefs.clearUserPref("identity.fxaccounts.remote.uri");
});
@ -18,6 +19,7 @@ let gTests = [
desc: "Test the remote commands",
setup: function ()
{
Services.prefs.setBoolPref("identity.fxaccounts.enabled", true);
Services.prefs.setCharPref("identity.fxaccounts.remote.uri",
"https://example.com/browser/browser/base/content/test/general/accounts_testRemoteCommands.html");
},

Просмотреть файл

@ -101,6 +101,9 @@ browser.jar:
content/browser/sync/utils.js (content/sync/utils.js)
content/browser/sync/progress.js (content/sync/progress.js)
content/browser/sync/progress.xhtml (content/sync/progress.xhtml)
* content/browser/sync/customize.xul (content/sync/customize.xul)
content/browser/sync/customize.js (content/sync/customize.js)
content/browser/sync/customize.css (content/sync/customize.css)
#endif
content/browser/safeMode.css (content/safeMode.css)
content/browser/safeMode.js (content/safeMode.js)

Просмотреть файл

@ -15,25 +15,29 @@
</vbox>
<footer id="PanelUI-footer">
<!-- The parentNode is used so that the footer is presented as the anchor
instead of just the button being the anchor. -->
<toolbarbutton id="PanelUI-customize" label="&appMenuCustomize.label;"
exitLabel="&appMenuCustomizeExit.label;"
oncommand="gCustomizeMode.toggle();"/>
<toolbarseparator/>
<toolbarbutton id="PanelUI-help" label="&helpMenu.label;"
tooltiptext="&helpMenu.label;"
oncommand="PanelUI.showHelpView(this.parentNode);"/>
<toolbarseparator/>
<toolbarbutton id="PanelUI-quit"
<toolbarbutton id="PanelUI-fxa-status" label="&fxaSignIn.label;"
oncommand="gFxAccounts.toggle(event);"
hidden="true"/>
<hbox id="PanelUI-footer-inner">
<toolbarbutton id="PanelUI-customize" label="&appMenuCustomize.label;"
exitLabel="&appMenuCustomizeExit.label;"
oncommand="gCustomizeMode.toggle();"/>
<toolbarseparator/>
<toolbarbutton id="PanelUI-help" label="&helpMenu.label;"
tooltiptext="&helpMenu.label;"
oncommand="PanelUI.showHelpView(this.parentNode);"/>
<toolbarseparator/>
<toolbarbutton id="PanelUI-quit"
#ifdef XP_WIN
label="&quitApplicationCmdWin.label;"
tooltiptext="&quitApplicationCmdWin.label;"
label="&quitApplicationCmdWin.label;"
tooltiptext="&quitApplicationCmdWin.label;"
#else
label="&quitApplicationCmd.label;"
tooltiptext="&quitApplicationCmd.label;"
label="&quitApplicationCmd.label;"
tooltiptext="&quitApplicationCmd.label;"
#endif
command="cmd_quitApplication"/>
command="cmd_quitApplication"/>
</hbox>
</footer>
</panelview>

Просмотреть файл

@ -113,9 +113,9 @@
<children />
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
<xul:label class="toolbarbutton-text" crop="right" flex="1"
xbl:inherits="value=label,accesskey,crop"/>
xbl:inherits="value=label,accesskey,crop,wrap"/>
<xul:label class="toolbarbutton-multiline-text" flex="1"
xbl:inherits="xbl:text=label,accesskey"/>
xbl:inherits="xbl:text=label,accesskey,wrap"/>
</content>
</binding>
</bindings>

Просмотреть файл

@ -8,6 +8,17 @@ Components.utils.import("resource://gre/modules/Services.jsm");
const PAGE_NO_ACCOUNT = 0;
const PAGE_HAS_ACCOUNT = 1;
const PAGE_NEEDS_UPDATE = 2;
const PAGE_PLEASE_WAIT = 3;
const FXA_PAGE_LOGGED_OUT = 4;
const FXA_PAGE_LOGGED_IN = 5;
// Indexes into the "login status" deck.
// We are in a successful verified state - everything should work!
const FXA_LOGIN_VERIFIED = 0;
// We have logged in to an unverified account.
const FXA_LOGIN_UNVERIFIED = 1;
// We are logged in locally, but the server rejected our credentials.
const FXA_LOGIN_FAILED = 2;
let gSyncPane = {
_stringBundle: null,
@ -44,6 +55,10 @@ let gSyncPane = {
return;
}
// it may take some time before we can determine what provider to use
// and the state of that provider, so show the "please wait" page.
this.page = PAGE_PLEASE_WAIT;
let onUnload = function () {
window.removeEventListener("unload", onUnload, false);
try {
@ -88,16 +103,59 @@ let gSyncPane = {
},
updateWeavePrefs: function () {
if (Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED ||
Weave.Svc.Prefs.get("firstSync", "") == "notReady") {
let service = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
// service.fxAccountsEnabled is false iff sync is already configured for
// the legacy provider.
if (service.fxAccountsEnabled) {
// determine the fxa status...
this.page = PAGE_PLEASE_WAIT;
Components.utils.import("resource://gre/modules/FxAccounts.jsm");
fxAccounts.getSignedInUser().then(data => {
if (!data) {
this.page = FXA_PAGE_LOGGED_OUT;
return;
}
this.page = FXA_PAGE_LOGGED_IN;
// We are logged in locally, but maybe we are in a state where the
// server rejected our credentials (eg, password changed on the server)
let fxaLoginStatus = document.getElementById("fxaLoginStatus");
let enginesListDisabled;
// Not Verfied implies login error state, so check that first.
if (!data.verified) {
fxaLoginStatus.selectedIndex = FXA_LOGIN_UNVERIFIED;
enginesListDisabled = true;
// So we think we are logged in, so login problems are next.
} else if (Weave.Status.login != Weave.LOGIN_SUCCEEDED) {
fxaLoginStatus.selectedIndex = FXA_LOGIN_FAILED;
enginesListDisabled = true;
// Else we must be golden!
} else {
fxaLoginStatus.selectedIndex = FXA_LOGIN_VERIFIED;
enginesListDisabled = false;
}
document.getElementById("fxaEmailAddress1").textContent = data.email;
document.getElementById("fxaEmailAddress2").textContent = data.email;
document.getElementById("fxaEmailAddress3").textContent = data.email;
document.getElementById("fxaSyncComputerName").value = Weave.Service.clientsEngine.localName;
let enginesList = document.getElementById("fxaSyncEnginesList")
enginesList.disabled = enginesListDisabled;
// *sigh* - disabling the <richlistbox> draws each item as if it is disabled,
// but doesn't disable the checkboxes.
for (let checkbox of enginesList.querySelectorAll("checkbox")) {
checkbox.disabled = enginesListDisabled;
}
});
// If fxAccountEnabled is false and we are in a "not configured" state,
// then fxAccounts is probably fully disabled rather than just unconfigured,
// so handle this case. This block can be removed once we remove support
// for fxAccounts being disabled.
} else if (Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED ||
Weave.Svc.Prefs.get("firstSync", "") == "notReady") {
this.page = PAGE_NO_ACCOUNT;
let service = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
// no concept of "pair" in an fxAccounts world.
if (service.fxAccountsEnabled) {
document.getElementById("pairDevice").hidden = true;
}
// else: sync was previously configured for the legacy provider, so we
// make the "old" panels available.
} else if (Weave.Status.login == Weave.LOGIN_FAILED_INVALID_PASSPHRASE ||
Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) {
this.needsUpdate();
@ -163,10 +221,7 @@ let gSyncPane = {
.wrappedJSObject;
if (service.fxAccountsEnabled) {
let win = Services.wm.getMostRecentWindow("navigator:browser");
win.switchToTabHavingURI("about:accounts", true);
// seeing as we are doing this in a tab we close the prefs dialog.
window.close();
this.openContentInBrowser("about:accounts");
} else {
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
if (win) {
@ -179,6 +234,56 @@ let gSyncPane = {
}
},
openContentInBrowser: function(url) {
let win = Services.wm.getMostRecentWindow("navigator:browser");
if (!win) {
// no window to use, so use _openLink to create a new one. We don't
// always use that as it prefers to open a new window rather than use
// an existing one.
gSyncUtils._openLink(url);
return;
}
win.switchToTabHavingURI(url, true);
// seeing as we are doing this in a tab we close the prefs dialog.
window.close();
},
reSignIn: function() {
this.openContentInBrowser("about:accounts");
},
manageFirefoxAccount: function() {
let url = Services.prefs.getCharPref("identity.fxaccounts.settings.uri");
this.openContentInBrowser(url);
},
verifyFirefoxAccount: function() {
Components.utils.import("resource://gre/modules/FxAccounts.jsm");
fxAccounts.resendVerificationEmail().then(() => {
fxAccounts.getSignedInUser().then(data => {
let sb = this._stringBundle;
let title = sb.GetStringFromName("firefoxAccountsVerificationSentTitle");
let heading = sb.formatStringFromName("firefoxAccountsVerificationSentHeading",
[data.email], 1);
let description = sb.GetStringFromName("firefoxAccountVerificationSentDescription");
Services.prompt.alert(window, title, heading + "\n\n" + description);
});
});
},
openOldSyncSupportPage: function() {
let url = Services.urlFormatter.formatURLPref('app.support.baseURL') + "old-sync"
this.openContentInBrowser(url);
},
unlinkFirefoxAccount: function(confirm) {
Components.utils.import('resource://gre/modules/FxAccounts.jsm');
fxAccounts.signOut().then(() => {
this.updateWeavePrefs();
});
},
openQuotaDialog: function () {
let win = Services.wm.getMostRecentWindow("Sync:ViewQuota");
if (win) {

Просмотреть файл

@ -38,6 +38,8 @@
<deck id="weavePrefsDeck">
<!-- These panels are for the "legacy" sync provider -->
<vbox id="noAccount" align="center">
<spacer flex="1"/>
<description id="syncDesc">
@ -175,6 +177,137 @@
onclick="gSyncPane.startOver(true); return false;"
value="&unlinkDevice.label;"/>
</vbox>
<!-- These panels are for the Firefox Accounts identity provider -->
<vbox id="fxaDeterminingStatus" align="center">
<spacer flex="1"/>
<p>&determiningStatus.label;</p>
<spacer flex="1"/>
</vbox>
<vbox id="noFxaAccount">
<description>&welcome.description;</description>
<label class="text-link"
onclick="gSyncPane.openContentInBrowser('about:accounts?signin=true'); return false;"
value="&welcome.startButton.label;"/>
<spacer flex="1"/>
<label class="text-link"
onclick="gSyncPane.openOldSyncSupportPage(); return false;"
value="&welcome.useOldSync.label;"/>
<spacer flex="10"/>
</vbox>
<vbox id="hasFxaAccount">
<groupbox id="fxaGroup">
<caption label="&syncBrand.fxa-singular.label;"/>
<deck id="fxaLoginStatus">
<!-- logged in and verified and all is good -->
<hbox flex="1">
<label id="fxaEmailAddress1"/>
<label class="text-link"
onclick="gSyncPane.manageFirefoxAccount();"
value="&manage.label;"/>
<spacer flex="1"/>
<vbox align="end">
<button onclick="gSyncPane.unlinkFirefoxAccount(true);"
label="&unlink.label;" />
</vbox>
</hbox>
<!-- logged in to an unverified account -->
<hbox flex="1">
<description>
&signedInUnverified.beforename.label;
<span id="fxaEmailAddress2"></span>
&signedInUnverified.aftername.label;
</description>
<spacer flex="1"/>
<vbox align="end">
<button onclick="gSyncPane.verifyFirefoxAccount();"
caption="&verify.label;"/>
<label class="text-link"
onclick="/* no warning as account can't have previously synced */ gSyncPane.unlinkFirefoxAccount(false);"
value="&forget.label;"/>
</vbox>
</hbox>
<!-- logged in locally but server rejected credentials -->
<hbox flex="1">
<description>
&signedInLoginFailure.beforename.label;
<span id="fxaEmailAddress3"></span>
&signedInLoginFailure.aftername.label;
</description>
<spacer flex="1"/>
<vbox align="end">
<button onclick="gSyncPane.reSignIn();"
label="&signIn.label;"/>
<label class="text-link"
onclick="gSyncPane.unlinkFirefoxAccount(true);"
value="&forget.label;"/>
</vbox>
</hbox>
</deck>
</groupbox>
<groupbox id="syncOptions">
<caption label="&syncBrand.fullName.label;"/>
<vbox>
<label value="&syncMy.label;" />
<richlistbox id="fxaSyncEnginesList"
orient="vertical"
onselect="if (this.selectedCount) this.clearSelection();">
<richlistitem>
<checkbox label="&engine.addons.label;"
accesskey="&engine.addons.accesskey;"
preference="engine.addons"/>
</richlistitem>
<richlistitem>
<checkbox label="&engine.bookmarks.label;"
accesskey="&engine.bookmarks.accesskey;"
preference="engine.bookmarks"/>
</richlistitem>
<richlistitem>
<checkbox label="&engine.passwords.label;"
accesskey="&engine.passwords.accesskey;"
preference="engine.passwords"/>
</richlistitem>
<richlistitem>
<checkbox label="&engine.prefs.label;"
accesskey="&engine.prefs.accesskey;"
preference="engine.prefs"/>
</richlistitem>
<richlistitem>
<checkbox label="&engine.history.label;"
accesskey="&engine.history.accesskey;"
preference="engine.history"/>
</richlistitem>
<richlistitem>
<checkbox label="&engine.tabs.label;"
accesskey="&engine.tabs.accesskey;"
preference="engine.tabs"/>
</richlistitem>
</richlistbox>
</vbox>
</groupbox>
<vbox>
<label value="&syncDeviceName.label;"
accesskey="&syncDeviceName.accesskey;"
control="syncComputerName"/>
<textbox id="fxaSyncComputerName"
onchange="gSyncUtils.changeName(this)"/>
</vbox>
<hbox id="tosPP" pack="center">
<label class="text-link"
onclick="event.stopPropagation();gSyncUtils.openToS();"
value="&prefs.tosLink.label;"/>
<label class="text-link"
onclick="event.stopPropagation();gSyncUtils.openPrivacyPolicy();"
value="&fxaPrivacyNotice.link.label;"/>
</hbox>
</vbox>
</deck>
</prefpane>
</overlay>

Просмотреть файл

@ -50,7 +50,6 @@ function SelectorSearch(aInspector, aContentDocument, aInputNode) {
let options = {
panelId: "inspector-searchbox-panel",
listBoxId: "searchbox-panel-listbox",
fixedWidth: true,
autoSelect: true,
position: "before_start",
direction: "ltr",

Просмотреть файл

@ -76,7 +76,6 @@ function MarkupView(aInspector, aFrame, aControllerWindow) {
// Creating the popup to be used to show CSS suggestions.
let options = {
fixedWidth: true,
autoSelect: true,
theme: "auto"
};

Просмотреть файл

@ -25,7 +25,6 @@ loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.j
* - theme {String} String related to the theme of the popup.
* - autoSelect {Boolean} Boolean to allow the first entry of the popup
* panel to be automatically selected when the popup shows.
* - fixedWidth {Boolean} Boolean to control dynamic width of the popup.
* - direction {String} The direction of the text in the panel. rtl or ltr
* - onSelect {String} The select event handler for the richlistbox
* - onClick {String} The click event handler for the richlistbox.
@ -35,7 +34,6 @@ function AutocompletePopup(aDocument, aOptions = {})
{
this._document = aDocument;
this.fixedWidth = aOptions.fixedWidth || false;
this.autoSelect = aOptions.autoSelect || false;
this.position = aOptions.position || "after_start";
this.direction = aOptions.direction || "ltr";
@ -75,7 +73,6 @@ function AutocompletePopup(aDocument, aOptions = {})
else {
this._document.documentElement.appendChild(this._panel);
}
this._list = null;
}
else {
this._list = this._panel.firstChild;
@ -137,14 +134,13 @@ AutocompletePopup.prototype = {
*/
openPopup: function AP_openPopup(aAnchor, aXOffset = 0, aYOffset = 0)
{
this.__maxLabelLength = -1;
this._updateSize();
this._panel.openPopup(aAnchor, this.position, aXOffset, aYOffset);
if (this.autoSelect) {
this.selectFirstItem();
}
if (!this.fixedWidth) {
this._updateSize();
}
},
/**
@ -241,9 +237,7 @@ AutocompletePopup.prototype = {
if (this.autoSelect) {
this.selectFirstItem();
}
if (!this.fixedWidth) {
this._updateSize();
}
this._updateSize();
}
},
@ -260,6 +254,28 @@ AutocompletePopup.prototype = {
else {
this.selectedIndex = 0;
}
this._list.ensureIndexIsVisible(this._list.selectedIndex);
},
__maxLabelLength: -1,
get _maxLabelLength() {
if (this.__maxLabelLength != -1) {
return this.__maxLabelLength;
}
let max = 0;
for (let i = 0; i < this._list.childNodes.length; i++) {
let item = this._list.childNodes[i]._autocompleteItem;
let str = item.label;
if (item.count) {
str += (item.count + "");
}
max = Math.max(str.length, max);
}
this.__maxLabelLength = max;
return this.__maxLabelLength;
},
/**
@ -272,24 +288,8 @@ AutocompletePopup.prototype = {
if (!this._panel) {
return;
}
// Flush the layout so that we get the latest height.
this._panel.boxObject.height;
let height = {};
this._list.scrollBoxObject.getScrolledSize({}, height);
// Change the width of the popup only if the scrollbar is visible.
if (height.value > this._panel.clientHeight) {
this._list.width = this._panel.clientWidth + this._scrollbarWidth;
}
// Height change is required, otherwise the panel is drawn at an offset
// the first time.
this._list.height = this._list.clientHeight;
// This brings the panel back at right position.
this._list.top = 0;
// Move the panel to -1,-1 to realign the popup with its anchor node when
// decreasing the panel height.
this._panel.moveTo(-1, -1);
// Changing panel height might make the selected item out of view, so
// bring it back to view.
this._list.style.width = (this._maxLabelLength + 3) +"ch";
this._list.ensureIndexIsVisible(this._list.selectedIndex);
},
@ -305,16 +305,17 @@ AutocompletePopup.prototype = {
this._list.removeChild(this._list.firstChild);
}
if (!this.fixedWidth) {
// Reset the panel and list dimensions. New dimensions are calculated when
// a new set of items is added to the autocomplete popup.
this._list.width = "";
this._list.height = "";
this._panel.width = "";
this._panel.height = "";
this._panel.top = "";
this._panel.left = "";
}
this.__maxLabelLength = -1;
// Reset the panel and list dimensions. New dimensions are calculated when
// a new set of items is added to the autocomplete popup.
this._list.width = "";
this._list.style.width = "";
this._list.height = "";
this._panel.width = "";
this._panel.height = "";
this._panel.top = "";
this._panel.left = "";
},
/**
@ -496,38 +497,6 @@ AutocompletePopup.prototype = {
this._list.focus();
},
/**
* Determine the scrollbar width in the current document.
*
* @private
*/
get _scrollbarWidth()
{
if (this.__scrollbarWidth !== null) {
return this.__scrollbarWidth;
}
let doc = this._document;
if (doc.defaultView.matchMedia("(-moz-overlay-scrollbars)").matches) {
// This is for the Mac's floating scrollbar, which actually is drawn over
// the content, thus taking no extra width.
return (this.__scrollbarWidth = 0);
}
let hbox = doc.createElementNS(XUL_NS, "hbox");
hbox.setAttribute("style", "height: 0%; overflow: hidden");
let scrollbar = doc.createElementNS(XUL_NS, "scrollbar");
scrollbar.setAttribute("orient", "vertical");
hbox.appendChild(scrollbar);
doc.documentElement.appendChild(hbox);
this.__scrollbarWidth = scrollbar.clientWidth;
doc.documentElement.removeChild(hbox);
return this.__scrollbarWidth;
},
/**
* Manages theme switching for the popup based on the devtools.theme pref.
*

Просмотреть файл

@ -1089,7 +1089,6 @@ function CssRuleView(aInspector, aDoc, aStore, aPageStyle)
this._prefObserver.on(PREF_ORIG_SOURCES, this._onSourcePrefChanged);
let options = {
fixedWidth: true,
autoSelect: true,
theme: "auto"
};

Просмотреть файл

@ -96,8 +96,19 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY showAllTabsCmd.label "Show All Tabs">
<!ENTITY showAllTabsCmd.accesskey "A">
<!ENTITY syncPanel.descriptionSyncing "&brandShortName; is now syncing.">
<!ENTITY syncPanel.descriptionPrefs "You can manage Sync from your browser's Preferences.">
<!ENTITY fxaSignIn.label "Sign in to &syncBrand.shortName.label;">
<!ENTITY syncStartPanel.title "&brandShortName; is now syncing.">
<!ENTITY syncStartPanel.subTitle "You can manage &syncBrand.shortName.label; in Options.">
<!ENTITY syncStartPanel.subTitleUnix "You can manage &syncBrand.shortName.label; in Preferences.">
<!ENTITY syncErrorPanel.title "Cannot connect to &syncBrand.shortName.label;">
<!ENTITY syncErrorPanel.subTitle "Please sign in to resume syncing.">
<!ENTITY syncErrorPanel.prefButton.label "Options">
<!ENTITY syncErrorPanel.prefButton.accesskey "O">
<!ENTITY syncErrorPanel.prefButtonUnix.label "Preferences">
<!ENTITY syncErrorPanel.prefButtonUnix.accesskey "P">
<!ENTITY syncErrorPanel.signInButton.label "Sign In">
<!ENTITY syncErrorPanel.signInButton.accesskey "S">
<!ENTITY fullScreenMinimize.tooltip "Minimize">
<!ENTITY fullScreenRestore.tooltip "Restore">

Просмотреть файл

@ -135,3 +135,9 @@ syncUnlinkConfirm.label=Unlink
featureEnableRequiresRestart=%S must restart to enable this feature.
featureDisableRequiresRestart=%S must restart to disable this feature.
shouldRestartTitle=Restart %S
###Preferences::Sync::Firefox Accounts
firefoxAccountsVerificationSentTitle=Verification Sent
# LOCALIZATION NOTE: %S = user's email address.
firefoxAccountsVerificationSentHeading=A verification link has been sent to %S
firefoxAccountVerificationSentDescription=Please check your email and click the verification link to begin syncing.

Просмотреть файл

@ -45,3 +45,23 @@
<!-- Footer stuff -->
<!ENTITY prefs.tosLink.label "Terms of Service">
<!ENTITY prefs.ppLink.label "Privacy Policy">
<!-- Firefox Accounts stuff -->
<!ENTITY fxaPrivacyNotice.link.label "Privacy Notice">
<!ENTITY determiningStatus.label "Determining your Firefox Account status…">
<!ENTITY signedInUnverified.beforename.label "">
<!ENTITY signedInUnverified.aftername.label "is not verified.">
<!ENTITY signedInLoginFailure.beforename.label "Please sign in to reconnect">
<!ENTITY signedInLoginFailure.aftername.label "">
<!ENTITY notSignedIn.label "You are not signed in.">
<!ENTITY signIn.label "Sign in">
<!ENTITY manage.label "Manage">
<!ENTITY unlink.label "Unlink This Browser…">
<!ENTITY verify.label "Verify Email">
<!ENTITY forget.label "Forget this Email">
<!ENTITY welcome.description "Access your tabs, bookmarks, passwords and more wherever you use &brandShortName;.">
<!ENTITY welcome.startButton.label "Sign in or Create an Account">
<!ENTITY welcome.useOldSync.label "Using an older version of Sync?">

Просмотреть файл

@ -4,3 +4,5 @@
<!ENTITY syncBrand.shortName.label "Sync">
<!ENTITY syncBrand.fullName.label "Firefox Sync">
<!ENTITY syncBrand.fxa-singular.label "Firefox Account">
<!ENTITY syncBrand.fxa-plural.label "Firefox Accounts">

Просмотреть файл

@ -0,0 +1,27 @@
<!-- 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/. -->
<!ENTITY syncCustomize.dialog.title "Sync Selection">
<!ENTITY syncCustomize.acceptButton.label "Start">
<!ENTITY syncCustomize.title "What would you like to sync?">
<!ENTITY syncCustomize.subTitle "You can manage this selection in Options.">
<!ENTITY syncCustomize.subTitleUnix "You can manage this selection in Preferences.">
<!--
These engine names are the same as in browser/preferences/sync.dtd except
for the last two that are marked as being specific to Desktop browsers.
-->
<!ENTITY engine.bookmarks.label "Bookmarks">
<!ENTITY engine.bookmarks.accesskey "m">
<!ENTITY engine.history.label "History">
<!ENTITY engine.history.accesskey "r">
<!ENTITY engine.tabs.label "Tabs">
<!ENTITY engine.tabs.accesskey "T">
<!ENTITY engine.passwords.label "Passwords">
<!ENTITY engine.passwords.accesskey "P">
<!ENTITY engine.addons.label "Desktop Add-ons">
<!ENTITY engine.addons.accesskey "A">
<!ENTITY engine.prefs.label "Desktop Preferences">
<!ENTITY engine.prefs.accesskey "S">

Просмотреть файл

@ -18,6 +18,7 @@
locale/browser/aboutSessionRestore.dtd (%chrome/browser/aboutSessionRestore.dtd)
#ifdef MOZ_SERVICES_SYNC
locale/browser/syncProgress.dtd (%chrome/browser/syncProgress.dtd)
locale/browser/syncCustomize.dtd (%chrome/browser/syncCustomize.dtd)
locale/browser/aboutSyncTabs.dtd (%chrome/browser/aboutSyncTabs.dtd)
#endif
locale/browser/browser.dtd (%chrome/browser/browser.dtd)

Просмотреть файл

@ -245,7 +245,7 @@ gTests.push({
run: function () {
let mozTab = yield addTab("about:mozilla");
// addTab will dismiss navbar, but lets check anyway.
yield hideNavBar();
ok(!ContextUI.navbarVisible, "navbar dismissed");
BrowserUI.doCommand("cmd_newTab");

Просмотреть файл

@ -0,0 +1,55 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var gSessionStore = Cc["@mozilla.org/browser/sessionstore;1"]
.getService(Ci.nsISessionStore);
function test() {
runTests();
}
function getState() {
return JSON.parse(gSessionStore.getBrowserState());
}
function getTabData() {
return getState().windows[0].tabs;
}
function isValidTabData(aData) {
return aData && aData.entries && aData.entries.length &&
typeof aData.index == "number";
}
gTests.push({
desc: "getBrowserState tests",
run: function() {
// Wait for Session Manager to be initialized.
yield waitForCondition(() => window.__SSID);
info(window.__SSID);
let tabData1 = getTabData();
ok(tabData1.every(isValidTabData), "Tab data starts out valid");
// Open a tab.
let tab = Browser.addTab("about:mozilla");
let tabData2 = getTabData();
is(tabData2.length, tabData1.length, "New tab not added yet.");
// Wait for the tab's session data to be initialized.
yield waitForMessage("Content:SessionHistory", tab.browser.messageManager);
yield waitForMs(0);
let tabData3 = getTabData();
is(tabData3.length, tabData1.length + 1, "New tab added.");
ok(tabData3.every(isValidTabData), "Tab data still valid");
// Close the tab.
Browser.closeTab(tab, { forceClose: true } );
let tabData4 = getTabData();
is(tabData4.length, tabData1.length, "Closed tab removed.");
ok(tabData4.every(isValidTabData), "Tab data valid again");
}
});

Просмотреть файл

@ -56,6 +56,7 @@ support-files =
[browser_private_browsing.js]
[browser_prompt.js]
[browser_remotetabs.js]
[browser_sessionstore.js]
[browser_snappedState.js]
[browser_tabs.js]
[browser_tabs_container.js]

Просмотреть файл

@ -338,6 +338,7 @@ SessionStore.prototype = {
// Assign it a unique identifier and create its data object
aWindow.__SSID = "window" + gUUIDGenerator.generateUUID().toString();
this._windows[aWindow.__SSID] = { tabs: [], selected: 0, _closedTabs: [] };
this._orderedWindows.push(aWindow.__SSID);
// Perform additional initialization when the first window is loading
if (this._loadState == STATE_STOPPED) {
@ -348,9 +349,6 @@ SessionStore.prototype = {
if (!this.shouldRestore()) {
this._clearCache();
Services.obs.notifyObservers(null, "sessionstore-windows-restored", "");
// If nothing is being restored, we only have our single Metro window.
this._orderedWindows.push(aWindow.__SSID);
}
}
@ -554,15 +552,13 @@ SessionStore.prototype = {
_getTabData: function(aWindow) {
return aWindow.Browser.tabs
.filter(tab => !tab.isPrivate)
.filter(tab => !tab.isPrivate && tab.browser.__SS_data)
.map(tab => {
let browser = tab.browser;
if (browser.__SS_data) {
let tabData = browser.__SS_data;
if (browser.__SS_extdata)
tabData.extData = browser.__SS_extdata;
return tabData;
}
let tabData = browser.__SS_data;
if (browser.__SS_extdata)
tabData.extData = browser.__SS_extdata;
return tabData;
});
},
@ -801,6 +797,7 @@ SessionStore.prototype = {
} catch (ex) { /* currentGroupId is undefined if user has no tab groups */ }
// Move all window data from sessionstore.js to this._windows.
this._orderedWindows = [];
for (let i = 0; i < data.windows.length; i++) {
let SSID;
if (i != windowIndex) {

Просмотреть файл

@ -1682,21 +1682,30 @@ toolbarbutton.chevron > .toolbarbutton-icon {
/* Sync Panel */
#sync-popup {
.sync-panel {
padding: 10px;
}
#sync-popup-icon {
.sync-panel-icon {
width: 32px;
background: url("chrome://browser/content/abouthome/sync.png") center center no-repeat;
background: url("chrome://browser/content/abouthome/sync.png") top left no-repeat;
}
#sync-popup-inner {
.sync-panel-inner {
width: 0;
padding-left: 10px;
}
#sync-popup-desc-prefs {
.sync-panel-button-box {
margin-top: 1em;
}
#sync-error-panel-title {
font-weight: bold;
}
#sync-start-panel-subtitle,
#sync-error-panel-subtitle {
margin: 0;
}

Просмотреть файл

@ -3596,30 +3596,54 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
margin-top: .5em;
}
/* Sync Panel */
/* Sync Panels */
#sync-popup {
.sync-panel {
padding: 10px;
}
#sync-popup-icon {
.sync-panel-icon {
width: 32px;
background: url("chrome://browser/content/abouthome/sync.png") center center no-repeat;
background: url("chrome://browser/content/abouthome/sync.png") top left no-repeat;
}
@media (min-resolution: 2dppx) {
#sync-popup-icon {
background: url("chrome://browser/content/abouthome/sync@2x.png") center center no-repeat;
.sync-panel-icon {
background: url("chrome://browser/content/abouthome/sync@2x.png") top left no-repeat;
background-size: 32px 32px;
}
}
#sync-popup-inner {
.sync-panel-inner {
width: 0;
padding-left: 10px;
}
#sync-popup-desc-prefs {
.sync-panel-button-box {
margin-top: 1em;
}
.sync-panel-button {
@hudButton@
margin: 0;
min-width: 72px;
min-height: 22px;
}
.sync-panel-button:hover:active {
@hudButtonPressed@
}
.sync-panel-button:-moz-focusring {
@hudButtonFocused@
}
#sync-error-panel-title {
font-weight: bold;
}
#sync-start-panel-subtitle,
#sync-error-panel-subtitle {
margin: 0;
}

Просмотреть файл

@ -6,8 +6,8 @@
%define menuPanelWidth 22.35em
%define exitSubviewGutterWidth 38px
%define buttonStateHover :not(:-moz-any([disabled],[checked="true"],[open],:active)):hover
%define buttonStateActive :not([disabled]):-moz-any([open],[checked="true"],:hover:active)
%define buttonStateHover :not(:-moz-any([disabled],[open],[checked="true"],:active)):-moz-any(:hover,[_moz-menuactive])
%define buttonStateActive :not([disabled]):-moz-any([open],[checked="true"],:hover:active,[_moz-menuactive]:active)
%include ../browser.inc
@ -216,11 +216,16 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
#PanelUI-footer {
display: flex;
flex-direction: column;
background-color: rgba(0, 0, 0, 0.05);
box-shadow: 0 -1px 0 rgba(0,0,0,.15);
padding: 0;
margin: 0;
min-height: 4em;
}
#PanelUI-footer-inner {
display: flex;
box-shadow: 0 -1px 0 rgba(0,0,0,.15);
}
#PanelUI-footer > toolbarseparator {
@ -234,10 +239,12 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
}
#PanelUI-help,
#PanelUI-fxa-status,
#PanelUI-customize,
#PanelUI-quit {
margin: 0;
padding: 10px 0;
min-height: 2em;
-moz-appearance: none;
box-shadow: none;
background-image: none;
@ -248,11 +255,21 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
-moz-box-orient: horizontal;
}
#PanelUI-fxa-status {
width: calc(@menuPanelWidth@ + 20px);
border-bottom-style: solid;
}
#PanelUI-fxa-status[signedin] {
font-weight: bold;
}
#PanelUI-help,
#PanelUI-quit {
min-width: 46px;
}
#PanelUI-fxa-status > .toolbarbutton-text,
#PanelUI-customize > .toolbarbutton-text {
text-align: start;
}
@ -267,6 +284,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
-moz-margin-end: 0;
}
#PanelUI-fxa-status,
#PanelUI-customize {
flex: 1;
-moz-padding-start: 15px;
@ -283,6 +301,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
list-style-image: url(chrome://browser/skin/menuPanel-exit.png);
}
#PanelUI-fxa-status,
#PanelUI-customize,
#PanelUI-help,
#PanelUI-quit {
@ -314,6 +333,12 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
box-shadow: none;
}
#PanelUI-fxa-status:not([disabled]):hover {
background-color: rgba(0,0,0,0.1);
border-bottom-color: rgba(0,0,0,0.1);
box-shadow: 0 -1px 0 rgba(0,0,0,0.2);
}
#PanelUI-quit:not([disabled]):hover {
background-color: #d94141;
outline-color: #c23a3a;

Просмотреть файл

@ -2141,21 +2141,30 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
/* Sync Panel */
#sync-popup {
.sync-panel {
padding: 10px;
}
#sync-popup-icon {
.sync-panel-icon {
width: 32px;
background: url("chrome://browser/content/abouthome/sync.png") center center no-repeat;
background: url("chrome://browser/content/abouthome/sync.png") top left no-repeat;
}
#sync-popup-inner {
.sync-panel-inner {
width: 0;
padding-left: 10px;
}
#sync-popup-desc-prefs {
.sync-panel-button-box {
margin-top: 1em;
}
#sync-error-panel-title {
font-weight: bold;
}
#sync-start-panel-subtitle,
#sync-error-panel-subtitle {
margin: 0;
}

Просмотреть файл

@ -72,10 +72,17 @@ DEBUGGER_INFO = {
},
# valgrind doesn't explain much about leaks unless you set the
# '--leak-check=full' flag.
# '--leak-check=full' flag. But there are a lot of objects that are
# semi-deliberately leaked, so we set '--show-possibly-lost=no' to avoid
# uninteresting output from those objects. We set '--smc-check==all-non-file'
# and '--vex-iropt-register-updates=allregs-at-mem-access' so that valgrind
# deals properly with JIT'd JavaScript code.
"valgrind": {
"interactive": False,
"args": "--leak-check=full"
"args": " ".join(["--leak-check=full",
"--show-possibly-lost=no",
"--smc-check=all-non-file,"
"--vex-iropt-register-updates=allregs-at-mem-access"])
}
}

Просмотреть файл

@ -12,6 +12,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=882703
SimpleTest.waitForExplicitFinish();
video = document.createElement("video");
isnot(video.textTracks, null, "Video should have a list of TextTracks.");
video.addTextTrack("subtitles", "", "");
track = video.textTracks[0];

Просмотреть файл

@ -8225,10 +8225,20 @@ nsGlobalWindow::EnterModalState()
}
}
// Clear the capturing content if it is under topDoc.
// Usually the activeESM check above does that, but there are cases when
// we don't have activeESM, or it is for different document.
nsIDocument* topDoc = topWin->GetExtantDoc();
nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
if (capturingContent && topDoc &&
nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
nsIPresShell::SetCapturingContent(nullptr, 0);
}
if (topWin->mModalStateDepth == 0) {
NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
mSuspendedDoc = topWin->GetExtantDoc();
mSuspendedDoc = topDoc;
if (mSuspendedDoc) {
mSuspendedDoc->SuppressEventHandling();
}

Просмотреть файл

@ -682,12 +682,12 @@ bool TabParent::SendRealMouseEvent(WidgetMouseEvent& event)
if (mIsDestroyed) {
return false;
}
WidgetMouseEvent e(event);
MaybeForwardEventToRenderFrame(event, nullptr, &e);
if (!MapEventCoordinatesForChildProcess(&e)) {
WidgetMouseEvent outEvent(event);
MaybeForwardEventToRenderFrame(event, nullptr, &outEvent);
if (!MapEventCoordinatesForChildProcess(&outEvent)) {
return false;
}
return PBrowserParent::SendRealMouseEvent(e);
return PBrowserParent::SendRealMouseEvent(outEvent);
}
CSSIntPoint TabParent::AdjustTapToChildWidget(const CSSIntPoint& aPoint)
@ -750,12 +750,12 @@ bool TabParent::SendMouseWheelEvent(WidgetWheelEvent& event)
if (mIsDestroyed) {
return false;
}
WidgetWheelEvent e(event);
MaybeForwardEventToRenderFrame(event, nullptr, &e);
if (!MapEventCoordinatesForChildProcess(&e)) {
WidgetWheelEvent outEvent(event);
MaybeForwardEventToRenderFrame(event, nullptr, &outEvent);
if (!MapEventCoordinatesForChildProcess(&outEvent)) {
return false;
}
return PBrowserParent::SendMouseWheelEvent(event);
return PBrowserParent::SendMouseWheelEvent(outEvent);
}
bool TabParent::SendRealKeyEvent(WidgetKeyboardEvent& event)
@ -763,12 +763,12 @@ bool TabParent::SendRealKeyEvent(WidgetKeyboardEvent& event)
if (mIsDestroyed) {
return false;
}
WidgetKeyboardEvent e(event);
MaybeForwardEventToRenderFrame(event, nullptr, &e);
if (!MapEventCoordinatesForChildProcess(&e)) {
WidgetKeyboardEvent outEvent(event);
MaybeForwardEventToRenderFrame(event, nullptr, &outEvent);
if (!MapEventCoordinatesForChildProcess(&outEvent)) {
return false;
}
return PBrowserParent::SendRealKeyEvent(e);
return PBrowserParent::SendRealKeyEvent(outEvent);
}
bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event)
@ -797,30 +797,36 @@ bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event)
++mEventCaptureDepth;
}
WidgetTouchEvent e(event);
// PresShell::HandleEventInternal adds touches on touch end/cancel.
// This confuses remote content into thinking that the added touches
// are part of the touchend/cancel, when actually they're not.
// PresShell::HandleEventInternal adds touches on touch end/cancel. This
// confuses remote content and the panning and zooming logic into thinking
// that the added touches are part of the touchend/cancel, when actually
// they're not.
if (event.message == NS_TOUCH_END || event.message == NS_TOUCH_CANCEL) {
for (int i = e.touches.Length() - 1; i >= 0; i--) {
if (!e.touches[i]->mChanged) {
e.touches.RemoveElementAt(i);
for (int i = event.touches.Length() - 1; i >= 0; i--) {
if (!event.touches[i]->mChanged) {
event.touches.RemoveElementAt(i);
}
}
}
// Create an out event for remote content that is identical to the event that
// we send to the render frame. The out event will be transformed in such a
// way that its async transform in the compositor is unapplied. The event that
// it is created from does not get mutated.
WidgetTouchEvent outEvent(event);
ScrollableLayerGuid guid;
MaybeForwardEventToRenderFrame(event, &guid, &e);
MaybeForwardEventToRenderFrame(event, &guid, &outEvent);
if (mIsDestroyed) {
return false;
}
MapEventCoordinatesForChildProcess(mChildProcessOffsetAtTouchStart, &e);
MapEventCoordinatesForChildProcess(mChildProcessOffsetAtTouchStart, &outEvent);
return (e.message == NS_TOUCH_MOVE) ?
PBrowserParent::SendRealTouchMoveEvent(e, guid) :
PBrowserParent::SendRealTouchEvent(e, guid);
return (outEvent.message == NS_TOUCH_MOVE) ?
PBrowserParent::SendRealTouchMoveEvent(outEvent, guid) :
PBrowserParent::SendRealTouchEvent(outEvent, guid);
}
/*static*/ TabParent*

Просмотреть файл

@ -579,24 +579,15 @@ Promise::Reject(nsPIDOMWindow* aWindow, JSContext* aCx,
}
already_AddRefed<Promise>
Promise::Then(const Optional<nsRefPtr<AnyCallback>>& aResolveCallback,
const Optional<nsRefPtr<AnyCallback>>& aRejectCallback)
Promise::Then(AnyCallback* aResolveCallback, AnyCallback* aRejectCallback)
{
nsRefPtr<Promise> promise = new Promise(GetParentObject());
nsRefPtr<PromiseCallback> resolveCb =
PromiseCallback::Factory(promise,
aResolveCallback.WasPassed()
? aResolveCallback.Value()
: nullptr,
PromiseCallback::Resolve);
PromiseCallback::Factory(promise, aResolveCallback, PromiseCallback::Resolve);
nsRefPtr<PromiseCallback> rejectCb =
PromiseCallback::Factory(promise,
aRejectCallback.WasPassed()
? aRejectCallback.Value()
: nullptr,
PromiseCallback::Reject);
PromiseCallback::Factory(promise, aRejectCallback, PromiseCallback::Reject);
AppendCallbacks(resolveCb, rejectCb);
@ -604,9 +595,9 @@ Promise::Then(const Optional<nsRefPtr<AnyCallback>>& aResolveCallback,
}
already_AddRefed<Promise>
Promise::Catch(const Optional<nsRefPtr<AnyCallback>>& aRejectCallback)
Promise::Catch(AnyCallback* aRejectCallback)
{
Optional<nsRefPtr<AnyCallback>> resolveCb;
nsRefPtr<AnyCallback> resolveCb;
return Then(resolveCb, aRejectCallback);
}

Просмотреть файл

@ -83,12 +83,10 @@ public:
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
already_AddRefed<Promise>
Then(const Optional<nsRefPtr<AnyCallback>>& aResolveCallback,
const Optional<nsRefPtr<AnyCallback>>& aRejectCallback);
Then(AnyCallback* aResolveCallback, AnyCallback* aRejectCallback);
already_AddRefed<Promise>
Catch(const Optional<nsRefPtr<AnyCallback>>& aRejectCallback);
Catch(AnyCallback* aRejectCallback);
// FIXME(nsm): Bug 956197
static already_AddRefed<Promise>

Просмотреть файл

@ -8,6 +8,8 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "js/OldDebugAPI.h"
namespace mozilla {
namespace dom {
@ -177,8 +179,7 @@ WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
// If invoking callback threw an exception, run resolver's reject with the
// thrown exception as argument and the synchronous flag set.
JS::Rooted<JS::Value> value(cx,
mCallback->Call(mNextPromise->GetParentObject(), aValue, rv,
CallbackObject::eRethrowExceptions));
mCallback->Call(aValue, rv, CallbackObject::eRethrowExceptions));
rv.WouldReportJSException();
@ -192,6 +193,67 @@ WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
return;
}
// If the return value is the same as the promise itself, throw TypeError.
if (value.isObject()) {
JS::Rooted<JSObject*> valueObj(cx, &value.toObject());
Promise* returnedPromise;
nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise);
if (NS_SUCCEEDED(r) && returnedPromise == mNextPromise) {
const char* fileName = nullptr;
uint32_t lineNumber = 0;
// Try to get some information about the callback to report a sane error,
// but don't try too hard (only deals with scripted functions).
JS::Rooted<JSObject*> unwrapped(cx,
js::CheckedUnwrap(mCallback->Callback()));
if (unwrapped) {
JSAutoCompartment ac(cx, unwrapped);
if (JS_ObjectIsFunction(cx, unwrapped)) {
JS::Rooted<JS::Value> asValue(cx, JS::ObjectValue(*unwrapped));
JS::Rooted<JSFunction*> func(cx, JS_ValueToFunction(cx, asValue));
MOZ_ASSERT(func);
JSScript* script = JS_GetFunctionScript(cx, func);
if (script) {
fileName = JS_GetScriptFilename(cx, script);
lineNumber = JS_GetScriptBaseLineNumber(cx, script);
}
}
}
// We're back in aValue's compartment here.
JS::Rooted<JSString*> stack(cx, JS_GetEmptyString(JS_GetRuntime(cx)));
JS::Rooted<JSString*> fn(cx, JS_NewStringCopyZ(cx, fileName));
if (!fn) {
// Out of memory. Promise will stay unresolved.
JS_ClearPendingException(cx);
return;
}
JS::Rooted<JSString*> message(cx,
JS_NewStringCopyZ(cx,
"then() cannot return same Promise that it resolves."));
if (!message) {
// Out of memory. Promise will stay unresolved.
JS_ClearPendingException(cx);
return;
}
JS::Rooted<JS::Value> typeError(cx);
if (!JS::CreateTypeError(cx, stack, fn, lineNumber, 0,
nullptr, message, &typeError)) {
// Out of memory. Promise will stay unresolved.
JS_ClearPendingException(cx);
return;
}
mNextPromise->RejectInternal(cx, typeError, Promise::SyncTask);
return;
}
}
// Otherwise, run resolver's resolve with value and the synchronous flag
// set.
Maybe<JSAutoCompartment> ac2;

Просмотреть файл

@ -564,6 +564,15 @@ function promiseWithThenReplaced() {
});
}
function promiseStrictHandlers() {
var promise = Promise.resolve(5);
promise.then(function() {
"use strict";
ok(this === undefined, "Strict mode callback should have this === undefined.");
runTest();
});
}
var tests = [ promiseResolve, promiseReject,
promiseException, promiseGC, promiseAsync,
promiseDoubleThen, promiseThenException,
@ -589,6 +598,7 @@ var tests = [ promiseResolve, promiseReject,
promiseThenableThrowsAfterCallback,
promiseThenableRejectThenResolve,
promiseWithThenReplaced,
promiseStrictHandlers,
];
function runTest() {

Просмотреть файл

@ -174,7 +174,7 @@ function promiseCastArray() {
}
function promiseCastThenable() {
var p = Promise.cast({ then: function(resolve) { resolve(2); } });
var p = Promise.cast({ then: function(onFulfill, onReject) { onFulfill(2); } });
ok(p instanceof Promise, "Should cast to a Promise.");
p.then(function(v) {
is(v, 2, "Should resolve to 2.");

Просмотреть файл

@ -11,6 +11,8 @@
// have different types for "platform-provided function" and "user-provided
// function"; for now, we just use "object".
callback PromiseInit = void (object resolve, object reject);
[TreatNonCallableAsNull]
callback AnyCallback = any (any value);
[Func="mozilla::dom::Promise::EnabledForScope", Constructor(PromiseInit init)]
@ -27,12 +29,14 @@ interface Promise {
[NewObject, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
static Promise reject(optional any value);
// The [TreatNonCallableAsNull] annotation is required since then() should do
// nothing instead of throwing errors when non-callable arguments are passed.
[NewObject]
Promise then(optional AnyCallback? fulfillCallback,
optional AnyCallback? rejectCallback);
Promise then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null,
[TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
[NewObject]
Promise catch(optional AnyCallback? rejectCallback);
Promise catch([TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
[NewObject, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
static Promise all(sequence<any> iterable);

Просмотреть файл

@ -1639,6 +1639,7 @@ XMLHttpRequest::MaybePin(ErrorResult& aRv)
JSContext* cx = GetCurrentThreadJSContext();
if (!mWorkerPrivate->AddFeature(cx, this)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}

Просмотреть файл

@ -853,17 +853,8 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent) {
APZC_LOG("%p got a scale-end in state %d\n", this, mState);
// When a pinch ends, it might either turn into a pan (if only one finger
// was lifted) or not (if both fingers were lifted). GestureEventListener
// sets mCurrentSpan to a negative value in the latter case, and sets
// mFocusPoint to the remaining touch point in the former case.
if (aEvent.mCurrentSpan >= 0) {
SetState(PANNING);
mX.StartTouch(aEvent.mFocusPoint.x);
mY.StartTouch(aEvent.mFocusPoint.y);
} else {
SetState(NOTHING);
}
SetState(NOTHING);
{
ReentrantMonitorAutoEnter lock(mMonitor);

Просмотреть файл

@ -267,25 +267,24 @@ nsEventStatus GestureEventListener::HandlePinchGestureEvent(const MultiTouchInpu
} else if (mState == GESTURE_PINCH) {
PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_END,
aEvent.mTime,
ScreenPoint(), // may change below
1.0f, // may change below
1.0f, // may change below
ScreenPoint(),
1.0f,
1.0f,
aEvent.modifiers);
if (mTouches.Length() > 0) {
// Pinch is changing to pan. APZC will start a pan at mFocusPoint
// (which isn't really a focus point in this case...).
pinchEvent.mFocusPoint = mTouches[0].mScreenPoint;
} else {
// Pinch is ending, no pan to follow. APZC will check for the spans
// being negative.
pinchEvent.mCurrentSpan = pinchEvent.mPreviousSpan = -1.0f;
}
mAsyncPanZoomController->HandleInputEvent(pinchEvent);
mState = GESTURE_NONE;
// If the user left a finger on the screen, spoof a touch start event and
// send it to APZC so that they can continue panning from that point.
if (mTouches.Length() == 1) {
MultiTouchInput touchEvent(MultiTouchInput::MULTITOUCH_START,
aEvent.mTime,
aEvent.modifiers);
touchEvent.mTouches.AppendElement(mTouches[0]);
mAsyncPanZoomController->HandleInputEvent(touchEvent);
}
rv = nsEventStatus_eConsumeNoDefault;
} else if (mState == GESTURE_WAITING_PINCH) {
mState = GESTURE_NONE;

Просмотреть файл

@ -2169,7 +2169,7 @@ Assembler::as_vcvtFixed(VFPRegister vd, bool isSigned, uint32_t fixedPoint, bool
int32_t imm5 = fixedPoint;
imm5 = (sx ? 32 : 16) - imm5;
JS_ASSERT(imm5 >= 0);
imm5 = imm5 >> 1 | (imm5 & 1) << 6;
imm5 = imm5 >> 1 | (imm5 & 1) << 5;
return writeVFPInst(sf, 0x02BA0040 | VD(vd) | toFixed << 18 | sx << 7 |
(!isSigned) << 16 | imm5 | c);
}

Просмотреть файл

@ -2183,8 +2183,17 @@ public:
virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem) {
SetCount(++mCount);
return new (aBuilder) nsDisplayScrollLayer(aBuilder, aItem, aItem->Frame(), mScrolledFrame, mScrollFrame);
// If the display item is for a frame that is absolutely positioned, it
// should only scroll with the scrolled content if its frame its contained
// within the scrolled content's frame.
bool shouldWrap = !aItem->Frame()->IsAbsolutelyPositioned() ||
nsLayoutUtils::IsProperAncestorFrame(mScrolledFrame, aItem->Frame(), nullptr);
if (shouldWrap) {
SetCount(++mCount);
return new (aBuilder) nsDisplayScrollLayer(aBuilder, aItem, aItem->Frame(), mScrolledFrame, mScrollFrame);
} else {
return aItem;
}
}
protected:

Просмотреть файл

@ -270,6 +270,7 @@ public:
bool IsLTR() const;
bool IsScrollbarOnRight() const;
bool IsScrollingActive() const { return mScrollingActive || mShouldBuildScrollableLayer; }
bool IsProcessingAsyncScroll() const { return mAsyncScroll != nullptr; }
void ResetScrollPositionForLayerPixelAlignment()
{
mScrollPosForLayerPixelAlignment = GetScrollPosition();
@ -636,6 +637,9 @@ public:
virtual bool IsScrollingActive() MOZ_OVERRIDE {
return mHelper.IsScrollingActive();
}
virtual bool IsProcessingAsyncScroll() MOZ_OVERRIDE {
return mHelper.IsProcessingAsyncScroll();
}
virtual void ResetScrollPositionForLayerPixelAlignment() MOZ_OVERRIDE {
mHelper.ResetScrollPositionForLayerPixelAlignment();
}
@ -934,6 +938,9 @@ public:
virtual bool IsScrollingActive() MOZ_OVERRIDE {
return mHelper.IsScrollingActive();
}
virtual bool IsProcessingAsyncScroll() MOZ_OVERRIDE {
return mHelper.IsProcessingAsyncScroll();
}
virtual void ResetScrollPositionForLayerPixelAlignment() MOZ_OVERRIDE {
mHelper.ResetScrollPositionForLayerPixelAlignment();
}

Просмотреть файл

@ -250,6 +250,11 @@ public:
* expectation that scrolling is going to happen.
*/
virtual bool IsScrollingActive() = 0;
/**
* Returns true if the scrollframe is currently processing an async
* or smooth scroll.
*/
virtual bool IsProcessingAsyncScroll() = 0;
/**
* Call this when the layer(s) induced by active scrolling are being
* completely redrawn.

Просмотреть файл

@ -301,7 +301,7 @@
android:permission="@ANDROID_PACKAGE_NAME@.permissions.BROWSER_PROVIDER"/>
<provider android:name="org.mozilla.gecko.db.HomeProvider"
android:authorities="@ANDROID_PACKAGE_NAME@.db.homelists"
android:authorities="@ANDROID_PACKAGE_NAME@.db.home"
android:permission="@ANDROID_PACKAGE_NAME@.permissions.BROWSER_PROVIDER"/>
<service

Просмотреть файл

@ -1362,15 +1362,15 @@ abstract public class BrowserApp extends GeckoApp
}
final Tabs tabs = Tabs.getInstance();
final int tabId = tabs.getTabIdForUrl(url, tabs.getSelectedTab().isPrivate());
if (tabId < 0) {
final Tab tab = tabs.getFirstTabForUrl(url, tabs.getSelectedTab().isPrivate());
if (tab == null) {
return false;
}
// Set the target tab to null so it does not get selected (on editing
// mode exit) in lieu of the tab we are about to select.
mTargetTabForEditingMode = null;
Tabs.getInstance().selectTab(tabId);
tabs.selectTab(tab.getId());
mBrowserToolbar.cancelEdit();

Просмотреть файл

@ -393,7 +393,7 @@ public class GeckoAppShell
* The Gecko-side API: API methods that Gecko calls
*/
@WrapElementForJNI(generateStatic = true, noThrow = true)
@WrapElementForJNI(allowMultithread = true, generateStatic = true, noThrow = true)
public static void handleUncaughtException(Thread thread, Throwable e) {
if (thread == null) {
thread = Thread.currentThread();

Просмотреть файл

@ -163,7 +163,7 @@ public class Tabs implements GeckoEventListener {
return count;
}
public synchronized int isOpen(String url) {
public int isOpen(String url) {
for (Tab tab : mOrder) {
if (tab.getURL().equals(url)) {
return tab.getId();
@ -645,32 +645,44 @@ public class Tabs implements GeckoEventListener {
/**
* Looks for an open tab with the given URL.
* @param url the URL of the tab we're looking for
*
* @return first Tab with the given URL, or null if there is no such tab.
*/
public Tab getFirstTabForUrl(String url) {
return getFirstTabForUrlHelper(url, null);
}
/**
* Looks for an open tab with the given URL and private state.
* @param url the URL of the tab we're looking for
* @param isPrivate if true, only look for tabs that are private. if false,
* only look for tabs that are non-private.
*
* @return id of an open tab with the given URL; -1 if the tab doesn't exist.
* @return first Tab with the given URL, or null if there is no such tab.
*/
public int getTabIdForUrl(String url, boolean isPrivate) {
public Tab getFirstTabForUrl(String url, boolean isPrivate) {
return getFirstTabForUrlHelper(url, isPrivate);
}
private Tab getFirstTabForUrlHelper(String url, Boolean isPrivate) {
if (url == null) {
return null;
}
for (Tab tab : mOrder) {
if (isPrivate != null && isPrivate != tab.isPrivate()) {
continue;
}
String tabUrl = tab.getURL();
if (AboutPages.isAboutReader(tabUrl)) {
tabUrl = ReaderModeUtils.getUrlFromAboutReader(tabUrl);
}
if (TextUtils.equals(tabUrl, url) && isPrivate == tab.isPrivate()) {
return tab.getId();
if (url.equals(tabUrl)) {
return tab;
}
}
return -1;
}
public int getTabIdForUrl(String url) {
return getTabIdForUrl(url, Tabs.getInstance().getSelectedTab().isPrivate());
}
public synchronized Tab getTabForUrl(String url) {
int tabId = getTabIdForUrl(url);
return getTab(tabId);
return null;
}
/**

Просмотреть файл

@ -239,7 +239,7 @@ public class Favicons {
// Attempt to determine the Favicon URL from the Tabs datastructure. Can dodge having to use
// the database sometimes by doing this.
String targetURL;
Tab theTab = Tabs.getInstance().getTabForUrl(pageURL);
Tab theTab = Tabs.getInstance().getFirstTabForUrl(pageURL);
if (theTab != null) {
targetURL = theTab.getFaviconURL();
if (targetURL != null) {

Просмотреть файл

@ -219,16 +219,11 @@ public class DynamicPanel extends HomeFragment {
public Cursor loadCursor() {
final ContentResolver cr = getContext().getContentResolver();
// XXX: Use the test URI for static fake data
final Uri fakeItemsUri = HomeItems.CONTENT_FAKE_URI.buildUpon().
appendQueryParameter(BrowserContract.PARAM_PROFILE, "default").build();
final String selection = HomeItems.DATASET_ID + " = ?";
final String[] selectionArgs = new String[] { mDatasetId };
Log.i(LOGTAG, "Loading fake data for list provider: " + mDatasetId);
return cr.query(fakeItemsUri, null, selection, selectionArgs, null);
// XXX: You can use CONTENT_FAKE_URI for development to pull items from fake_home_items.json.
return cr.query(HomeItems.CONTENT_URI, null, selection, selectionArgs, null);
}
}

Просмотреть файл

@ -120,8 +120,8 @@ public class TwoLinePageRow extends TwoLineRow
*/
private void updateDisplayedUrl() {
boolean isPrivate = Tabs.getInstance().getSelectedTab().isPrivate();
int tabId = Tabs.getInstance().getTabIdForUrl(mPageUrl, isPrivate);
if (!mShowIcons || tabId < 0) {
Tab tab = Tabs.getInstance().getFirstTabForUrl(mPageUrl, isPrivate);
if (!mShowIcons || tab == null) {
setSecondaryText(mPageUrl);
setSecondaryIcon(NO_ICON);
} else {

Просмотреть файл

@ -638,7 +638,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
// Set TabCounter based on visibility
if (isVisible() && ViewHelper.getAlpha(mTabsCounter) != 0) {
if (isVisible() && ViewHelper.getAlpha(mTabsCounter) != 0 && !isEditing()) {
mTabsCounter.setCountWithAnimation(count);
} else {
mTabsCounter.setCount(count);
@ -863,6 +863,10 @@ public class BrowserToolbar extends GeckoRelativeLayout
// in setButtonEnabled().
final float alpha = (enabled ? 1.0f : 0.24f);
if (!enabled) {
mTabsCounter.onEnterEditingMode();
}
mTabs.setEnabled(enabled);
ViewHelper.setAlpha(mTabsCounter, alpha);
mMenu.setEnabled(enabled);

Просмотреть файл

@ -102,6 +102,16 @@ public class TabCounter extends GeckoTextSwitcher
mCount = count;
}
// Alpha animations in editing mode cause action bar corruption on the
// Nexus 7 (bug 961749). As a workaround, skip these animations in editing
// mode.
void onEnterEditingMode() {
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
getChildAt(i).clearAnimation();
}
}
private AnimationSet createAnimation(float startAngle, float endAngle,
FadeMode fadeMode,
float zEnd, boolean reverse) {

Просмотреть файл

@ -30,11 +30,6 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Xml;
/**
* Mozilla: Extra imports.
*/
import android.content.pm.ApplicationInfo;
/**
* Mozilla: Unused import.
*/
@ -262,11 +257,6 @@ public class ActivityChooserModel extends DataSetObservable {
*/
//private final PackageMonitor mPackageMonitor = new DataModelPackageMonitor();
/**
* Mozilla: Count to monitor added and removed packages.
*/
private int mApplicationsCount;
/**
* Context for accessing resources.
*/
@ -742,15 +732,6 @@ public class ActivityChooserModel extends DataSetObservable {
* @return Whether loading was performed.
*/
private boolean loadActivitiesIfNeeded() {
/**
* Mozilla: Hack to find change in the installed/uninstalled applications.
*/
List<ApplicationInfo> applications = mContext.getPackageManager().getInstalledApplications(0);
if (applications != null && applications.size() != mApplicationsCount) {
mApplicationsCount = applications.size();
mReloadActivities = true;
}
if (mReloadActivities && mIntent != null) {
mReloadActivities = false;
mActivities.clear();

Просмотреть файл

@ -560,6 +560,23 @@ var SelectionHandler = {
this.startSelection(aElement, { mode : this.SELECT_ALL });
},
/*
* Helper function for moving the selection inside an editable element.
*
* @param aAnchorX the stationary handle's x-coordinate in client coordinates
* @param aX the moved handle's x-coordinate in client coordinates
* @param aCaretPos the current position of the caret
*/
_moveSelectionInEditable: function sh_moveSelectionInEditable(aAnchorX, aX, aCaretPos) {
let anchorOffset = aX < aAnchorX ? this._targetElement.selectionEnd
: this._targetElement.selectionStart;
let newOffset = aCaretPos.offset;
let [start, end] = anchorOffset <= newOffset ?
[anchorOffset, newOffset] :
[newOffset, anchorOffset];
this._targetElement.setSelectionRange(start, end);
},
/*
* Moves the selection as the user drags a selection handle.
*
@ -597,8 +614,8 @@ var SelectionHandler = {
// are reversed, so we need to reverse the logic to extend the selection.
if ((aIsStartHandle && !this._isRTL) || (!aIsStartHandle && this._isRTL)) {
if (targetIsEditable) {
// XXX This will just collapse the selection if the start handle goes past the end handle.
this._targetElement.selectionStart = caretPos.offset;
let anchorX = this._isRTL ? this._cache.start.x : this._cache.end.x;
this._moveSelectionInEditable(anchorX, aX, caretPos);
} else {
let focusNode = selection.focusNode;
let focusOffset = selection.focusOffset;
@ -607,8 +624,8 @@ var SelectionHandler = {
}
} else {
if (targetIsEditable) {
// XXX This will just collapse the selection if the end handle goes past the start handle.
this._targetElement.selectionEnd = caretPos.offset;
let anchorX = this._isRTL ? this._cache.end.x : this._cache.start.x;
this._moveSelectionInEditable(anchorX, aX, caretPos);
} else {
selection.extend(caretPos.offsetNode, caretPos.offset);
}

Просмотреть файл

@ -28,7 +28,6 @@ function dump(a) {
const STATE_STOPPED = 0;
const STATE_RUNNING = 1;
const STATE_QUITTING = -1;
function SessionStore() { }
@ -76,11 +75,7 @@ SessionStore.prototype = {
observerService.addObserver(this, "final-ui-startup", true);
observerService.addObserver(this, "domwindowopened", true);
observerService.addObserver(this, "domwindowclosed", true);
observerService.addObserver(this, "browser-lastwindow-close-granted", true);
observerService.addObserver(this, "browser:purge-session-history", true);
observerService.addObserver(this, "quit-application-requested", true);
observerService.addObserver(this, "quit-application-granted", true);
observerService.addObserver(this, "quit-application", true);
observerService.addObserver(this, "Session:Restore", true);
break;
case "final-ui-startup":
@ -98,60 +93,9 @@ SessionStore.prototype = {
case "domwindowclosed": // catch closed windows
this.onWindowClose(aSubject);
break;
case "browser-lastwindow-close-granted":
// If a save has been queued, kill the timer and save state now
if (this._saveTimer) {
this._saveTimer.cancel();
this._saveTimer = null;
this.saveState();
}
// Freeze the data at what we've got (ignoring closing windows)
this._loadState = STATE_QUITTING;
break;
case "quit-application-requested":
// Get a current snapshot of all windows
this._forEachBrowserWindow(function(aWindow) {
self._collectWindowData(aWindow);
});
break;
case "quit-application-granted":
// Get a current snapshot of all windows
this._forEachBrowserWindow(function(aWindow) {
self._collectWindowData(aWindow);
});
// Freeze the data at what we've got (ignoring closing windows)
this._loadState = STATE_QUITTING;
break;
case "quit-application":
// Freeze the data at what we've got (ignoring closing windows)
this._loadState = STATE_QUITTING;
observerService.removeObserver(this, "domwindowopened");
observerService.removeObserver(this, "domwindowclosed");
observerService.removeObserver(this, "browser-lastwindow-close-granted");
observerService.removeObserver(this, "quit-application-requested");
observerService.removeObserver(this, "quit-application-granted");
observerService.removeObserver(this, "quit-application");
observerService.removeObserver(this, "Session:Restore");
// If a save has been queued, kill the timer and save state now
if (this._saveTimer) {
this._saveTimer.cancel();
this._saveTimer = null;
this.saveState();
}
break;
case "browser:purge-session-history": // catch sanitization
this._clearDisk();
// If the browser is shutting down, simply return after clearing the
// session data on disk as this notification fires after the
// quit-application notification so the browser is about to exit.
if (this._loadState == STATE_QUITTING)
return;
// Clear all data about closed tabs
for (let [ssid, win] in Iterator(this._windows))
win.closedTabs = [];
@ -237,7 +181,7 @@ SessionStore.prototype = {
return;
// Ignore non-browser windows and windows opened while shutting down
if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser" || this._loadState == STATE_QUITTING)
if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser")
return;
// Assign it a unique identifier (timestamp) and create its data object

Просмотреть файл

@ -217,7 +217,7 @@ let HomePanels = {
sendMessageToJava({
type: "HomePanels:Remove",
id: panel.id
id: id
});
},

Просмотреть файл

@ -24,7 +24,7 @@ const DB_PATH = OS.Path.join(OS.Constants.Path.profileDir, "home.sqlite");
const SQL = {
createItemsTable:
"CREATE TABLE items (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"dataset_id TEXT NOT NULL, " +
"url TEXT," +
"title TEXT," +
@ -77,6 +77,7 @@ HomeStorage.prototype = {
// XXX: Factor this out to some migration path.
if (!(yield db.tableExists("items"))) {
yield db.execute(SQL.createItemsTable);
yield db.setSchemaVersion(SCHEMA_VERSION);
}
// Insert data into DB.

Просмотреть файл

@ -123,12 +123,6 @@ MissingRequiredTabChild(mozilla::dom::TabChild* tabChild,
const char* context)
{
if (UsingNeckoIPCSecurity()) {
// Bug 833935: during navigation away from page some loads may lack
// TabParent: we don't want to kill browser for that. Doesn't happen in
// test harness, so fail in debug mode so we can catch new code that fails
// to pass security info.
MOZ_ASSERT(tabChild);
if (!tabChild) {
printf_stderr("WARNING: child tried to open %s IPDL channel w/o "
"security info\n", context);

Просмотреть файл

@ -136,6 +136,17 @@ class BaseBootstrapper(object):
self.run_as_root(command)
def apt_update(self):
command = ['apt-get', 'update']
self.run_as_root(command)
def apt_add_architecture(self, arch):
command = ['dpkg', '--add-architecture']
command.extemd(arch)
self.run_as_root(command)
def check_output(self, *args, **kwargs):
"""Run subprocess.check_output even if Python doesn't provide it."""
fn = getattr(subprocess, 'check_output', BaseBootstrapper._check_output)

Просмотреть файл

@ -33,7 +33,9 @@ Or, if you prefer Git:
class Bootstrapper(object):
"""Main class that performs system bootstrap."""
def bootstrap(self):
def __init__(self, finished=FINISHED):
self.instance = None
self.finished = finished
cls = None
args = {}
@ -85,9 +87,12 @@ class Bootstrapper(object):
raise NotImplementedError('Bootstrap support is not yet available '
'for your OS.')
instance = cls(**args)
instance.install_system_packages()
instance.ensure_mercurial_modern()
instance.ensure_python_modern()
self.instance = cls(**args)
print(FINISHED)
def bootstrap(self):
self.instance.install_system_packages()
self.instance.ensure_mercurial_modern()
self.instance.ensure_python_modern()
print(self.finished)

Просмотреть файл

@ -14,14 +14,13 @@ class CentOSBootstrapper(BaseBootstrapper):
self.version = version
self.dist_id = dist_id
def install_system_packages(self):
kern = platform.uname()
self.yum_groupinstall(
self.group_packages = [
'Development Tools',
'Development Libraries',
'GNOME Software Development')
self.yum_install(
'GNOME Software Development',
]
self.packages = [
'alsa-lib-devel',
'autoconf213',
'curl-devel',
@ -36,7 +35,14 @@ class CentOSBootstrapper(BaseBootstrapper):
'mesa-libGL-devel',
'pulseaudio-libs-devel',
'wireless-tools-devel',
'yasm')
'yasm',
]
def install_system_packages(self):
kern = platform.uname()
self.yum_groupinstall(*self.group_packages)
self.yum_install(*self.packages)
yasm = 'http://pkgs.repoforge.org/yasm/yasm-1.1.0-1.el6.rf.i686.rpm'
if 'x86_64' in kern[2]:

Просмотреть файл

@ -42,9 +42,10 @@ class DebianBootstrapper(BaseBootstrapper):
self.version = version
self.dist_id = dist_id
self.packages = self.COMMON_PACKAGES + self.DISTRO_PACKAGES
def install_system_packages(self):
packages = self.COMMON_PACKAGES + self.DISTRO_PACKAGES
self.apt_install(*packages)
self.apt_install(*self.packages)
def _update_package_manager(self):
self.run_as_root(['apt-get', 'update'])

Просмотреть файл

@ -13,13 +13,13 @@ class FedoraBootstrapper(BaseBootstrapper):
self.version = version
self.dist_id = dist_id
def install_system_packages(self):
self.yum_groupinstall(
self.group_packages = [
'Development Tools',
'Development Libraries',
'GNOME Software Development')
'GNOME Software Development',
]
self.yum_install(
self.packages = [
'alsa-lib-devel',
'autoconf213',
'gcc-c++',
@ -32,7 +32,12 @@ class FedoraBootstrapper(BaseBootstrapper):
'mesa-libGL-devel',
'pulseaudio-libs-devel',
'wireless-tools-devel',
'yasm')
'yasm',
]
def install_system_packages(self):
self.yum_groupinstall(*self.group_packages)
self.yum_install(*self.packages)
def upgrade_mercurial(self, current):
self.yum_update('mercurial')

Просмотреть файл

@ -15,22 +15,7 @@ class FreeBSDBootstrapper(BaseBootstrapper):
BaseBootstrapper.__init__(self)
self.version = int(version.split('.')[0])
def pkg_install(self, *packages):
if self.which('pkg'):
command = ['pkg', 'install', '-x']
command.extend([i[0] for i in packages])
else:
command = ['pkg_add', '-Fr']
command.extend([i[-1] for i in packages])
self.run_as_root(command)
def install_system_packages(self):
# using clang since 9.0
if self.version < 9:
self.pkg_install(('gcc',))
self.pkg_install(
self.packages = [
('autoconf-2.13', 'autoconf213'),
('dbus-glib',),
('gmake',),
@ -42,7 +27,26 @@ class FreeBSDBootstrapper(BaseBootstrapper):
('mercurial',),
('pulseaudio',),
('yasm',),
('zip',))
('zip',),
]
# using clang since 9.0
if self.version < 9:
self.packages.append(('gcc',))
def pkg_install(self, *packages):
if self.which('pkg'):
command = ['pkg', 'install', '-x']
command.extend([i[0] for i in packages])
else:
command = ['pkg_add', '-Fr']
command.extend([i[-1] for i in packages])
self.run_as_root(command)
def install_system_packages(self):
self.pkg_install(*self.packages)
def upgrade_mercurial(self, current):
self.pkg_install('mercurial')

Просмотреть файл

@ -10,9 +10,7 @@ class OpenBSDBootstrapper(BaseBootstrapper):
def __init__(self, version):
BaseBootstrapper.__init__(self)
def install_system_packages(self):
# we use -z because there's no other way to say "any autoconf-2.13"
self.run_as_root(['pkg_add', '-z',
self.packages = [
'mercurial',
'llvm',
'autoconf-2.13',
@ -26,4 +24,9 @@ class OpenBSDBootstrapper(BaseBootstrapper):
'gtar',
'wget',
'unzip',
'zip'])
'zip',
]
def install_system_packages(self):
# we use -z because there's no other way to say "any autoconf-2.13"
self.run_as_root(['pkg_add', '-z'] + self.packages)

Просмотреть файл

@ -172,3 +172,13 @@ function uninstallFakePAC() {
let CID = PACSystemSettings.CID;
Cm.nsIComponentRegistrar.unregisterFactory(CID, PACSystemSettings);
}
// We want to ensure the legacy provider is used for most of these tests; the
// tests that know how to deal with the Firefox Accounts identity hack things
// to ensure that still works.
function setDefaultIdentityConfig() {
Cu.import("resource://gre/modules/Services.jsm");
Services.prefs.setBoolPref("identity.fxaccounts.enabled", false);
// Services.prefs.setBoolPref("services.sync.fxaccounts.enabled", false);
}
setDefaultIdentityConfig();

Просмотреть файл

@ -69,7 +69,9 @@ WeaveService.prototype = {
// first check if Firefox accounts is available at all. This is so we can
// get this landed without forcing Fxa to be used (and require nightly
// testers to manually set this pref)
// Once we decide we want Fxa to be available, we just remove this block.
// Once we decide we want Fxa to be available, we just remove this block
// (although a fly in this ointment is tests - it might be that we must
// just set this as a pref with a default of true)
let fxAccountsAvailable;
try {
fxAccountsAvailable = Services.prefs.getBoolPref("identity.fxaccounts.enabled");
@ -101,58 +103,12 @@ WeaveService.prototype = {
return this.fxAccountsEnabled = fxAccountsEnabled;
},
maybeInitWithFxAccountsAndEnsureLoaded: function() {
Components.utils.import("resource://services-sync/main.js");
// FxAccounts imports lots of stuff, so only do this as we need it
Cu.import("resource://gre/modules/FxAccounts.jsm");
// This isn't quite sufficient here to handle all the cases. Cases
// we need to handle:
// - User is signed in to FxAccounts, btu hasn't set up sync.
return fxAccounts.getSignedInUser().then(
(accountData) => {
if (accountData) {
Cu.import("resource://services-sync/browserid_identity.js");
// The Sync Identity module needs to be set in both these places if
// it's swapped out as we are doing here. When Weave.Service initializes
// it grabs a reference to Weave.Status._authManager, and for references
// to Weave.Service.identity to resolve correctly, we also need to reset
// Weave.Service.identity as well.
Weave.Service.identity = Weave.Status._authManager = new BrowserIDManager(),
// Init the identity module with any account data from
// firefox accounts. The Identity module will fetch the signed in
// user from fxAccounts directly.
Weave.Service.identity.initWithLoggedInUser().then(function () {
// Set the cluster data that we got from the token
Weave.Service.clusterURL = Weave.Service.identity.clusterURL;
// checkSetup() will check the auth state of the identity module
// and records that status in Weave.Status
if (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED) {
// This makes sure that Weave.Service is loaded
Svc.Obs.notify("weave:service:setup-complete");
// TODO: this shouldn't be here. It should be at the end
// of the promise chain of the 'fxaccounts:onverified' handler.
Weave.Utils.nextTick(Weave.Service.sync, Weave.Service);
this.ensureLoaded();
}
}.bind(this));
} else if (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED) {
// This makes sure that Weave.Service is loaded
this.ensureLoaded();
}
},
(err) => {dump("err in getting logged in account "+err.message)}
).then(null, (err) => {dump("err in processing logged in account "+err.message)});
},
observe: function (subject, topic, data) {
switch (topic) {
case "app-startup":
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
os.addObserver(this, "final-ui-startup", true);
os.addObserver(this, "fxaccounts:onverified", true);
os.addObserver(this, "fxaccounts:onlogout", true);
break;
case "final-ui-startup":
@ -160,53 +116,24 @@ WeaveService.prototype = {
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timer.initWithCallback({
notify: function() {
if (this.fxAccountsEnabled) {
// init the fxAccounts identity manager.
this.maybeInitWithFxAccountsAndEnsureLoaded();
} else {
// init the "old" style, sync-specific identity manager.
// We only load more if it looks like Sync is configured.
let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH);
if (!prefs.prefHasUserValue("username")) {
return;
}
// We only load more if it looks like Sync is configured.
let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH);
if (!prefs.prefHasUserValue("username")) {
return;
}
// We have a username. So, do a more thorough check. This will
// import a number of modules and thus increase memory
// accordingly. We could potentially copy code performed by
// this check into this file if our above code is yielding too
// many false positives.
Components.utils.import("resource://services-sync/main.js");
if (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED) {
this.ensureLoaded();
}
// We have a username. So, do a more thorough check. This will
// import a number of modules and thus increase memory
// accordingly. We could potentially copy code performed by
// this check into this file if our above code is yielding too
// many false positives.
Components.utils.import("resource://services-sync/main.js");
if (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED) {
this.ensureLoaded();
}
}.bind(this)
}, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
break;
case 'fxaccounts:onverified':
// Tell sync that if this is a first sync, it should try and sync the
// server data with what is on the client - despite the name implying
// otherwise, this is what "resetClient" does.
// TOOD: This implicitly assumes we're in the CLIENT_NOT_CONFIGURED state, and
// if we're not, we should handle it here.
Components.utils.import("resource://services-sync/main.js"); // ensure 'Weave' exists
Weave.Svc.Prefs.set("firstSync", "resetClient");
this.maybeInitWithFxAccountsAndEnsureLoaded().then(() => {
// and off we go...
// TODO: I have this being done in maybeInitWithFxAccountsAndEnsureLoaded
// because I had a bug in the promise chains that was triggering this
// too early. This should be fixed.
//Weave.Utils.nextTick(Weave.Service.sync, Weave.Service);
});
break;
case 'fxaccounts:onlogout':
Components.utils.import("resource://services-sync/main.js"); // ensure 'Weave' exists
// startOver is throwing some errors and we can't re-log in in this
// session - so for now, we don't do this!
//Weave.Service.startOver();
break;
}
}
};

Просмотреть файл

@ -150,7 +150,10 @@ this.configureIdentity = function(identityOverrides) {
if (ns.Service.identity instanceof BrowserIDManager) {
// do the FxAccounts thang...
configureFxAccountIdentity(ns.Service.identity, config);
return ns.Service.identity.initWithLoggedInUser();
return ns.Service.identity.initializeWithCurrentIdentity().then(() => {
// need to wait until this identity manager is readyToAuthenticate.
return ns.Service.identity.whenReadyToAuthenticate.promise;
});
}
// old style identity provider.
setBasicCredentials(config.username, config.sync.password, config.sync.syncKey);
@ -172,7 +175,9 @@ this.SyncTestingInfrastructure = function (server, username, password, syncKey)
config.sync.password = password;
if (syncKey)
config.sync.syncKey = syncKey;
configureIdentity(config);
let cb = Async.makeSpinningCallback();
configureIdentity(config).then(cb, cb);
cb.wait();
let i = server.identity;
let uri = i.primaryScheme + "://" + i.primaryHost + ":" +
@ -224,16 +229,16 @@ this.add_identity_test = function(test, testFunction) {
test.add_task(function() {
note("sync");
let oldIdentity = Status._authManager;
Status._authManager = ns.Service.identity = new IdentityManager();
Status.__authManager = ns.Service.identity = new IdentityManager();
yield testFunction();
Status._authManager = ns.Service.identity = oldIdentity;
Status.__authManager = ns.Service.identity = oldIdentity;
});
// another task for the FxAccounts identity manager.
test.add_task(function() {
note("FxAccounts");
let oldIdentity = Status._authManager;
Status._authManager = ns.Service.identity = new BrowserIDManager();
Status.__authManager = ns.Service.identity = new BrowserIDManager();
yield testFunction();
Status._authManager = ns.Service.identity = oldIdentity;
Status.__authManager = ns.Service.identity = oldIdentity;
});
}

Просмотреть файл

@ -18,6 +18,7 @@ Cu.import("resource://services-common/tokenserverclient.js");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://services-sync/stages/cluster.js");
// Lazy imports to prevent unnecessary load on startup.
XPCOMUtils.defineLazyModuleGetter(this, "BulkKeyBundle",
@ -26,6 +27,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "BulkKeyBundle",
XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
"resource://gre/modules/FxAccounts.jsm");
XPCOMUtils.defineLazyGetter(this, 'fxAccountsCommon', function() {
let ob = {};
Cu.import("resource://gre/modules/FxAccountsCommon.js", ob);
return ob;
});
function deriveKeyBundle(kB) {
let out = CryptoUtils.hkdf(kB, undefined,
"identity.mozilla.com/picl/v1/oldsync", 2*32);
@ -39,6 +46,8 @@ function deriveKeyBundle(kB) {
this.BrowserIDManager = function BrowserIDManager() {
this._fxaService = fxAccounts;
this._tokenServerClient = new TokenServerClient();
// will be a promise that resolves when we are ready to authenticate
this.whenReadyToAuthenticate = null;
this._log = Log.repository.getLogger("Sync.BrowserIDManager");
this._log.Level = Log.Level[Svc.Prefs.get("log.logger.identity")];
@ -53,6 +62,107 @@ this.BrowserIDManager.prototype = {
_token: null,
_account: null,
// it takes some time to fetch a sync key bundle, so until this flag is set,
// we don't consider the lack of a keybundle as a failure state.
_shouldHaveSyncKeyBundle: false,
get readyToAuthenticate() {
// We are finished initializing when we *should* have a sync key bundle,
// although we might not actually have one due to auth failures etc.
return this._shouldHaveSyncKeyBundle;
},
get needsCustomization() {
try {
return Services.prefs.getBoolPref("services.sync.needsCustomization");
} catch (e) {
return false;
}
},
initialize: function() {
Services.obs.addObserver(this, fxAccountsCommon.ONVERIFIED_NOTIFICATION, false);
Services.obs.addObserver(this, fxAccountsCommon.ONLOGOUT_NOTIFICATION, false);
return this.initializeWithCurrentIdentity();
},
initializeWithCurrentIdentity: function() {
this._log.trace("initializeWithCurrentIdentity");
Components.utils.import("resource://services-sync/main.js");
// Reset the world before we do anything async.
this.whenReadyToAuthenticate = Promise.defer();
this._shouldHaveSyncKeyBundle = false;
this.username = ""; // this calls resetCredentials which drops the key bundle.
return fxAccounts.getSignedInUser().then(accountData => {
if (!accountData) {
this._log.info("initializeWithCurrentIdentity has no user logged in");
this._account = null;
return;
}
if (this.needsCustomization) {
// If the user chose to "Customize sync options" when signing
// up with Firefox Accounts, ask them to choose what to sync.
const url = "chrome://browser/content/sync/customize.xul";
const features = "centerscreen,chrome,modal,dialog,resizable=no";
let win = Services.wm.getMostRecentWindow("navigator:browser");
let data = {accepted: false};
win.openDialog(url, "_blank", features, data);
if (data.accepted) {
Services.prefs.clearUserPref("services.sync.needsCustomization");
} else {
// Log out if the user canceled the dialog.
return fxAccounts.signOut();
}
}
this._account = accountData.email;
// We start a background keybundle fetch...
this._log.info("Starting background fetch for key bundle.");
this._fetchSyncKeyBundle().then(() => {
this._shouldHaveSyncKeyBundle = true; // and we should actually have one...
this.whenReadyToAuthenticate.resolve();
this._log.info("Background fetch for key bundle done");
}).then(null, err => {
this._shouldHaveSyncKeyBundle = true; // but we probably don't have one...
this.whenReadyToAuthenticate.reject(err);
// report what failed...
this._log.error("Background fetch for key bundle failed: " + err);
throw err;
});
// and we are done - the fetch continues on in the background...
}).then(null, err => {
dump("err in processing logged in account "+err.message);
});
},
observe: function (subject, topic, data) {
switch (topic) {
case fxAccountsCommon.ONVERIFIED_NOTIFICATION:
case fxAccountsCommon.ONLOGIN_NOTIFICATION:
// For now, we just assume it's the same user logging back in.
// Bug 958927 exists to work out what to do if that's not true. It might
// be that the :onlogout observer does a .startOver (or maybe not - TBD)
// But for now, do nothing, and sync will just start re-synching in its
// own sweet time...
this.initializeWithCurrentIdentity();
break;
case fxAccountsCommon.ONLOGOUT_NOTIFICATION:
Components.utils.import("resource://services-sync/main.js");
// Setting .username calls resetCredentials which drops the key bundle
// and resets _shouldHaveSyncKeyBundle.
this.username = "";
this._account = null;
Weave.Service.logout();
break;
}
},
/**
* Provide override point for testing token expiration.
*/
@ -60,8 +170,6 @@ this.BrowserIDManager.prototype = {
return Date.now();
},
clusterURL: null,
get account() {
return this._account;
},
@ -148,6 +256,7 @@ this.BrowserIDManager.prototype = {
this._syncKey = null;
this._syncKeyBundle = null;
this._syncKeyUpdated = true;
this._shouldHaveSyncKeyBundle = false;
},
/**
@ -166,8 +275,8 @@ this.BrowserIDManager.prototype = {
// No need to check this.syncKey as our getter for that attribute
// uses this.syncKeyBundle
// If bundle creation failed.
if (!this.syncKeyBundle) {
// If bundle creation started, but failed.
if (this._shouldHaveSyncKeyBundle && !this.syncKeyBundle) {
return LOGIN_FAILED_NO_PASSPHRASE;
}
@ -221,45 +330,24 @@ this.BrowserIDManager.prototype = {
return userData;
},
// initWithLoggedInUser will fetch the logged in user from firefox accounts,
// and if such a logged in user exists, will use that user to initialize
// the identity module. Returns a Promise.
initWithLoggedInUser: function() {
// Get the signed in user from FxAccounts.
return this._fxaService.getSignedInUser()
.then(userData => {
if (!userData) {
this._log.warn("initWithLoggedInUser found no logged in user");
throw new Error("initWithLoggedInUser found no logged in user");
}
// Make a note of the last logged in user.
this._account = userData.email;
// Fetch a sync token for the logged in user from the token server.
return this._refreshTokenForLoggedInUser();
})
.then(token => {
this._token = token;
// Set the username to be the uid returned by the token server.
// TODO: check here to see if the uid is different that the current
// this.username. If so, we may need to reinit sync, detect if the new
// user has sync set up, etc
this.username = this._token.uid.toString();
return this._fxaService.getKeys();
})
.then(userData => {
// both Jelly and FxAccounts give us kA/kB as hex.
let kB = Utils.hexToBytes(userData.kB);
this._syncKeyBundle = deriveKeyBundle(kB);
// Set the clusterURI for this user based on the endpoint in the
// token. This is a bit of a hack, and we should figure out a better
// way of distributing it to components that need it.
let clusterURI = Services.io.newURI(this._token.endpoint, null, null);
clusterURI.path = "/";
this.clusterURL = clusterURI.spec;
this._log.info("initWithLoggedUser has username " + this.username + ", endpoint is " + this.clusterURL);
});
_fetchSyncKeyBundle: function() {
// Fetch a sync token for the logged in user from the token server.
return this._refreshTokenForLoggedInUser(
).then(token => {
this._token = token;
return this._fxaService.getKeys();
}).then(userData => {
// unlikely, but if the logged in user somehow changed between these
// calls we better fail.
if (!userData || userData.email !== this.account) {
throw new Error("The currently logged-in user has changed.");
}
// Set the username to be the uid returned by the token server.
this.username = this._token.uid.toString();
// both Jelly and FxAccounts give us kA/kB as hex.
let kB = Utils.hexToBytes(userData.kB);
this._syncKeyBundle = deriveKeyBundle(kB);
});
},
// Refresh the sync token for the currently logged in Firefox Accounts user.
@ -368,5 +456,45 @@ this.BrowserIDManager.prototype = {
}
request.setHeader("authorization", header.headers.authorization);
return request;
},
createClusterManager: function(service) {
return new BrowserIDClusterManager(service);
}
};
/* An implementation of the ClusterManager for this identity
*/
function BrowserIDClusterManager(service) {
ClusterManager.call(this, service);
}
BrowserIDClusterManager.prototype = {
__proto__: ClusterManager.prototype,
_findCluster: function() {
let promiseClusterURL = function() {
return fxAccounts.getSignedInUser().then(userData => {
return this.identity._fetchTokenForUser(userData).then(token => {
// Set the clusterURI for this user based on the endpoint in the
// token. This is a bit of a hack, and we should figure out a better
// way of distributing it to components that need it.
let clusterURI = Services.io.newURI(token.endpoint, null, null);
clusterURI.path = "/";
return clusterURI.spec;
});
});
}.bind(this);
let cb = Async.makeSpinningCallback();
promiseClusterURL().then(function (clusterURL) {
cb(null, clusterURL);
},
function (err) {
cb(err);
});
return cb.wait();
},
}

Просмотреть файл

@ -119,6 +119,7 @@ LOGIN_FAILED_NETWORK_ERROR: "error.login.reason.network",
LOGIN_FAILED_SERVER_ERROR: "error.login.reason.server",
LOGIN_FAILED_INVALID_PASSPHRASE: "error.login.reason.recoverykey",
LOGIN_FAILED_LOGIN_REJECTED: "error.login.reason.account",
LOGIN_FAILED_NOT_READY: "error.login.reason.initializing",
// sync failure status codes
METARECORD_DOWNLOAD_FAIL: "error.sync.reason.metarecord_download_fail",

Просмотреть файл

@ -9,6 +9,7 @@ this.EXPORTED_SYMBOLS = ["IdentityManager"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://services-sync/util.js");
@ -21,7 +22,8 @@ for (let symbol of ["BulkKeyBundle", "SyncKeyBundle"]) {
}
/**
* Manages identity and authentication for Sync.
* Manages "legacy" identity and authentication for Sync.
* See browserid_identity for the Firefox Accounts based identity manager.
*
* The following entities are managed:
*
@ -81,6 +83,24 @@ IdentityManager.prototype = {
_syncKeyBundle: null,
/**
* Initialize the identity provider. Returns a promise that is resolved
* when initialization is complete and the provider can be queried for
* its state
*/
initialize: function() {
// nothing to do for this identity provider
return Promise.resolve();
},
/**
* Indicates if the identity manager is still initializing
*/
get readyToAuthenticate() {
// We initialize in a fully sync manner, so we are always finished.
return true;
},
get account() {
return Svc.Prefs.get("account", this.username);
},
@ -505,5 +525,10 @@ IdentityManager.prototype = {
onRESTRequestBasic: function onRESTRequestBasic(request) {
let up = this.username + ":" + this.basicPassword;
request.setHeader("authorization", "Basic " + btoa(up));
},
createClusterManager: function(service) {
Cu.import("resource://services-sync/stages/cluster.js");
return new ClusterManager(service);
}
};

Просмотреть файл

@ -12,9 +12,11 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/engines.js");
Cu.import("resource://services-sync/status.js");
Cu.import("resource://services-sync/util.js");
XPCOMUtils.defineLazyModuleGetter(this, "Status",
"resource://services-sync/status.js");
this.SyncScheduler = function SyncScheduler(service) {
this.service = service;
this.init();

Просмотреть файл

@ -30,7 +30,6 @@ Cu.import("resource://services-sync/policies.js");
Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/resource.js");
Cu.import("resource://services-sync/rest.js");
Cu.import("resource://services-sync/stages/cluster.js");
Cu.import("resource://services-sync/stages/enginesync.js");
Cu.import("resource://services-sync/status.js");
Cu.import("resource://services-sync/userapi.js");
@ -323,7 +322,7 @@ Sync11Service.prototype = {
this._log.info("Loading Weave " + WEAVE_VERSION);
this._clusterManager = new ClusterManager(this);
this._clusterManager = this.identity.createClusterManager(this);
this.recordManager = new RecordManager(this);
this.enabled = true;
@ -649,6 +648,13 @@ Sync11Service.prototype = {
},
verifyLogin: function verifyLogin() {
// If the identity isn't ready it might not know the username...
if (!this.identity.readyToAuthenticate) {
this._log.info("Not ready to authenticate in verifyLogin.");
this.status.login = LOGIN_FAILED_NOT_READY;
return false;
}
if (!this.identity.username) {
this._log.warn("No username in verifyLogin.");
this.status.login = LOGIN_FAILED_NO_USERNAME;

Просмотреть файл

@ -12,13 +12,31 @@ const Cu = Components.utils;
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://services-sync/identity.js");
Cu.import("resource://services-sync/browserid_identity.js");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://services-common/async.js");
this.Status = {
_log: Log.repository.getLogger("Sync.Status"),
_authManager: new IdentityManager(),
__authManager: null,
ready: false,
get _authManager() {
if (this.__authManager) {
return this.__authManager;
}
let service = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
let idClass = service.fxAccountsEnabled ? BrowserIDManager : IdentityManager;
this.__authManager = new idClass();
// .initialize returns a promise, so we need to spin until it resolves.
let cb = Async.makeSpinningCallback();
this.__authManager.initialize().then(cb, cb);
cb.wait();
return this.__authManager;
},
get service() {
return this._service;
},

Просмотреть файл

@ -73,3 +73,6 @@ pref("services.sync.log.logger.userapi", "Debug");
pref("services.sync.log.cryptoDebug", false);
pref("services.sync.tokenServerURI", "http://auth.oldsync.dev.lcip.org/1.0/sync/1.1");
pref("services.sync.fxa.termsURL", "https://accounts.firefox.com/legal/terms");
pref("services.sync.fxa.privacyURL", "https://accounts.firefox.com/legal/privacy");

Просмотреть файл

@ -532,6 +532,7 @@ class BaseMarionetteTestRunner(object):
self.shuffle = shuffle
self.sdcard = sdcard
self.mixin_run_tests = []
self.manifest_skipped_tests = []
if testvars:
if not os.path.exists(testvars):
@ -806,22 +807,30 @@ class BaseMarionetteTestRunner(object):
manifest = TestManifest()
manifest.read(filepath)
all_tests = manifest.active_tests(exists=False, disabled=False)
manifest_tests = manifest.active_tests(exists=False,
disabled=False,
disabled=True,
device=self.device,
app=self.appName,
**mozinfo.info)
skip_tests = list(set([x['path'] for x in all_tests]) -
set([x['path'] for x in manifest_tests]))
for skipped in skip_tests:
self.logger.info('TEST-SKIP | %s | device=%s, app=%s' %
(os.path.basename(skipped),
self.device,
self.appName))
unfiltered_tests = []
for test in manifest_tests:
if test.get('disabled'):
self.manifest_skipped_tests.append(test)
else:
unfiltered_tests.append(test)
target_tests = manifest.get(tests=unfiltered_tests, **testargs)
for test in unfiltered_tests:
if test['path'] not in [x['path'] for x in target_tests]:
test.setdefault('disabled', 'filtered by type (%s)' % self.type)
self.manifest_skipped_tests.append(test)
for test in self.manifest_skipped_tests:
self.logger.info('TEST-SKIP | %s | %s' % (
os.path.basename(test['path']),
test['disabled']))
self.todo += 1
target_tests = manifest.get(tests=manifest_tests, **testargs)
if self.shuffle:
random.shuffle(target_tests)
for i in target_tests:
@ -874,17 +883,32 @@ class BaseMarionetteTestRunner(object):
def generate_xml(self, results_list):
def _extract_xml(test, result='passed'):
def _extract_xml_from_result(test_result, result='passed'):
_extract_xml(
test_name=unicode(test_result.name).split()[0],
test_class=test_result.test_class,
duration=test_result.duration,
result=result,
output='\n'.join(test_result.output))
def _extract_xml_from_skipped_manifest_test(test):
_extract_xml(
test_name=test['name'],
result='skipped',
output=test['disabled'])
def _extract_xml(test_name, test_class='', duration=0,
result='passed', output=''):
testcase = doc.createElement('testcase')
testcase.setAttribute('classname', test.test_class)
testcase.setAttribute('name', unicode(test.name).split()[0])
testcase.setAttribute('time', str(test.duration))
testcase.setAttribute('classname', test_class)
testcase.setAttribute('name', test_name)
testcase.setAttribute('time', str(duration))
testsuite.appendChild(testcase)
if result in ['failure', 'error', 'skipped']:
f = doc.createElement(result)
f.setAttribute('message', 'test %s' % result)
f.appendChild(doc.createTextNode(test.reason))
f.appendChild(doc.createTextNode(output))
testcase.appendChild(f)
doc = dom.Document()
@ -905,33 +929,38 @@ class BaseMarionetteTestRunner(object):
for results in results_list])))
testsuite.setAttribute('errors', str(sum([len(results.errors)
for results in results_list])))
testsuite.setAttribute('skips', str(sum([len(results.skipped) +
len(results.expectedFailures)
for results in results_list])))
testsuite.setAttribute(
'skips', str(sum([len(results.skipped) +
len(results.expectedFailures)
for results in results_list]) +
len(self.manifest_skipped_tests)))
for results in results_list:
for result in results.errors:
_extract_xml(result, result='error')
_extract_xml_from_result(result, result='error')
for result in results.failures:
_extract_xml(result, result='failure')
_extract_xml_from_result(result, result='failure')
if hasattr(results, 'unexpectedSuccesses'):
for test in results.unexpectedSuccesses:
# unexpectedSuccesses is a list of Testcases only, no tuples
_extract_xml(test, result='failure')
_extract_xml_from_result(test, result='failure')
if hasattr(results, 'skipped'):
for result in results.skipped:
_extract_xml(result, result='skipped')
_extract_xml_from_result(result, result='skipped')
if hasattr(results, 'expectedFailures'):
for result in results.expectedFailures:
_extract_xml(result, result='skipped')
_extract_xml_from_result(result, result='skipped')
for result in results.tests_passed:
_extract_xml(result)
_extract_xml_from_result(result)
for test in self.manifest_skipped_tests:
_extract_xml_from_skipped_manifest_test(test)
doc.appendChild(testsuite)
return doc.toprettyxml(encoding='utf-8')

Просмотреть файл

@ -44,15 +44,31 @@ class HTMLReportingTestRunnerMixin(object):
tests = sum([results.testsRun for results in results_list])
failures = sum([len(results.failures) for results in results_list])
expected_failures = sum([len(results.expectedFailures) for results in results_list])
skips = sum([len(results.skipped) for results in results_list])
skips = sum([len(results.skipped) for results in results_list]) + len(self.manifest_skipped_tests)
errors = sum([len(results.errors) for results in results_list])
passes = sum([results.passed for results in results_list])
unexpected_passes = sum([len(results.unexpectedSuccesses) for results in results_list])
test_time = self.elapsedtime.total_seconds()
test_logs = []
def _extract_html(test):
def _extract_html_from_result(result):
_extract_html(
result=result.result,
test_name=result.name,
test_class=result.test_class,
debug=result.debug,
output='\n'.join(result.output))
def _extract_html_from_skipped_manifest_test(test):
_extract_html(
result='skipped',
test_name=test['name'],
output=test.get('disabled'))
def _extract_html(result, test_name, test_class='', duration=0,
debug=None, output=''):
additional_html = []
debug = debug or {}
links_html = []
result_map = {
@ -61,13 +77,13 @@ class HTMLReportingTestRunnerMixin(object):
'UNEXPECTED-FAIL': 'failure',
'UNEXPECTED-PASS': 'unexpected pass'}
if test.result in ['SKIPPED', 'UNEXPECTED-FAIL', 'KNOWN-FAIL', 'ERROR']:
if test.debug.get('screenshot'):
screenshot = 'data:image/png;base64,%s' % test.debug['screenshot']
if result.upper() in ['SKIPPED', 'UNEXPECTED-FAIL', 'KNOWN-FAIL', 'ERROR']:
if debug.get('screenshot'):
screenshot = 'data:image/png;base64,%s' % debug['screenshot']
additional_html.append(html.div(
html.a(html.img(src=screenshot), href="#"),
class_='screenshot'))
for name, content in test.debug.items():
for name, content in debug.items():
try:
if 'screenshot' in name:
href = '#'
@ -86,7 +102,7 @@ class HTMLReportingTestRunnerMixin(object):
pass
log = html.div(class_='log')
for line in '\n'.join(test.output).splitlines():
for line in output.splitlines():
separator = line.startswith(' ' * 10)
if separator:
log.append(line[:80])
@ -99,16 +115,19 @@ class HTMLReportingTestRunnerMixin(object):
additional_html.append(log)
test_logs.append(html.tr([
html.td(result_map.get(test.result, test.result).title(), class_='col-result'),
html.td(test.test_class, class_='col-class'),
html.td(unicode(test.name), class_='col-name'),
html.td(int(test.duration), class_='col-duration'),
html.td(result_map.get(result, result).title(), class_='col-result'),
html.td(test_class, class_='col-class'),
html.td(test_name, class_='col-name'),
html.td(str(duration), class_='col-duration'),
html.td(links_html, class_='col-links'),
html.td(additional_html, class_='debug')],
class_=result_map.get(test.result, test.result).lower() + ' results-table-row'))
class_=result_map.get(result, result).lower() + ' results-table-row'))
for results in results_list:
[_extract_html(test) for test in results.tests]
[_extract_html_from_result(test) for test in results.tests]
for test in self.manifest_skipped_tests:
_extract_html_from_skipped_manifest_test(test)
generated = datetime.datetime.now()
doc = html.html(

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше