Merge inbound to mozilla-central. a=merge

This commit is contained in:
Csoregi Natalia 2018-08-18 12:46:20 +03:00
commit 3e61ab4489
293 changed files with 6412 additions and 1771 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1433158 - libvpx library update requires a clobber
Bug 1346211 - Modifying ICU data file requires a clobber.

View File

@ -239,7 +239,7 @@ ROLE(TABLE,
ROLE_SYSTEM_TABLE,
ROLE_SYSTEM_TABLE,
"android.widget.GridView",
eNoNameRule)
eNameFromSubtreeIfReqRule)
ROLE(COLUMNHEADER,
"columnheader",

View File

@ -37,6 +37,11 @@
// more own inner text, separated by 1 space.
testName("chkbx", "Flash the screen 5 times");
// Example 4 from section 4.3.1 under 2.F.
// Name from content should include all the child nodes, including
// table cells.
testName("input_with_html_label", "foo bar baz");
SimpleTest.finish();
}
@ -73,5 +78,14 @@
<!-- Label from combined text and subtree -->
<div id="chkbx" role="checkbox" aria-checked="false">Flash the screen
<span role="textbox" aria-multiline="false"> 5 </span> times</div>
<!-- Label with name from content should include table -->
<input id="input_with_html_label" />
<label for="input_with_html_label" id="label">
<div>foo</div>
<table><tr><td>bar</td></tr></table>
<div>baz</div>
</label>
</body>
</html>

View File

@ -1,55 +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/. */
"use strict";
/*
* Handles the validation callback from nsIFormFillController and
* the display of the help panel on invalid elements.
*
* FormSubmitObserver implements the nsIFormSubmitObserver interface
* to get notifications about invalid forms. See HTMLFormElement
* for details.
*/
"use strict";
var EXPORTED_SYMBOLS = ["FormSubmitChild"];
var EXPORTED_SYMBOLS = [ "FormSubmitObserver" ];
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
ChromeUtils.import("resource://gre/modules/BrowserUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
function FormSubmitObserver(aWindow, aTabChildGlobal) {
this.init(aWindow, aTabChildGlobal);
}
class FormSubmitChild extends ActorChild {
constructor(mm) {
super(mm);
FormSubmitObserver.prototype =
{
_validationMessage: "",
_content: null,
_element: null,
/*
* Public apis
*/
init(aWindow, aTabChildGlobal) {
this._content = aWindow;
this._tab = aTabChildGlobal;
this._mm =
this._content.docShell.messageManager;
this._tab.addEventListener("pageshow", this);
this._tab.addEventListener("unload", this);
},
uninit() {
this._content.removeEventListener("pageshow", this);
this._content.removeEventListener("unload", this);
this._mm = null;
this._validationMessage = "";
this._element = null;
this._content = null;
this._tab = null;
},
this.mm.addEventListener("pageshow", this);
}
/*
* Events
@ -57,14 +30,15 @@ FormSubmitObserver.prototype =
handleEvent(aEvent) {
switch (aEvent.type) {
case "MozInvalidForm":
aEvent.preventDefault();
this.notifyInvalidSubmit(aEvent.target, aEvent.detail);
break;
case "pageshow":
if (this._isRootDocumentEvent(aEvent)) {
this._hidePopup();
}
break;
case "unload":
this.uninit();
break;
case "input":
this._onInput(aEvent);
break;
@ -72,26 +46,18 @@ FormSubmitObserver.prototype =
this._onBlur(aEvent);
break;
}
},
}
/*
* nsIFormSubmitObserver
*/
notifyInvalidSubmit(aFormElement, aInvalidElements) {
// We are going to handle invalid form submission attempt by focusing the
// first invalid element and show the corresponding validation message in a
// panel attached to the element.
if (!aInvalidElements.length) {
return;
}
// Show a validation message on the first focusable element.
for (let i = 0; i < aInvalidElements.length; i++) {
for (let element of aInvalidElements) {
// Insure that this is the FormSubmitObserver associated with the
// element / window this notification is about.
let element = aInvalidElements.queryElementAt(i, Ci.nsISupports);
if (this._content != element.ownerGlobal.top.document.defaultView) {
if (this.content != element.ownerGlobal.top.document.defaultView) {
return;
}
@ -128,7 +94,7 @@ FormSubmitObserver.prototype =
this._showPopup(element);
break;
}
},
}
/*
* Internal
@ -154,7 +120,7 @@ FormSubmitObserver.prototype =
this._validationMessage = element.validationMessage;
this._showPopup(element);
}
},
}
/*
* Blur event handler in which we disconnect from the form element and
@ -165,7 +131,7 @@ FormSubmitObserver.prototype =
aEvent.originalTarget.removeEventListener("blur", this);
this._element = null;
this._hidePopup();
},
}
/*
* Send the show popup message to chrome with appropriate position
@ -197,25 +163,23 @@ FormSubmitObserver.prototype =
} else {
offset = parseInt(style.paddingLeft) + parseInt(style.borderLeftWidth);
}
let zoomFactor = this._content.windowUtils.fullZoom;
let zoomFactor = this.content.windowUtils.fullZoom;
panelData.offset = Math.round(offset * zoomFactor);
panelData.position = "after_start";
}
this._mm.sendAsyncMessage("FormValidation:ShowPopup", panelData);
},
this.mm.sendAsyncMessage("FormValidation:ShowPopup", panelData);
}
_hidePopup() {
this._mm.sendAsyncMessage("FormValidation:HidePopup", {});
},
this.mm.sendAsyncMessage("FormValidation:HidePopup", {});
}
_isRootDocumentEvent(aEvent) {
if (this._content == null) {
if (this.content == null) {
return true;
}
let target = aEvent.originalTarget;
return (target == this._content.document ||
(target.ownerDocument && target.ownerDocument == this._content.document));
},
QueryInterface: ChromeUtils.generateQI([Ci.nsIFormSubmitObserver, Ci.nsISupportsWeakReference])
};
return (target == this.content.document ||
(target.ownerDocument && target.ownerDocument == this.content.document));
}
}

View File

@ -0,0 +1,72 @@
/* 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 EXPORTED_SYMBOLS = ["LightweightThemeChild"];
ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
/**
* LightweightThemeChild forwards theme data to in-content pages.
*/
class LightweightThemeChild extends ActorChild {
constructor(mm) {
super(mm);
this.init();
}
/**
* Initializes the actor for the current page, sending it any existing
* theme data, and adding shared data change listeners so it can
* notify the page of future updates.
*
* This is called when the actor is constructed, and any time
* ActorManagerChild receives a pageshow event for the page we're
* attached to.
*/
init() {
Services.cpmm.sharedData.addEventListener("change", this);
this.update(this.mm.chromeOuterWindowID, this.content);
}
/**
* Cleans up any global listeners registered by the actor.
*
* This is called by ActorManagerChild any time it receives a pagehide
* event for the page we're attached to.
*/
cleanup() {
Services.cpmm.sharedData.removeEventListener("change", this);
}
/**
* Handles "change" events on the child sharedData map, and notifies
* our content page if its theme data was among the changed keys.
*/
handleEvent(event) {
if (event.type === "change") {
if (event.changedKeys.includes(`theme/${this.mm.chromeOuterWindowID}`)) {
this.update(this.mm.chromeOuterWindowID, this.content);
}
}
}
/**
* Forward the theme data to the page.
* @param {Object} outerWindowID The outerWindowID the parent process window has.
* @param {Object} content The receiving global
*/
update(outerWindowID, content) {
const event = Cu.cloneInto({
detail: {
data: Services.cpmm.sharedData.get(`theme/${outerWindowID}`)
},
}, content);
content.dispatchEvent(new content.CustomEvent("LightweightTheme:Set",
event));
}
}

View File

@ -42,8 +42,8 @@ class PluginChild extends ActorChild {
// Cache of plugin crash information sent from the parent
this.pluginCrashData = new Map();
this.mm.addEventListener("pagehide", this, true);
this.mm.addEventListener("pageshow", this, true);
this.mm.addEventListener("pagehide", this, {capture: true, mozSystemGroup: true});
this.mm.addEventListener("pageshow", this, {capture: true, mozSystemGroup: true});
}
receiveMessage(msg) {

View File

@ -7,6 +7,9 @@
with Files("**"):
BUG_COMPONENT = ("Firefox", "General")
with Files("LightweightThemeChild.jsm"):
BUG_COMPONENT = ("WebExtensions", "Themes")
with Files("LightWeightThemeInstallChild.jsm"):
BUG_COMPONENT = ("Firefox", "Theme")
@ -30,6 +33,8 @@ FINAL_TARGET_FILES.actors += [
'ContentSearchChild.jsm',
'ContextMenuChild.jsm',
'DOMFullscreenChild.jsm',
'FormSubmitChild.jsm',
'LightweightThemeChild.jsm',
'LightWeightThemeInstallChild.jsm',
'LinkHandlerChild.jsm',
'NetErrorChild.jsm',

View File

@ -10,7 +10,6 @@
/* eslint no-unused-vars: ["error", {args: "none"}] */
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
// TabChildGlobal
var global = this;
@ -19,7 +18,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ContentMetaHandler: "resource:///modules/ContentMetaHandler.jsm",
LoginFormFactory: "resource://gre/modules/LoginManagerContent.jsm",
InsecurePasswordUtils: "resource://gre/modules/InsecurePasswordUtils.jsm",
FormSubmitObserver: "resource:///modules/FormSubmitObserver.jsm",
ContextMenuChild: "resource:///actors/ContextMenuChild.jsm",
});
@ -30,15 +28,6 @@ XPCOMUtils.defineLazyGetter(this, "LoginManagerContent", () => {
return tmp.LoginManagerContent;
});
XPCOMUtils.defineLazyProxy(this, "formSubmitObserver", () => {
return new FormSubmitObserver(content, this);
}, {
// stub QI
QueryInterface: ChromeUtils.generateQI([Ci.nsIFormSubmitObserver, Ci.nsISupportsWeakReference])
});
Services.obs.addObserver(formSubmitObserver, "invalidformsubmit", true);
// NOTE: Much of this logic is duplicated in BrowserCLH.js for Android.
addMessageListener("RemoteLogins:fillForm", function(message) {
// intercept if ContextMenu.jsm had sent a plain object for remote targets

View File

@ -22,22 +22,6 @@ ActorManagerChild.attach(this, "browsers");
// TabChildGlobal
var global = this;
XPCOMUtils.defineLazyProxy(this, "LightweightThemeChildHelper",
"resource:///modules/LightweightThemeChildHelper.jsm");
let themeablePagesWhitelist = new Set([
"about:home",
"about:newtab",
"about:welcome",
]);
addEventListener("pageshow", function({ originalTarget }) {
if (originalTarget.defaultView == content && themeablePagesWhitelist.has(content.document.documentURI)) {
LightweightThemeChildHelper.listen(themeablePagesWhitelist);
LightweightThemeChildHelper.update(chromeOuterWindowID, content);
}
}, false, true);
// Keep a reference to the translation content handler to avoid it it being GC'ed.
var trHandler = null;
if (Services.prefs.getBoolPref("browser.translation.detectLanguage")) {

View File

@ -39,7 +39,7 @@ support-files =
file_bug1045809_1.html
file_bug1045809_2.html
[browser_csp_block_all_mixedcontent.js]
skip-if = (verify && debug && (os == 'mac'))
skip-if = (verify && debug && (os == 'mac')) || (os == 'linux') || (os == 'mac') # Bug 1438402
tags = mcb
support-files =
file_csp_block_all_mixedcontent.html

View File

@ -19,8 +19,8 @@ let ACTORS = {
events: {
"AboutReaderContentLoaded": {wantUntrusted: true},
"DOMContentLoaded": {},
"pageshow": {},
"pagehide": {},
"pageshow": {mozSystemGroup: true},
"pagehide": {mozSystemGroup: true},
},
messages: [
"Reader:ToggleReaderMode",
@ -120,6 +120,15 @@ let ACTORS = {
},
},
FormSubmit: {
child: {
module: "resource:///actors/FormSubmitChild.jsm",
events: {
"MozInvalidForm": {},
},
},
},
LightWeightThemeInstall: {
child: {
module: "resource:///actors/LightWeightThemeInstallChild.jsm",
@ -131,6 +140,16 @@ let ACTORS = {
},
},
LightweightTheme: {
child: {
module: "resource:///actors/LightweightThemeChild.jsm",
matches: ["about:home", "about:newtab", "about:welcome"],
events: {
"pageshow": {mozSystemGroup: true},
},
},
},
LinkHandler: {
child: {
module: "resource:///actors/LinkHandlerChild.jsm",

View File

@ -109,7 +109,7 @@ export default class AddressForm extends PaymentStateSubscriberMixin(PaymentRequ
}
render(state) {
let record = {};
let record;
let {
page,
"address-page": addressPage,
@ -286,7 +286,6 @@ export default class AddressForm extends PaymentStateSubscriberMixin(PaymentRequ
updateSaveButtonState() {
this.saveButton.disabled = !this.form.checkValidity();
log.debug("updateSaveButtonState", this.saveButton.disabled);
}
async saveRecord() {

View File

@ -188,6 +188,9 @@ export default class BasicCardForm extends PaymentStateSubscriberMixin(PaymentRe
billingAddressSelect.value = Object.keys(addresses)[0];
}
}
// Need to recalculate the populated state since
// billingAddressSelect is updated after loadRecord.
this.formHandler.updatePopulatedState(billingAddressSelect);
this.updateRequiredState();
this.updateSaveButtonState();

View File

@ -1,8 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
div[required] > label > span:first-of-type::after,
:-moz-any(label, div)[required] > span:first-of-type::after {
content: attr(fieldRequiredSymbol);
}

View File

@ -204,19 +204,13 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
}
// Ensure `selectedShippingOption` never refers to a deleted shipping option and
// refers to a shipping option if one exists.
// matches the merchant's selected option if the user hasn't made a choice.
if (shippingOptions && (!selectedShippingOption ||
!shippingOptions.find(option => option.id == selectedShippingOption))) {
// Use the DOM's computed selected shipping option:
selectedShippingOption = state.request.shippingOption;
// Otherwise, default to selecting the first option:
if (!selectedShippingOption && shippingOptions.length) {
selectedShippingOption = shippingOptions[0].id;
}
this._cachedState.selectedShippingOption = selectedShippingOption;
this.requestStore.setState({
selectedShippingOption,
// Use the DOM's computed selected shipping option:
selectedShippingOption: state.request.shippingOption,
});
}

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
html {
:root {
height: 100%;
}
@ -159,7 +159,7 @@ payment-dialog[changes-prevented][complete-status="success"] #pay {
}
#cancel {
margin-left: auto;
margin-inline-start: auto;
}
#disabled-overlay {

View File

@ -84,13 +84,16 @@
<meta http-equiv="Content-Security-Policy" content="default-src 'self' chrome:"/>
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css"/>
<link rel="stylesheet" href="resource://formautofill/editDialog-shared.css"/>
<link rel="stylesheet" href="resource://formautofill/editAddress.css"/>
<link rel="stylesheet" href="resource://formautofill/editCreditCard.css"/>
<link rel="stylesheet" href="resource://formautofill/editDialog.css"/>
<link rel="stylesheet" href="paymentRequest.css"/>
<link rel="stylesheet" href="components/rich-select.css"/>
<link rel="stylesheet" href="components/address-option.css"/>
<link rel="stylesheet" href="components/basic-card-option.css"/>
<link rel="stylesheet" href="components/shipping-option.css"/>
<link rel="stylesheet" href="components/payment-details-item.css"/>
<link rel="stylesheet" href="containers/form.css"/>
<link rel="stylesheet" href="containers/address-form.css"/>
<link rel="stylesheet" href="containers/basic-card-form.css"/>
<link rel="stylesheet" href="containers/order-details.css"/>

View File

@ -112,14 +112,21 @@ var PaymentTestUtils = {
let popupBox = Cu.waiveXrays(picker).dropdown.popupBox;
let selectedOptionIndex = popupBox.selectedIndex;
let selectedOption = Cu.waiveXrays(picker).dropdown.selectedOption;
return {
let result = {
optionCount: popupBox.children.length,
selectedOptionIndex,
};
if (!selectedOption) {
return result;
}
return Object.assign(result, {
selectedOptionID: selectedOption.getAttribute("value"),
selectedOptionLabel: selectedOption.getAttribute("label"),
selectedOptionCurrency: selectedOption.getAttribute("amount-currency"),
selectedOptionValue: selectedOption.getAttribute("amount-value"),
};
});
},
getShippingAddresses: () => {

View File

@ -145,10 +145,9 @@ add_task(async function test_default_shippingOptions_noneSelected() {
);
let shippingOptions =
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getShippingOptions);
is(shippingOptions.selectedOptionCurrency, "USD", "Shipping options should be in USD");
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getShippingOptions);
is(shippingOptions.optionCount, 2, "there should be two shipping options");
is(shippingOptions.selectedOptionID, "1", "default selected should be the first");
is(shippingOptions.selectedOptionIndex, "-1", "no options should be selected");
let shippingOptionDetailsEUR = deepClone(PTU.Details.twoShippingOptionsEUR);
info("prepare EUR options by deselecting all and giving unique IDs");
@ -157,6 +156,8 @@ add_task(async function test_default_shippingOptions_noneSelected() {
opt.id += "-EUR";
});
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.selectShippingOptionById, "1");
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
details: Object.assign(shippingOptionDetailsEUR, PTU.Details.total1pt75EUR),
@ -173,10 +174,8 @@ add_task(async function test_default_shippingOptions_noneSelected() {
shippingOptions =
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getShippingOptions);
is(shippingOptions.selectedOptionCurrency, "EUR", "Shipping options should be in EUR");
is(shippingOptions.optionCount, 2, "there should be two shipping options");
is(shippingOptions.selectedOptionID, "1-EUR",
"default selected should be the first");
is(shippingOptions.selectedOptionIndex, "-1", "no options should be selected again");
spawnPaymentDialogTask(frame, PTU.DialogContentTasks.manuallyClickCancel);
await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");

View File

@ -31,6 +31,8 @@ add_task(async function test_dropdown() {
await PTU.DialogContentUtils.waitForState(content, (state) => {
return state.page.id == "address-page" && !state.page.guid;
}, "Check add page state");
content.document.querySelector("#country").scrollIntoView();
});
info("going to open the country <select>");

View File

@ -276,8 +276,8 @@ async function setupPaymentDialog(browser, {methodData, details, options, mercha
return;
}
field.value = value;
field.dispatchEvent(new content.window.Event("input"));
field.dispatchEvent(new content.window.Event("change"));
field.dispatchEvent(new content.window.Event("input", {bubbles: true}));
field.dispatchEvent(new content.window.Event("change", {bubbles: true}));
return;
}
while (field.value) {

View File

@ -5,6 +5,7 @@ support-files =
!/browser/extensions/formautofill/content/editAddress.xhtml
!/browser/extensions/formautofill/content/editCreditCard.xhtml
../../../../../browser/extensions/formautofill/content/autofillEditForms.js
../../../../../browser/extensions/formautofill/skin/shared/editDialog-shared.css
../../../../../testing/modules/sinon-2.3.2.js
../../res/**
payments_common.js

View File

@ -61,8 +61,8 @@ async function fillField(field, value) {
return;
}
field.value = value;
field.dispatchEvent(new Event("input"));
field.dispatchEvent(new Event("change"));
field.dispatchEvent(new Event("input", {bubbles: true}));
field.dispatchEvent(new Event("change", {bubbles: true}));
return;
}
while (field.value) {

View File

@ -17,7 +17,7 @@ Test the address-form element
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../../res/paymentRequest.css"/>
<link rel="stylesheet" type="text/css" href="../../res/containers/form.css"/>
<link rel="stylesheet" type="text/css" href="editDialog-shared.css"/>
<link rel="stylesheet" type="text/css" href="../../res/containers/address-form.css"/>
</head>
<body>
@ -72,6 +72,11 @@ add_task(async function test_initialState() {
display.appendChild(form);
await asyncElementRendered();
is(page.id, "payment-summary", "Check initial page after appending");
// :-moz-ui-invalid, unlike :invalid, only applies to fields showing the error outline.
let fieldsVisiblyInvalid = form.querySelectorAll(":-moz-ui-invalid");
is(fieldsVisiblyInvalid.length, 0, "Check no fields are visibly invalid on an empty 'add' form");
form.remove();
});
@ -117,10 +122,9 @@ add_task(async function test_saveButton() {
fillField(form.form.querySelector("#organization"), "Allizom");
fillField(form.form.querySelector("#street-address"), "404 Internet Super Highway");
fillField(form.form.querySelector("#address-level2"), "Firefoxity City");
fillField(form.form.querySelector("#country"), "US");
fillField(form.form.querySelector("#address-level1"), "CA");
fillField(form.form.querySelector("#postal-code"), "00001");
fillField(form.form.querySelector("#country"), "US");
fillField(form.form.querySelector("#email"), "test@example.com");
fillField(form.form.querySelector("#tel"), "+15555551212");
ok(!form.saveButton.disabled, "Save button is enabled after filling");
@ -128,8 +132,13 @@ add_task(async function test_saveButton() {
info("blanking the street-address");
fillField(form.form.querySelector("#street-address"), "");
ok(form.saveButton.disabled, "Save button is disabled after blanking street-address");
form.form.querySelector("#street-address").blur();
let fieldsVisiblyInvalid = form.querySelectorAll(":-moz-ui-invalid");
is(fieldsVisiblyInvalid.length, 1, "Check 1 field visibly invalid after blanking and blur");
is(fieldsVisiblyInvalid[0].id, "street-address", "Check #street-address is visibly invalid");
fillField(form.form.querySelector("#street-address"), "404 Internet Super Highway");
is(form.querySelectorAll(":-moz-ui-invalid").length, 0, "Check no fields visibly invalid");
ok(!form.saveButton.disabled, "Save button is enabled after re-filling street-address");
let messagePromise = promiseContentToChromeMessage("updateAutofillRecord");
@ -200,6 +209,8 @@ add_task(async function test_edit() {
},
});
await asyncElementRendered();
is(form.querySelectorAll(":-moz-ui-invalid").length, 0,
"Check no fields are visibly invalid on an 'edit' form with a complete address");
checkAddressForm(form, address1);
ok(!form.saveButton.disabled, "Save button should be enabled upon edit for a valid address");
@ -224,6 +235,10 @@ add_task(async function test_edit() {
is(form.saveButton.textContent, "Update", "Check label");
checkAddressForm(form, minimalAddress);
ok(form.saveButton.disabled, "Save button should be disabled if only the name is filled");
ok(form.querySelectorAll(":-moz-ui-invalid").length > 3,
"Check fields are visibly invalid on an 'edit' form with only the given-name filled");
ok(form.querySelectorAll("#country:-moz-ui-invalid").length, 1,
"Check that the country `select` is marked as invalid");
info("change to no selected address");
await form.requestStore.setState({
@ -233,7 +248,11 @@ add_task(async function test_edit() {
"address-page": {},
});
await asyncElementRendered();
checkAddressForm(form, {});
is(form.querySelectorAll(":-moz-ui-invalid").length, 0,
"Check no fields are visibly invalid on an empty 'add' form after being an edit form");
checkAddressForm(form, {
country: "US",
});
ok(form.saveButton.disabled, "Save button should be disabled for an empty form");
form.remove();
@ -355,7 +374,7 @@ add_task(async function test_field_validation() {
form.remove();
});
add_task(async function test_customValidity() {
add_task(async function test_customMerchantValidity() {
let form = new AddressForm();
await form.promiseReady;
const state = {
@ -406,6 +425,49 @@ add_task(async function test_customValidity() {
form.remove();
});
add_task(async function test_customMerchantValidity_reset() {
let form = new AddressForm();
await form.promiseReady;
const state = {
page: {
id: "address-page",
},
"address-page": {
title: "Sample page title",
},
request: {
paymentDetails: {
shippingAddressErrors: {
addressLine: "Street address needs to start with a D",
city: "City needs to start with a B",
country: "Country needs to start with a C",
organization: "organization needs to start with an A",
phone: "Telephone needs to start with a 9",
postalCode: "Postal code needs to start with a 0",
recipient: "Name needs to start with a Z",
region: "Region needs to start with a Y",
},
},
},
};
await form.requestStore.setState(state);
display.appendChild(form);
await asyncElementRendered();
ok(form.querySelectorAll(":-moz-ui-invalid").length > 0, "Check fields are visibly invalid");
info("merchant cleared the errors");
await form.requestStore.setState({
request: {
paymentDetails: {
shippingAddressErrors: {},
},
},
});
await asyncElementRendered();
is(form.querySelectorAll(":-moz-ui-invalid").length, 0,
"Check fields are visibly valid - custom validity cleared");
});
add_task(async function test_field_validation() {
sinon.stub(PaymentDialogUtils, "getFormFormat").returns({
addressLevel1Label: "state",

View File

@ -122,6 +122,9 @@ add_task(async function test_update() {
ok(options[1].textContent.includes("Mrs. Bar"), "Check that name is the same in second address");
ok(options[1].getAttribute("street-address").includes("P.O. Box 123"),
"Check second address is the same");
ok(options[2].textContent.includes("Mrs. Fields"),
"Check that name is the same in third address");
is(options[2].getAttribute("street-address"), null, "Check third address is missing");
});
add_task(async function test_change_selected_address() {

View File

@ -59,6 +59,11 @@ add_task(async function test_initialState() {
display.appendChild(form);
await asyncElementRendered();
is(page.id, "payment-summary", "Check initial page after appending");
// :-moz-ui-invalid, unlike :invalid, only applies to fields showing the error outline.
let fieldsVisiblyInvalid = form.querySelectorAll(":-moz-ui-invalid");
is(fieldsVisiblyInvalid.length, 0, "Check no fields are visibly invalid on an empty 'add' form");
form.remove();
});
@ -97,21 +102,30 @@ add_task(async function test_saveButton() {
await asyncElementRendered();
ok(form.saveButton.disabled, "Save button should initially be disabled");
form.form.querySelector("#cc-number").focus();
sendString("4111 1111-1111 1111");
fillField(form.form.querySelector("#cc-number"), "4111 1111-1111 1111");
form.form.querySelector("#cc-name").focus();
// Check .disabled after .focus() so that it's after both "input" and "change" events.
ok(form.saveButton.disabled, "Save button should still be disabled without a name");
sendString("J. Smith");
form.form.querySelector("#cc-exp-month").focus();
sendString("11");
form.form.querySelector("#cc-exp-year").focus();
fillField(form.form.querySelector("#cc-exp-month"), "11");
let year = (new Date()).getFullYear().toString();
sendString(year);
fillField(form.form.querySelector("#cc-exp-year"), year);
form.saveButton.focus();
ok(!form.saveButton.disabled,
"Save button should be enabled since the required fields are filled");
info("blanking the cc-number field");
fillField(form.form.querySelector("#cc-number"), "");
ok(form.saveButton.disabled, "Save button is disabled after blanking cc-number");
form.form.querySelector("#cc-number").blur();
let fieldsVisiblyInvalid = form.querySelectorAll(":-moz-ui-invalid");
is(fieldsVisiblyInvalid.length, 1, "Check 1 field visibly invalid after blanking and blur");
is(fieldsVisiblyInvalid[0].id, "cc-number", "Check #cc-number is visibly invalid");
fillField(form.form.querySelector("#cc-number"), "4111 1111-1111 1111");
is(form.querySelectorAll(":-moz-ui-invalid").length, 0, "Check no fields visibly invalid");
ok(!form.saveButton.disabled, "Save button is enabled after re-filling cc-number");
let messagePromise = promiseContentToChromeMessage("updateAutofillRecord");
is(form.saveButton.textContent, "Add", "Check label");
synthesizeMouseAtCenter(form.saveButton, {});
@ -292,7 +306,10 @@ add_task(async function test_edit() {
});
await asyncElementRendered();
is(form.saveButton.textContent, "Update", "Check label");
is(form.querySelectorAll(":-moz-ui-invalid").length, 0,
"Check no fields are visibly invalid on an 'edit' form with a complete card");
checkCCForm(form, card1);
ok(!form.saveButton.disabled, "Save button should be enabled upon edit for a valid card");
let requiredElements = [...form.form.elements].filter(e => e.required && !e.disabled);
ok(requiredElements.length, "There should be at least one required element");
@ -331,6 +348,8 @@ add_task(async function test_edit() {
},
});
await asyncElementRendered();
ok(form.querySelectorAll(":-moz-ui-invalid").length > 0,
"Check fields are visibly invalid on an 'edit' form with missing fields");
checkCCForm(form, minimalCard);
info("change to no selected card");
@ -343,6 +362,8 @@ add_task(async function test_edit() {
},
});
await asyncElementRendered();
is(form.querySelectorAll(":-moz-ui-invalid").length, 0,
"Check no fields are visibly invalid after converting to an 'add' form");
checkCCForm(form, {});
form.remove();
@ -359,15 +380,13 @@ add_task(async function test_field_validity_updates() {
let nameInput = form.form.querySelector("#cc-name");
info("test with valid cc-number but missing cc-name");
ccNumber.focus();
sendString("4111111111111111");
fillField(ccNumber, "4111111111111111");
ok(ccNumber.checkValidity(), "cc-number field is valid with good input");
ok(!nameInput.checkValidity(), "cc-name field is invalid when empty");
ok(form.saveButton.disabled, "Save button should be disabled with incomplete input");
info("correct by adding cc-name value");
nameInput.focus();
sendString("First");
fillField(nameInput, "First");
ok(ccNumber.checkValidity(), "cc-number field is valid with good input");
ok(nameInput.checkValidity(), "cc-name field is valid with a value");
ok(!form.saveButton.disabled, "Save button should not be disabled with good input");
@ -379,6 +398,7 @@ add_task(async function test_field_validity_updates() {
sendString("Surname");
ok(!ccNumber.checkValidity(), "cc-number field becomes invalid with bad input");
ok(form.querySelector("#cc-number:-moz-ui-invalid"), "cc-number field is visibly invalid");
ok(nameInput.checkValidity(), "cc-name field is valid with a value");
ok(form.saveButton.disabled, "Save button becomes disabled with bad input");
@ -394,6 +414,31 @@ add_task(async function test_field_validity_updates() {
form.remove();
});
add_task(async function test_numberCustomValidityReset() {
let form = new BasicCardForm();
form.dataset.updateButtonLabel = "Add";
await form.promiseReady;
display.appendChild(form);
await asyncElementRendered();
fillField(form.querySelector("#cc-number"), "junk");
sendKey("TAB");
ok(form.querySelector("#cc-number:-moz-ui-invalid"), "cc-number field is visibly invalid");
info("simulate triggering an add again to reset the form");
await form.requestStore.setState({
page: {
id: "basic-card-page",
},
"basic-card-page": {
},
});
ok(!form.querySelector("#cc-number:-moz-ui-invalid"), "cc-number field is not visibly invalid");
form.remove();
});
</script>
</body>

View File

@ -22,7 +22,8 @@ add_task(async function test_timezone() {
let dateObj = new Date();
let dateString = dateObj.toString();
ok(dateString.endsWith("(UTC)"), "The date string is in UTC timezone.");
ok(dateString.endsWith("(Coordinated Universal Time)"),
"The date string is in UTC timezone.");
is(dateObj.getFullYear(), dateObj.getUTCFullYear(),
"The full year reports in UTC timezone.");
is(dateObj.getMonth(), dateObj.getUTCMonth(), "The month reports in UTC timezone.");

View File

@ -5,6 +5,7 @@ CARGO="${TOOLTOOL_DIR}/rustc/bin/cargo"
RUSTC="${TOOLTOOL_DIR}/rustc/bin/rustc"
RUSTDOC="${TOOLTOOL_DIR}/rustc/bin/rustdoc"
RUSTFMT="${TOOLTOOL_DIR}/rustc/bin/rustfmt"
CBINDGEN="${TOOLTOOL_DIR}/cbindgen/cbindgen"
export NODEJS="${TOOLTOOL_DIR}/node/bin/node"

View File

@ -6,6 +6,7 @@ RUSTC="${TOOLTOOL_DIR}/rustc/bin/rustc"
CARGO="${TOOLTOOL_DIR}/rustc/bin/cargo"
RUSTDOC="${TOOLTOOL_DIR}/rustc/bin/rustdoc"
RUSTFMT="${TOOLTOOL_DIR}/rustc/bin/rustfmt"
CBINDGEN="${TOOLTOOL_DIR}/cbindgen/cbindgen"
NODEJS="${TOOLTOOL_DIR}/node/node.exe"

View File

@ -18,7 +18,7 @@ const EDIT_ADDRESS_KEYWORDS = [
"state", "province", "city", "country", "zip", "postalCode", "email", "tel",
];
const MANAGE_CREDITCARDS_KEYWORDS = ["manageCreditCardsTitle", "addNewCreditCardTitle", "showCreditCardsBtnLabel"];
const EDIT_CREDITCARD_KEYWORDS = ["cardNumber", "nameOnCard", "cardExpires"];
const EDIT_CREDITCARD_KEYWORDS = ["cardNumber", "nameOnCard", "cardExpiresMonth", "cardExpiresYear"];
const FIELD_STATES = {
NORMAL: "NORMAL",
AUTO_FILLED: "AUTO_FILLED",

View File

@ -19,7 +19,31 @@ class EditAutofillForm {
loadRecord(record = {}) {
for (let field of this._elements.form.elements) {
let value = record[field.id];
field.value = typeof(value) == "undefined" ? "" : value;
value = typeof(value) == "undefined" ? "" : value;
if (record.guid) {
field.value = value;
} else if (field.localName == "select") {
this.setDefaultSelectedOptionByValue(field, value);
} else {
// Use .defaultValue instead of .value to avoid setting the `dirty` flag
// which triggers form validation UI.
field.defaultValue = value;
}
}
if (!record.guid) {
// Reset the dirty value flag and validity state.
this._elements.form.reset();
}
for (let field of this._elements.form.elements) {
this.updatePopulatedState(field);
}
}
setDefaultSelectedOptionByValue(select, value) {
for (let option of select.options) {
option.defaultSelected = option.value == value;
}
}
@ -43,17 +67,26 @@ class EditAutofillForm {
*/
handleEvent(event) {
switch (event.type) {
case "input": {
this.handleInput(event);
break;
}
case "change": {
this.handleChange(event);
break;
}
case "input": {
this.handleInput(event);
break;
}
}
}
/**
* Handle change events
*
* @param {DOMEvent} event
*/
handleChange(event) {
this.updatePopulatedState(event.target);
}
/**
* Handle input events
*
@ -68,8 +101,18 @@ class EditAutofillForm {
this._elements.form.addEventListener("input", this);
}
// An interface to be inherited.
handleChange(event) {}
/**
* Set the field-populated attribute if the field has a value.
*
* @param {DOMElement} field The field that will be checked for a value.
*/
updatePopulatedState(field) {
let span = field.parentNode.querySelector(".label-text");
if (!span) {
return;
}
span.toggleAttribute("field-populated", !!field.value.trim());
}
}
class EditAddress extends EditAutofillForm {
@ -239,11 +282,14 @@ class EditAddress extends EditAutofillForm {
}
handleChange(event) {
this.formatForm(event.target.value);
if (event.target == this._elements.country) {
this.formatForm(event.target.value);
}
super.handleChange(event);
}
attachEventListeners() {
this._elements.country.addEventListener("change", this);
this._elements.form.addEventListener("change", this);
super.attachEventListeners();
}
}
@ -264,6 +310,7 @@ class EditCreditCard extends EditAutofillForm {
Object.assign(this._elements, {
ccNumber: this._elements.form.querySelector("#cc-number"),
invalidCardNumberStringElement: this._elements.form.querySelector("#invalidCardNumberString"),
month: this._elements.form.querySelector("#cc-exp-month"),
year: this._elements.form.querySelector("#cc-exp-year"),
billingAddress: this._elements.form.querySelector("#billingAddressGUID"),
billingAddressRow: this._elements.form.querySelector(".billingAddressRow"),
@ -282,6 +329,11 @@ class EditCreditCard extends EditAutofillForm {
// Re-generating the years will reset the selected option.
this.generateYears();
super.loadRecord(record);
// Resetting the form in the super.loadRecord won't clear custom validity
// state so reset it here. Since the cc-number field is disabled upon editing
// we don't need to recaclulate its validity here.
this._elements.ccNumber.setCustomValidity("");
}
}
@ -330,7 +382,7 @@ class EditCreditCard extends EditAutofillForm {
}
attachEventListeners() {
this._elements.ccNumber.addEventListener("change", this);
this._elements.form.addEventListener("change", this);
super.attachEventListeners();
}

View File

@ -17,45 +17,45 @@
<script src="chrome://formautofill/content/autofillEditForms.js"></script>
</head>
<body dir="&locale.dir;">
<form id="form" autocomplete="off">
<form id="form" class="editAddressForm" autocomplete="off">
<div>
<div id="name-container">
<label id="given-name-container">
<span data-localization="givenName"/>
<span data-localization="givenName" class="label-text"/>
<input id="given-name" type="text" required="required"/>
</label>
<label id="additional-name-container">
<span data-localization="additionalName"/>
<span data-localization="additionalName" class="label-text"/>
<input id="additional-name" type="text"/>
</label>
<label id="family-name-container">
<span data-localization="familyName"/>
<span data-localization="familyName" class="label-text"/>
<input id="family-name" type="text"/>
</label>
</div>
<label id="organization-container">
<span data-localization="organization2"/>
<span data-localization="organization2" class="label-text"/>
<input id="organization" type="text"/>
</label>
<label id="street-address-container">
<span data-localization="streetAddress"/>
<span data-localization="streetAddress" class="label-text"/>
<textarea id="street-address" rows="3" required="required"/>
</label>
<label id="address-level2-container">
<span data-localization="city"/>
<span data-localization="city" class="label-text"/>
<input id="address-level2" type="text" required="required"/>
</label>
<label id="address-level1-container">
<span/>
<span class="label-text"/>
<input id="address-level1" type="text" required="required"/>
</label>
<label id="postal-code-container">
<span/>
<span class="label-text"/>
<input id="postal-code" type="text" required="required"/>
</label>
<div id="country-container">
<label id="country-label">
<span data-localization="country"/>
<span data-localization="country" class="label-text"/>
<select id="country" required="required">
<option/>
</select>
@ -63,11 +63,11 @@
<p id="country-warning-message" data-localization="countryWarningMessage2"/>
</div>
<label id="tel-container">
<span data-localization="tel"/>
<span data-localization="tel" class="label-text"/>
<input id="tel" type="tel"/>
</label>
<label id="email-container">
<span data-localization="email"/>
<span data-localization="email" class="label-text"/>
<input id="email" type="email" required="required"/>
</label>
</div>

View File

@ -17,18 +17,18 @@
<script src="chrome://formautofill/content/autofillEditForms.js"></script>
</head>
<body dir="&locale.dir;">
<form id="form" autocomplete="off">
<form id="form" class="editCreditCardForm" autocomplete="off">
<label>
<span data-localization="cardNumber"/>
<span data-localization="cardNumber" class="label-text"/>
<span id="invalidCardNumberString" hidden="hidden" data-localization="invalidCardNumber"></span>
<input id="cc-number" type="text" required="required" minlength="9" pattern="[- 0-9]+"/>
</label>
<label>
<span data-localization="nameOnCard"/>
<span data-localization="nameOnCard" class="label-text"/>
<input id="cc-name" type="text" required="required"/>
</label>
<div>
<span data-localization="cardExpires"/>
<label>
<span data-localization="cardExpiresMonth" class="label-text"/>
<select id="cc-exp-month">
<option/>
<option value="1">01</option>
@ -44,12 +44,15 @@
<option value="11">11</option>
<option value="12">12</option>
</select>
</label>
<label>
<span data-localization="cardExpiresYear" class="label-text"/>
<select id="cc-exp-year">
<option/>
</select>
</div>
</label>
<label class="billingAddressRow">
<span data-localization="billingAddress"/>
<span data-localization="billingAddress" class="label-text"/>
<select id="billingAddressGUID">
</select>
</label>

View File

@ -138,5 +138,6 @@ editCreditCardTitle = Edit Credit Card
cardNumber = Card Number
invalidCardNumber = Please enter a valid card number
nameOnCard = Name on Card
cardExpires = Expires
cardExpiresMonth = Exp. Month
cardExpiresYear = Exp. Year
billingAddress = Billing Address

View File

@ -3,6 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Linux specific rules */
body {
:root[subdialog] body {
font-size: 0.85rem;
}
}

View File

@ -2,18 +2,9 @@
* 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/. */
html {
width: 620px;
}
label > span {
flex: 0 0 9.5em;
}
input,
select {
.editAddressForm input,
.editAddressForm select {
flex: 1 0 auto;
width: calc(50% - 9.5em);
margin: 0;
}
@ -27,11 +18,16 @@ select {
#organization-container,
#address-level2-container,
#tel-container {
display: flex;
flex: 0 1 50%;
}
#tel-container {
padding-inline-end: 50%;
#given-name-container,
#additional-name-container,
#family-name-container {
display: flex;
margin-left: 0;
margin-right: 0;
}
#name-container,

View File

@ -2,32 +2,28 @@
* 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/. */
html {
width: 500px;
}
form {
.editCreditCardForm {
justify-content: center;
}
form > label,
form > div {
.editCreditCardForm > label,
.editCreditCardForm > div {
flex: 1 0 100%;
align-self: center;
margin: 0 0 0.5em !important;
}
#billingAddressGUID,
input {
.editCreditCardForm #billingAddressGUID,
.editCreditCardForm input {
flex: 1 0 auto;
}
select {
.editCreditCardForm select {
margin: 0;
margin-inline-end: 0.7em;
}
label > span,
div > span {
.editCreditCardForm label > span,
.editCreditCardForm div > span {
flex: 0 0 9.5em;
}

View File

@ -2,53 +2,66 @@
* 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/. */
form,
label,
div,
p {
display: flex;
:root {
--in-field-label-size: .8em;
/* Use the animation-easing-function that is defined in xul.css. */
--animation-easing-function: cubic-bezier(.07,.95,0,1);
}
form,
div {
flex-wrap: wrap;
}
form {
:root[subdialog] form {
/* Add extra space to ensure invalid input box is displayed properly */
padding: 2px;
}
form label,
form > p {
:root[subdialog] form label,
:root[subdialog] form > p {
margin: 0 0 0.5em !important;
}
label > span,
div > span {
box-sizing: border-box;
padding-inline-end: 0.7em;
align-self: center;
text-align: end;
-moz-user-select: none;
form input[type="email"],
form input[type="tel"],
form input[type="text"],
form textarea,
form select {
padding-top: calc(var(--in-field-label-size) + .4em);
}
option {
padding: 0.3em 0.5em;
}
textarea {
resize: none;
}
button {
padding-right: 10px;
padding-left: 10px;
}
input,
select {
box-sizing: border-box;
margin: 0;
padding-bottom: 5px;
}
form :-moz-any(label, div) {
position: relative;
display: block;
line-height: 1em;
margin-left: 0;
margin-right: 0;
}
form :-moz-any(label, div) > .label-text {
position: absolute;
color: GrayText;
pointer-events: none;
left: 10px;
top: .2em;
transition: top .2s var(--animation-easing-function),
font-size .2s var(--animation-easing-function);
}
form :-moz-any(label, div):focus-within > .label-text,
form :-moz-any(label, div) > .label-text[field-populated] {
top: 0;
font-size: var(--in-field-label-size);
}
form :-moz-any(label, div):focus-within > .label-text {
color: var(--in-content-item-selected);
}
form div[required] > label > .label-text::after,
form :-moz-any(label, div)[required] > .label-text::after {
content: attr(fieldRequiredSymbol);
}
#controls-container {

View File

@ -3,10 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* The save button should be on the left and cancel on the right for Windows */
#save {
#controlsContainer > #save {
order: 0;
}
#cancel {
#controlsContainer > #cancel {
order: 1;
}

View File

@ -1,68 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
ChromeUtils.import("resource://gre/modules/Services.jsm");
var EXPORTED_SYMBOLS = ["LightweightThemeChildHelper"];
/**
* LightweightThemeChildHelper forwards theme data to in-content pages.
*/
var LightweightThemeChildHelper = {
listener: null,
whitelist: null,
/**
* Listen to theme updates for the current process
* @param {Array} whitelist The pages that can receive theme updates.
*/
listen(whitelist) {
if (!this.listener) {
// Clone the whitelist to avoid leaking the global the whitelist
// originates from.
this.whitelist = new Set([...whitelist]);
this.listener = ({ changedKeys }) => {
if (changedKeys.find(change => change.startsWith("theme/"))) {
this._updateProcess(changedKeys);
}
};
Services.cpmm.sharedData.addEventListener("change", this.listener);
}
},
/**
* Update the theme data for the whole process
* @param {Array} changedKeys The sharedData keys that were changed.
*/
_updateProcess(changedKeys) {
const windowEnumerator = Services.ww.getWindowEnumerator();
while (windowEnumerator.hasMoreElements()) {
const {
chromeOuterWindowID,
content,
} = windowEnumerator.getNext().docShell.messageManager;
if (changedKeys.includes(`theme/${chromeOuterWindowID}`) &&
content && this.whitelist.has(content.document.documentURI)) {
this.update(chromeOuterWindowID, content);
}
}
},
/**
* Forward the theme data to the page.
* @param {Object} outerWindowID The outerWindowID the parent process window has.
* @param {Object} content The receiving global
*/
update(outerWindowID, content) {
const event = Cu.cloneInto({
detail: {
data: Services.cpmm.sharedData.get(`theme/${outerWindowID}`)
},
}, content);
content.dispatchEvent(new content.CustomEvent("LightweightTheme:Set",
event));
},
};

View File

@ -61,9 +61,6 @@ with Files("ExtensionsUI.jsm"):
with Files("LaterRun.jsm"):
BUG_COMPONENT = ("Firefox", "Tours")
with Files("LightweightThemeChildHelper.jsm"):
BUG_COMPONENT = ("WebExtensions", "Themes")
with Files("OpenInTabsUtils.jsm"):
BUG_COMPONENT = ("Firefox", "Tabbed Browser")
@ -130,11 +127,9 @@ EXTRA_JS_MODULES += [
'ExtensionsUI.jsm',
'FaviconLoader.jsm',
'Feeds.jsm',
'FormSubmitObserver.jsm',
'FormValidationHandler.jsm',
'HomePage.jsm',
'LaterRun.jsm',
'LightweightThemeChildHelper.jsm',
'OpenInTabsUtils.jsm',
'PageActions.jsm',
'PermissionUI.jsm',

View File

@ -65,7 +65,7 @@ def nodejs_suitability(require, node, version):
MAYBE_FILE_A_BUG = '''
If you believe this is a bug, <https://mzl.la/2vLbXAv> is a good way
to file. Executing `mach bootstrap --no-system changes` should
to file. Executing `mach bootstrap --no-system-changes` should
install a compatible version in ~/.mozbuild on most platforms.
More details: <https://bit.ly/2BbyD1E>
'''

View File

@ -284,6 +284,11 @@ def rust_tests(enable_rust_tests, rustdoc):
set_config('MOZ_RUST_TESTS', rust_tests)
# cbindgen is needed by the style system build.
cbindgen = check_prog('CBINDGEN', add_rustup_path('cbindgen'), paths=toolchain_search_path,
when=depends(build_project)
(lambda build_project: build_project != 'js'))
# Bindgen can use rustfmt to format Rust file, but it's not required.
js_option(env='RUSTFMT', nargs=1, help='Path to the rustfmt program')

View File

@ -654,6 +654,9 @@ def toolchain_search_path(vc_compiler_path):
bootstrap_clang_path = os.path.join(mozbuild_state_dir, 'clang', 'bin')
result.append(bootstrap_clang_path)
bootstrap_cbindgen_path = os.path.join(mozbuild_state_dir, 'cbindgen')
result.append(bootstrap_cbindgen_path)
if vc_compiler_path:
# We're going to alter PATH for good in windows.configure, but we also
# need to do it for the valid_compiler() check below. This is only needed

View File

@ -16,6 +16,7 @@ unset RUSTC
unset CARGO
unset RUSTDOC
unset RUSTFMT
unset CBINDGEN
unset MAKECAB
unset TOOLCHAIN_PREFIX
unset BINDGEN_CFLAGS

View File

@ -7,5 +7,6 @@ RUSTC="$TOOLTOOL_DIR/rustc/bin/rustc"
CARGO="$TOOLTOOL_DIR/rustc/bin/cargo"
RUSTDOC="$TOOLTOOL_DIR/rustc/bin/rustdoc"
RUSTFMT="$TOOLTOOL_DIR/rustc/bin/rustfmt"
CBINDGEN="$TOOLTOOL_DIR/cbindgen/cbindgen"
ac_add_options --enable-rust-simd

View File

@ -84,8 +84,10 @@ included_inclnames_to_ignore = set([
'prtypes.h', # NSPR
'selfhosted.out.h', # generated in $OBJDIR
'shellmoduleloader.out.h', # generated in $OBJDIR
'unicode/timezone.h', # ICU
'unicode/basictz.h', # ICU
'unicode/locid.h', # ICU
'unicode/plurrule.h', # ICU
'unicode/timezone.h', # ICU
'unicode/ucal.h', # ICU
'unicode/uchar.h', # ICU
'unicode/uclean.h', # ICU
@ -103,6 +105,7 @@ included_inclnames_to_ignore = set([
'unicode/ureldatefmt.h', # ICU
'unicode/ustring.h', # ICU
'unicode/utypes.h', # ICU
'unicode/uversion.h', # ICU
'vtune/VTuneWrapper.h' # VTune
])

Binary file not shown.

View File

@ -1,9 +1,9 @@
This is the debugger.html project output.
See https://github.com/devtools-html/debugger.html
Version 82
Version 83
Comparison: https://github.com/devtools-html/debugger.html/compare/release-81...release-82
Comparison: https://github.com/devtools-html/debugger.html/compare/release-82...release-83
Packages:
- babel-plugin-transform-es2015-modules-commonjs @6.26.2

View File

@ -1406,6 +1406,12 @@ html .toggle-button.end.vertical svg {
background-color: white;
}
.sources-list .tree .label .suffix {
font-style: italic;
font-size: 0.9em;
color: var(--theme-comment);
}
.sources-list .tree img.arrow.expanded {
transform: rotate(0deg);
}

View File

@ -25259,7 +25259,6 @@ const isControlFlow = node => isForStatement(node) || t.isWhileStatement(node) |
const isAssignment = node => t.isVariableDeclarator(node) || t.isAssignmentExpression(node) || t.isAssignmentPattern(node);
const isImport = node => t.isImport(node) || t.isImportDeclaration(node);
const isReturn = node => t.isReturnStatement(node);
const isCall = node => t.isCallExpression(node) || t.isJSXElement(node);
const inStepExpression = parent => t.isArrayExpression(parent) || t.isObjectProperty(parent) || t.isCallExpression(parent) || t.isJSXElement(parent) || t.isSequenceExpression(parent);
@ -25268,10 +25267,6 @@ const inExpression = (parent, grandParent) => inStepExpression(parent) || t.isJS
const isExport = node => t.isExportNamedDeclaration(node) || t.isExportDefaultDeclaration(node);
function getStartLine(node) {
return node.loc.start.line;
}
// Finds the first call item in a step expression so that we can step
// to the beginning of the list and either step in or over. e.g. [], x(), { }
function isFirstCall(node, parentNode, grandParentNode) {
@ -25295,29 +25290,6 @@ function isFirstCall(node, parentNode, grandParentNode) {
return children.find(child => isCall(child)) === node;
}
// Check to see if the node is a step expression and if any of its children
// expressions include calls. e.g. [ a() ], { a: a() }
function hasCall(node) {
let children = [];
if (t.isArrayExpression(node)) {
children = node.elements;
}
if (t.isObjectExpression(node)) {
children = node.properties.map(({ value }) => value);
}
if (t.isSequenceExpression(node)) {
children = node.expressions;
}
if (t.isCallExpression(node)) {
children = node.arguments;
}
return children.find(child => isCall(child));
}
function getPausePoints(sourceId) {
const state = {};
(0, _ast.traverseAst)(sourceId, { enter: onEnter }, state);
@ -25332,7 +25304,7 @@ function onEnter(node, ancestors, state) {
const grandParentNode = grandParent && grandParent.node;
const startLocation = node.loc.start;
if (isImport(node) || t.isClassDeclaration(node) || isExport(node) || t.isDebuggerStatement(node) || t.isThrowStatement(node) || t.isBreakStatement(node) || t.isContinueStatement(node)) {
if (isImport(node) || t.isClassDeclaration(node) || isExport(node) || t.isDebuggerStatement(node) || t.isThrowStatement(node) || t.isBreakStatement(node) || t.isContinueStatement(node) || t.isReturnStatement(node)) {
return addStopPoint(state, startLocation);
}
@ -25352,20 +25324,12 @@ function onEnter(node, ancestors, state) {
return addEmptyPoint(state, startLocation);
}
if (isReturn(node)) {
// We do not want to pause at the return if the
// argument is a call on the same line e.g. return foo()
return addPoint(state, startLocation, !isCall(node.argument) || getStartLine(node) != getStartLine(node.argument));
}
if (isAssignment(node)) {
// step at assignments unless the right side is a call or default assignment
// e.g. `var a = b()`, `a = b(c = 2)`, `a = [ b() ]`
const value = node.right || node.init;
// step at assignments unless the right side is a default assignment
// e.g. `( b = 2 ) => {}`
const defaultAssignment = t.isFunction(parentNode) && parent.key === "params";
const includesCall = isCall(value) || hasCall(value);
return addPoint(state, startLocation, !includesCall && !defaultAssignment);
return addPoint(state, startLocation, !defaultAssignment);
}
if (isCall(node)) {

View File

@ -24,8 +24,6 @@ var _selectors = require("../selectors/index");
var _select = require("../actions/sources/select");
var _ui = require("../reducers/ui");
var _editor = require("../utils/editor/index");
var _fileSearch = require("./file-search");
@ -224,7 +222,7 @@ function setProjectDirectoryRoot(newRoot) {
dispatch,
getState
}) => {
const curRoot = (0, _ui.getProjectDirectoryRoot)(getState());
const curRoot = (0, _selectors.getProjectDirectoryRoot)(getState());
if (newRoot && curRoot) {
const newRootArr = newRoot.replace(/\/+/g, "/").split("/");

View File

@ -204,7 +204,7 @@ class SourceTreeItem extends _react.Component {
} = this.props;
const suffix = hasMatchingGeneratedSource ? _react2.default.createElement("span", {
className: "suffix"
}, "[sm]") : null;
}, L10N.getStr("sourceFooter.mappedSuffix")) : null;
return _react2.default.createElement("div", {
className: (0, _classnames2.default)("node", {
focused

View File

@ -73,9 +73,9 @@ var _initialiseProps = function () {
})), _react2.default.createElement("div", {
id: `${item.id}-title`,
className: "title"
}, item.title), _react2.default.createElement("div", {
}, item.title), item.subtitle != item.title ? _react2.default.createElement("div", {
id: `${item.id}-subtitle`,
className: "subtitle"
}, item.subtitle));
}, item.subtitle) : null);
};
};

View File

@ -20,6 +20,8 @@ exports.getSourceInSources = getSourceInSources;
exports.getSources = getSources;
exports.getUrls = getUrls;
exports.getSourceList = getSourceList;
exports.getProjectDirectoryRoot = getProjectDirectoryRoot;
exports.getRelativeSources = getRelativeSources;
var _reselect = require("devtools/client/debugger/new/dist/vendors").vendored["reselect"];
@ -41,8 +43,10 @@ function initialSourcesState() {
return {
sources: {},
urls: {},
relativeSources: {},
selectedLocation: undefined,
pendingSelectedLocation: _prefs.prefs.pendingSelectedLocation
pendingSelectedLocation: _prefs.prefs.pendingSelectedLocation,
projectDirectoryRoot: _prefs.prefs.projectDirectoryRoot
};
}
@ -137,6 +141,9 @@ function update(state = initialSourcesState(), action) {
break;
case "SET_PROJECT_DIRECTORY_ROOT":
return recalculateRelativeSources(state, action.url);
case "NAVIGATE":
const source = state.selectedLocation && state.sources[state.selectedLocation.sourceId];
const url = source && source.url;
@ -200,6 +207,8 @@ function updateSource(state, source) {
const existingUrls = state.urls[source.url];
const urls = existingUrls ? [...existingUrls, source.id] : [source.id];
return { ...state,
relativeSources: updateRelativeSource({ ...state.relativeSources
}, updatedSource, state.projectDirectoryRoot),
sources: { ...state.sources,
[source.id]: updatedSource
},
@ -209,6 +218,27 @@ function updateSource(state, source) {
};
}
function updateRelativeSource(relativeSources, source, root) {
if (!(0, _source.underRoot)(source, root)) {
return relativeSources;
}
const relativeSource = { ...source,
relativeUrl: (0, _source.getRelativeUrl)(source, root)
};
relativeSources[source.id] = relativeSource;
return relativeSources;
}
function recalculateRelativeSources(state, root) {
_prefs.prefs.projectDirectoryRoot = root;
const relativeSources = Object.values(state.sources).reduce((sources, source) => updateRelativeSource(sources, source, root), {});
return { ...state,
projectDirectoryRoot: root,
relativeSources
};
}
function updateBlackBoxList(url, isBlackBoxed) {
const tabs = getBlackBoxList();
const i = tabs.indexOf(url);
@ -323,4 +353,13 @@ const getSelectedSource = exports.getSelectedSource = (0, _reselect.createSelect
return sources[selectedLocation.sourceId];
});
function getProjectDirectoryRoot(state) {
return state.sources.projectDirectoryRoot;
}
function getRelativeSources(state) {
return state.sources.relativeSources;
}
exports.default = update;

View File

@ -12,7 +12,6 @@ exports.getShownSource = getShownSource;
exports.getPaneCollapse = getPaneCollapse;
exports.getHighlightedLineRange = getHighlightedLineRange;
exports.getConditionalPanelLine = getConditionalPanelLine;
exports.getProjectDirectoryRoot = getProjectDirectoryRoot;
exports.getOrientation = getOrientation;
var _makeRecord = require("../utils/makeRecord");
@ -36,7 +35,6 @@ const createUIState = exports.createUIState = (0, _makeRecord2.default)({
activeSearch: null,
contextMenu: {},
shownSource: null,
projectDirectoryRoot: _prefs.prefs.projectDirectoryRoot,
startPanelCollapsed: _prefs.prefs.startPanelCollapsed,
endPanelCollapsed: _prefs.prefs.endPanelCollapsed,
frameworkGroupingOn: _prefs.prefs.frameworkGroupingOn,
@ -112,10 +110,6 @@ function update(state = createUIState(), action) {
case "CLOSE_CONDITIONAL_PANEL":
return state.set("conditionalPanelLine", null);
case "SET_PROJECT_DIRECTORY_ROOT":
_prefs.prefs.projectDirectoryRoot = action.url;
return state.set("projectDirectoryRoot", action.url);
case "SET_PRIMARY_PANE_TAB":
return state.set("selectedPrimaryPaneTab", action.tabName);
@ -178,10 +172,6 @@ function getConditionalPanelLine(state) {
return state.ui.get("conditionalPanelLine");
}
function getProjectDirectoryRoot(state) {
return state.ui.get("projectDirectoryRoot");
}
function getOrientation(state) {
return state.ui.get("orientation");
}

View File

@ -1,52 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getRelativeSources = undefined;
var _selectors = require("../selectors/index");
var _lodash = require("devtools/client/shared/vendor/lodash");
var _sourcesTree = require("../utils/sources-tree/index");
var _reselect = require("devtools/client/debugger/new/dist/vendors").vendored["reselect"];
/* 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/>. */
function getRelativeUrl(source, root) {
const {
group,
path
} = (0, _sourcesTree.getURL)(source);
if (!root) {
return path;
} // + 1 removes the leading "/"
const url = group + path;
return url.slice(url.indexOf(root) + root.length + 1);
}
function formatSource(source, root) {
// NOTE: Flow https://github.com/facebook/flow/issues/6342 issue
return { ...source,
relativeUrl: getRelativeUrl(source, root)
};
}
function underRoot(source, root) {
return source.url && source.url.includes(root);
}
/*
* Gets the sources that are below a project root
*/
const getRelativeSources = exports.getRelativeSources = (0, _reselect.createSelector)(_selectors.getSources, _selectors.getProjectDirectoryRoot, (sources, root) => {
const relativeSources = (0, _lodash.chain)(sources).pickBy(source => underRoot(source, root)).mapValues(source => formatSource(source, root)).value();
return relativeSources;
});

View File

@ -262,15 +262,6 @@ Object.defineProperty(exports, "getVisibleSelectedFrame", {
}
});
var _getRelativeSources = require("./getRelativeSources");
Object.defineProperty(exports, "getRelativeSources", {
enumerable: true,
get: function () {
return _getRelativeSources.getRelativeSources;
}
});
var _breakpointSources = require("./breakpointSources");
Object.defineProperty(exports, "getBreakpointSources", {

View File

@ -11,7 +11,6 @@ DevToolsModules(
'breakpointAtLocation.js',
'breakpointSources.js',
'getCallStackFrames.js',
'getRelativeSources.js',
'inComponent.js',
'index.js',
'isSelectedFrameVisible.js',

View File

@ -32,6 +32,8 @@ exports.isLoaded = isLoaded;
exports.isLoading = isLoading;
exports.getTextAtPosition = getTextAtPosition;
exports.getSourceClassnames = getSourceClassnames;
exports.getRelativeUrl = getRelativeUrl;
exports.underRoot = underRoot;
var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
@ -497,4 +499,23 @@ function getSourceClassnames(source, sourceMetaData) {
}
return sourceTypes[(0, _sourcesTree.getFileExtension)(source)] || defaultClassName;
}
function getRelativeUrl(source, root) {
const {
group,
path
} = (0, _sourcesTree.getURL)(source);
if (!root) {
return path;
} // + 1 removes the leading "/"
const url = group + path;
return url.slice(url.indexOf(root) + root.length + 1);
}
function underRoot(source, root) {
return source.url && source.url.includes(root);
}

View File

@ -46,8 +46,9 @@ add_task(async function test() {
await testCase(dbg, {
name: "sequences",
count: 4,
steps: [[23,2], [25,8], [31,4], [34,2], [37,0]]
count: 5,
steps: [[23,2], [25,8], [29,8], [31,4], [34,2], [37,0]]
});
await testCase(dbg, {

View File

@ -549,6 +549,10 @@ sourceFooter.mappedSource=(From %S)
# with a mapped source. %S is replaced by the source map origin.
sourceFooter.mappedSourceTooltip=(Source mapped from %S)
# LOCALIZATION NOTE (sourceFooter.mappedSuffix): Text associated
# with a mapped source. Displays next to URLs in tree and tabs.
sourceFooter.mappedSuffix=(mapped)
# LOCALIZATION NOTE (sourceFooter.codeCoverage): Text associated
# with a code coverage button
sourceFooter.codeCoverage=Code coverage

View File

@ -2913,11 +2913,11 @@ function getType(item) {
}
function getValue(item) {
if (item && item.contents && item.contents.hasOwnProperty("value")) {
if (nodeHasValue(item)) {
return item.contents.value;
}
if (item && item.contents && item.contents.hasOwnProperty("getterValue")) {
if (nodeHasGetterValue(item)) {
return item.contents.getterValue;
}
@ -2944,6 +2944,14 @@ function nodeHasChildren(item) {
return Array.isArray(item.contents);
}
function nodeHasValue(item) {
return item && item.contents && item.contents.hasOwnProperty("value");
}
function nodeHasGetterValue(item) {
return item && item.contents && item.contents.hasOwnProperty("getterValue");
}
function nodeIsObject(item) {
const value = getValue(item);
return value && value.type === "object";
@ -3391,18 +3399,15 @@ function makeNodesForProperties(objProps, parent) {
}
function setNodeFullText(loadedProps, node) {
if (nodeHasFullText(node)) {
if (nodeHasFullText(node) || !nodeIsLongString(node)) {
return node;
}
if (nodeIsLongString(node)) {
const {fullText} = loadedProps;
if (node.contents.value) {
node.contents.value.fullText = fullText;
} else if (node.contents.getterValue) {
node.contents.getterValue.fullText = fullText;
}
const { fullText } = loadedProps;
if (nodeHasValue(node)) {
node.contents.value.fullText = fullText;
} else if (nodeHasGetterValue(node)) {
node.contents.getterValue.fullText = fullText;
}
return node;

View File

@ -8503,11 +8503,12 @@ nsContentUtils::SendMouseEvent(const nsCOMPtr<nsIPresShell>& aPresShell,
/* static */
void
nsContentUtils::FirePageHideEvent(nsIDocShellTreeItem* aItem,
EventTarget* aChromeEventHandler)
EventTarget* aChromeEventHandler,
bool aOnlySystemGroup)
{
nsCOMPtr<nsIDocument> doc = aItem->GetDocument();
NS_ASSERTION(doc, "What happened here?");
doc->OnPageHide(true, aChromeEventHandler);
doc->OnPageHide(true, aChromeEventHandler, aOnlySystemGroup);
int32_t childCount = 0;
aItem->GetChildCount(&childCount);
@ -8519,7 +8520,7 @@ nsContentUtils::FirePageHideEvent(nsIDocShellTreeItem* aItem,
for (uint32_t i = 0; i < kids.Length(); ++i) {
if (kids[i]) {
FirePageHideEvent(kids[i], aChromeEventHandler);
FirePageHideEvent(kids[i], aChromeEventHandler, aOnlySystemGroup);
}
}
}
@ -8532,7 +8533,8 @@ nsContentUtils::FirePageHideEvent(nsIDocShellTreeItem* aItem,
void
nsContentUtils::FirePageShowEvent(nsIDocShellTreeItem* aItem,
EventTarget* aChromeEventHandler,
bool aFireIfShowing)
bool aFireIfShowing,
bool aOnlySystemGroup)
{
int32_t childCount = 0;
aItem->GetChildCount(&childCount);
@ -8544,14 +8546,15 @@ nsContentUtils::FirePageShowEvent(nsIDocShellTreeItem* aItem,
for (uint32_t i = 0; i < kids.Length(); ++i) {
if (kids[i]) {
FirePageShowEvent(kids[i], aChromeEventHandler, aFireIfShowing);
FirePageShowEvent(kids[i], aChromeEventHandler, aFireIfShowing,
aOnlySystemGroup);
}
}
nsCOMPtr<nsIDocument> doc = aItem->GetDocument();
NS_ASSERTION(doc, "What happened here?");
if (doc->IsShowing() == aFireIfShowing) {
doc->OnPageShow(true, aChromeEventHandler);
doc->OnPageShow(true, aChromeEventHandler, aOnlySystemGroup);
}
}

View File

@ -2850,10 +2850,12 @@ public:
static void FirePageShowEvent(nsIDocShellTreeItem* aItem,
mozilla::dom::EventTarget* aChromeEventHandler,
bool aFireIfShowing);
bool aFireIfShowing,
bool aOnlySystemGroup = false);
static void FirePageHideEvent(nsIDocShellTreeItem* aItem,
mozilla::dom::EventTarget* aChromeEventHandler);
mozilla::dom::EventTarget* aChromeEventHandler,
bool aOnlySystemGroup = false);
static already_AddRefed<nsPIWindowRoot> GetWindowRoot(nsIDocument* aDoc);

View File

@ -8320,7 +8320,8 @@ nsIDocument::GetContentInThisDocument(nsIFrame* aFrame) const
void
nsIDocument::DispatchPageTransition(EventTarget* aDispatchTarget,
const nsAString& aType,
bool aPersisted)
bool aPersisted,
bool aOnlySystemGroup)
{
if (!aDispatchTarget) {
return;
@ -8339,6 +8340,9 @@ nsIDocument::DispatchPageTransition(EventTarget* aDispatchTarget,
event->SetTrusted(true);
event->SetTarget(this);
if (aOnlySystemGroup) {
event->WidgetEventPtr()->mFlags.mOnlySystemGroupDispatchInContent = true;
}
EventDispatcher::DispatchDOMEvent(aDispatchTarget, nullptr, event,
nullptr, nullptr);
}
@ -8352,7 +8356,8 @@ NotifyPageShow(nsIDocument* aDocument, void* aData)
}
void
nsIDocument::OnPageShow(bool aPersisted, EventTarget* aDispatchStartTarget)
nsIDocument::OnPageShow(bool aPersisted, EventTarget* aDispatchStartTarget,
bool aOnlySystemGroup)
{
mVisible = true;
@ -8405,7 +8410,8 @@ nsIDocument::OnPageShow(bool aPersisted, EventTarget* aDispatchStartTarget)
if (!target) {
target = do_QueryInterface(GetWindow());
}
DispatchPageTransition(target, NS_LITERAL_STRING("pageshow"), aPersisted);
DispatchPageTransition(target, NS_LITERAL_STRING("pageshow"), aPersisted,
aOnlySystemGroup);
}
}
@ -8452,7 +8458,8 @@ HasHttpScheme(nsIURI* aURI)
}
void
nsIDocument::OnPageHide(bool aPersisted, EventTarget* aDispatchStartTarget)
nsIDocument::OnPageHide(bool aPersisted, EventTarget* aDispatchStartTarget,
bool aOnlySystemGroup)
{
if (IsTopLevelContentDocument() && GetDocGroup() &&
Telemetry::CanRecordExtended()) {
@ -8524,7 +8531,8 @@ nsIDocument::OnPageHide(bool aPersisted, EventTarget* aDispatchStartTarget)
}
{
PageUnloadingEventTimeStamp timeStamp(this);
DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted);
DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted,
aOnlySystemGroup);
}
}

View File

@ -1341,7 +1341,8 @@ protected:
void DispatchPageTransition(mozilla::dom::EventTarget* aDispatchTarget,
const nsAString& aType,
bool aPersisted);
bool aPersisted,
bool aOnlySystemGroup = false);
// Call this before the document does something that will unbind all content.
// That will stop us from doing a lot of work as each element is removed.
@ -2197,12 +2198,14 @@ public:
* PageTransitionEvent.webidl for a description of the |aPersisted|
* parameter. If aDispatchStartTarget is null, the pageshow event is
* dispatched on the ScriptGlobalObject for this document, otherwise it's
* dispatched on aDispatchStartTarget.
* dispatched on aDispatchStartTarget. If |aOnlySystemGroup| is true, the
* event is only dispatched to listeners in the system group.
* Note: if aDispatchStartTarget isn't null, the showing state of the
* document won't be altered.
*/
virtual void OnPageShow(bool aPersisted,
mozilla::dom::EventTarget* aDispatchStartTarget);
mozilla::dom::EventTarget* aDispatchStartTarget,
bool aOnlySystemGroup = false);
/**
* Notification that the page has been hidden, for documents which are loaded
@ -2212,12 +2215,14 @@ public:
* window. See PageTransitionEvent.webidl for a description of the
* |aPersisted| parameter. If aDispatchStartTarget is null, the pagehide
* event is dispatched on the ScriptGlobalObject for this document,
* otherwise it's dispatched on aDispatchStartTarget.
* otherwise it's dispatched on aDispatchStartTarget. If |aOnlySystemGroup| is
* true, the event is only dispatched to listeners in the system group.
* Note: if aDispatchStartTarget isn't null, the showing state of the
* document won't be altered.
*/
void OnPageHide(bool aPersisted,
mozilla::dom::EventTarget* aDispatchStartTarget);
mozilla::dom::EventTarget* aDispatchStartTarget,
bool aOnlySystemGroup = false);
/*
* We record the set of links in the document that are relevant to

View File

@ -51,10 +51,12 @@ function prepareForVisibilityEvents(browser, expectedOrder) {
rmvHide = BrowserTestUtils.addContentEventListener(browser, "pagehide",
() => eventListener("pagehide"),
false, checkFn, false, false);
{}, checkFn,
false, false);
rmvShow = BrowserTestUtils.addContentEventListener(browser, "pageshow",
() => eventListener("pageshow"),
false, checkFn, false, false);
{}, checkFn,
false, false);
});
}
@ -93,7 +95,7 @@ add_task(async function test_swap_frameloader_pagevisibility_events() {
await ContentTask.spawn(emptyBrowser, {}, async() => {
if (content.document.visibilityState === "hidden") {
info("waiting for hidden emptyBrowser to pageshow");
await ContentTaskUtils.waitForEvent(content, "pageshow");
await ContentTaskUtils.waitForEvent(content, "pageshow", {});
}
});

View File

@ -129,7 +129,7 @@ Test swapFrameLoaders with different frame types and remoteness
});
addEventListener("pagehide", function({ inFrameSwap }) {
sendAsyncMessage("pagehide", inFrameSwap);
});
}, {mozSystemGroup: true});
}`;
}

View File

@ -12,6 +12,7 @@
#include "nsIContentInlines.h"
#include "nsIDocument.h"
#include "nsINode.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsPIDOMWindow.h"
#include "AnimationEvent.h"
#include "BeforeUnloadEvent.h"
@ -104,22 +105,23 @@ static bool IsEventTargetChrome(EventTarget* aEventTarget,
}
nsIDocument* doc = nullptr;
nsCOMPtr<nsINode> node = do_QueryInterface(aEventTarget);
if (node) {
if (nsCOMPtr<nsINode> node = do_QueryInterface(aEventTarget)) {
doc = node->OwnerDoc();
} else {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aEventTarget);
if (!window) {
return false;
}
} else if (nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aEventTarget)) {
doc = window->GetExtantDoc();
}
// nsContentUtils::IsChromeDoc is null-safe.
bool isChrome = nsContentUtils::IsChromeDoc(doc);
if (aDocument && doc) {
nsCOMPtr<nsIDocument> retVal = doc;
retVal.swap(*aDocument);
bool isChrome = false;
if (doc) {
isChrome = nsContentUtils::IsChromeDoc(doc);
if (aDocument) {
nsCOMPtr<nsIDocument> retVal = doc;
retVal.swap(*aDocument);
}
} else if (nsCOMPtr<nsIScriptObjectPrincipal> sop =
do_QueryInterface(aEventTarget->GetOwnerGlobal())) {
isChrome = nsContentUtils::IsSystemPrincipal(sop->GetPrincipal());
}
return isChrome;
}

View File

@ -14,6 +14,7 @@
#include "mozilla/dom/nsCSPUtils.h"
#include "mozilla/dom/nsCSPContext.h"
#include "mozilla/dom/nsMixedContentBlocker.h"
#include "mozilla/dom/CustomEvent.h"
#include "mozilla/dom/HTMLFormControlsCollection.h"
#include "mozilla/dom/HTMLFormElementBinding.h"
#include "mozilla/Move.h"
@ -1826,7 +1827,7 @@ HTMLFormElement::ForgetCurrentSubmission()
}
bool
HTMLFormElement::CheckFormValidity(nsIMutableArray* aInvalidElements) const
HTMLFormElement::CheckFormValidity(nsTArray<RefPtr<Element>>* aInvalidElements) const
{
bool ret = true;
@ -1854,7 +1855,7 @@ HTMLFormElement::CheckFormValidity(nsIMutableArray* aInvalidElements) const
// Add all unhandled invalid controls to aInvalidElements if the caller
// requested them.
if (defaultAction && aInvalidElements) {
aInvalidElements->AppendElement(ToSupports(sortedControls[i]));
aInvalidElements->AppendElement(sortedControls[i]);
}
}
}
@ -1891,87 +1892,105 @@ HTMLFormElement::CheckValidFormSubmission()
return true;
}
AutoTArray<RefPtr<Element>, 32> invalidElements;
if (CheckFormValidity(&invalidElements)) {
return true;
}
// For the first invalid submission, we should update element states.
// We have to do that _before_ calling the observers so we are sure they
// will not interfere (like focusing the element).
if (!mEverTriedInvalidSubmit) {
mEverTriedInvalidSubmit = true;
/*
* We are going to call update states assuming elements want to
* be notified because we can't know.
* Submissions shouldn't happen during parsing so it _should_ be safe.
*/
nsAutoScriptBlocker scriptBlocker;
for (uint32_t i = 0, length = mControls->mElements.Length();
i < length; ++i) {
// Input elements can trigger a form submission and we want to
// update the style in that case.
if (mControls->mElements[i]->IsHTMLElement(nsGkAtoms::input) &&
// We don't use nsContentUtils::IsFocusedContent here, because it
// doesn't really do what we want for number controls: it's true
// for the anonymous textnode inside, but not the number control
// itself. We can use the focus state, though, because that gets
// synced to the number control by the anonymous text control.
mControls->mElements[i]->State().HasState(NS_EVENT_STATE_FOCUS)) {
static_cast<HTMLInputElement*>(mControls->mElements[i])
->UpdateValidityUIBits(true);
}
mControls->mElements[i]->UpdateState(true);
}
// Because of backward compatibility, <input type='image'> is not in
// elements but can be invalid.
// TODO: should probably be removed when bug 606491 will be fixed.
for (uint32_t i = 0, length = mControls->mNotInElements.Length();
i < length; ++i) {
mControls->mNotInElements[i]->UpdateState(true);
}
}
AutoJSAPI jsapi;
if (!jsapi.Init(GetOwnerGlobal())) {
return false;
}
JS::Rooted<JS::Value> detail(jsapi.cx());
if (!ToJSValue(jsapi.cx(), invalidElements, &detail)) {
return false;
}
RefPtr<CustomEvent> event = NS_NewDOMCustomEvent(OwnerDoc(),
nullptr, nullptr);
event->InitCustomEvent(jsapi.cx(),
NS_LITERAL_STRING("MozInvalidForm"),
/* CanBubble */ true,
/* Cancelable */ true,
detail);
event->SetTrusted(true);
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
DispatchEvent(*event);
bool result = !event->DefaultPrevented();
nsCOMPtr<nsISimpleEnumerator> theEnum;
nsresult rv = service->EnumerateObservers(NS_INVALIDFORMSUBMIT_SUBJECT,
getter_AddRefs(theEnum));
// Return true on error here because that's what we always did
NS_ENSURE_SUCCESS(rv, true);
NS_ENSURE_SUCCESS(rv, result);
bool hasObserver = false;
rv = theEnum->HasMoreElements(&hasObserver);
// Do not check form validity if there is no observer for
// NS_INVALIDFORMSUBMIT_SUBJECT.
if (NS_SUCCEEDED(rv) && hasObserver) {
nsCOMPtr<nsIMutableArray> invalidElements =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
// Return true on error here because that's what we always did
NS_ENSURE_SUCCESS(rv, true);
result = false;
if (!CheckFormValidity(invalidElements.get())) {
// For the first invalid submission, we should update element states.
// We have to do that _before_ calling the observers so we are sure they
// will not interfere (like focusing the element).
if (!mEverTriedInvalidSubmit) {
mEverTriedInvalidSubmit = true;
nsCOMPtr<nsISupports> inst;
nsCOMPtr<nsIFormSubmitObserver> observer;
bool more = true;
while (NS_SUCCEEDED(theEnum->HasMoreElements(&more)) && more) {
theEnum->GetNext(getter_AddRefs(inst));
observer = do_QueryInterface(inst);
/*
* We are going to call update states assuming elements want to
* be notified because we can't know.
* Submissions shouldn't happen during parsing so it _should_ be safe.
*/
nsAutoScriptBlocker scriptBlocker;
for (uint32_t i = 0, length = mControls->mElements.Length();
i < length; ++i) {
// Input elements can trigger a form submission and we want to
// update the style in that case.
if (mControls->mElements[i]->IsHTMLElement(nsGkAtoms::input) &&
// We don't use nsContentUtils::IsFocusedContent here, because it
// doesn't really do what we want for number controls: it's true
// for the anonymous textnode inside, but not the number control
// itself. We can use the focus state, though, because that gets
// synced to the number control by the anonymous text control.
mControls->mElements[i]->State().HasState(NS_EVENT_STATE_FOCUS)) {
static_cast<HTMLInputElement*>(mControls->mElements[i])
->UpdateValidityUIBits(true);
}
mControls->mElements[i]->UpdateState(true);
}
// Because of backward compatibility, <input type='image'> is not in
// elements but can be invalid.
// TODO: should probably be removed when bug 606491 will be fixed.
for (uint32_t i = 0, length = mControls->mNotInElements.Length();
i < length; ++i) {
mControls->mNotInElements[i]->UpdateState(true);
}
if (observer) {
observer->NotifyInvalidSubmit(this, invalidElements);
}
nsCOMPtr<nsISupports> inst;
nsCOMPtr<nsIFormSubmitObserver> observer;
bool more = true;
while (NS_SUCCEEDED(theEnum->HasMoreElements(&more)) && more) {
theEnum->GetNext(getter_AddRefs(inst));
observer = do_QueryInterface(inst);
if (observer) {
observer->NotifyInvalidSubmit(this,
static_cast<nsIArray*>(invalidElements));
}
}
// The form is invalid. Observers have been alerted. Do not submit.
return false;
}
} else {
}
if (result) {
NS_WARNING("There is no observer for \"invalidformsubmit\". \
One should be implemented!");
}
return true;
return result;
}
bool

View File

@ -517,7 +517,7 @@ protected:
*
* @return Whether the form is currently valid.
*/
bool CheckFormValidity(nsIMutableArray* aInvalidElements) const;
bool CheckFormValidity(nsTArray<RefPtr<Element>>* aInvalidElements) const;
// Clear the mImageNameLookupTable and mImageElements.
void Clear();

View File

@ -304,7 +304,8 @@ ImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
void
ImageDocument::OnPageShow(bool aPersisted,
EventTarget* aDispatchStartTarget)
EventTarget* aDispatchStartTarget,
bool aOnlySystemGroup)
{
if (aPersisted) {
mOriginalZoomLevel = IsSiteSpecific() ? 1.0 : GetZoomLevel();
@ -315,7 +316,8 @@ ImageDocument::OnPageShow(bool aPersisted,
RefPtr<ImageDocument> kungFuDeathGrip(this);
UpdateSizeFromLayout();
MediaDocument::OnPageShow(aPersisted, aDispatchStartTarget);
MediaDocument::OnPageShow(aPersisted, aDispatchStartTarget,
aOnlySystemGroup);
}
NS_IMETHODIMP

View File

@ -43,7 +43,8 @@ public:
virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject) override;
virtual void Destroy() override;
virtual void OnPageShow(bool aPersisted,
EventTarget* aDispatchStartTarget) override;
EventTarget* aDispatchStartTarget,
bool aOnlySystemGroup = false) override;
NS_DECL_NSIIMAGEDOCUMENT
NS_DECL_IMGINOTIFICATIONOBSERVER

View File

@ -9,6 +9,7 @@
#include "nsAString.h"
#include "nsGenericHTMLElement.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/CustomEvent.h"
#include "mozilla/dom/HTMLFormElement.h"
#include "mozilla/dom/HTMLFieldSetElement.h"
#include "mozilla/dom/HTMLInputElement.h"
@ -145,6 +146,30 @@ nsIConstraintValidation::ReportValidity()
return false;
}
AutoTArray<RefPtr<Element>, 1> invalidElements;
invalidElements.AppendElement(element);
AutoJSAPI jsapi;
if (!jsapi.Init(element->GetOwnerGlobal())) {
return false;
}
JS::Rooted<JS::Value> detail(jsapi.cx());
if (!ToJSValue(jsapi.cx(), invalidElements, &detail)) {
return false;
}
RefPtr<CustomEvent> event = NS_NewDOMCustomEvent(element->OwnerDoc(),
nullptr, nullptr);
event->InitCustomEvent(jsapi.cx(),
NS_LITERAL_STRING("MozInvalidForm"),
/* CanBubble */ true,
/* Cancelable */ true,
detail);
event->SetTrusted(true);
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
element->DispatchEvent(*event);
nsCOMPtr<nsIObserverService> service =
mozilla::services::GetObserverService();
if (!service) {
@ -162,10 +187,6 @@ nsIConstraintValidation::ReportValidity()
bool hasObserver = false;
rv = theEnum->HasMoreElements(&hasObserver);
nsCOMPtr<nsIMutableArray> invalidElements =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
invalidElements->AppendElement(element);
NS_ENSURE_SUCCESS(rv, true);
nsCOMPtr<nsISupports> inst;
nsCOMPtr<nsIFormSubmitObserver> observer;

View File

@ -11,6 +11,7 @@ interface nsIURI;
interface nsIArray;
webidl HTMLFormElement;
webidl Element;
[scriptable, uuid(867cb7e7-835d-408b-9788-d2834d284e03)]
interface nsIFormSubmitObserver: nsISupports
@ -18,7 +19,7 @@ interface nsIFormSubmitObserver: nsISupports
void notify(in HTMLFormElement formNode, in mozIDOMWindow window, in nsIURI actionURL, out boolean cancelSubmit);
void notifyInvalidSubmit(in HTMLFormElement formNode,
in nsIArray invalidElements);
in Array<Element> invalidElements);
};
%{C++

View File

@ -47,18 +47,6 @@ function runTest()
var formSubmitted = [ false, false ];
var invalidHandled = false;
var os = SpecialPowers.Cc['@mozilla.org/observer-service;1']
.getService(SpecialPowers.Ci.nsIObserverService);
var observers = os.enumerateObservers("invalidformsubmit");
// The following test should not be done if there is no observer for
// "invalidformsubmit" because the form submission will not be canceled in that
// case.
if (!observers.hasMoreElements()) {
SimpleTest.finish();
return;
}
// Initialize
document.forms[0].addEventListener('submit', function(aEvent) {
formSubmitted[0] = true;

View File

@ -2377,12 +2377,12 @@ TabChild::RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext)
RefPtr<nsDocShell> docShell = static_cast<nsDocShell*>(ourDocShell.get());
nsCOMPtr<EventTarget> ourEventTarget = ourWindow->GetParentTarget();
nsCOMPtr<EventTarget> ourEventTarget = nsGlobalWindowOuter::Cast(ourWindow);
docShell->SetInFrameSwap(true);
nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, false);
nsContentUtils::FirePageHideEvent(ourDocShell, ourEventTarget);
nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, false, true);
nsContentUtils::FirePageHideEvent(ourDocShell, ourEventTarget, true);
// Owner content type may have changed, so store the possibly updated context
// and notify others.
@ -2410,7 +2410,7 @@ TabChild::RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext)
RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
}
nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, true);
nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, true, true);
docShell->SetInFrameSwap(false);

View File

@ -2756,14 +2756,7 @@ HTMLEditor::GetSelectedElement(Selection& aSelection,
return selectedElement.forget();
}
nsresult rv;
nsCOMPtr<nsIContentIterator> iter =
do_CreateInstance("@mozilla.org/content/post-content-iterator;1",
&rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return nullptr;
}
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
bool found = !!selectedElement;
const nsAtom* tagNameLookingFor = aTagName;
@ -3016,28 +3009,24 @@ HTMLEditor::GetLinkedObjects(nsIArray** aNodeList)
return rv;
}
nsCOMPtr<nsIContentIterator> iter =
do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &rv);
NS_ENSURE_TRUE(iter, NS_ERROR_NULL_POINTER);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIDocument> doc = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
nsCOMPtr<nsIDocument> doc = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
iter->Init(doc->GetRootElement());
iter->Init(doc->GetRootElement());
// loop through the content iterator for each content node
while (!iter->IsDone()) {
nsCOMPtr<nsINode> node = iter->GetCurrentNode();
if (node) {
// Let nsURIRefObject make the hard decisions:
nsCOMPtr<nsIURIRefObject> refObject;
rv = NS_NewHTMLURIRefObject(getter_AddRefs(refObject), node);
if (NS_SUCCEEDED(rv)) {
nodes->AppendElement(refObject);
}
// loop through the content iterator for each content node
while (!iter->IsDone()) {
nsCOMPtr<nsINode> node = iter->GetCurrentNode();
if (node) {
// Let nsURIRefObject make the hard decisions:
nsCOMPtr<nsIURIRefObject> refObject;
rv = NS_NewHTMLURIRefObject(getter_AddRefs(refObject), node);
if (NS_SUCCEEDED(rv)) {
nodes->AppendElement(refObject);
}
iter->Next();
}
iter->Next();
}
nodes.forget(aNodeList);
@ -3275,14 +3264,7 @@ HTMLEditor::GetEmbeddedObjects(nsIArray** aNodeList)
return rv;
}
nsCOMPtr<nsIContentIterator> iter =
do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &rv);
if (NS_WARN_IF(!iter)) {
return NS_ERROR_FAILURE;
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
nsCOMPtr<nsIDocument> doc = GetDocument();
if (NS_WARN_IF(!doc)) {
@ -3802,10 +3784,7 @@ HTMLEditor::CollapseAdjacentTextNodes(nsRange* aInRange)
// build a list of editable text nodes
nsresult rv = NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIContentIterator> iter =
do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
iter->Init(aInRange);
@ -3830,7 +3809,7 @@ HTMLEditor::CollapseAdjacentTextNodes(nsRange* aInRange)
// get the prev sibling of the right node, and see if its leftTextNode
nsCOMPtr<nsINode> prevSibOfRightNode = rightTextNode->GetPreviousSibling();
if (prevSibOfRightNode && prevSibOfRightNode == leftTextNode) {
rv = JoinNodesWithTransaction(*leftTextNode, *rightTextNode);
nsresult rv = JoinNodesWithTransaction(*leftTextNode, *rightTextNode);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

View File

@ -1485,11 +1485,7 @@ TextEditor::GetTextLength(int32_t* aCount)
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIContentIterator> iter =
do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
uint32_t totalLength = 0;
iter->Init(rootElement);

View File

@ -23,13 +23,13 @@ using namespace mozilla;
//------------------------------------------------------------
nsFilteredContentIterator::nsFilteredContentIterator(nsComposeTxtSrvFilter* aFilter) :
mIterator(NS_NewContentIterator()),
mPreIterator(NS_NewPreContentIterator()),
mFilter(aFilter),
mDidSkip(false),
mIsOutOfRange(false),
mDirection(eDirNotSet)
{
mIterator = do_CreateInstance("@mozilla.org/content/post-content-iterator;1");
mPreIterator = do_CreateInstance("@mozilla.org/content/pre-content-iterator;1");
}
//------------------------------------------------------------

View File

@ -130,7 +130,10 @@ ImageCacheKey::SchemeIs(const char* aScheme)
/* static */ void*
ImageCacheKey::GetSpecialCaseDocumentToken(nsIDocument* aDocument, nsIURI* aURI)
{
if (!aDocument) {
// Cookie-averse documents can never have storage granted to them. Since they
// may not have inner windows, they would require special handling below, so
// just bail out early here.
if (!aDocument || aDocument->IsCookieAverse()) {
return nullptr;
}
@ -141,10 +144,11 @@ ImageCacheKey::GetSpecialCaseDocumentToken(nsIDocument* aDocument, nsIURI* aURI)
return aDocument;
}
// If we must disable the storage, we want to create a unique cache key for
// this image.
if (nsContentUtils::StorageDisabledByAntiTracking(aDocument, aURI)) {
return aDocument;
// If the window is 3rd party resource, let's see if first-party storage
// access is granted for this image.
if (nsContentUtils::IsTrackingResourceWindow(aDocument->GetInnerWindow())) {
return nsContentUtils::StorageDisabledByAntiTracking(aDocument, aURI) ?
aDocument : nullptr;
}
// Another scenario is if this image is a 3rd party resource loaded by a
@ -153,8 +157,7 @@ ImageCacheKey::GetSpecialCaseDocumentToken(nsIDocument* aDocument, nsIURI* aURI)
// this point. The best approach here is to be conservative: if we are sure
// that the permission is granted, let's return a nullptr. Otherwise, let's
// make a unique image cache.
if (!aDocument->IsCookieAverse() &&
!AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(),
if (!AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(),
aURI)) {
return aDocument;
}

7
intl/icu/GIT-INFO Normal file
View File

@ -0,0 +1,7 @@
commit 4a3ba8eee90ea1414d4f7ee36563e6c9b28fda96
Author: Yoshito Umaoka <y.umaoka@gmail.com>
Date: Wed Jun 20 05:34:56 2018 +0000
ICU-13823 Merged #13840 number parser memory overflow fix (r41541) to maint-62 for 62.1 GA.
X-SVN-Rev: 41542

View File

@ -1,10 +0,0 @@
Path: icu4c
URL: https://ssl.icu-project.org/repos/icu/tags/release-62-1/icu4c
Relative URL: ^/tags/release-62-1/icu4c
Repository Root: https://ssl.icu-project.org/repos/icu
Repository UUID: 251d0590-4201-4cf1-90de-194747b24ca1
Node Kind: directory
Last Changed Author: yoshito
Last Changed Rev: 41542
Last Changed Date: 2018-06-20 05:34:56 +0000 (Wed, 20 Jun 2018)

View File

@ -14,7 +14,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="de"/>
</identity>
</ldml>

View File

@ -12,7 +12,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="el"/>
</identity>
<special xmlns:icu="http://www.icu-project.org/">

View File

@ -12,7 +12,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="en"/>
</identity>
</ldml>

View File

@ -12,7 +12,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="en"/>
<territory type="US"/>
</identity>

View File

@ -12,7 +12,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="en"/>
<territory type="US"/>
<variant type="POSIX"/>

View File

@ -14,7 +14,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="es"/>
</identity>
</ldml>

View File

@ -12,7 +12,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="fi"/>
</identity>
<special xmlns:icu="http://www.icu-project.org/">

View File

@ -14,7 +14,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="fr"/>
</identity>
</ldml>

View File

@ -14,7 +14,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="it"/>
</identity>
</ldml>

View File

@ -12,7 +12,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="ja"/>
</identity>
<special xmlns:icu="http://www.icu-project.org/">

View File

@ -14,7 +14,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="pt"/>
</identity>
</ldml>

View File

@ -12,7 +12,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="root"/>
</identity>
<special xmlns:icu="http://www.icu-project.org/">

View File

@ -14,7 +14,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="ru"/>
</identity>
</ldml>

View File

@ -12,7 +12,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="root"/>
</identity>
<special xmlns:icu="http://www.icu-project.org/">

View File

@ -12,7 +12,7 @@
>
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="root"/>
</identity>
</ldml>

View File

@ -7,7 +7,7 @@
<!DOCTYPE ldml SYSTEM "http://www.unicode.org/repos/cldr/trunk/common/dtd/ldml.dtd">
<ldml>
<identity>
<version number="$Revision: 40674 $"/>
<version number="$Revision$"/>
<language type="be"/>
</identity>
<rbnf>

Some files were not shown because too many files have changed in this diff Show More