зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
1a7d69f8be
|
@ -4961,6 +4961,7 @@ dependencies = [
|
|||
"cssparser",
|
||||
"cstr",
|
||||
"env_logger",
|
||||
"euclid",
|
||||
"geckoservo",
|
||||
"libc",
|
||||
"log",
|
||||
|
|
|
@ -1583,9 +1583,6 @@ pref("browser.newtabpage.activity-stream.feeds.section.topstories", true);
|
|||
// The pref controls if search hand-off is enabled for Activity Stream.
|
||||
pref("browser.newtabpage.activity-stream.improvesearch.handoffToAwesomebar", true);
|
||||
|
||||
// This pref controls the visibility of Colorway Closet settings in the customize panel
|
||||
pref("browser.newtabpage.activity-stream.colorway-closet.enabled", false);
|
||||
|
||||
pref("browser.newtabpage.activity-stream.logowordmark.alwaysVisible", true);
|
||||
|
||||
// Used to display triplet cards on newtab
|
||||
|
|
|
@ -677,24 +677,14 @@ var gHistorySwipeAnimation = {
|
|||
* Whether we're dealing with a vertical swipe or not.
|
||||
*/
|
||||
startAnimation: function HSA_startAnimation() {
|
||||
// If the animation is running but we are in the process of stopping it
|
||||
// then we want to reset and restart the animation.
|
||||
if (this.isAnimationRunning() && !this._isStoppingAnimation) {
|
||||
return;
|
||||
}
|
||||
|
||||
let createBoxes = true;
|
||||
if (this._isStoppingAnimation) {
|
||||
// Boxes already exist, just need to reset them. Reset the transition that was in the process of stopping.
|
||||
this._prevBox.style.transition = "";
|
||||
this._nextBox.style.transition = "";
|
||||
createBoxes = false;
|
||||
}
|
||||
|
||||
// old boxes can still be around (if completing fade out for example), we
|
||||
// always want to remove them and recreate them because they can be
|
||||
// attached to an old browser stack that's no longer in use.
|
||||
this._removeBoxes();
|
||||
this._isStoppingAnimation = false;
|
||||
this._canGoBack = this.canGoBack();
|
||||
this._canGoForward = this.canGoForward();
|
||||
if (createBoxes && this.active) {
|
||||
if (this.active) {
|
||||
this._addBoxes();
|
||||
}
|
||||
this.updateAnimation(0);
|
||||
|
@ -704,7 +694,7 @@ var gHistorySwipeAnimation = {
|
|||
* Stops the swipe animation.
|
||||
*/
|
||||
stopAnimation: function HSA_stopAnimation() {
|
||||
if (!this.isAnimationRunning()) {
|
||||
if (!this.isAnimationRunning() || this._isStoppingAnimation) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -533,6 +533,13 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
|||
false
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"gAlwaysOpenPanel",
|
||||
"browser.download.alwaysOpenPanel",
|
||||
true
|
||||
);
|
||||
|
||||
customElements.setElementCreationCallback("translation-notification", () => {
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://browser/content/translation-notification.js",
|
||||
|
@ -621,7 +628,7 @@ async function gLazyFindCommand(cmd, ...args) {
|
|||
|
||||
var gPageIcons = {
|
||||
"about:home": "chrome://branding/content/icon32.png",
|
||||
"about:myfirefox": "chrome://branding/content/icon32.png",
|
||||
"about:firefoxview": "chrome://branding/content/icon32.png",
|
||||
"about:newtab": "chrome://branding/content/icon32.png",
|
||||
"about:welcome": "chrome://branding/content/icon32.png",
|
||||
"about:privatebrowsing": "chrome://browser/skin/privatebrowsing/favicon.svg",
|
||||
|
@ -630,7 +637,7 @@ var gPageIcons = {
|
|||
var gInitialPages = [
|
||||
"about:blank",
|
||||
"about:home",
|
||||
...(AppConstants.NIGHTLY_BUILD ? ["about:myfirefox"] : []),
|
||||
...(AppConstants.NIGHTLY_BUILD ? ["about:firefoxview"] : []),
|
||||
"about:newtab",
|
||||
"about:privatebrowsing",
|
||||
"about:sessionrestore",
|
||||
|
@ -6319,9 +6326,9 @@ nsBrowserAccess.prototype = {
|
|||
break;
|
||||
}
|
||||
case Ci.nsIBrowserDOMWindow.OPEN_PRINT_BROWSER: {
|
||||
let browser = PrintUtils.startPrintWindow(aOpenWindowInfo.parent, {
|
||||
openWindowInfo: aOpenWindowInfo,
|
||||
});
|
||||
let browser = PrintUtils.handleStaticCloneCreatedForPrint(
|
||||
aOpenWindowInfo
|
||||
);
|
||||
if (browser) {
|
||||
browsingContext = browser.browsingContext;
|
||||
}
|
||||
|
@ -6401,9 +6408,9 @@ nsBrowserAccess.prototype = {
|
|||
aSkipLoad
|
||||
) {
|
||||
if (aWhere == Ci.nsIBrowserDOMWindow.OPEN_PRINT_BROWSER) {
|
||||
return PrintUtils.startPrintWindow(aParams.openWindowInfo.parent, {
|
||||
openWindowInfo: aParams.openWindowInfo,
|
||||
});
|
||||
return PrintUtils.handleStaticCloneCreatedForPrint(
|
||||
aParams.openWindowInfo
|
||||
);
|
||||
}
|
||||
|
||||
if (aWhere != Ci.nsIBrowserDOMWindow.OPEN_NEWTAB) {
|
||||
|
@ -7317,6 +7324,29 @@ var ToolbarContextMenu = {
|
|||
Services.prefs.setBoolPref("browser.download.autohideButton", autoHide);
|
||||
},
|
||||
|
||||
updateDownloadsAlwaysOpenPanel(popup) {
|
||||
let separator = document.getElementById(
|
||||
"toolbarDownloadsAnchorMenuSeparator"
|
||||
);
|
||||
let checkbox = document.getElementById(
|
||||
"toolbar-context-always-open-downloads-panel"
|
||||
);
|
||||
let isDownloads =
|
||||
popup.triggerNode &&
|
||||
["downloads-button", "wrapper-downloads-button"].includes(
|
||||
popup.triggerNode.id
|
||||
);
|
||||
separator.hidden = checkbox.hidden = !isDownloads;
|
||||
gAlwaysOpenPanel
|
||||
? checkbox.setAttribute("checked", "true")
|
||||
: checkbox.removeAttribute("checked");
|
||||
},
|
||||
|
||||
onDownloadsAlwaysOpenPanelChange(event) {
|
||||
let alwaysOpen = event.target.getAttribute("checked") == "true";
|
||||
Services.prefs.setBoolPref("browser.download.alwaysOpenPanel", alwaysOpen);
|
||||
},
|
||||
|
||||
_getUnwrappedTriggerNode(popup) {
|
||||
// Toolbar buttons are wrapped in customize mode. Unwrap if necessary.
|
||||
let { triggerNode } = popup;
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
<link rel="localization" href="preview/firefoxSuggest.ftl"/>
|
||||
<link rel="localization" href="browser/toolbarContextMenu.ftl"/>
|
||||
<link rel="localization" href="browser/screenshots.ftl"/>
|
||||
<link rel="localization" href="preview/myFirefox.ftl"/>
|
||||
<link rel="localization" href="preview/firefoxView.ftl"/>
|
||||
|
||||
<title data-l10n-id="browser-main-window-title"></title>
|
||||
|
||||
|
|
|
@ -335,7 +335,7 @@
|
|||
</panel>
|
||||
|
||||
<menupopup id="toolbar-context-menu"
|
||||
onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator')); ToolbarContextMenu.updateDownloadsAutoHide(this); ToolbarContextMenu.updateExtension(this)">
|
||||
onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator')); ToolbarContextMenu.updateDownloadsAutoHide(this); ToolbarContextMenu.updateDownloadsAlwaysOpenPanel(this); ToolbarContextMenu.updateExtension(this)">
|
||||
<menuitem oncommand="ToolbarContextMenu.openAboutAddonsForContextAction(this.parentElement)"
|
||||
data-lazy-l10n-id="toolbar-context-menu-manage-extension"
|
||||
contexttype="toolbaritem"
|
||||
|
@ -362,6 +362,12 @@
|
|||
data-lazy-l10n-id="toolbar-context-menu-remove-from-toolbar"
|
||||
contexttype="toolbaritem"
|
||||
class="customize-context-removeFromToolbar"/>
|
||||
<menuseparator id="toolbarDownloadsAnchorMenuSeparator"/>
|
||||
<menuitem id="toolbar-context-always-open-downloads-panel"
|
||||
oncommand="ToolbarContextMenu.onDownloadsAlwaysOpenPanelChange(event);"
|
||||
type="checkbox"
|
||||
data-lazy-l10n-id="toolbar-context-menu-always-open-downloads-panel"
|
||||
contexttype="toolbaritem"/>
|
||||
<menuitem id="toolbar-context-openANewTab"
|
||||
contexttype="tabbar"
|
||||
command="cmd_newNavigatorTab"
|
||||
|
|
|
@ -21,7 +21,7 @@ const kESModuleList = new Set([
|
|||
/browser\/proxy-card.js$/,
|
||||
/browser\/vpn-card.js$/,
|
||||
/browser\/content\/browser\/certerror\/aboutNetError\.js$/,
|
||||
/browser\/content\/browser\/myfirefox\.js$/,
|
||||
/browser\/content\/browser\/firefoxview\.js$/,
|
||||
/browser\/content\/browser\/recently-closed-tabs\.js$/,
|
||||
/browser\/content\/browser\/tabs-pickup\.js$/,
|
||||
/toolkit\/content\/global\/certviewer\/components\/.*\.js$/,
|
||||
|
|
|
@ -70,7 +70,7 @@ static const RedirEntry kRedirMap[] = {
|
|||
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::IS_SECURE_CHROME_UI},
|
||||
{"myfirefox", "chrome://browser/content/myfirefox.html",
|
||||
{"firefoxview", "chrome://browser/content/firefoxview.html",
|
||||
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::IS_SECURE_CHROME_UI |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT},
|
||||
{"policies", "chrome://browser/content/policies/aboutPolicies.html",
|
||||
|
|
|
@ -12,7 +12,7 @@ pages = [
|
|||
'home',
|
||||
'logins',
|
||||
'loginsimportreport',
|
||||
'myfirefox',
|
||||
'firefoxview',
|
||||
'newtab',
|
||||
'ion',
|
||||
'pocket-home',
|
||||
|
|
|
@ -640,7 +640,7 @@ if (Services.prefs.getBoolPref("browser.tabs.firefox-view")) {
|
|||
let tabbrowser = window.gBrowser;
|
||||
let tab = window.__firefoxViewTab;
|
||||
if (!tab) {
|
||||
tab = tabbrowser.addTrustedTab("about:myfirefox", { index: 0 });
|
||||
tab = tabbrowser.addTrustedTab("about:firefoxview", { index: 0 });
|
||||
tabbrowser.hideTab(tab);
|
||||
window.__firefoxViewTab = tab;
|
||||
|
||||
|
|
|
@ -2,79 +2,23 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure the downloads panel opens automatically with a new download.
|
||||
* Check that the downloads panel opens when a download is spoofed.
|
||||
*/
|
||||
add_task(async function test_downloads_panel_opens() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.download.improvements_to_download_panel", true],
|
||||
["browser.download.always_ask_before_handling_new_types", false],
|
||||
],
|
||||
});
|
||||
|
||||
info("waiting for panel to open");
|
||||
async function checkPanelOpens() {
|
||||
info("Waiting for panel to open.");
|
||||
let promise = promisePanelOpened();
|
||||
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
|
||||
is(
|
||||
DownloadsPanel.isPanelShowing,
|
||||
true,
|
||||
"Panel state should indicate a preparation to be opened"
|
||||
"Panel state should indicate a preparation to be opened."
|
||||
);
|
||||
await promise;
|
||||
|
||||
is(DownloadsPanel.panel.state, "open", "Panel should be opened");
|
||||
is(DownloadsPanel.panel.state, "open", "Panel should be opened.");
|
||||
|
||||
DownloadsPanel.hidePanel();
|
||||
});
|
||||
|
||||
add_task(async function test_customizemode_doesnt_wreck_things() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.download.improvements_to_download_panel", true],
|
||||
["browser.download.always_ask_before_handling_new_types", false],
|
||||
],
|
||||
});
|
||||
|
||||
// Enter customize mode:
|
||||
let customizationReadyPromise = BrowserTestUtils.waitForEvent(
|
||||
gNavToolbox,
|
||||
"customizationready"
|
||||
);
|
||||
gCustomizeMode.enter();
|
||||
await customizationReadyPromise;
|
||||
|
||||
info("try to open the panel (will not work, in customize mode)");
|
||||
let promise = promisePanelOpened();
|
||||
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
|
||||
await TestUtils.waitForCondition(
|
||||
() => DownloadsPanel._state == DownloadsPanel.kStateHidden,
|
||||
"Should try to show but stop short and hide the panel"
|
||||
);
|
||||
is(
|
||||
DownloadsPanel._state,
|
||||
DownloadsPanel.kStateHidden,
|
||||
"Should not start opening the panel."
|
||||
);
|
||||
|
||||
let afterCustomizationPromise = BrowserTestUtils.waitForEvent(
|
||||
gNavToolbox,
|
||||
"aftercustomization"
|
||||
);
|
||||
gCustomizeMode.exit();
|
||||
await afterCustomizationPromise;
|
||||
|
||||
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
|
||||
is(
|
||||
DownloadsPanel.isPanelShowing,
|
||||
true,
|
||||
"Panel state should indicate a preparation to be opened"
|
||||
);
|
||||
await promise;
|
||||
|
||||
is(DownloadsPanel.panel.state, "open", "Panel should be opened");
|
||||
|
||||
DownloadsPanel.hidePanel();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a download and check that the downloads panel opens correctly according
|
||||
|
@ -129,6 +73,80 @@ async function downloadAndCheckPanel({ openDownloadsListOnStart = true } = {}) {
|
|||
is(DownloadsPanel.panel.state, "closed", "Panel should be closed");
|
||||
}
|
||||
|
||||
function clickCheckbox(checkbox) {
|
||||
// Clicking a checkbox toggles its checkedness first.
|
||||
if (checkbox.getAttribute("checked") == "true") {
|
||||
checkbox.removeAttribute("checked");
|
||||
} else {
|
||||
checkbox.setAttribute("checked", "true");
|
||||
}
|
||||
// Then it runs the command and closes the popup.
|
||||
checkbox.doCommand();
|
||||
checkbox.parentElement.hidePopup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the downloads panel opens automatically with a new download.
|
||||
*/
|
||||
add_task(async function test_downloads_panel_opens() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.download.improvements_to_download_panel", true],
|
||||
["browser.download.always_ask_before_handling_new_types", false],
|
||||
],
|
||||
});
|
||||
await checkPanelOpens();
|
||||
});
|
||||
|
||||
add_task(async function test_customizemode_doesnt_wreck_things() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.download.improvements_to_download_panel", true],
|
||||
["browser.download.always_ask_before_handling_new_types", false],
|
||||
],
|
||||
});
|
||||
|
||||
// Enter customize mode:
|
||||
let customizationReadyPromise = BrowserTestUtils.waitForEvent(
|
||||
gNavToolbox,
|
||||
"customizationready"
|
||||
);
|
||||
gCustomizeMode.enter();
|
||||
await customizationReadyPromise;
|
||||
|
||||
info("try to open the panel (will not work, in customize mode)");
|
||||
let promise = promisePanelOpened();
|
||||
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
|
||||
await TestUtils.waitForCondition(
|
||||
() => DownloadsPanel._state == DownloadsPanel.kStateHidden,
|
||||
"Should try to show but stop short and hide the panel"
|
||||
);
|
||||
is(
|
||||
DownloadsPanel._state,
|
||||
DownloadsPanel.kStateHidden,
|
||||
"Should not start opening the panel."
|
||||
);
|
||||
|
||||
let afterCustomizationPromise = BrowserTestUtils.waitForEvent(
|
||||
gNavToolbox,
|
||||
"aftercustomization"
|
||||
);
|
||||
gCustomizeMode.exit();
|
||||
await afterCustomizationPromise;
|
||||
|
||||
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
|
||||
is(
|
||||
DownloadsPanel.isPanelShowing,
|
||||
true,
|
||||
"Panel state should indicate a preparation to be opened"
|
||||
);
|
||||
await promise;
|
||||
|
||||
is(DownloadsPanel.panel.state, "open", "Panel should be opened");
|
||||
|
||||
DownloadsPanel.hidePanel();
|
||||
});
|
||||
|
||||
/**
|
||||
* Make sure the downloads panel _does not_ open automatically if we set the
|
||||
* pref telling it not to do that.
|
||||
|
@ -386,3 +404,55 @@ add_task(async function test_downloads_panel_inactive_window() {
|
|||
|
||||
testRunnerWindow = null;
|
||||
});
|
||||
|
||||
/**
|
||||
* When right-clicking the downloads toolbar button, there should be a menuitem
|
||||
* for toggling alwaysOpenPanel. Check that it works correctly.
|
||||
*/
|
||||
add_task(async function test_alwaysOpenPanel_menuitem() {
|
||||
const alwaysOpenPanelPref = "browser.download.alwaysOpenPanel";
|
||||
let checkbox = document.getElementById(
|
||||
"toolbar-context-always-open-downloads-panel"
|
||||
);
|
||||
let button = document.getElementById("downloads-button");
|
||||
|
||||
Services.prefs.clearUserPref(alwaysOpenPanelPref);
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.download.autohideButton", false]],
|
||||
});
|
||||
registerCleanupFunction(async () => {
|
||||
await SpecialPowers.popPrefEnv();
|
||||
Services.prefs.clearUserPref(alwaysOpenPanelPref);
|
||||
});
|
||||
|
||||
is(button.hidden, false, "Downloads button should not be hidden.");
|
||||
|
||||
info("Check context menu for downloads button.");
|
||||
await openContextMenu(button);
|
||||
is(checkbox.hidden, false, "Always Open checkbox is visible.");
|
||||
is(checkbox.getAttribute("checked"), "true", "Always Open is enabled.");
|
||||
|
||||
info("Disable Always Open via context menu.");
|
||||
clickCheckbox(checkbox);
|
||||
is(
|
||||
Services.prefs.getBoolPref(alwaysOpenPanelPref),
|
||||
false,
|
||||
"Always Open pref has been set to false."
|
||||
);
|
||||
|
||||
await downloadAndCheckPanel();
|
||||
|
||||
await openContextMenu(button);
|
||||
is(checkbox.hidden, false, "Always Open checkbox is visible.");
|
||||
isnot(checkbox.getAttribute("checked"), "true", "Always Open is disabled.");
|
||||
|
||||
info("Enable Always Open via context menu");
|
||||
clickCheckbox(checkbox);
|
||||
is(
|
||||
Services.prefs.getBoolPref(alwaysOpenPanelPref),
|
||||
true,
|
||||
"Pref has been set to true"
|
||||
);
|
||||
|
||||
await checkPanelOpens();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
# 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/.
|
||||
|
||||
-firefoxview-brand-name = Firefox View
|
||||
|
||||
toolbar-button-firefox-view =
|
||||
.label = { -firefoxview-brand-name }
|
||||
.tooltiptext = { -firefoxview-brand-name }
|
||||
|
||||
firefoxview-page-title = { -firefoxview-brand-name }
|
||||
|
||||
firefoxview-colorway-button = Colorway Closet
|
||||
|
||||
# Used instead of the localized relative time when a timestamp is within a minute or so of now
|
||||
firefoxview-just-now-timestamp = Just now
|
||||
|
||||
# This is a headline for an area in the product where users can resume and re-open tabs they have previously viewed on other devices.
|
||||
firefoxview-tabpickup-header = Tab Pickup
|
||||
firefoxview-tabpickup-description = Pick up where you left off on another device.
|
||||
|
||||
firefoxview-tabpickup-recenttabs-description = Recent tabs list would go here
|
||||
|
||||
# Variables:
|
||||
# $percentValue (Number): the percentage value for setup completion
|
||||
firefoxview-tabpickup-progress-label = { $percentValue }% complete
|
||||
|
||||
firefoxview-tabpickup-step-signin-header = Step 1 of 3: Sign in to { -brand-product-name }
|
||||
firefoxview-tabpickup-step-signin-description = To get your mobile tabs on this device, sign in to { -brand-product-name } and turn on sync.
|
||||
firefoxview-tabpickup-step-signin-primarybutton = Continue
|
||||
|
||||
# These are placeholders for now..
|
||||
|
||||
firefoxview-tabpickup-adddevice-header = Step 2 of 3: Sign in on a mobile device
|
||||
firefoxview-tabpickup-adddevice-description = Step 2 description.
|
||||
firefoxview-tabpickup-adddevice-primarybutton = Get { -brand-product-name } for mobile
|
||||
|
||||
firefoxview-tabpickup-synctabs-header = Step 3 of 3: Sync open tabs
|
||||
firefoxview-tabpickup-synctabs-description = Step 3 description.
|
||||
firefoxview-tabpickup-synctabs-primarybutton = Sync open tabs
|
||||
|
||||
firefoxview-tabpickup-setupsuccess-header = Setup Complete!
|
||||
firefoxview-tabpickup-setupsuccess-description = Step 4 description.
|
||||
firefoxview-tabpickup-setupsuccess-primarybutton = Get my other tabs
|
||||
|
||||
firefoxview-closed-tabs-title = Recently closed
|
||||
firefoxview-closed-tabs-collapse-button =
|
||||
.title = Show or hide recently closed tabs list
|
||||
|
||||
firefoxview-closed-tabs-description = Reopen pages you’ve closed on this device.
|
||||
firefoxview-closed-tabs-placeholder = History is empty <br/> The next time you close a tab, you can reopen it here.
|
||||
|
||||
# Variables:
|
||||
# $targetURI (string) - URL that will be opened in the new tab
|
||||
firefoxview-closed-tabs-tab-button =
|
||||
.title = Open { $targetURI } in a new tab
|
|
@ -8,13 +8,13 @@
|
|||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src chrome:; object-src 'none'">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<title data-l10n-id="myfirefox-page-title"></title>
|
||||
<title data-l10n-id="firefoxview-page-title"></title>
|
||||
<link rel="localization" href="branding/brand.ftl">
|
||||
<link rel="localization" href="preview/myFirefox.ftl"/>
|
||||
<link rel="localization" href="preview/firefoxView.ftl"/>
|
||||
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
|
||||
<link rel="stylesheet" href="chrome://browser/content/myfirefox.css">
|
||||
<link rel="stylesheet" href="chrome://browser/content/firefoxview.css">
|
||||
<script type="module" src="chrome://browser/content/tabs-pickup.js"></script>
|
||||
<script type="module" src="chrome://browser/content/myfirefox.js"></script>
|
||||
<script type="module" src="chrome://browser/content/firefoxview.js"></script>
|
||||
<script type="module" src="chrome://browser/content/recently-closed-tabs.js"></script>
|
||||
</head>
|
||||
|
||||
|
@ -26,52 +26,52 @@
|
|||
<template id="sync-setup-template">
|
||||
<named-deck class="sync-setup-container" data-prefix="id:">
|
||||
<div name="sync-setup-view0" data-prefix="id:-view0" class="card setup-step" data-prefix="aria-labelledby:-view0-header">
|
||||
<h2 data-prefix="id:-view0-header" data-l10n-id="myfirefox-tabpickup-step-signin-header" class="card-header"></h2>
|
||||
<h2 data-prefix="id:-view0-header" data-l10n-id="firefoxview-tabpickup-step-signin-header" class="card-header"></h2>
|
||||
<section class="step-body">
|
||||
<p class="step-content" data-l10n-id="myfirefox-tabpickup-step-signin-description"></p>
|
||||
<button class="primary" data-action="view0-primary-action" data-l10n-id="myfirefox-tabpickup-step-signin-primarybutton"></button>
|
||||
<p class="step-content" data-l10n-id="firefoxview-tabpickup-step-signin-description"></p>
|
||||
<button class="primary" data-action="view0-primary-action" data-l10n-id="firefoxview-tabpickup-step-signin-primarybutton"></button>
|
||||
</section>
|
||||
<footer>
|
||||
<progress data-prefix="id:-view0-progress" class="step-progress" max="100" value="11"></progress>
|
||||
<label
|
||||
data-prefix="for:-view0-progress"
|
||||
data-l10n-id="myfirefox-tabpickup-progress-label"
|
||||
data-l10n-id="firefoxview-tabpickup-progress-label"
|
||||
data-l10n-args='{"percentValue":"11"}'></label>
|
||||
</footer>
|
||||
</div>
|
||||
<div name="sync-setup-view1" data-prefix="id:-view1" class="card setup-step" data-prefix="aria-labelledby:-view1-header">
|
||||
<h2 data-prefix="id:-view1-header" data-l10n-id="myfirefox-tabpickup-adddevice-header" class="card-header"></h2>
|
||||
<h2 data-prefix="id:-view1-header" data-l10n-id="firefoxview-tabpickup-adddevice-header" class="card-header"></h2>
|
||||
<section class="step-body">
|
||||
<p class="step-content" data-l10n-id="myfirefox-tabpickup-adddevice-description"></p>
|
||||
<button class="primary" data-action="view1-primary-action" data-l10n-id="myfirefox-tabpickup-adddevice-primarybutton"></button>
|
||||
<p class="step-content" data-l10n-id="firefoxview-tabpickup-adddevice-description"></p>
|
||||
<button class="primary" data-action="view1-primary-action" data-l10n-id="firefoxview-tabpickup-adddevice-primarybutton"></button>
|
||||
</section>
|
||||
<footer>
|
||||
<progress data-prefix="id:-view1-progress" class="step-progress" max="100" value="33"></progress>
|
||||
<label
|
||||
data-prefix="for:-view1-progress"
|
||||
data-l10n-id="myfirefox-tabpickup-progress-label"
|
||||
data-l10n-id="firefoxview-tabpickup-progress-label"
|
||||
data-l10n-args='{"percentValue":"33"}'></label>
|
||||
</footer>
|
||||
</div>
|
||||
<div name="sync-setup-view2" data-prefix="id:-view2" class="card setup-step" data-prefix="aria-labelledby:-view2-header">
|
||||
<h2 data-prefix="id:-view2-header" data-l10n-id="myfirefox-tabpickup-synctabs-header" class="card-header"></h2>
|
||||
<h2 data-prefix="id:-view2-header" data-l10n-id="firefoxview-tabpickup-synctabs-header" class="card-header"></h2>
|
||||
<section class="step-body">
|
||||
<p class="step-content" data-l10n-id="myfirefox-tabpickup-synctabs-description"></p>
|
||||
<button class="primary" data-action="view2-primary-action" data-l10n-id="myfirefox-tabpickup-synctabs-primarybutton"></button>
|
||||
<p class="step-content" data-l10n-id="firefoxview-tabpickup-synctabs-description"></p>
|
||||
<button class="primary" data-action="view2-primary-action" data-l10n-id="firefoxview-tabpickup-synctabs-primarybutton"></button>
|
||||
</section>
|
||||
<footer>
|
||||
<progress data-prefix="id:-view2-progress" class="step-progress" max="100" value="66"></progress>
|
||||
<label
|
||||
data-prefix="for:-view2-progress"
|
||||
data-l10n-id="myfirefox-tabpickup-progress-label"
|
||||
data-l10n-id="firefoxview-tabpickup-progress-label"
|
||||
data-l10n-args='{"percentValue":"66"}'></label>
|
||||
</footer>
|
||||
</div>
|
||||
<div name="sync-setup-view3" data-prefix="id:-view3" class="card setup-step" data-prefix="aria-labelledby:-view3-header">
|
||||
<h2 data-prefix="id:-view2-header" data-l10n-id="myfirefox-tabpickup-setupsuccess-header" class="card-header"></h2>
|
||||
<h2 data-prefix="id:-view2-header" data-l10n-id="firefoxview-tabpickup-setupsuccess-header" class="card-header"></h2>
|
||||
<section class="step-body">
|
||||
<p class="step-content" data-l10n-id="myfirefox-tabpickup-setupsuccess-description"></p>
|
||||
<button class="primary" data-action="view3-primary-action" data-l10n-id="myfirefox-tabpickup-setupsuccess-primarybutton"></button>
|
||||
<p class="step-content" data-l10n-id="firefoxview-tabpickup-setupsuccess-description"></p>
|
||||
<button class="primary" data-action="view3-primary-action" data-l10n-id="firefoxview-tabpickup-setupsuccess-primarybutton"></button>
|
||||
</section>
|
||||
</div>
|
||||
</named-deck>
|
||||
|
@ -79,23 +79,23 @@
|
|||
<template id="synced-tabs-template">
|
||||
<div class="synced-tabs-container" data-prefix="id:" hidden>
|
||||
<div class="card">
|
||||
<h2 data-l10n-id="myfirefox-tabpickup-recenttabs-description"></h2>
|
||||
<h2 data-l10n-id="firefoxview-tabpickup-recenttabs-description"></h2>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<section is="tabs-pickup-container" id="tabs-pickup-container">
|
||||
<h1 data-l10n-id="myfirefox-tabpickup-header"></h1>
|
||||
<p data-l10n-id="myfirefox-tabpickup-description"></p>
|
||||
<h1 data-l10n-id="firefoxview-tabpickup-header"></h1>
|
||||
<p data-l10n-id="firefoxview-tabpickup-description"></p>
|
||||
</section>
|
||||
<aside>
|
||||
<button data-l10n-id="myfirefox-colorway-button" id="colorway-closet-button"></button>
|
||||
<button data-l10n-id="firefoxview-colorway-button" id="colorway-closet-button"></button>
|
||||
</aside>
|
||||
<section is="recently-closed-tabs-container" id="recently-closed-tabs-container">
|
||||
<header class="page-section-header">
|
||||
<h1 data-l10n-id="myfirefox-closed-tabs-title" ></h1>
|
||||
<button data-l10n-id="myfirefox-closed-tabs-collapse-button" id="collapsible-tabs-button" class="ghost-button twisty icon arrow-up"></button>
|
||||
<p class="section-description" data-l10n-id="myfirefox-closed-tabs-description"></p>
|
||||
<h1 data-l10n-id="firefoxview-closed-tabs-title" ></h1>
|
||||
<button data-l10n-id="firefoxview-closed-tabs-collapse-button" id="collapsible-tabs-button" class="ghost-button twisty icon arrow-up"></button>
|
||||
<p class="section-description" data-l10n-id="firefoxview-closed-tabs-description"></p>
|
||||
</header>
|
||||
<div id="collapsible-tabs-container">
|
||||
<recently-closed-tabs-list>
|
||||
|
@ -103,7 +103,7 @@
|
|||
</recently-closed-tabs-list>
|
||||
<div hidden="true" id="recently-closed-tabs-placeholder" class="placeholder-content">
|
||||
<icon class="icon history"></icon>
|
||||
<p data-l10n-id="myfirefox-closed-tabs-placeholder"></p>
|
||||
<p data-l10n-id="firefoxview-closed-tabs-placeholder"></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
|
@ -3,9 +3,9 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
browser.jar:
|
||||
content/browser/myfirefox.html
|
||||
content/browser/myfirefox.js
|
||||
content/browser/myfirefox.css
|
||||
content/browser/firefoxview.html
|
||||
content/browser/firefoxview.js
|
||||
content/browser/firefoxview.css
|
||||
content/browser/tabs-pickup.js
|
||||
content/browser/recently-closed-tabs.js
|
||||
|
|
@ -22,7 +22,7 @@ class RecentlyClosedTabsList extends HTMLElement {
|
|||
|
||||
get fluentStrings() {
|
||||
if (!this._fluentStrings) {
|
||||
this._fluentStrings = new Localization(["preview/myFirefox.ftl"], true);
|
||||
this._fluentStrings = new Localization(["preview/firefoxView.ftl"], true);
|
||||
}
|
||||
return this._fluentStrings;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class RecentlyClosedTabsList extends HTMLElement {
|
|||
if (elapsed <= nowThresholdMs) {
|
||||
// Use a different string for very recent timestamps
|
||||
formattedTime = this.fluentStrings.formatValueSync(
|
||||
"myfirefox-just-now-timestamp"
|
||||
"firefoxview-just-now-timestamp"
|
||||
);
|
||||
} else {
|
||||
formattedTime = relativeTimeFormat.formatBestUnit(new Date(timestamp));
|
||||
|
@ -114,7 +114,7 @@ class RecentlyClosedTabsList extends HTMLElement {
|
|||
|
||||
const targetURI = this.getTargetURI(tab);
|
||||
li.dataset.targetURI = targetURI;
|
||||
document.l10n.setAttributes(li, "myfirefox-closed-tabs-tab-button", {
|
||||
document.l10n.setAttributes(li, "firefoxview-closed-tabs-tab-button", {
|
||||
targetURI,
|
||||
});
|
||||
|
|
@ -156,7 +156,7 @@ const tabsSetupFlowManager = new (class {
|
|||
|
||||
async openFxASignup() {
|
||||
const url = await this.fxAccounts.constructor.config.promiseConnectAccountURI(
|
||||
"myfirefox"
|
||||
"firefoxview"
|
||||
);
|
||||
switchToTabHavingURI(url, true);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
[DEFAULT]
|
||||
run-if = nightly_build # about:firefoxview is only enabled on Nightly
|
||||
|
||||
[browser_firefoxview.js]
|
||||
[browser_setup_state.js]
|
|
@ -1,11 +1,11 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function about_myfirefox_smoke_test() {
|
||||
add_task(async function about_firefoxview_smoke_test() {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: "about:myfirefox",
|
||||
url: "about:firefoxview",
|
||||
},
|
||||
async browser => {
|
||||
const { document } = browser.contentWindow;
|
|
@ -0,0 +1,185 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const { UIState } = ChromeUtils.import("resource://services-sync/UIState.jsm");
|
||||
const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
||||
|
||||
function promiseSyncReady() {
|
||||
let service = Cc["@mozilla.org/weave/service;1"].getService(Ci.nsISupports)
|
||||
.wrappedJSObject;
|
||||
return service.whenLoaded();
|
||||
}
|
||||
|
||||
function setupMocks({ fxaDevices = null, state = UIState.STATUS_SIGNED_IN }) {
|
||||
const sandbox = sinon.createSandbox();
|
||||
sandbox.stub(fxAccounts.device, "recentDeviceList").get(() => fxaDevices);
|
||||
sandbox.stub(UIState, "get").returns({
|
||||
status: state,
|
||||
syncEnabled: true,
|
||||
});
|
||||
sandbox.stub(fxAccounts.device, "refreshDeviceList").resolves(true);
|
||||
|
||||
sandbox
|
||||
.stub(Weave.Service.clientsEngine, "getClientByFxaDeviceId")
|
||||
.callsFake(fxaDeviceId => {
|
||||
let target = fxaDevices.find(c => c.id == fxaDeviceId);
|
||||
return target ? target.clientRecord : null;
|
||||
});
|
||||
sandbox.stub(Weave.Service.clientsEngine, "getClientType").returns("desktop");
|
||||
|
||||
return sandbox;
|
||||
}
|
||||
|
||||
function testSetupState(browser, expected) {
|
||||
const { document } = browser.contentWindow;
|
||||
for (let [selector, shouldBeVisible] of Object.entries(
|
||||
expected.expectedVisible
|
||||
)) {
|
||||
const elem = document.querySelector(selector);
|
||||
if (shouldBeVisible) {
|
||||
ok(
|
||||
BrowserTestUtils.is_visible(elem),
|
||||
`Expected ${selector} to be visible`
|
||||
);
|
||||
} else {
|
||||
ok(BrowserTestUtils.is_hidden(elem), `Expected ${selector} to be hidden`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_setup(async function() {
|
||||
await promiseSyncReady();
|
||||
// gSync.init() is called in a requestIdleCallback. Force its initialization.
|
||||
gSync.init();
|
||||
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"about:firefoxview"
|
||||
);
|
||||
registerCleanupFunction(async function() {
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_unconfigured_initial_state() {
|
||||
const browser = gBrowser.selectedBrowser;
|
||||
const sandbox = setupMocks({ state: UIState.STATUS_NOT_CONFIGURED });
|
||||
|
||||
Services.obs.notifyObservers(null, UIState.ON_UPDATE);
|
||||
testSetupState(browser, {
|
||||
expectedVisible: {
|
||||
"#tabpickup-steps-view0": true,
|
||||
"#tabpickup-steps-view1": false,
|
||||
"#tabpickup-steps-view2": false,
|
||||
"#tabpickup-steps-view3": false,
|
||||
},
|
||||
});
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_signed_in() {
|
||||
const browser = gBrowser.selectedBrowser;
|
||||
const sandbox = setupMocks({
|
||||
state: UIState.STATUS_SIGNED_IN,
|
||||
fxaDevices: [
|
||||
{
|
||||
id: 1,
|
||||
name: "This Device",
|
||||
isCurrentDevice: true,
|
||||
type: "desktop",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(null, UIState.ON_UPDATE);
|
||||
testSetupState(browser, {
|
||||
expectedVisible: {
|
||||
"#tabpickup-steps-view0": false,
|
||||
"#tabpickup-steps-view1": true,
|
||||
"#tabpickup-steps-view2": false,
|
||||
"#tabpickup-steps-view3": false,
|
||||
},
|
||||
});
|
||||
is(fxAccounts.device.recentDeviceList?.length, 1, "Just 1 device connected");
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_2nd_desktop_connected() {
|
||||
const browser = gBrowser.selectedBrowser;
|
||||
const sandbox = setupMocks({
|
||||
state: UIState.STATUS_SIGNED_IN,
|
||||
fxaDevices: [
|
||||
{
|
||||
id: 1,
|
||||
name: "This Device",
|
||||
isCurrentDevice: true,
|
||||
type: "desktop",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Other Device",
|
||||
type: "desktop",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(null, UIState.ON_UPDATE);
|
||||
testSetupState(browser, {
|
||||
expectedVisible: {
|
||||
"#tabpickup-steps-view0": false,
|
||||
"#tabpickup-steps-view1": true,
|
||||
"#tabpickup-steps-view2": false,
|
||||
"#tabpickup-steps-view3": false,
|
||||
},
|
||||
});
|
||||
is(fxAccounts.device.recentDeviceList?.length, 2, "2 devices connected");
|
||||
ok(
|
||||
fxAccounts.device.recentDeviceList?.every(
|
||||
device => device.type !== "mobile"
|
||||
),
|
||||
"No connected device is type:mobile"
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_mobile_connected() {
|
||||
const browser = gBrowser.selectedBrowser;
|
||||
const sandbox = setupMocks({
|
||||
state: UIState.STATUS_SIGNED_IN,
|
||||
fxaDevices: [
|
||||
{
|
||||
id: 1,
|
||||
name: "This Device",
|
||||
isCurrentDevice: true,
|
||||
type: "desktop",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Other Device",
|
||||
type: "mobile",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(null, UIState.ON_UPDATE);
|
||||
testSetupState(browser, {
|
||||
expectedVisible: {
|
||||
"#tabpickup-steps-view0": false,
|
||||
"#tabpickup-steps-view1": false,
|
||||
"#tabpickup-steps-view2": true,
|
||||
"#tabpickup-steps-view3": false,
|
||||
},
|
||||
});
|
||||
is(fxAccounts.device.recentDeviceList?.length, 2, "2 devices connected");
|
||||
ok(
|
||||
fxAccounts.device.recentDeviceList?.some(
|
||||
device => device.type !== "mobile"
|
||||
),
|
||||
"A connected device is type:mobile"
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
|
@ -65,7 +65,7 @@ DIRS += ["build"]
|
|||
if CONFIG["NIGHTLY_BUILD"]:
|
||||
DIRS += [
|
||||
"colorways",
|
||||
"myfirefox",
|
||||
"firefoxview",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -1,56 +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/.
|
||||
|
||||
-myfirefox-brand-name = My Firefox
|
||||
|
||||
toolbar-button-firefox-view =
|
||||
.label = { -myfirefox-brand-name }
|
||||
.tooltiptext = { -myfirefox-brand-name }
|
||||
|
||||
myfirefox-page-title = { -myfirefox-brand-name }
|
||||
|
||||
myfirefox-colorway-button = Colorway Closet
|
||||
|
||||
# Used instead of the localized relative time when a timestamp is within a minute or so of now
|
||||
myfirefox-just-now-timestamp = Just now
|
||||
|
||||
# This is a headline for an area in the product where users can resume and re-open tabs they have previously viewed on other devices.
|
||||
myfirefox-tabpickup-header = Tab Pickup
|
||||
myfirefox-tabpickup-description = Pick up where you left off on another device.
|
||||
|
||||
myfirefox-tabpickup-recenttabs-description = Recent tabs list would go here
|
||||
|
||||
# Variables:
|
||||
# $percentValue (Number): the percentage value for setup completion
|
||||
myfirefox-tabpickup-progress-label = { $percentValue }% complete
|
||||
|
||||
myfirefox-tabpickup-step-signin-header = Step 1 of 3: Sign in to { -brand-product-name }
|
||||
myfirefox-tabpickup-step-signin-description = To get your mobile tabs on this device, sign in to { -brand-product-name } and turn on sync.
|
||||
myfirefox-tabpickup-step-signin-primarybutton = Continue
|
||||
|
||||
# These are placeholders for now..
|
||||
|
||||
myfirefox-tabpickup-adddevice-header = Step 2 of 3: Sign in on a mobile device
|
||||
myfirefox-tabpickup-adddevice-description = Step 2 description.
|
||||
myfirefox-tabpickup-adddevice-primarybutton = Get { -brand-product-name } for mobile
|
||||
|
||||
myfirefox-tabpickup-synctabs-header = Step 3 of 3: Sync open tabs
|
||||
myfirefox-tabpickup-synctabs-description = Step 3 description.
|
||||
myfirefox-tabpickup-synctabs-primarybutton = Sync open tabs
|
||||
|
||||
myfirefox-tabpickup-setupsuccess-header = Setup Complete!
|
||||
myfirefox-tabpickup-setupsuccess-description = Step 4 description.
|
||||
myfirefox-tabpickup-setupsuccess-primarybutton = Get my other tabs
|
||||
|
||||
myfirefox-closed-tabs-title = Recently closed
|
||||
myfirefox-closed-tabs-collapse-button =
|
||||
.title = Show or hide recently closed tabs list
|
||||
|
||||
myfirefox-closed-tabs-description = Reopen pages you’ve closed on this device.
|
||||
myfirefox-closed-tabs-placeholder = History is empty <br/> The next time you close a tab, you can reopen it here.
|
||||
|
||||
# Variables:
|
||||
# $targetURI (string) - URL that will be opened in the new tab
|
||||
myfirefox-closed-tabs-tab-button =
|
||||
.title = Open { $targetURI } in a new tab
|
|
@ -1,4 +0,0 @@
|
|||
[DEFAULT]
|
||||
run-if = nightly_build # about:myfirefox is only enabled on Nightly
|
||||
|
||||
[browser_myfirefox.js]
|
|
@ -178,7 +178,6 @@ export class BaseContent extends React.PureComponent {
|
|||
filteredSections.filter(section => section.enabled).length === 0;
|
||||
const searchHandoffEnabled = prefs["improvesearch.handoffToAwesomebar"];
|
||||
const showCustomizationMenu = this.state.customizeMenuVisible;
|
||||
const showColorwayCloset = prefs["colorway-closet.enabled"];
|
||||
const enabledSections = {
|
||||
topSitesEnabled: prefs["feeds.topsites"],
|
||||
pocketEnabled: prefs["feeds.section.topstories"],
|
||||
|
@ -221,7 +220,6 @@ export class BaseContent extends React.PureComponent {
|
|||
pocketRegion={pocketRegion}
|
||||
mayHaveSponsoredTopSites={mayHaveSponsoredTopSites}
|
||||
showing={showCustomizationMenu}
|
||||
showColorwayCloset={showColorwayCloset}
|
||||
/>
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions*/}
|
||||
<div className={outerClassName} onClick={this.closeCustomizationMenu}>
|
||||
|
|
|
@ -1,9 +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/. */
|
||||
|
||||
import React from "react";
|
||||
|
||||
export const ColorwayCloset = ({ dispatch }) => (
|
||||
<div id="colorway-closet">Colorway Closet Placeholder</div>
|
||||
);
|
|
@ -7,7 +7,6 @@ import { ContentSection } from "content-src/components/CustomizeMenu/ContentSect
|
|||
import { connect } from "react-redux";
|
||||
import React from "react";
|
||||
import { CSSTransition } from "react-transition-group";
|
||||
import { ColorwayCloset } from "content-src/components/CustomizeMenu/ColorwayCloset/ColorwayCloset";
|
||||
|
||||
export class _CustomizeMenu extends React.PureComponent {
|
||||
constructor(props) {
|
||||
|
@ -63,11 +62,6 @@ export class _CustomizeMenu extends React.PureComponent {
|
|||
data-l10n-id="newtab-custom-close-button"
|
||||
ref={c => (this.closeButton = c)}
|
||||
/>
|
||||
{this.props.showColorwayCloset ? (
|
||||
<ColorwayCloset dispatch={this.props.dispatch} />
|
||||
) : (
|
||||
<React.Fragment />
|
||||
)}
|
||||
<BackgroundsSection />
|
||||
<ContentSection
|
||||
openPreferences={this.props.openPreferences}
|
||||
|
|
|
@ -13937,16 +13937,6 @@ class ContentSection extends (external_React_default()).PureComponent {
|
|||
}
|
||||
|
||||
}
|
||||
;// CONCATENATED MODULE: ./content-src/components/CustomizeMenu/ColorwayCloset/ColorwayCloset.jsx
|
||||
/* 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 ColorwayCloset = ({
|
||||
dispatch
|
||||
}) => /*#__PURE__*/external_React_default().createElement("div", {
|
||||
id: "colorway-closet"
|
||||
}, "Colorway Closet Placeholder");
|
||||
;// CONCATENATED MODULE: ./content-src/components/CustomizeMenu/CustomizeMenu.jsx
|
||||
/* 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,
|
||||
|
@ -13956,7 +13946,6 @@ const ColorwayCloset = ({
|
|||
|
||||
|
||||
|
||||
|
||||
class _CustomizeMenu extends (external_React_default()).PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -14003,9 +13992,7 @@ class _CustomizeMenu extends (external_React_default()).PureComponent {
|
|||
className: "close-button",
|
||||
"data-l10n-id": "newtab-custom-close-button",
|
||||
ref: c => this.closeButton = c
|
||||
}), this.props.showColorwayCloset ? /*#__PURE__*/external_React_default().createElement(ColorwayCloset, {
|
||||
dispatch: this.props.dispatch
|
||||
}) : /*#__PURE__*/external_React_default().createElement((external_React_default()).Fragment, null), /*#__PURE__*/external_React_default().createElement(BackgroundsSection, null), /*#__PURE__*/external_React_default().createElement(ContentSection, {
|
||||
}), /*#__PURE__*/external_React_default().createElement(BackgroundsSection, null), /*#__PURE__*/external_React_default().createElement(ContentSection, {
|
||||
openPreferences: this.props.openPreferences,
|
||||
setPref: this.props.setPref,
|
||||
enabledSections: this.props.enabledSections,
|
||||
|
@ -14418,7 +14405,6 @@ class BaseContent extends (external_React_default()).PureComponent {
|
|||
const noSectionsEnabled = !prefs["feeds.topsites"] && !pocketEnabled && filteredSections.filter(section => section.enabled).length === 0;
|
||||
const searchHandoffEnabled = prefs["improvesearch.handoffToAwesomebar"];
|
||||
const showCustomizationMenu = this.state.customizeMenuVisible;
|
||||
const showColorwayCloset = prefs["colorway-closet.enabled"];
|
||||
const enabledSections = {
|
||||
topSitesEnabled: prefs["feeds.topsites"],
|
||||
pocketEnabled: prefs["feeds.section.topstories"],
|
||||
|
@ -14441,8 +14427,7 @@ class BaseContent extends (external_React_default()).PureComponent {
|
|||
enabledSections: enabledSections,
|
||||
pocketRegion: pocketRegion,
|
||||
mayHaveSponsoredTopSites: mayHaveSponsoredTopSites,
|
||||
showing: showCustomizationMenu,
|
||||
showColorwayCloset: showColorwayCloset
|
||||
showing: showCustomizationMenu
|
||||
}), /*#__PURE__*/external_React_default().createElement("div", {
|
||||
className: outerClassName,
|
||||
onClick: this.closeCustomizationMenu
|
||||
|
|
|
@ -171,16 +171,6 @@ this.PrefsFeed = class PrefsFeed {
|
|||
value: placeholderPrefValue,
|
||||
});
|
||||
|
||||
// Read the pref for search Clorway Closet from firefox.js and store it
|
||||
// in our internal list of prefs to watch
|
||||
let colorwayClosetPrefValue = Services.prefs.getBoolPref(
|
||||
"browser.newtabpage.activity-stream.colorway-closet.enabled"
|
||||
);
|
||||
values["colorway-closet.enabled"] = colorwayClosetPrefValue;
|
||||
this._prefMap.set("colorway-closet.enabled", {
|
||||
value: colorwayClosetPrefValue,
|
||||
});
|
||||
|
||||
// Add experiment values and default values
|
||||
values.featureConfig = NimbusFeatures.newtab.getAllVariables() || {};
|
||||
values.pocketConfig = NimbusFeatures.pocketNewtab.getAllVariables() || {};
|
||||
|
|
|
@ -100,7 +100,7 @@ function test() {
|
|||
aCallback();
|
||||
};
|
||||
|
||||
launcherDialog.promptForSaveToFileAsync(launcher, aWin, null, null, null);
|
||||
launcherDialog.promptForSaveToFileAsync(launcher, aWin, "", "", false);
|
||||
}
|
||||
|
||||
testOnWindow(false, function(win, downloadDir) {
|
||||
|
|
|
@ -17,7 +17,7 @@ add_task(async function test_first_time_save() {
|
|||
await BrowserTestUtils.withNewTab({ gBrowser, url: FORM_URL }, async function(
|
||||
browser
|
||||
) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
let tabPromise = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
"about:preferences#privacy"
|
||||
|
@ -31,7 +31,7 @@ add_task(async function test_first_time_save() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
let cb = getDoorhangerCheckbox();
|
||||
ok(cb.hidden, "Sync checkbox should be hidden");
|
||||
// Open the panel via main button
|
||||
|
@ -100,7 +100,7 @@ add_task(async function test_first_time_save_with_sync_account() {
|
|||
await BrowserTestUtils.withNewTab({ gBrowser, url: FORM_URL }, async function(
|
||||
browser
|
||||
) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
let tabPromise = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
"about:preferences#privacy-address-autofill"
|
||||
|
@ -114,7 +114,7 @@ add_task(async function test_first_time_save_with_sync_account() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
let cb = getDoorhangerCheckbox();
|
||||
ok(!cb.hidden, "Sync checkbox should be visible");
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
"use strict";
|
||||
|
||||
const IFRAME_URL_PATH = BASE_URL + "autocomplete_iframe.html";
|
||||
|
@ -44,34 +43,32 @@ add_task(async function test_iframe_autocomplete() {
|
|||
await expectWarningText(browser, "Also autofills organization, email");
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
|
||||
let promiseShown = promiseNotificationShown();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
let loadPromise = BrowserTestUtils.browserLoaded(browser, true);
|
||||
let onLoaded = BrowserTestUtils.browserLoaded(browser, true);
|
||||
await SpecialPowers.spawn(iframeBC, [], async function() {
|
||||
Assert.equal(
|
||||
content.document.getElementById("street-address").value,
|
||||
"32 Vassar Street MIT Room 32-G524"
|
||||
);
|
||||
Assert.equal(content.document.getElementById("country").value, "US");
|
||||
|
||||
let org = content.document.getElementById("organization");
|
||||
Assert.equal(org.value, "World Wide Web Consortium");
|
||||
|
||||
// Now, modify the organization.
|
||||
org.setUserInput("Example Inc.");
|
||||
|
||||
await new Promise(resolve => content.setTimeout(resolve, 1000));
|
||||
content.document.querySelector("input[type=submit]").click();
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
return (
|
||||
content.document.getElementById("street-address").value ==
|
||||
"32 Vassar Street MIT Room 32-G524" &&
|
||||
content.document.getElementById("country").value == "US" &&
|
||||
content.document.getElementById("organization").value ==
|
||||
"World Wide Web Consortium"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
await loadPromise;
|
||||
await promiseShown;
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(iframeBC, {
|
||||
focusSelector: "#organization",
|
||||
newValues: {
|
||||
"#organization": "Example Inc.",
|
||||
},
|
||||
});
|
||||
await onPopupShown;
|
||||
await onLoaded;
|
||||
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed");
|
||||
let onUpdated = waitForStorageChangedEvents("update");
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
await onChanged;
|
||||
await onUpdated;
|
||||
|
||||
// Check that the organization was updated properly.
|
||||
let addresses = await getAddresses();
|
||||
|
@ -87,19 +84,21 @@ add_task(async function test_iframe_autocomplete() {
|
|||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, iframeBC);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
await waitForAutofill(iframeBC, "#organization", "Example Inc.");
|
||||
|
||||
// Open the dropdown and select the Clear Form item.
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, iframeBC);
|
||||
await openPopupForSubframe(browser, iframeBC, "#street-address");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, iframeBC);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
await SpecialPowers.spawn(iframeBC, [], async function() {
|
||||
Assert.equal(content.document.getElementById("street-address").value, "");
|
||||
Assert.equal(content.document.getElementById("country").value, "");
|
||||
Assert.equal(content.document.getElementById("organization").value, "");
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
return (
|
||||
content.document.getElementById("street-address").value == "" &&
|
||||
content.document.getElementById("country").value == "" &&
|
||||
content.document.getElementById("organization").value == ""
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
|
|
|
@ -9,7 +9,7 @@ add_task(async function test_update_address() {
|
|||
await BrowserTestUtils.withNewTab({ gBrowser, url: FORM_URL }, async function(
|
||||
browser
|
||||
) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await openPopupOn(browser, "form #organization");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
|
@ -25,7 +25,7 @@ add_task(async function test_update_address() {
|
|||
form.querySelector("input[type=submit]").click();
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
});
|
||||
|
||||
|
@ -41,7 +41,7 @@ add_task(async function test_create_new_address() {
|
|||
await BrowserTestUtils.withNewTab({ gBrowser, url: FORM_URL }, async function(
|
||||
browser
|
||||
) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await openPopupOn(browser, "form #tel");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
|
@ -57,7 +57,7 @@ add_task(async function test_create_new_address() {
|
|||
form.querySelector("input[type=submit]").click();
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(SECONDARY_BUTTON);
|
||||
});
|
||||
|
||||
|
@ -73,7 +73,7 @@ add_task(async function test_create_new_address_merge() {
|
|||
await BrowserTestUtils.withNewTab({ gBrowser, url: FORM_URL }, async function(
|
||||
browser
|
||||
) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await openPopupOn(browser, "form #tel");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
|
@ -89,7 +89,7 @@ add_task(async function test_create_new_address_merge() {
|
|||
form.querySelector("input[type=submit]").click();
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(SECONDARY_BUTTON);
|
||||
});
|
||||
|
||||
|
@ -104,7 +104,7 @@ add_task(async function test_submit_untouched_fields() {
|
|||
await BrowserTestUtils.withNewTab({ gBrowser, url: FORM_URL }, async function(
|
||||
browser
|
||||
) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await openPopupOn(browser, "form #organization");
|
||||
info("before down");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
|
@ -129,7 +129,7 @@ add_task(async function test_submit_untouched_fields() {
|
|||
info("after submit");
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
});
|
||||
|
||||
|
@ -145,7 +145,7 @@ add_task(async function test_submit_reduced_fields() {
|
|||
|
||||
let url = BASE_URL + "autocomplete_simple_basic.html";
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url }, async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await openPopupOn(browser, "form#simple input[name=tel]");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
|
@ -161,7 +161,7 @@ add_task(async function test_submit_reduced_fields() {
|
|||
form.querySelector("input[type=submit]").click();
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
});
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ add_task(async function test_submit_creditCard_cancel_saving() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -24,7 +24,7 @@ add_task(async function test_submit_creditCard_cancel_saving() {
|
|||
!SpecialPowers.Services.prefs.prefHasUserValue(SYNC_USERNAME_PREF),
|
||||
"Sync account should not exist by default"
|
||||
);
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
let cb = getDoorhangerCheckbox();
|
||||
ok(cb.hidden, "Sync checkbox should be hidden");
|
||||
await clickDoorhangerButton(SECONDARY_BUTTON);
|
||||
|
@ -51,7 +51,7 @@ add_task(async function test_submit_creditCard_saved() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
|
@ -64,7 +64,7 @@ add_task(async function test_submit_creditCard_saved() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
}
|
||||
);
|
||||
|
@ -214,7 +214,7 @@ add_task(async function test_iframe_unload_save_card() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_IFRAME_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
let iframeBC = browser.browsingContext.children[0];
|
||||
await focusUpdateSubmitForm(
|
||||
iframeBC,
|
||||
|
@ -237,7 +237,7 @@ add_task(async function test_iframe_unload_save_card() {
|
|||
frame.remove();
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
}
|
||||
);
|
||||
|
@ -268,7 +268,7 @@ add_task(async function test_submit_changed_subset_creditCard_form() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -279,7 +279,7 @@ add_task(async function test_submit_changed_subset_creditCard_form() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
}
|
||||
);
|
||||
|
@ -387,7 +387,7 @@ add_task(async function test_submit_creditCard_never_save() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -396,7 +396,7 @@ add_task(async function test_submit_creditCard_never_save() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MENU_BUTTON, 0);
|
||||
}
|
||||
);
|
||||
|
@ -429,7 +429,7 @@ add_task(async function test_submit_creditCard_with_sync_account() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -438,7 +438,7 @@ add_task(async function test_submit_creditCard_with_sync_account() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
let cb = getDoorhangerCheckbox();
|
||||
ok(!cb.hidden, "Sync checkbox should be visible");
|
||||
is(
|
||||
|
@ -516,7 +516,7 @@ add_task(async function test_submit_creditCard_with_synced_already() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -525,7 +525,7 @@ add_task(async function test_submit_creditCard_with_synced_already() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
let cb = getDoorhangerCheckbox();
|
||||
ok(cb.hidden, "Sync checkbox should be hidden");
|
||||
await clickDoorhangerButton(SECONDARY_BUTTON);
|
||||
|
@ -545,7 +545,7 @@ add_task(async function test_submit_manual_mergeable_creditCard_form() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -556,7 +556,7 @@ add_task(async function test_submit_manual_mergeable_creditCard_form() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
}
|
||||
);
|
||||
|
@ -597,7 +597,7 @@ add_task(async function test_update_autofill_form_name() {
|
|||
let osKeyStoreLoginShown = OSKeyStoreTestUtils.waitForOSKeyStoreLogin(
|
||||
true
|
||||
);
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
|
||||
await openPopupOn(browser, "form #cc-name");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
|
@ -612,7 +612,7 @@ add_task(async function test_update_autofill_form_name() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
}
|
||||
);
|
||||
|
@ -657,7 +657,7 @@ add_task(async function test_update_autofill_form_exp_date() {
|
|||
let osKeyStoreLoginShown = OSKeyStoreTestUtils.waitForOSKeyStoreLogin(
|
||||
true
|
||||
);
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await openPopupOn(browser, "form #cc-name");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
|
@ -671,7 +671,7 @@ add_task(async function test_update_autofill_form_exp_date() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
}
|
||||
);
|
||||
|
@ -716,7 +716,7 @@ add_task(async function test_create_new_autofill_form() {
|
|||
let osKeyStoreLoginShown = OSKeyStoreTestUtils.waitForOSKeyStoreLogin(
|
||||
true
|
||||
);
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await openPopupOn(browser, "form #cc-name");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
|
@ -729,7 +729,7 @@ add_task(async function test_create_new_autofill_form() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(SECONDARY_BUTTON);
|
||||
await osKeyStoreLoginShown;
|
||||
}
|
||||
|
@ -814,7 +814,7 @@ add_task(async function test_submit_creditCard_with_invalid_network() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -826,7 +826,7 @@ add_task(async function test_submit_creditCard_with_invalid_network() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
}
|
||||
);
|
||||
|
@ -850,7 +850,7 @@ add_task(async function test_submit_form_with_combined_expiry_field() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_COMBINED_EXPIRY_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -859,7 +859,7 @@ add_task(async function test_submit_form_with_combined_expiry_field() {
|
|||
"#cc-exp": "05/28",
|
||||
},
|
||||
});
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
}
|
||||
);
|
||||
|
@ -889,7 +889,7 @@ add_task(async function test_submit_third_party_creditCard_logo() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -898,7 +898,7 @@ add_task(async function test_submit_third_party_creditCard_logo() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
let doorhanger = getNotification();
|
||||
let creditCardLogo = doorhanger.querySelector(".desc-message-box image");
|
||||
let creditCardLogoWithoutExtension = creditCardLogo.src.split(".", 1)[0];
|
||||
|
@ -930,7 +930,7 @@ add_task(async function test_update_third_party_creditCard_logo() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -941,7 +941,7 @@ add_task(async function test_update_third_party_creditCard_logo() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
|
||||
let doorhanger = getNotification();
|
||||
let creditCardLogo = doorhanger.querySelector(".desc-message-box image");
|
||||
|
@ -966,7 +966,7 @@ add_task(async function test_submit_generic_creditCard_logo() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -975,7 +975,7 @@ add_task(async function test_submit_generic_creditCard_logo() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
let doorhanger = getNotification();
|
||||
let creditCardLogo = doorhanger.querySelector(".desc-message-box image");
|
||||
let creditCardLogoWithoutExtension = creditCardLogo.src.split(".", 1)[0];
|
||||
|
@ -1006,7 +1006,7 @@ add_task(async function test_update_generic_creditCard_logo() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -1017,7 +1017,7 @@ add_task(async function test_update_generic_creditCard_logo() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
|
||||
let doorhanger = getNotification();
|
||||
let creditCardLogo = doorhanger.querySelector(".desc-message-box image");
|
||||
|
@ -1043,7 +1043,7 @@ add_task(async function test_save_panel_spaces_in_cc_number_logo() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -1051,7 +1051,7 @@ add_task(async function test_save_panel_spaces_in_cc_number_logo() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
let doorhanger = getNotification();
|
||||
let creditCardLogo = doorhanger.querySelector(".desc-message-box image");
|
||||
let creditCardLogoWithoutExtension = creditCardLogo.src.split(".", 1)[0];
|
||||
|
@ -1082,7 +1082,7 @@ add_task(async function test_update_panel_with_spaces_in_cc_number_logo() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -1093,7 +1093,7 @@ add_task(async function test_update_panel_with_spaces_in_cc_number_logo() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
|
||||
let doorhanger = getNotification();
|
||||
let creditCardLogo = doorhanger.querySelector(".desc-message-box image");
|
||||
|
|
|
@ -27,7 +27,7 @@ add_task(async function test_new_submitted_card_is_normalized() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let promiseShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
@ -81,7 +81,7 @@ add_task(async function test_updated_card_is_normalized() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let promiseShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#cc-name",
|
||||
newValues: {
|
||||
|
|
|
@ -209,7 +209,7 @@ add_task(async function test_submit_creditCard_new() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed");
|
||||
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
|
@ -223,7 +223,7 @@ add_task(async function test_submit_creditCard_new() {
|
|||
},
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(command, idx);
|
||||
if (expectChanged !== undefined) {
|
||||
await onChanged;
|
||||
|
@ -382,7 +382,7 @@ add_task(async function test_submit_creditCard_update() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: CREDITCARD_FORM_URL },
|
||||
async function(browser) {
|
||||
let promiseShown = promiseNotificationShown();
|
||||
let onPopupShown = waitForPopupShown();
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed");
|
||||
|
||||
await openPopupOn(browser, "form #cc-name");
|
||||
|
@ -397,7 +397,7 @@ add_task(async function test_submit_creditCard_update() {
|
|||
"#cc-exp-year": "2019",
|
||||
},
|
||||
});
|
||||
await promiseShown;
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(command, idx);
|
||||
if (expectChanged !== undefined) {
|
||||
await onChanged;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
openPopupOn, openPopupForSubframe, closePopup, closePopupForSubframe,
|
||||
clickDoorhangerButton, getAddresses, saveAddress, removeAddresses, saveCreditCard, setStorage,
|
||||
getDisplayedPopupItems, getDoorhangerCheckbox, waitForPopupEnabled,
|
||||
getNotification, promiseNotificationShown, getDoorhangerButton, removeAllRecords, expectWarningText, testDialog */
|
||||
getNotification, waitForPopupShown, getDoorhangerButton, removeAllRecords, expectWarningText, testDialog */
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -458,6 +458,7 @@ async function runAndWaitForAutocompletePopupOpen(browser, taskFn) {
|
|||
return (
|
||||
(item.getAttribute("originaltype") == "autofill-profile" ||
|
||||
item.getAttribute("originaltype") == "autofill-insecureWarning" ||
|
||||
item.getAttribute("originaltype") == "autofill-clear-button" ||
|
||||
item.getAttribute("originaltype") == "autofill-footer") &&
|
||||
item.hasAttribute("formautofillattached")
|
||||
);
|
||||
|
@ -640,7 +641,7 @@ function getNotification(index = 0) {
|
|||
return notifications[index];
|
||||
}
|
||||
|
||||
function promiseNotificationShown() {
|
||||
function waitForPopupShown() {
|
||||
return BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ const TESTCASES = [
|
|||
<input autocomplete="family-name">
|
||||
<input id="street-addr" autocomplete="street-address">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -85,7 +85,7 @@ const TESTCASES = [
|
|||
<input id="line2" autocomplete="address-line2">
|
||||
<input id="line3" autocomplete="address-line3">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -108,7 +108,7 @@ const TESTCASES = [
|
|||
<input id="street-addr" autocomplete="street-address">
|
||||
<input id="line1" autocomplete="address-line1">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -131,7 +131,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line2" autocomplete="address-line2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -156,7 +156,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line3" autocomplete="address-line3">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -183,7 +183,7 @@ const TESTCASES = [
|
|||
<input id="address-line1">
|
||||
<input id="address-line3">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -214,7 +214,7 @@ const TESTCASES = [
|
|||
<option id="option-country-US" value="US">United States</option>
|
||||
</select>
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -249,7 +249,7 @@ const TESTCASES = [
|
|||
<option id="option-country-OO" value="OO">United States</option>
|
||||
</select>
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -284,7 +284,7 @@ const TESTCASES = [
|
|||
<option id="option-country-2" value="">United States</option>
|
||||
</select>
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -319,7 +319,7 @@ const TESTCASES = [
|
|||
<option id="option-country-same2" value="sametoo">United States</option>
|
||||
</select>
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -355,7 +355,7 @@ const TESTCASES = [
|
|||
<option id="option-country-dummy2" value="">Dummy 2</option>
|
||||
</select>
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -377,7 +377,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line2" autocomplete="address-line2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -401,7 +401,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line2" autocomplete="address-line2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -425,7 +425,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line2" autocomplete="address-line2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -449,7 +449,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line2" autocomplete="address-line2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -473,7 +473,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line2" autocomplete="address-line2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -497,7 +497,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line2" autocomplete="address-line2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -521,7 +521,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line2" autocomplete="address-line2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -544,7 +544,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line2" autocomplete="address-line2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -568,7 +568,7 @@ const TESTCASES = [
|
|||
<input id="line1" autocomplete="address-line1">
|
||||
<input id="line2" autocomplete="address-line2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
profileData: [{ ...DEFAULT_ADDRESS_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "123",
|
||||
|
@ -592,7 +592,7 @@ const TESTCASES = [
|
|||
<input autocomplete="family-name" maxlength="1">
|
||||
<input autocomplete="postal-code" maxlength="5">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, ADDRESS_RECORD_2)],
|
||||
profileData: [{ ...ADDRESS_RECORD_2 }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "address2",
|
||||
|
@ -611,7 +611,7 @@ const TESTCASES = [
|
|||
<input autocomplete="additional-name" maxlength="0">
|
||||
<input autocomplete="family-name" maxlength="1">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, ADDRESS_RECORD_2)],
|
||||
profileData: [{ ...ADDRESS_RECORD_2 }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: "address2",
|
||||
|
@ -655,7 +655,7 @@ const TESTCASES = [
|
|||
<option id="option-cc-exp-year-28" value="2028">28</option>
|
||||
</select>
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [
|
||||
{
|
||||
|
@ -706,7 +706,7 @@ const TESTCASES = [
|
|||
<option label="2035" id="option-cc-exp-year-35" value="object:47">dummy</option>
|
||||
</select>
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [
|
||||
{
|
||||
|
@ -723,7 +723,7 @@ const TESTCASES = [
|
|||
<option value="3/17">3/17</option>
|
||||
<option value="1/25" id="selected-cc-exp">1/25</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -735,7 +735,7 @@ const TESTCASES = [
|
|||
<option value="3/2017">3/2017</option>
|
||||
<option value="1/2025" id="selected-cc-exp">1/2025</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -747,7 +747,7 @@ const TESTCASES = [
|
|||
<option value="03/17">03/17</option>
|
||||
<option value="01/25" id="selected-cc-exp">01/25</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -759,7 +759,7 @@ const TESTCASES = [
|
|||
<option value="03/2017">03/2017</option>
|
||||
<option value="01/2025" id="selected-cc-exp">01/2025</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -771,7 +771,7 @@ const TESTCASES = [
|
|||
<option value="3-17">3-17</option>
|
||||
<option value="1-25" id="selected-cc-exp">1-25</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -783,7 +783,7 @@ const TESTCASES = [
|
|||
<option value="3-2017">3-2017</option>
|
||||
<option value="1-2025" id="selected-cc-exp">1-2025</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -795,7 +795,7 @@ const TESTCASES = [
|
|||
<option value="03-17">03-17</option>
|
||||
<option value="01-25" id="selected-cc-exp">01-25</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -807,7 +807,7 @@ const TESTCASES = [
|
|||
<option value="03-2017">03-2017</option>
|
||||
<option value="01-2025" id="selected-cc-exp">01-2025</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -819,7 +819,7 @@ const TESTCASES = [
|
|||
<option value="17-03">17-03</option>
|
||||
<option value="25-01" id="selected-cc-exp">25-01</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -831,7 +831,7 @@ const TESTCASES = [
|
|||
<option value="2017-03">2017-03</option>
|
||||
<option value="2025-01" id="selected-cc-exp">2025-01</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -843,7 +843,7 @@ const TESTCASES = [
|
|||
<option value="2017/3">2017/3</option>
|
||||
<option value="2025/1" id="selected-cc-exp">2025/1</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -855,7 +855,7 @@ const TESTCASES = [
|
|||
<option value="0317">0317</option>
|
||||
<option value="0125" id="selected-cc-exp">0125</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -867,7 +867,7 @@ const TESTCASES = [
|
|||
<option value="1703">1703</option>
|
||||
<option value="2501" id="selected-cc-exp">2501</option>
|
||||
</select></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
expectedOptionElements: [{ "cc-exp": "selected-cc-exp" }],
|
||||
},
|
||||
|
@ -880,13 +880,10 @@ const TESTCASES = [
|
|||
<option value="01/25">01/25</option>
|
||||
</select></form>`,
|
||||
profileData: [
|
||||
Object.assign(
|
||||
{},
|
||||
{
|
||||
guid: "123",
|
||||
"cc-exp-year": 2025,
|
||||
}
|
||||
),
|
||||
{
|
||||
guid: "123",
|
||||
"cc-exp-year": 2025,
|
||||
},
|
||||
],
|
||||
expectedResult: [
|
||||
{
|
||||
|
@ -905,13 +902,10 @@ const TESTCASES = [
|
|||
<option value="01/25">01/25</option>
|
||||
</select></form>`,
|
||||
profileData: [
|
||||
Object.assign(
|
||||
{},
|
||||
{
|
||||
guid: "123",
|
||||
"cc-exp-month": 1,
|
||||
}
|
||||
),
|
||||
{
|
||||
guid: "123",
|
||||
"cc-exp-month": 1,
|
||||
},
|
||||
],
|
||||
expectedResult: [
|
||||
{
|
||||
|
@ -935,13 +929,10 @@ const TESTCASES = [
|
|||
</select>
|
||||
</form>`,
|
||||
profileData: [
|
||||
Object.assign(
|
||||
{},
|
||||
{
|
||||
guid: "123",
|
||||
"cc-exp-year": 2025,
|
||||
}
|
||||
),
|
||||
{
|
||||
guid: "123",
|
||||
"cc-exp-year": 2025,
|
||||
},
|
||||
],
|
||||
expectedResult: [
|
||||
{
|
||||
|
@ -965,13 +956,10 @@ const TESTCASES = [
|
|||
</select>
|
||||
</form>`,
|
||||
profileData: [
|
||||
Object.assign(
|
||||
{},
|
||||
{
|
||||
guid: "123",
|
||||
"cc-exp-month": 1,
|
||||
}
|
||||
),
|
||||
{
|
||||
guid: "123",
|
||||
"cc-exp-month": 1,
|
||||
},
|
||||
],
|
||||
expectedResult: [
|
||||
{
|
||||
|
@ -985,95 +973,101 @@ const TESTCASES = [
|
|||
description: "Fill a cc-exp without placeholder on the cc-exp field",
|
||||
document: `<form><input autocomplete="cc-number">
|
||||
<input autocomplete="cc-exp"></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [Object.assign({}, DEFAULT_EXPECTED_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_EXPECTED_CREDITCARD_RECORD],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp format [mm/yy].",
|
||||
document: `<form><input autocomplete="cc-number">
|
||||
<input placeholder="mm/yy" autocomplete="cc-exp"></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp": "01/25",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp format [mm / yy].",
|
||||
document: `<form><input autocomplete="cc-number">
|
||||
<input placeholder="mm / yy" autocomplete="cc-exp"></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp": "01/25",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp format [MM / YY].",
|
||||
document: `<form><input autocomplete="cc-number">
|
||||
<input placeholder="MM / YY" autocomplete="cc-exp"></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp": "01/25",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp format [mm / yyyy].",
|
||||
document: `<form><input autocomplete="cc-number">
|
||||
<input placeholder="mm / yyyy" autocomplete="cc-exp"></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp": "01/2025",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp format [mm - yyyy].",
|
||||
document: `<form><input autocomplete="cc-number">
|
||||
<input placeholder="mm - yyyy" autocomplete="cc-exp"></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp": "01-2025",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp format [yyyy-mm].",
|
||||
document: `<form><input autocomplete="cc-number">
|
||||
<input placeholder="yyyy-mm" autocomplete="cc-exp"></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp": "2025-01",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp format [mmm yyyy].",
|
||||
document: `<form><input autocomplete="cc-number">
|
||||
<input placeholder="mmm yyyy" autocomplete="cc-exp"></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_CREDITCARD_RECORD],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp format [mm foo yyyy].",
|
||||
document: `<form><input autocomplete="cc-number">
|
||||
<input placeholder="mm foo yyyy" autocomplete="cc-exp"></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_CREDITCARD_RECORD],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp format [mm - - yyyy].",
|
||||
document: `<form><input autocomplete="cc-number">
|
||||
<input placeholder="mm - - yyyy" autocomplete="cc-exp"></form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_CREDITCARD_RECORD],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp-month field [mm].",
|
||||
|
@ -1082,11 +1076,12 @@ const TESTCASES = [
|
|||
<input autocomplete="cc-exp-month" placeholder="MM">
|
||||
<input autocomplete="cc-exp-year">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp-month-formatted": getCCExpMonthFormatted(),
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -1096,11 +1091,12 @@ const TESTCASES = [
|
|||
<input autocomplete="cc-exp-month">
|
||||
<input autocomplete="cc-exp-year" placeholder="YY">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp-year-formatted": getCCExpYearFormatted(),
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -1110,11 +1106,12 @@ const TESTCASES = [
|
|||
<input autocomplete="cc-exp-month" maxlength="2">
|
||||
<input autocomplete="cc-exp-year" maxlength="2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp-year": 25,
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -1124,8 +1121,8 @@ const TESTCASES = [
|
|||
<input autocomplete="cc-exp-month" maxlength="4">
|
||||
<input autocomplete="cc-exp-year" maxlength="4">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_CREDITCARD_RECORD],
|
||||
},
|
||||
// Bug 1687679: The default value of an expiration month, when filled in an input element,
|
||||
// is a two character length string. Because of this, testing a maxlength of 1 is invalid.
|
||||
|
@ -1136,12 +1133,13 @@ const TESTCASES = [
|
|||
<input autocomplete="cc-exp-month" maxlength="1">
|
||||
<input autocomplete="cc-exp-year" maxlength="1">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp-year": 5,
|
||||
"cc-exp-month": 1,
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -1151,7 +1149,7 @@ const TESTCASES = [
|
|||
<input autocomplete="cc-exp-month" maxlength="0">
|
||||
<input autocomplete="cc-exp-year" maxlength="0">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
{
|
||||
guid: DEFAULT_CREDITCARD_RECORD.guid,
|
||||
|
@ -1167,8 +1165,8 @@ const TESTCASES = [
|
|||
<input autocomplete="cc-exp-month" maxlength="-2">
|
||||
<input autocomplete="cc-exp-year" maxlength="-2">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_CREDITCARD_RECORD],
|
||||
},
|
||||
{
|
||||
description: "Test maxlength=10 on numeric fields.",
|
||||
|
@ -1177,8 +1175,8 @@ const TESTCASES = [
|
|||
<input autocomplete="cc-exp-month" maxlength="10">
|
||||
<input autocomplete="cc-exp-year" maxlength="10">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [DEFAULT_CREDITCARD_RECORD],
|
||||
},
|
||||
{
|
||||
description: "Test (special case) maxlength=5 on cc-exp field.",
|
||||
|
@ -1186,11 +1184,12 @@ const TESTCASES = [
|
|||
<input autocomplete="cc-number">
|
||||
<input autocomplete="cc-exp" maxlength="5">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
profileData: [{ ...DEFAULT_CREDITCARD_RECORD }],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
{
|
||||
...DEFAULT_CREDITCARD_RECORD,
|
||||
"cc-exp": "01/25",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
@ -51,6 +51,9 @@ toolbar-context-menu-pin-to-overflow-menu =
|
|||
toolbar-context-menu-auto-hide-downloads-button-2 =
|
||||
.label = Hide Button When Empty
|
||||
.accesskey = H
|
||||
toolbar-context-menu-always-open-downloads-panel =
|
||||
.label = Show Panel When Download Begins
|
||||
.accesskey = S
|
||||
toolbar-context-menu-remove-from-toolbar =
|
||||
.label = Remove from Toolbar
|
||||
.accesskey = R
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
preview/interventions.ftl (../components/urlbar/content/interventions.ftl)
|
||||
preview/firefoxSuggest.ftl (../components/urlbar/content/firefoxSuggest.ftl)
|
||||
#ifdef NIGHTLY_BUILD
|
||||
preview/myFirefox.ftl (../components/myfirefox/myFirefox.ftl)
|
||||
preview/firefoxView.ftl (../components/firefoxview/firefoxView.ftl)
|
||||
#endif
|
||||
browser (%browser/**/*.ftl)
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
[gold] Ignore bitcode from sections inside object files
|
||||
|
||||
-fembed-bitcode will put bitcode into special sections within object
|
||||
files, but this is not meant to be used by LTO, so the gold plugin
|
||||
should ignore it.
|
||||
|
||||
https://github.com/llvm/llvm-project/issues/47216
|
||||
|
||||
diff --git a/llvm/test/tools/gold/X86/Inputs/bcsection-lib.ll b/llvm/test/tools/gold/X86/Inputs/bcsection-lib.ll
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/llvm/test/tools/gold/X86/Inputs/bcsection-lib.ll
|
||||
@@ -0,0 +1,6 @@
|
||||
+declare void @elf_func()
|
||||
+
|
||||
+define i32 @lib_func() {
|
||||
+ call void @elf_func()
|
||||
+ ret i32 0
|
||||
+}
|
||||
diff --git a/llvm/test/tools/gold/X86/Inputs/bcsection.s b/llvm/test/tools/gold/X86/Inputs/bcsection.s
|
||||
--- a/llvm/test/tools/gold/X86/Inputs/bcsection.s
|
||||
+++ b/llvm/test/tools/gold/X86/Inputs/bcsection.s
|
||||
@@ -1,2 +1,7 @@
|
||||
+.global elf_func
|
||||
+
|
||||
+elf_func:
|
||||
+ ret
|
||||
+
|
||||
.section .llvmbc
|
||||
.incbin "bcsection.bc"
|
||||
diff --git a/llvm/test/tools/gold/X86/bcsection.ll b/llvm/test/tools/gold/X86/bcsection.ll
|
||||
--- a/llvm/test/tools/gold/X86/bcsection.ll
|
||||
+++ b/llvm/test/tools/gold/X86/bcsection.ll
|
||||
@@ -2,16 +2,29 @@
|
||||
; RUN: llvm-as -o %t/bcsection.bc %s
|
||||
|
||||
; RUN: llvm-mc -I=%t -filetype=obj -triple=x86_64-unknown-unknown -o %t/bcsection.bco %p/Inputs/bcsection.s
|
||||
-; RUN: llvm-nm --no-llvm-bc %t/bcsection.bco 2>&1 | FileCheck %s -check-prefix=NO-SYMBOLS
|
||||
-; NO-SYMBOLS: no symbols
|
||||
+; RUN: llc -filetype=obj -mtriple=x86_64-unknown-unknown -o %t/bcsection-lib.o %p/Inputs/bcsection-lib.ll
|
||||
|
||||
-; RUN: %gold -r -o %t/bcsection.o -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext %t/bcsection.bco
|
||||
-; RUN: llvm-nm --no-llvm-bc %t/bcsection.o | FileCheck %s
|
||||
+; RUN: %gold -shared --no-undefined -o %t/bcsection.so -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext %t/bcsection.bco %t/bcsection-lib.o
|
||||
+
|
||||
+; This test checks that the gold plugin does not attempt to use the bitcode
|
||||
+; in the .llvmbc section for LTO. bcsection-lib.o calls a function that is
|
||||
+; present the symbol table of bcsection.bco, but not included in the embedded
|
||||
+; bitcode. If the linker were to use the bitcode, then the symbols in the
|
||||
+; symbol table of bcsection.bco will be ignored and the link will fail.
|
||||
+;
|
||||
+; bcsection.bco:
|
||||
+; .text:
|
||||
+; elf_func
|
||||
+; .llvmbc:
|
||||
+; bitcode_func
|
||||
+;
|
||||
+; bcsection-lib.o:
|
||||
+; calls elf_func()
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-unknown"
|
||||
|
||||
; CHECK: main
|
||||
-define i32 @main() {
|
||||
+define i32 @bitcode_func() {
|
||||
ret i32 0
|
||||
}
|
||||
diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp
|
||||
--- a/llvm/tools/gold/gold-plugin.cpp
|
||||
+++ b/llvm/tools/gold/gold-plugin.cpp
|
||||
@@ -540,6 +540,14 @@
|
||||
BufferRef = Buffer->getMemBufferRef();
|
||||
}
|
||||
|
||||
+ // Only use bitcode files for LTO. InputFile::create() will load bitcode
|
||||
+ // from special sections within a binary object, this bitcode is typically
|
||||
+ // generated by -fembed-bitcode and is not meant for LTO use.
|
||||
+ if (identify_magic(BufferRef.getBuffer()) != file_magic::bitcode) {
|
||||
+ *claimed = 0;
|
||||
+ return LDPS_OK;
|
||||
+ }
|
||||
+
|
||||
*claimed = 1;
|
||||
|
||||
Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(BufferRef);
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
"Remove-FlushViewOfFile-when-unmaping-gcda-files.patch",
|
||||
"fuzzing_ccov_build_clang_12.patch",
|
||||
"win64-no-symlink.patch",
|
||||
"D116995.diff",
|
||||
"revert-llvmorg-14-init-14141-gd6d3000a2f6d.patch",
|
||||
"revert-llvmorg-14-init-11890-gf86deb18cab6.patch",
|
||||
"llvmorg-15-init-283-g4db89e23190d.patch"
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
From 8ce475543d784f8ce0f7e80f7faff39fa8eb92da Mon Sep 17 00:00:00 2001
|
||||
From: Jason Merrill <jason@redhat.com>
|
||||
Date: Mon, 11 Apr 2022 14:50:14 -0400
|
||||
Subject: [PATCH] c++: rodata and defaulted ctor [PR104142]
|
||||
|
||||
Trivial initialization shouldn't bump a variable out of .rodata; if the
|
||||
result of build_aggr_init is an empty STATEMENT_LIST, throw it away.
|
||||
|
||||
PR c++/104142
|
||||
|
||||
gcc/cp/ChangeLog:
|
||||
|
||||
* decl.cc (check_initializer): Check TREE_SIDE_EFFECTS.
|
||||
|
||||
gcc/testsuite/ChangeLog:
|
||||
|
||||
* g++.dg/opt/const7.C: New test.
|
||||
---
|
||||
gcc/cp/decl.c | 4 ++++
|
||||
gcc/testsuite/g++.dg/opt/const7.C | 7 +++++++
|
||||
2 files changed, 11 insertions(+)
|
||||
create mode 100644 gcc/testsuite/g++.dg/opt/const7.C
|
||||
|
||||
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
|
||||
index bffbd004167..7b0872cd55e 100644
|
||||
--- a/gcc/cp/decl.c
|
||||
+++ b/gcc/cp/decl.c
|
||||
@@ -7227,6 +7227,10 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
|
||||
if (init && init != error_mark_node)
|
||||
init_code = build2 (INIT_EXPR, type, decl, init);
|
||||
|
||||
+ if (init_code && !TREE_SIDE_EFFECTS (init_code)
|
||||
+ && init_code != error_mark_node)
|
||||
+ init_code = NULL_TREE;
|
||||
+
|
||||
if (init_code)
|
||||
{
|
||||
/* We might have set these in cp_finish_decl. */
|
||||
diff --git a/gcc/testsuite/g++.dg/opt/const7.C b/gcc/testsuite/g++.dg/opt/const7.C
|
||||
new file mode 100644
|
||||
index 00000000000..5bcf94897a8
|
||||
--- /dev/null
|
||||
+++ b/gcc/testsuite/g++.dg/opt/const7.C
|
||||
@@ -0,0 +1,7 @@
|
||||
+// PR c++/104142
|
||||
+// { dg-do compile { target c++11 } }
|
||||
+// { dg-additional-options -Wunused-variable }
|
||||
+
|
||||
+struct B { B()=default; };
|
||||
+static const B b_var; // { dg-bogus "" }
|
||||
+// { dg-final { scan-assembler-symbol-section {b_var} {^\.(const|rodata)|\[RO\]} } }
|
||||
--
|
||||
2.36.0.1.g2bbe56bd8d
|
||||
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 6.1 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 2.3 KiB |
|
@ -1,10 +0,0 @@
|
|||
==================
|
||||
Other coding style
|
||||
==================
|
||||
|
||||
SVG practices
|
||||
-------------
|
||||
|
||||
Check `SVG
|
||||
Guidelines <https://developer.mozilla.org/docs/Mozilla/Developer_guide/SVG_Guidelines>`__ for
|
||||
more details.
|
|
@ -0,0 +1,572 @@
|
|||
CSS Guidelines
|
||||
==============
|
||||
|
||||
This document contains guidelines defining how CSS inside the Firefox
|
||||
codebase should be written, it is notably relevant for Firefox front-end
|
||||
engineers.
|
||||
|
||||
Basics
|
||||
------
|
||||
|
||||
Here are some basic tips that can optimize reviews if you are changing
|
||||
CSS:
|
||||
|
||||
- Avoid ``!important`` but if you have to use it, make sure it's
|
||||
obvious why you're using it (ideally with a comment). The
|
||||
`Overriding CSS`_ section contains more information about this.
|
||||
- Avoid magic numbers; prefer automatic sizing or alignment methods.
|
||||
Some examples to avoid:
|
||||
|
||||
- absolutely positioned elements
|
||||
- hardcoded values such as: ``vertical-align: -2px;`` . The reason
|
||||
you should avoid such "hardcoded" values is that, they don't
|
||||
necessarily work for all font-size configurations.
|
||||
|
||||
- Avoid setting styles in JavaScript. It's generally better to set a
|
||||
class and then specify the styles in CSS.
|
||||
- ``classList`` is generally better than ``className``. There's less
|
||||
chance of overwriting an existing class.
|
||||
- Only use generic selectors such as ``:last-child``, when it is what
|
||||
you mean semantically. If not, using a semantic class name is more
|
||||
descriptive and usually better.
|
||||
|
||||
Boilerplate
|
||||
~~~~~~~~~~~
|
||||
|
||||
Make sure each file starts with the standard copyright header (see
|
||||
`License Boilerplate <https://www.mozilla.org/MPL/headers/>`__).
|
||||
|
||||
Before adding more CSS
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It is good practice to check if the CSS that is being written is needed,
|
||||
it can be the case that a common component has been already written
|
||||
could be reused with or without changes. Most of the time, the common
|
||||
component already follows the a11y/theme standards defined in this
|
||||
guide. So, when possible, always prefer editing common components to
|
||||
writing your own.
|
||||
|
||||
Also, it is good practice to introduce a common class when the new
|
||||
element you are styling reuses some styles from another element, this
|
||||
allows the maintenance cost and the amount of code duplication to be
|
||||
reduced.
|
||||
|
||||
Formatting
|
||||
----------
|
||||
|
||||
Spacing & Indentation
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- 2 spaces indentation is preferred
|
||||
- Add a space after each comma, **except** within color functions:
|
||||
|
||||
.. code:: css
|
||||
|
||||
linear-gradient(to bottom, black 1px, rgba(255,255,255,0.2) 1px)
|
||||
|
||||
- Always add a space before ``!important``.
|
||||
|
||||
Omit units on 0 values
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Do this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
margin: 0;
|
||||
|
||||
Not this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
margin: 0px;
|
||||
|
||||
Use expanded syntax
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It is often harder to understand what the shorthand is doing and the
|
||||
shorthand can also hide some unwanted default values. It is good to
|
||||
privilege expanded syntax to make your intentions explicit.
|
||||
|
||||
Do this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
border-color: red;
|
||||
|
||||
Not this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
border: red;
|
||||
|
||||
Put multiple selectors on different lines
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Do this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
Not this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
h1, h2, h3 {
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
Naming standards for class names
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- ``lower-case-with-dashes`` is the most common.
|
||||
- But ``camelCase`` is also used sometimes. Try to follow the style of
|
||||
existing or related code.
|
||||
|
||||
Other tips
|
||||
~~~~~~~~~~
|
||||
|
||||
- Assume ``="true"`` in attribute selectors.
|
||||
|
||||
- Example: Use ``option[checked]``, not ``option[checked="true"]``.
|
||||
|
||||
- Avoid ID selectors unless it is really the wanted goal, since IDs
|
||||
have higher specificity and therefore are harder to override.
|
||||
- Using descendant selectors is good practice for performance when
|
||||
possible:
|
||||
|
||||
- For example:
|
||||
``.autocomplete-item[selected] > .autocomplete-item-title`` would
|
||||
be more efficient than
|
||||
``.autocomplete-item[selected] .autocomplete-item-title``
|
||||
|
||||
Overriding CSS
|
||||
--------------
|
||||
|
||||
Before overriding any CSS rules, check whether overriding is really
|
||||
needed. Sometimes, when copy-pasting older code, it happens that the
|
||||
code in question contains unnecessary overrides. This could be because
|
||||
the CSS that it was overriding got removed in the meantime. In this
|
||||
case, dropping the override should work.
|
||||
|
||||
It is also good practice to look at whether the rule you are overriding
|
||||
is still needed: maybe the UX spec for the component has changed and
|
||||
that rule can actually be updated or removed. When this is the case,
|
||||
don't be afraid to remove or update that rule.
|
||||
|
||||
Once the two things above have been checked, check if the other rule you
|
||||
are overriding contains ``!important``, if that is case, try putting it
|
||||
in question, because it might have become obsolete.
|
||||
|
||||
Afterwards, check the specificity of the other selector; if it is
|
||||
causing your rule to be overridden, you can try reducing its
|
||||
specificity, either by simplifying the selector or by changing where the
|
||||
rule is placed in the stylesheet. If this isn't possible, you can also
|
||||
try introducing a ``:not()`` to prevent the other rule from applying,
|
||||
this is especially relevant for different element states (``:hover``,
|
||||
``:active``, ``[checked]`` or ``[disabled]``). However, never try to
|
||||
increase the selector of the rule you are adding as it can easily become
|
||||
hard to understand.
|
||||
|
||||
Finally, once you have checked all the things above, you can permit
|
||||
yourself to use ``!important`` along with a comment why it is needed.
|
||||
|
||||
Using CSS variables
|
||||
-------------------
|
||||
|
||||
Adding new variables
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Before adding new CSS variables, please consider the following
|
||||
questions:
|
||||
|
||||
#. **Is the variable value changed at runtime?**
|
||||
*(Either from JavaScript or overridden by another CSS file)*
|
||||
**If the answer is no**, consider using a preprocessor variable or
|
||||
inlining the value.
|
||||
|
||||
#. **Is the variable value used multiple times?**
|
||||
**If the answer is no and the value isn't changed at runtime**, then
|
||||
you likely don't need a CSS variable.
|
||||
|
||||
#. **Is there an alternative to using the variable like inheriting or
|
||||
using the ``currentcolor`` keyword?**
|
||||
Using inheriting or using ``currentcolor`` will prevent repetition of
|
||||
the value and it is usually good practice to do so.
|
||||
|
||||
In general, it's good to first think of how some CSS could be written
|
||||
cleanly without the CSS variable(s) and then think of how the CSS
|
||||
variable could improve that CSS.
|
||||
|
||||
Using variables
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Use the variable according to its naming
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Do this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
xul|tab:hover {
|
||||
background-color: var(--in-content-box-background-hover);
|
||||
}
|
||||
|
||||
Not this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
#certificateErrorDebugInformation {
|
||||
background-color: var(--in-content-box-background-hover);
|
||||
}
|
||||
|
||||
Localization
|
||||
------------
|
||||
|
||||
Text Direction
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
- For margins, padding and borders, use
|
||||
``inline-start``/``inline-end`` rather than ``left``/``right``.
|
||||
*Example:* Use ``margin-inline-start: 3px;`` instead of
|
||||
``margin-left: 3px``.
|
||||
- For RTL-aware positioning (left/right), use
|
||||
``inset-inline-start``/``inset-inline-end``.
|
||||
- For RTL-aware float layouts, ``float: inline-start|inline-end`` can
|
||||
be used instead of ``float: left|right``.
|
||||
- The RTL-aware equivalents of
|
||||
``border-{top/bottom}-{left/right}-radius`` are
|
||||
``border-{start/end}-{start/end}-radius``
|
||||
- When there is no special RTL-aware property available, use the pseudo
|
||||
``:-moz-locale-dir(ltr|rtl)`` (for XUL files) or ``:dir(ltr|rtl)``
|
||||
(for HTML files).
|
||||
- Remember that while a tab content's scrollbar still shows on the
|
||||
right in RTL, an overflow scrollbar will show on the left.
|
||||
- Write ``padding: 0 3px 4px;`` instead of
|
||||
``padding: 0 3px 4px 3px;``. This makes it more obvious that the
|
||||
padding is symmetrical (so RTL won't be an issue).
|
||||
|
||||
.. note::
|
||||
|
||||
See `CSS Logical Properties and
|
||||
Values <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties>`__
|
||||
for more information.
|
||||
|
||||
Testing
|
||||
~~~~~~~
|
||||
|
||||
To test for RTL layouts, you can go to ``about:config`` and set
|
||||
``intl.uidirection`` to ``-1``.
|
||||
|
||||
Writing cross-platform CSS
|
||||
--------------------------
|
||||
|
||||
Firefox supports many different platforms and each of those platforms
|
||||
can contain many different configurations:
|
||||
|
||||
- Windows 7, 8 and 10
|
||||
|
||||
- Default theme
|
||||
- Aero basic (Windows 7, 8)
|
||||
- Windows classic (Windows 7)
|
||||
- High contrast (All versions)
|
||||
|
||||
- Linux
|
||||
- macOS
|
||||
|
||||
File structure
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
- The ``browser/`` directory contains styles specific to Firefox
|
||||
- The ``toolkit/`` directory contains styles that are shared across all
|
||||
toolkit applications (Thunderbird and SeaMonkey)
|
||||
|
||||
Under each of those two directories, there is a ``themes`` directory
|
||||
containing 4 sub-directories:
|
||||
|
||||
- ``shared``
|
||||
- ``linux``
|
||||
- ``osx``
|
||||
- ``windows``
|
||||
|
||||
The ``shared`` directories contain styles shared across all 3 platforms,
|
||||
while the other 3 directories contain styles respective to their
|
||||
platform.
|
||||
|
||||
For new CSS, when possible try to privilege using the ``shared``
|
||||
directory, instead of writing the same CSS for the 3 platform specific
|
||||
directories, especially for large blocks of CSS.
|
||||
|
||||
Content CSS vs. Theme CSS
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following directories also contain CSS:
|
||||
|
||||
- ``browser/base/content/``
|
||||
- ``toolkit/content/``
|
||||
|
||||
These directories contain content CSS, that applies on all platforms,
|
||||
which is styling deemed to be essential for the browser to behave
|
||||
correctly. To determine whether some CSS is theme-side or content-side,
|
||||
it is useful to know that certain CSS properties are going to lean one
|
||||
way or the other: color - 99% of the time it will be theme CSS, overflow
|
||||
- 99% content.
|
||||
|
||||
+-----------------+--------------+----------------+----------------+
|
||||
| 99% theme | 70% theme | 70% content | 99% content |
|
||||
+=================+==============+================+================+
|
||||
| font-\*, color, | line-height, | cursor, width, | overflow, |
|
||||
| \*-color, | padding, | max-width, | direction, |
|
||||
| border-\*, | margin | top, | display, |
|
||||
| -moz-appearance | | bottom [2]_, | \*-align, |
|
||||
| [1]_ | | etc | align-\*, |
|
||||
| | | | \*-box-\*, |
|
||||
| | | | flex-\*, order |
|
||||
+-----------------+--------------+----------------+----------------+
|
||||
|
||||
If some CSS is layout or functionality related, then it is likely
|
||||
content CSS. If it is esthetics related, then it is likely theme CSS.
|
||||
|
||||
When importing your stylesheets, it's best to import the content CSS
|
||||
before the theme CSS, that way the theme values get to override the
|
||||
content values (which is probably what you want), and you're going to
|
||||
want them both after the global values, so your imports will look like
|
||||
this:
|
||||
|
||||
.. code:: xhtml
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/path/module.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/path/module.css" type="text/css"?>
|
||||
|
||||
.. [1] -moz-appearance is tricky. Generally, when specifying
|
||||
-moz-appearance: foo; you're giving hints as to how something should
|
||||
act, however -moz-appearance: none; is probably saying 'ignore
|
||||
browser preconceptions - I want a blank sheet', so that's more
|
||||
visual. However -moz-appearance values aren't implemented and don't
|
||||
behave consistently across platforms, so idealism aside
|
||||
-moz-appearance should always be in theme CSS.
|
||||
|
||||
.. [2] However there is probably a better way than using absolute
|
||||
positioning.
|
||||
|
||||
Colors
|
||||
~~~~~~
|
||||
|
||||
For common areas of the Firefox interface (panels, toolbar buttons,
|
||||
etc.), mozilla-central often comes with some useful CSS variables that
|
||||
are adjusted with the correct values for different platform
|
||||
configurations, so using those CSS variables can definitively save some
|
||||
testing time, as you can assume they already work correctly.
|
||||
|
||||
Using the ``currentcolor`` keyword or inheriting is also good practice,
|
||||
because sometimes the needed value is already in the color or on the
|
||||
parent element. This is especially useful in conjunction with icons
|
||||
using ``-moz-context-properties: fill;`` where the icon can adjust to
|
||||
the right platform color automatically from the text color. It is also
|
||||
possible to use ``currentcolor`` with other properties like
|
||||
``opacity`` or ``fill-opacity`` to have different
|
||||
opacities of the platform color.
|
||||
|
||||
High contrast mode
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Content area
|
||||
^^^^^^^^^^^^
|
||||
|
||||
On Windows high contrast mode, in the content area, Gecko does some
|
||||
automatic color adjustments regarding page colors. Part of those
|
||||
adjustments include making all ``box-shadow`` invisible, so this is
|
||||
something to be aware of if you create a focus ring or a border using
|
||||
the ``box-shadow`` property: consider using a ``border`` or an
|
||||
``outline`` if you want the border/focus ring to stay visible in
|
||||
high-contrast mode. An example of such bug is `bug
|
||||
1516767 <https://bugzilla.mozilla.org/show_bug.cgi?id=1516767>`__.
|
||||
|
||||
Another adjustment to be aware of is that Gecko removes all the
|
||||
``background-image`` when high contrast mode is enabled. Consider using
|
||||
an actual ``<img>`` tag (for HTML documents) or ``list-style-image``
|
||||
(for XUL documents) if rendering the image is important.
|
||||
|
||||
If you are not using Windows, one way to test against those adjustments
|
||||
on other platforms is:
|
||||
|
||||
- Going to about:preferences
|
||||
- Clicking on the "Colors..." button in the "Fonts & Colors"
|
||||
sub-section of the "Language and Appearance" section
|
||||
- Under "Override the colors specified by the page with your selections
|
||||
above", select the "Always" option
|
||||
|
||||
Chrome area
|
||||
^^^^^^^^^^^
|
||||
|
||||
The automatic adjustments previously mentioned only apply to pages
|
||||
rendered in the content area. The chrome area of Firefox uses colors as
|
||||
authored, which is why using pre-defined variables, ``currentcolor`` or
|
||||
inheritance is useful to integrate with the system theme with little
|
||||
hassle.
|
||||
|
||||
If not, as a last resort, using `system
|
||||
colors <https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#system_colors>`__
|
||||
also works for non-default Windows themes or Linux. In general, the
|
||||
following colors are used:
|
||||
|
||||
- ``-moz-Field``: textbox or field background colors, also used as the
|
||||
background color of listboxes or trees.
|
||||
- ``-moz-FieldText``: textbox or field text colors, also used as the
|
||||
text color of listboxes or trees.
|
||||
- ``-moz-Dialog``: window or dialog background color.
|
||||
- ``-moz-DialogText``: window or dialog text color.
|
||||
- ``GrayText``: used on disabled items as text color. Do not use it on
|
||||
text that is not disabled to desemphsize text, because it does not
|
||||
guarantee a sufficient contrast ratio for non-disabled text.
|
||||
- ``ThreeDShadow``: Used as border on elements.
|
||||
- ``ThreeDLightShadow``: Used as light border on elements.
|
||||
|
||||
Using the background/text pairs is especially important to ensure the
|
||||
contrast is respected in all situations. Never mix custom text colors
|
||||
with a system background color and vice-versa.
|
||||
|
||||
Note that using system colors is only useful for the chrome area, since
|
||||
content area colors are overridden by Gecko anyway.
|
||||
|
||||
Writing media queries
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Boolean media queries
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Do this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
@media (-moz-mac-yosemite-theme: 0) {
|
||||
|
||||
Not this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
@media not all and (-moz-mac-yosemite-theme) {
|
||||
|
||||
Privilege CSS for most common configuration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
It is better to put the most common configuration (latest version of an
|
||||
OS, or default theme for example) outside of the media query. In the
|
||||
following example, ``-moz-mac-yosemite-theme`` targets macOS 10.10 and
|
||||
higher, so it should be privileged over the styling for macOS 10.9.
|
||||
|
||||
Do this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
@media (-moz-mac-yosemite-theme: 0) {
|
||||
#placesList {
|
||||
box-shadow: inset -2px 0 0 hsla(0,0%,100%,.2);
|
||||
}
|
||||
}
|
||||
|
||||
Not this:
|
||||
|
||||
.. code:: css
|
||||
|
||||
#placesList {
|
||||
box-shadow: inset -2px 0 0 hsla(0,0%,100%,.2);
|
||||
}
|
||||
|
||||
@media (-moz-mac-yosemite-theme) {
|
||||
#placesList {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
Theme support
|
||||
-------------
|
||||
|
||||
Firefox comes built-in with 3 themes: default, light and dark. The
|
||||
built-in light/dark themes are a bit special as they load the
|
||||
``compacttheme.css`` stylesheet. In addition to this, Firefox supports a
|
||||
variety of WebExtension themes that can be installed from AMO. For
|
||||
testing purposes, `here is an example of a WebExtension
|
||||
theme. <https://addons.mozilla.org/en-US/firefox/addon/arc-dark-theme-we/>`__
|
||||
|
||||
Writing theme-friendly CSS
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Some CSS variables that are pre-adjusted for different platforms are
|
||||
also pre-adjusted for themes, so it's again a good idea to use them
|
||||
for theme support.
|
||||
- The text color of elements often contains valuable information from
|
||||
the theme colors, so ``currentcolor``/inheritance is again a good
|
||||
idea for theme support.
|
||||
- Never write CSS specially for the built-in light/dark theme in
|
||||
``compacttheme.css`` unless that CSS isn't supposed to affect
|
||||
WebExtension themes.
|
||||
- These selectors can be used to target dark areas:
|
||||
|
||||
- ``:-moz-lwtheme-brighttext``: dark window frame.
|
||||
- ``:root[lwt-toolbar-field-brighttext]``: dark address bar and
|
||||
searchbar.
|
||||
- ``:root[lwt-popup-brighttext]``: dark arrow panels and
|
||||
autocomplete panels.
|
||||
- ``:root[lwt-sidebar-brighttext]``: dark sidebars.
|
||||
|
||||
- If you'd like a different shade of a themed area and no CSS variable
|
||||
is adequate, using colors with alpha transparency is usually a good
|
||||
idea, as it will preserve the original theme author's color hue.
|
||||
|
||||
Variables
|
||||
~~~~~~~~~
|
||||
|
||||
For clarity, CSS variables that are only used when a theme is enabled
|
||||
have the ``--lwt-`` prefix.
|
||||
|
||||
Layout & performance
|
||||
--------------------
|
||||
|
||||
Layout
|
||||
~~~~~~
|
||||
|
||||
Mixing XUL flexbox and HTML flexbox can lead to undefined behavior.
|
||||
|
||||
CSS selectors
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
When targeting the root element of a page, using ``:root`` is the most
|
||||
performant way of doing so.
|
||||
|
||||
Reflows and style flushes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
See :ref:`Performance best practices for Firefox front-end engineers`
|
||||
for more information about this.
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
Text aliasing
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
When convenient, avoid setting the ``opacity`` property on
|
||||
text as it will cause text to be aliased differently.
|
||||
|
||||
HDPI support
|
||||
~~~~~~~~~~~~
|
||||
|
||||
It's recommended to use SVG since it keeps the CSS clean when supporting
|
||||
multiple resolutions. See the :ref:`SVG Guidelines` for more information
|
||||
on SVG usage.
|
||||
|
||||
However, if only 1x and 2x PNG assets are available, you can use this
|
||||
``@media`` query to target higher density displays (HDPI):
|
||||
|
||||
.. code:: css
|
||||
|
||||
@media (min-resolution: 1.1dppx)
|
|
@ -0,0 +1,284 @@
|
|||
RTL Guidelines
|
||||
==============
|
||||
|
||||
RTL languages such as Arabic, Hebrew, Persian and Urdu are read and
|
||||
written from right-to-left, and the user interface for these languages
|
||||
should be mirrored to ensure the content is easy to understand.
|
||||
|
||||
When a UI is changed from LTR to RTL (or vice-versa), it’s often called
|
||||
mirroring. An RTL layout is the mirror image of an LTR layout, and it
|
||||
affects layout, text, and graphics.
|
||||
|
||||
In RTL, anything that relates to time should be depicted as moving from
|
||||
right to left. For example, forward points to the left, and backwards
|
||||
points to the right.
|
||||
|
||||
Mirroring layout
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
When a UI is mirrored, these changes occur:
|
||||
|
||||
- Text fields icons are displayed on the opposite side of a field
|
||||
- Navigation buttons are displayed in reverse order
|
||||
- Icons that communicate direction, like arrows, are mirrored
|
||||
- Text is usually aligned to the right
|
||||
|
||||
In CSS, while it's possible to apply a rule for LTR and a separate one
|
||||
specifically for RTL, it's usually better to use CSS Logical Properties
|
||||
which provide the ability to control layout through logical, rather than
|
||||
physical mappings.
|
||||
|
||||
+----------------------------------+----------------------------------+
|
||||
| Do | Don't do |
|
||||
+==================================+==================================+
|
||||
| ``margin-inline-start: 5px;`` | ``margin-left: 5px;`` |
|
||||
+----------------------------------+----------------------------------+
|
||||
| ``padding-inline-end: 5px;`` | ``padding-right: 5px;`` |
|
||||
+----------------------------------+----------------------------------+
|
||||
| ``float: inline-start;`` | ``float: left;`` |
|
||||
+----------------------------------+----------------------------------+
|
||||
| ``inset-inline-start: 5px;`` | ``left: 5px;`` |
|
||||
+----------------------------------+----------------------------------+
|
||||
| ``border-inline-end: 1px;`` | ``border-right: 1px;`` |
|
||||
+----------------------------------+----------------------------------+
|
||||
| ``border-{start | ``border-{top/bot |
|
||||
| /end}-{start/end}-radius: 2px;`` | tom}-{left/right}-radius: 2px;`` |
|
||||
+----------------------------------+----------------------------------+
|
||||
| ``padding: 1px 2px;`` | ``padding: 1px 2px 1px 2px;`` |
|
||||
+----------------------------------+----------------------------------+
|
||||
| ``margin-block: 1px 3px;`` && | ``margin: 1px 2px 3px 4px;`` |
|
||||
| ``margin-inline: 4px 2px;`` | |
|
||||
+----------------------------------+----------------------------------+
|
||||
| ``text-align: start;`` or | ``text-align: left;`` |
|
||||
| ``text-align: match-parent;`` | |
|
||||
| (depends on the context) | |
|
||||
+----------------------------------+----------------------------------+
|
||||
|
||||
When there is no special RTL-aware property available, or when
|
||||
left/right properties must be used specifically for RTL, use the pseudo
|
||||
``:-moz-locale-dir(rtl)`` (for XUL files) or ``:dir(rtl)`` (for HTML
|
||||
files).
|
||||
|
||||
For example, this rule covers LTR to display searchicon.svg 7 pixels
|
||||
from the left:
|
||||
|
||||
.. code:: css
|
||||
|
||||
.search-box {
|
||||
background-image: url(chrome://path/to/searchicon.svg);
|
||||
background-position: 7px center;
|
||||
}
|
||||
|
||||
but an additional rule is necessary to cover RTL and place the search
|
||||
icon on the right:
|
||||
|
||||
.. code:: css
|
||||
|
||||
.search-box:dir(rtl) {
|
||||
background-position-x: right 7px;
|
||||
}
|
||||
|
||||
.. warning::
|
||||
|
||||
It may be inappropriate to use logical properties when embedding LTR
|
||||
within RTL contexts. This is described further in the document.
|
||||
|
||||
Mirroring elements
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
RTL content also affects the direction in which some icons and images
|
||||
are displayed, particularly those depicting a sequence of events.
|
||||
|
||||
What to mirror
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
- Icons that imply directionality like back/forward buttons
|
||||
- Icons that imply text direction, like
|
||||
`readerMode.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/browser/themes/shared/reader/readerMode.svg>`__
|
||||
- Icons that imply location of UI elements in the screen, like
|
||||
`sidebars-right.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/browser/themes/shared/icons/sidebars-right.svg>`__,
|
||||
`open-in-new.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/browser/themes/shared/icons/open-in-new.svg>`__,
|
||||
`default-theme.svg <https://searchfox.org/mozilla-central/rev/a78233c11a6baf2c308fbed17eb16c6e57b6a2ac/toolkit/mozapps/extensions/content/default-theme.svg>`__
|
||||
or
|
||||
`pane-collapse.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/devtools/client/debugger/images/pane-collapse.svg>`__
|
||||
- Icons representing objects that are meant to be handheld should look
|
||||
like they're being right-handed, like the `magnifying glass
|
||||
icon <https://searchfox.org/mozilla-central/rev/e7c61f4a68b974d5fecd216dc7407b631a24eb8f/toolkit/themes/windows/global/icons/search-textbox.svg>`__
|
||||
- Twisties in collapsed state (in RTL context only)
|
||||
|
||||
What NOT to mirror
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Text/numbers
|
||||
- Icons containing text/numbers
|
||||
- Icons/animations that are direction neutral
|
||||
- Icons that wouldn't look differently if they'd be mirrored, like `X
|
||||
buttons <https://searchfox.org/mozilla-central/rev/a78233c11a6baf2c308fbed17eb16c6e57b6a2ac/devtools/client/debugger/images/close.svg>`__
|
||||
or the `bookmark
|
||||
star <https://searchfox.org/mozilla-central/rev/a78233c11a6baf2c308fbed17eb16c6e57b6a2ac/browser/themes/shared/icons/bookmark-hollow.svg>`__
|
||||
icon
|
||||
- Icons that should look the same as LTR, like icons related to code
|
||||
(which is always LTR) like
|
||||
`tool-webconsole.svg <https://searchfox.org/mozilla-central/rev/74cc0f4dce444fe0757e2a6b8307d19e4d0e0212/devtools/client/themes/images/tool-webconsole.svg>`__
|
||||
- Checkmark icons
|
||||
- Video/audio player controls
|
||||
- Product logos
|
||||
- Order of size dimensions (e.g., ``1920x1080`` should not become
|
||||
``1080x1920``)
|
||||
- Order of size units (e.g., ``10 px`` should not become ``px 10``
|
||||
(unless the size unit is localizable))
|
||||
|
||||
How
|
||||
^^^
|
||||
|
||||
The most common way is by flipping the X axis:
|
||||
|
||||
.. code:: css
|
||||
|
||||
transform: scaleX(-1);
|
||||
|
||||
LTR text inside RTL contexts
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By default, in RTL locales, some symbols like "/", "." will be moved
|
||||
around and won't be displayed in the order that they were typed in. This
|
||||
may be problematic for URLs for instance, where you don't want dots to
|
||||
change position.
|
||||
|
||||
Here's a non-exhaustive list of elements that should be displayed like
|
||||
they would be in LTR locales:
|
||||
|
||||
- Paths (e.g., C:\Users\username\Desktop)
|
||||
- Full URLs
|
||||
- Code and code containers (like the DevTools' Inspector or the CSS
|
||||
rules panel)
|
||||
- about:config preference names and values
|
||||
- Telephone numbers
|
||||
- Usernames & passwords (most sites on the web expect LTR
|
||||
usernames/passwords, but there may be exceptions)
|
||||
- Other text fields where only LTR text is expected
|
||||
|
||||
To make sure these are displayed correctly, you can use one of the
|
||||
following on the relevant element:
|
||||
|
||||
- ``direction: ltr``
|
||||
- ``dir="ltr"`` in HTML
|
||||
|
||||
Since the direction of such elements is forced to LTR, the text will
|
||||
also be aligned to the left, which is undesirable from an UI
|
||||
perspective, given that is inconsistent with the rest of the RTL UI
|
||||
which has text usually aligned to the right. You can fix this using
|
||||
``text-align: match-parent``. In the following screenshot, both text
|
||||
fields (username and password) and the URL have their direction set to
|
||||
LTR (to display text correctly), but the text itself is aligned to the
|
||||
right for consistency with the rest of the UI:
|
||||
|
||||
.. image:: about-logins-rtl.png
|
||||
:alt: about:logins textboxes in RTL layout
|
||||
|
||||
However, since the direction in LTR, this also means that the start/end
|
||||
properties will correspond to left/right respectively, which is probably
|
||||
not what you expect. This means you have to use extra rules instead of
|
||||
using logical properties.
|
||||
|
||||
Here's a full code example:
|
||||
|
||||
.. code:: css
|
||||
|
||||
.url {
|
||||
direction: ltr; /* Force text direction to be LTR */
|
||||
|
||||
/* `start` (the default value) will correspond to `left`,
|
||||
so we match the parent's direction in order to align the text to the right */
|
||||
text-align: match-parent;
|
||||
}
|
||||
|
||||
/* :dir(ltr/rtl) isn't meaningful on .url, since it has direction: ltr, hence why it is matched on .container. */
|
||||
.container:dir(ltr) .url {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.container:dir(rtl) .url {
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
The LTR rule is separate from the global rule to avoid having the
|
||||
left padding apply on RTL without having to reset it in the RTL rule.
|
||||
|
||||
Auto-directionality
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Sometimes, the text direction on an element should vary dynamically
|
||||
depending on the situation. This can be the case for a search input for
|
||||
instance, a user may input a query in an LTR language, but may also
|
||||
input a query in a RTL language. In this case, the search input has to
|
||||
dynamically pick the correct directionality based on the first word, in
|
||||
order to display the query text correctly. The typical way to do this is
|
||||
to use ``dir="auto"`` in HTML. It is essential that
|
||||
``text-align: match-parent`` is set, to avoid having the text alignment
|
||||
change based on the query, and logical properties also cannot be used on
|
||||
the element itself given they can change meaning depending on the query.
|
||||
|
||||
Testing
|
||||
~~~~~~~
|
||||
|
||||
To test for RTL layouts in Firefox, you can go to about:config and
|
||||
set ``intl.l10n.pseudo`` to ``bidi`` or ``intl.uidirection`` to ``1``.
|
||||
The Firefox UI should immediately flip, but a restart may be required
|
||||
to take effect in some Firefox features and interactions.
|
||||
|
||||
.. note::
|
||||
|
||||
When testing with ``intl.uidirection`` set to ``1``, you may see some
|
||||
oddities regarding text ordering due to the nature of displaying LTR
|
||||
text in RTL layout.
|
||||
|
||||
.. image:: about-protections-rtl.png
|
||||
:alt: about:protections in RTL layout- English vs. Hebrew
|
||||
|
||||
This shouldn't be an issue when using an actual RTL locale or with
|
||||
``intl.l10n.pseudo`` set to ``bidi`` .
|
||||
|
||||
How to spot RTL-related issues
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Punctuation marks should appear on the left side of a
|
||||
word/sentence/paragraph on RTL, so if a *localizable* string appears
|
||||
in the UI with a dot, colon, ellipsis, question or exclamation mark
|
||||
on the right side of the text, this probably means that the text
|
||||
field is forced to be displayed as LTR.
|
||||
- If icons/images/checkmarks do not appear on the opposite side of
|
||||
text, when compared to LTR
|
||||
- If buttons (like the close button, "OK" and "Cancel" etc.) do not
|
||||
appear on the opposite side of the UI and not in the opposite order,
|
||||
when compared to LTR
|
||||
- If paddings/margins/borders are not the same from the opposite side,
|
||||
when compared to LTR
|
||||
- If on an Arabic or Persian build, digits are displayed as ``1 2 3``
|
||||
and not ``١ ٢ ٣`` (note that Hebrew uses ``1 2 3``)
|
||||
- If navigating in the UI using the left/right arrow keys does not
|
||||
select the correct element (i.e., pressing Left selects an item on
|
||||
the right)
|
||||
- If navigating in the UI using the Tab key does not focus elements
|
||||
from right to left, in an RTL context
|
||||
- If code is displayed as RTL (e.g., ``;padding: 20px`` - the semicolon
|
||||
should appear on the right side of the code). Code can still be
|
||||
aligned to the right if it appears in an RTL context
|
||||
|
||||
See also
|
||||
~~~~~~~~
|
||||
|
||||
- `RTL Best
|
||||
Practices <https://docs.google.com/document/d/1Rc8rvwsLI06xArFQouTinSh3wNte9Sqn9KWi1r7xY4Y/edit#heading=h.pw54h41h12ct>`__
|
||||
- Building RTL-Aware Web Apps & Websites: `Part
|
||||
1 <https://hacks.mozilla.org/2015/09/building-rtl-aware-web-apps-and-websites-part-1/>`__,
|
||||
`Part
|
||||
2 <https://hacks.mozilla.org/2015/10/building-rtl-aware-web-apps-websites-part-2/>`__
|
||||
|
||||
Credits
|
||||
~~~~~~~
|
||||
|
||||
Google's `Material Design guide for
|
||||
RTL <https://material.io/design/usability/bidirectionality.html>`__
|
|
@ -0,0 +1,347 @@
|
|||
SVG Guidelines
|
||||
==============
|
||||
|
||||
Pros and cons of SVG for images
|
||||
-------------------------------
|
||||
|
||||
When used as a document format there is usually a compelling reason that
|
||||
makes SVG the only solution. When used as an `image
|
||||
format <https://developer.mozilla.org/en-US/docs/Web/SVG/SVG_as_an_Image>`__,
|
||||
it is sometimes less obvious whether it would be best to use SVG or a
|
||||
raster image format for any given image. The vector format SVG and
|
||||
raster formats like PNG both have their place. When choosing whether or
|
||||
not to use SVG it is best to understand the advantages and disadvantages
|
||||
of both.
|
||||
|
||||
File size
|
||||
Whether SVG or a raster format will produce a smaller file for a
|
||||
given image depends very much on the image. For example, consider an
|
||||
image of a path with a gradient fill. The size of an SVG of this
|
||||
image will be the same regardless of the dimensions of the image. On
|
||||
the other hand the size of a raster file of the same image will
|
||||
likely vary tremendously depending on the dimensions of the image
|
||||
since the larger the dimensions the more pixel data the file needs to
|
||||
store. At very small dimensions (the extreme case being 1px x 1px)
|
||||
the raster file will likely be much smaller than the SVG file since
|
||||
it only needs to store one pixel of data. At large dimensions the
|
||||
raster file may be much larger than the SVG file.
|
||||
Scalability, with caveats
|
||||
One of the primary advantages of SVG is that as it is scaled it does
|
||||
not pixelate. However, this is not to say that it always does away
|
||||
with the need to have a collection of raster images for display at
|
||||
different scales. This can be particularly true for icons. While SVG
|
||||
may scale well enough for flat-ish icons without a lot of detail, for
|
||||
icons that try to pack in a lot of detail graphic artists generally
|
||||
`want to be able to pixel
|
||||
tweak <https://www.pushing-pixels.org/2011/11/04/about-those-vector-icons.html>`__.
|
||||
Performance
|
||||
While SVG provides a lot of flexibility in terms of scaling,
|
||||
themability, etc. this flexibility depends on doing computations for
|
||||
SVG images at the time they're displayed, rather than at the time the
|
||||
author creates them. Consider an image that involves some complex
|
||||
gradients and filters. If saved as a raster image then the work to
|
||||
rasterize the gradients and filters takes place on the authors
|
||||
computer before the result is stored in the raster file. This work
|
||||
doesn't need to be redone when the image is displayed on someone
|
||||
else's computer. On the other hand, if the image is saved as an SVG
|
||||
image then all this work needs to be done each time the SVG is
|
||||
displayed on someone else's computer. This isn't to say that SVG
|
||||
images are always slower than raster equivalents. In fact it can be
|
||||
faster to send vector information from an SVG to a user's GPU than it
|
||||
is to extract raster data from an equivalent raster image. And even
|
||||
when an SVG image is slower than a raster equivalent, the difference
|
||||
is usually not noticeable. However, just don't fall into the trap of
|
||||
thinking that SVGs are faster than equivalent raster images, or vice
|
||||
versa. Once again, "it depends".
|
||||
|
||||
Authoring guidelines
|
||||
--------------------
|
||||
|
||||
A lot of SVG files (particularly those generated by SVG editors) ship
|
||||
without being cleaned up and can contain a ton of junk that bloats the
|
||||
file size and slows down rendering. In general the best way to combat
|
||||
this is to first run SVG files through a linter such as
|
||||
`svgo <https://github.com/svg/svgo>`__ (see the Tools section below).
|
||||
However, when authoring SVGs by hand here are some best practices to
|
||||
help keep them lightweight. These rules are based on some real examples
|
||||
seen in Mozilla's code.
|
||||
|
||||
Basics
|
||||
~~~~~~
|
||||
|
||||
- Two spaces indenting
|
||||
- No useless whitespaces or line breaks (see below for more details)
|
||||
- Adding a license header
|
||||
- Use double quotes
|
||||
|
||||
Whitespace and line breaks
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Whitespace
|
||||
^^^^^^^^^^
|
||||
|
||||
In addition to trailing whitespace at the end of lines, there are a few
|
||||
more cases more specific to SVGs:
|
||||
|
||||
- Trailing whitespaces in attribute values (usually seen in path
|
||||
definitions)
|
||||
- Excessive whitespace in path or polygon points definition
|
||||
|
||||
Whitespace examples
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This path:
|
||||
|
||||
.. code:: svg
|
||||
|
||||
<path d=" M5,5 L1,1z ">
|
||||
|
||||
can be cut down to this:
|
||||
|
||||
.. code:: svg
|
||||
|
||||
<path d="M5,5 L1,1z">
|
||||
|
||||
Similarly, this polygon:
|
||||
|
||||
.. code:: svg
|
||||
|
||||
<polygon points=" 0,0 4,4 4,0 "/>
|
||||
|
||||
can be cut down to this:
|
||||
|
||||
.. code:: svg
|
||||
|
||||
<polygon points="0,0 4,4 4,0"/>
|
||||
|
||||
Line breaks
|
||||
^^^^^^^^^^^
|
||||
|
||||
You should only use line breaks for logical separation or if they help
|
||||
make the file readable. You should avoid line breaks between every
|
||||
single element or within attribute values. It's recommended to put the
|
||||
attributes on the same line as their tag names, if possible. You should
|
||||
also put the shortest attributes first, so they are easier to spot.
|
||||
|
||||
Unused tags and attributes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Editor metadata
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Vector editors (Inkscape, Adobe Illustrator, Sketch) usually add a bunch
|
||||
of metadata in SVG files while saving them. Metadata can mean many
|
||||
things, including:
|
||||
|
||||
- The typical "Created with *editor*" comments
|
||||
- Non-standard editor specific tags and attributes (``sketch:foo``,
|
||||
``illustrator:foo``, ``sopodi:foo``, …)
|
||||
- The `XML
|
||||
namespace <https://developer.mozilla.org/en-US/docs/Web/SVG/Namespaces_Crash_Course>`__
|
||||
definition that comes with the latter (``xmlns:sketch``,
|
||||
``xmlns:sopodi``, …)
|
||||
|
||||
Other metadata
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
In addition to non-standard editor metadata, standard compliant metadata
|
||||
also exists. Typical examples of this are ``<title>`` and ``<desc>``
|
||||
tags. Although this kind of data is supported by the browser, it can
|
||||
only be displayed when the SVG is opened in a new tab. Plus, in most of
|
||||
the cases, the filename is quite descriptive So it's recommended to
|
||||
remove that kind of metadata since it doesn't bring much value.
|
||||
|
||||
You shouldn't include DOCTYPEs in your SVGs either; they are a source of
|
||||
many issues, and the SVG WG recommends not to include them. See `SVG
|
||||
Authoring
|
||||
guidelines <https://jwatt.org/svg/authoring/#doctype-declaration>`__.
|
||||
|
||||
Avoid the use of CDATA sections
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
`CDATA
|
||||
sections <https://developer.mozilla.org/en-US/docs/Web/API/CDATASection>`__
|
||||
are used to avoid parsing some text as HTML. Most of time, CDATA isn't
|
||||
needed, for example, the content in ``<style>`` tags doesn't need to be
|
||||
wrapped in a CDATA section as the content inside the tag is already
|
||||
correctly parsed as CSS.
|
||||
|
||||
Invisible shapes
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
There are two kinds of invisible shapes: The off-screen ones and the
|
||||
uncolored ones.
|
||||
|
||||
The offscreen shapes are hard to spot, even with an automated tool, and
|
||||
are usually context aware. Those kinds of shapes are visible but off the
|
||||
`SVG view
|
||||
box <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox>`__.
|
||||
Here's `an
|
||||
example <https://hg.mozilla.org/mozilla-central/diff/9fb143f3b36a/browser/themes/shared/heartbeat-star-lit.svg>`__
|
||||
of a file with offscreen shapes.
|
||||
|
||||
On the other hand, the uncolored ones are easier to spot, since they
|
||||
usually come with styles making them invisible. They must meet two
|
||||
conditions: they must be devoid of any fill (or a transparent one) or
|
||||
stroke.
|
||||
|
||||
Unused attributes on root ``<svg>`` element
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The root ``<svg>`` element can also host many useless attributes. Here's
|
||||
an
|
||||
`example <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/browser/components/loop/content/shared/img/icons-10x10.svg>`__
|
||||
taking into account the list below:
|
||||
|
||||
- ``version``
|
||||
- ``x="0"`` and ``y="0"``
|
||||
- ``enable-background`` (unsupported by Gecko and now deprecated by the
|
||||
Filter Effects specification)
|
||||
- ``id`` (id on root element has no effect)
|
||||
- ``xmlns:xlink`` attribute when there are no ``xlink:href`` attributes
|
||||
used throughout the file
|
||||
- Other unused `XML
|
||||
Namespace <https://developer.mozilla.org/en-US/docs/Web/SVG/Namespaces_Crash_Course>`__
|
||||
definitions
|
||||
- ``xml:space`` when there is no text used in the file
|
||||
|
||||
Other
|
||||
^^^^^
|
||||
|
||||
- Empty tags, this may be obvious, but those are sometimes found in
|
||||
SVGs
|
||||
- Unreferenced ids (usually on gradient stops, but also on shapes or
|
||||
paths)
|
||||
- ``clip-rule`` attribute when the element *is not* a descendant of a
|
||||
``<clipPath>``
|
||||
- ``fill-rule`` attribute when the element *is* a descendant of a
|
||||
``<clipPath>``
|
||||
- Unreferenced/Unused clip paths, masks or defs
|
||||
(`example <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/toolkit/themes/shared/reader/RM-Plus-24x24.svg>`__)
|
||||
|
||||
Styling
|
||||
~~~~~~~
|
||||
|
||||
Styling basics
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
- Privilege short lowercase hex for colors
|
||||
- Don't use excessive precision for numeric values (usually comes from
|
||||
illustrator)
|
||||
- Use descriptive IDs
|
||||
- Avoid inline styles and use class names or SVG attributes
|
||||
|
||||
Styling examples
|
||||
''''''''''''''''
|
||||
|
||||
Here are some examples for excessive number precision:
|
||||
|
||||
- 5.000000e-02 → 0.05 (as seen
|
||||
`here <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/browser/themes/shared/devtools/images/tool-network.svg#l1.31>`__)
|
||||
- -3.728928e-10 → 0 (as seen
|
||||
`here <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/browser/themes/shared/aboutNetError_alert.svg#l1.12>`__)
|
||||
- translate(0.000000, -1.000000) → translate(0, -1) (as seen
|
||||
`here <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/browser/themes/shared/heartbeat-icon.svg#l1.13>`__)
|
||||
|
||||
As for descriptive IDs:
|
||||
|
||||
- For gradients: SVG_ID1 → gradient1 (as seen
|
||||
`here <https://hg.mozilla.org/mozilla-central/diff/2d38fecce226/browser/themes/shared/aboutNetError_alert.svg#l1.12>`__)
|
||||
|
||||
Use of class names
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Avoid using a class if that class is only used once in the file
|
||||
- If that class only sets a fill or a stroke, it's better to set the
|
||||
fill/stroke directly on the actual shape, instead of introducing a
|
||||
class just for that shape. You can also use SVG grouping to avoid
|
||||
duplicating those attributes
|
||||
- Avoid introducing variants of the same file (color/style variants),
|
||||
and use sprites instead (with class names)
|
||||
|
||||
Default style values
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There's usually no need to set the default style value unless you're
|
||||
overriding a style. Here are some commonly seen examples:
|
||||
|
||||
- ``style="display: none;"`` on ``<defs>`` elements (a ``<defs>``
|
||||
element is hidden by default)
|
||||
- ``type="text/css"`` on ``<style>`` elements
|
||||
- ``stroke: none`` or ``stroke-width: 0``
|
||||
|
||||
SVG grouping
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Style grouping
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Group similarly styled shapes under one ``<g>`` tag; this avoids having
|
||||
to set the same class/styles on many shapes.
|
||||
|
||||
Avoid excessive grouping
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Editors can sometimes do excessive grouping while exporting SVGs. This
|
||||
is due to the way editors work.
|
||||
|
||||
Nested groups
|
||||
'''''''''''''
|
||||
|
||||
Avoid multiple-level nesting of groups, these make the SVG less
|
||||
readable.
|
||||
|
||||
Nested transforms
|
||||
'''''''''''''''''
|
||||
|
||||
Some editors use ``<g>`` tags to do nested transforms, which is usually
|
||||
not needed. You can avoid this by doing basic algebra, for example:
|
||||
|
||||
.. code:: svg
|
||||
|
||||
<g transform="translate(-62, -310)"><shape transform="translate(60, 308)"/></g>
|
||||
|
||||
can be cut down to:
|
||||
|
||||
.. code:: svg
|
||||
|
||||
<shape transform="translate(-2,-2)"/>
|
||||
|
||||
because: -62+60 = -310+308 = -2
|
||||
|
||||
Performance tips
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
These rules are optional, but they help speeding up the SVG.
|
||||
|
||||
- Avoid using a ``<use>`` tag when that ``<use>`` tag is being
|
||||
referenced only once in the whole file.
|
||||
- Instead of using CSS/SVG
|
||||
`transforms <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform>`__,
|
||||
apply directly the transform on the path/shape definition.
|
||||
|
||||
Tools
|
||||
~~~~~
|
||||
|
||||
Tools can help to clean SVG files. Note, however that some of the rules
|
||||
stated above can be hard to detect with automated tools since they
|
||||
require too much context-awareness. To this date, there doesn't seem to
|
||||
be a tool that handles all of the above. However, there are some
|
||||
utilities that cover parts of this document:
|
||||
|
||||
- Mostly complete command line tool: https://github.com/svg/svgo
|
||||
- Alternatives to SVGO:
|
||||
|
||||
- https://github.com/RazrFalcon/svgcleaner
|
||||
- https://github.com/scour-project/scour
|
||||
|
||||
- GUI for command line tool (use with "Prettify code" and "Remove
|
||||
``<title>``" options on): https://jakearchibald.github.io/svgomg/
|
||||
- Good alternative to SVGO/SVGOMG:
|
||||
https://petercollingridge.appspot.com/svg-editor
|
||||
- Fixes the excessive number precision:
|
||||
https://simon.html5.org/tools/js/svg-optimizer/
|
||||
- Converts inline styles to SVG
|
||||
attributes: https://www.w3.org/wiki/SvgTidy
|
||||
- RaphaelJS has a couple of utilities that may be useful:
|
||||
`raphael.js <https://dmitrybaranovskiy.github.io/raphael/>`__
|
|
@ -1,7 +1,5 @@
|
|||
import-globals
|
||||
==============
|
||||
|
||||
Checks the filename of imported files e.g. ``Cu.import("some/path/Blah.jsm")``
|
||||
adds Blah to the global scope.
|
||||
|
||||
Note: uses modules.json for some files where there are multiple exports.
|
||||
Checks ``XPCOMUtils.defineLazyGetter`` etc and adds the name to the global
|
||||
scope.
|
||||
|
|
|
@ -82,7 +82,6 @@ class MOZ_STACK_CLASS DragDataProducer {
|
|||
bool* outDragSelectedText);
|
||||
[[nodiscard]] static nsresult GetAnchorURL(nsIContent* inNode,
|
||||
nsAString& outURL);
|
||||
static void GetNodeString(nsIContent* inNode, nsAString& outNodeString);
|
||||
static void CreateLinkText(const nsAString& inURL, const nsAString& inText,
|
||||
nsAString& outLinkText);
|
||||
|
||||
|
@ -261,42 +260,23 @@ nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable* aTransferable,
|
|||
supportsString = do_QueryInterface(tmp);
|
||||
if (!supportsString) return NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoString imageRequestMime;
|
||||
supportsString->GetData(imageRequestMime);
|
||||
nsAutoString contentType;
|
||||
supportsString->GetData(contentType);
|
||||
|
||||
// If we have a MIME type, check the extension is compatible
|
||||
if (!imageRequestMime.IsEmpty()) {
|
||||
// Build a URL to get the filename extension
|
||||
nsCOMPtr<nsIURL> imageURL = do_QueryInterface(sourceURI, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString extension;
|
||||
rv = imageURL->GetFileExtension(extension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ConvertUTF16toUTF8 mimeCString(imageRequestMime);
|
||||
bool isValidExtension;
|
||||
nsAutoCString primaryExtension;
|
||||
rv = CheckAndGetExtensionForMime(extension, mimeCString,
|
||||
&isValidExtension, &primaryExtension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!isValidExtension && !primaryExtension.IsEmpty()) {
|
||||
// The filename extension is missing or incompatible
|
||||
// with the MIME type, replace it with the primary
|
||||
// extension.
|
||||
nsAutoCString newFileName;
|
||||
rv = imageURL->GetFileBaseName(newFileName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
newFileName.Append(".");
|
||||
newFileName.Append(primaryExtension);
|
||||
CopyUTF8toUTF16(newFileName, targetFilename);
|
||||
}
|
||||
nsCOMPtr<nsIMIMEService> mimeService =
|
||||
do_GetService("@mozilla.org/mime;1");
|
||||
if (NS_WARN_IF(!mimeService)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mimeService->ValidateFileNameForSaving(
|
||||
targetFilename, NS_ConvertUTF16toUTF8(contentType),
|
||||
nsIMIMEService::VALIDATE_DEFAULT, targetFilename);
|
||||
} else {
|
||||
// make the filename safe for the filesystem
|
||||
targetFilename.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS,
|
||||
'-');
|
||||
}
|
||||
// make the filename safe for the filesystem
|
||||
targetFilename.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS,
|
||||
'-');
|
||||
#endif /* defined(XP_MACOSX) */
|
||||
|
||||
// get the target directory from the kFilePromiseDirectoryMime
|
||||
|
@ -342,13 +322,16 @@ DragDataProducer::DragDataProducer(nsPIDOMWindowOuter* aWindow,
|
|||
mIsAltKeyPressed(aIsAltKeyPressed),
|
||||
mIsAnchor(false) {}
|
||||
|
||||
//
|
||||
// FindParentLinkNode
|
||||
//
|
||||
// Finds the parent with the given link tag starting at |aContent|. If
|
||||
// it gets up to the root without finding it, we stop looking and
|
||||
// return null.
|
||||
//
|
||||
static nsIContent* FindDragTarget(nsIContent* aContent) {
|
||||
for (nsIContent* content = aContent; content;
|
||||
content = content->GetFlattenedTreeParent()) {
|
||||
if (nsContentUtils::ContentIsDraggable(content)) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static nsIContent* FindParentLinkNode(nsIContent* aContent) {
|
||||
for (nsIContent* content = aContent; content;
|
||||
content = content->GetFlattenedTreeParent()) {
|
||||
|
@ -399,26 +382,6 @@ void DragDataProducer::CreateLinkText(const nsAString& inURL,
|
|||
outLinkText = linkText;
|
||||
}
|
||||
|
||||
//
|
||||
// GetNodeString
|
||||
//
|
||||
// Gets the text associated with a node
|
||||
//
|
||||
void DragDataProducer::GetNodeString(nsIContent* inNode,
|
||||
nsAString& outNodeString) {
|
||||
nsCOMPtr<nsINode> node = inNode;
|
||||
|
||||
outNodeString.Truncate();
|
||||
|
||||
// use a range to get the text-equivalent of the node
|
||||
nsCOMPtr<Document> doc = node->OwnerDoc();
|
||||
RefPtr<nsRange> range = doc->CreateRange(IgnoreErrors());
|
||||
if (range) {
|
||||
range->SelectNode(*node, IgnoreErrors());
|
||||
range->ToString(outNodeString, IgnoreErrors());
|
||||
}
|
||||
}
|
||||
|
||||
nsresult DragDataProducer::GetImageData(imgIContainer* aImage,
|
||||
imgIRequest* aRequest) {
|
||||
nsCOMPtr<nsIURI> imgUri;
|
||||
|
@ -436,54 +399,27 @@ nsresult DragDataProducer::GetImageData(imgIContainer* aImage,
|
|||
nsCString mimeType;
|
||||
aRequest->GetMimeType(getter_Copies(mimeType));
|
||||
|
||||
nsAutoCString fileName;
|
||||
aRequest->GetFileName(fileName);
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
// Save the MIME type so we can make sure the extension
|
||||
// is compatible (and replace it if it isn't) when the
|
||||
// image is dropped. On Mac, we need to get the OS MIME
|
||||
// handler information in the parent due to sandboxing.
|
||||
CopyUTF8toUTF16(mimeType, mImageRequestMime);
|
||||
CopyUTF8toUTF16(fileName, mImageDestFileName);
|
||||
#else
|
||||
nsCOMPtr<nsIMIMEService> mimeService = do_GetService("@mozilla.org/mime;1");
|
||||
if (NS_WARN_IF(!mimeService)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
||||
mimeService->GetFromTypeAndExtension(mimeType, ""_ns,
|
||||
getter_AddRefs(mimeInfo));
|
||||
if (mimeInfo) {
|
||||
nsAutoCString extension;
|
||||
imgUrl->GetFileExtension(extension);
|
||||
|
||||
bool validExtension;
|
||||
if (extension.IsEmpty() ||
|
||||
NS_FAILED(mimeInfo->ExtensionExists(extension, &validExtension)) ||
|
||||
!validExtension) {
|
||||
// Fix the file extension in the URL
|
||||
nsAutoCString primaryExtension;
|
||||
mimeInfo->GetPrimaryExtension(primaryExtension);
|
||||
if (!primaryExtension.IsEmpty()) {
|
||||
rv = NS_MutateURI(imgUrl)
|
||||
.Apply(&nsIURLMutator::SetFileExtension, primaryExtension,
|
||||
nullptr)
|
||||
.Finalize(imgUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* defined(XP_MACOSX) */
|
||||
|
||||
nsAutoCString fileName;
|
||||
imgUrl->GetFileName(fileName);
|
||||
|
||||
NS_UnescapeURL(fileName);
|
||||
|
||||
#if !defined(XP_MACOSX)
|
||||
// make the filename safe for the filesystem
|
||||
fileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
|
||||
#endif
|
||||
|
||||
CopyUTF8toUTF16(fileName, mImageDestFileName);
|
||||
mimeService->ValidateFileNameForSaving(mImageDestFileName, mimeType,
|
||||
nsIMIMEService::VALIDATE_DEFAULT,
|
||||
mImageDestFileName);
|
||||
#endif
|
||||
|
||||
// and the image object
|
||||
mImage = aImage;
|
||||
|
@ -590,14 +526,7 @@ nsresult DragDataProducer::Produce(DataTransfer* aDataTransfer, bool* aCanDrag,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
draggedNode = mTarget;
|
||||
if (auto* el = nsGenericHTMLElement::FromNodeOrNull(draggedNode)) {
|
||||
if (el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
|
||||
nsGkAtoms::_false, eIgnoreCase)) {
|
||||
*aCanDrag = false;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
draggedNode = FindDragTarget(mTarget);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIImageLoadingContent> image;
|
||||
|
@ -631,10 +560,7 @@ nsresult DragDataProducer::Produce(DataTransfer* aDataTransfer, bool* aCanDrag,
|
|||
{
|
||||
// set for linked images, and links
|
||||
nsCOMPtr<nsIContent> linkNode;
|
||||
|
||||
RefPtr<HTMLAreaElement> areaElem =
|
||||
HTMLAreaElement::FromNodeOrNull(draggedNode);
|
||||
if (areaElem) {
|
||||
if (const auto* areaElem = HTMLAreaElement::FromNodeOrNull(draggedNode)) {
|
||||
// use the alt text (or, if missing, the href) as the title
|
||||
areaElem->GetAttr(nsGkAtoms::alt, mTitleString);
|
||||
if (mTitleString.IsEmpty()) {
|
||||
|
@ -702,10 +628,6 @@ nsresult DragDataProducer::Produce(DataTransfer* aDataTransfer, bool* aCanDrag,
|
|||
nodeToSerialize = draggedNode;
|
||||
}
|
||||
dragNode = nodeToSerialize;
|
||||
} else if (draggedNode && draggedNode->IsHTMLElement(nsGkAtoms::a)) {
|
||||
// set linkNode. The code below will handle this
|
||||
linkNode = draggedNode; // XXX test this
|
||||
GetNodeString(draggedNode, mTitleString);
|
||||
} else if (parentLink) {
|
||||
// parentLink will always be null if there's selected content
|
||||
linkNode = parentLink;
|
||||
|
|
|
@ -32,8 +32,6 @@
|
|||
#include "nsHTMLDocument.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
||||
// image copy stuff
|
||||
#include "nsIImageLoadingContent.h"
|
||||
|
@ -604,70 +602,39 @@ static nsresult AppendImagePromise(nsITransferable* aTransferable,
|
|||
nsCOMPtr<nsINode> node = do_QueryInterface(aImageElement, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Fix the file extension in the URL if necessary
|
||||
nsCOMPtr<nsIMIMEService> mimeService =
|
||||
do_GetService(NS_MIMESERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(mimeService, NS_OK);
|
||||
nsCOMPtr<nsIMIMEService> mimeService = do_GetService("@mozilla.org/mime;1");
|
||||
if (NS_WARN_IF(!mimeService)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> imgUri;
|
||||
rv = aImgRequest->GetFinalURI(getter_AddRefs(imgUri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURL> imgUrl = do_QueryInterface(imgUri);
|
||||
NS_ENSURE_TRUE(imgUrl, NS_OK);
|
||||
|
||||
nsAutoCString extension;
|
||||
rv = imgUrl->GetFileExtension(extension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCString mimeType;
|
||||
rv = aImgRequest->GetMimeType(getter_Copies(mimeType));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
||||
mimeService->GetFromTypeAndExtension(mimeType, ""_ns,
|
||||
getter_AddRefs(mimeInfo));
|
||||
NS_ENSURE_TRUE(mimeInfo, NS_OK);
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = imgUrl->GetSpec(spec);
|
||||
rv = imgUri->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// pass out the image source string
|
||||
nsString imageSourceString;
|
||||
CopyUTF8toUTF16(spec, imageSourceString);
|
||||
|
||||
bool validExtension;
|
||||
if (extension.IsEmpty() ||
|
||||
NS_FAILED(mimeInfo->ExtensionExists(extension, &validExtension)) ||
|
||||
!validExtension) {
|
||||
// Fix the file extension in the URL
|
||||
nsAutoCString primaryExtension;
|
||||
mimeInfo->GetPrimaryExtension(primaryExtension);
|
||||
if (!primaryExtension.IsEmpty()) {
|
||||
rv = NS_MutateURI(imgUri)
|
||||
.Apply(&nsIURLMutator::SetFileExtension, primaryExtension,
|
||||
nullptr)
|
||||
.Finalize(imgUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
nsCString mimeType;
|
||||
rv = aImgRequest->GetMimeType(getter_Copies(mimeType));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString fileName;
|
||||
imgUrl->GetFileName(fileName);
|
||||
rv = aImgRequest->GetFileName(fileName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_UnescapeURL(fileName);
|
||||
|
||||
// make the filename safe for the filesystem
|
||||
fileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
|
||||
|
||||
nsString imageDestFileName;
|
||||
CopyUTF8toUTF16(fileName, imageDestFileName);
|
||||
nsAutoString validFileName = NS_ConvertUTF8toUTF16(fileName);
|
||||
mimeService->ValidateFileNameForSaving(
|
||||
validFileName, mimeType, nsIMIMEService::VALIDATE_DEFAULT, validFileName);
|
||||
|
||||
rv = AppendString(aTransferable, imageSourceString, kFilePromiseURLMime);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = AppendString(aTransferable, imageDestFileName, kFilePromiseDestFilename);
|
||||
rv = AppendString(aTransferable, validFileName, kFilePromiseDestFilename);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aTransferable->SetRequestingPrincipal(node->NodePrincipal());
|
||||
|
|
|
@ -5187,7 +5187,7 @@ Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
|
|||
RefPtr<BrowsingContext> sourceBC = docToPrint->GetBrowsingContext();
|
||||
MOZ_DIAGNOSTIC_ASSERT(sourceBC);
|
||||
if (!sourceBC) {
|
||||
aError.ThrowNotSupportedError("No browsing context");
|
||||
aError.ThrowNotSupportedError("No browsing context for source document");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,7 +1,7 @@
|
|||
/* global context testDone:true */
|
||||
|
||||
var c = null;
|
||||
var request = "http://example.com/hmm?q=foobar" + context;
|
||||
var request = "https://example.com/hmm?q=foobar" + context;
|
||||
var response = new Response("This is some Response!");
|
||||
var name = "snafu" + context;
|
||||
var foobar = "foobar" + context;
|
||||
|
@ -146,7 +146,7 @@ caches
|
|||
})
|
||||
.then(function(storageMatchResponse) {
|
||||
ok(storageMatchResponse, "storage match with cacheName should succeed");
|
||||
var request2 = new Request("http://example.com/hmm?q=snafu" + context);
|
||||
var request2 = new Request("https://example.com/hmm?q=snafu" + context);
|
||||
return c.match(request2, { ignoreSearch: true });
|
||||
})
|
||||
.then(function(match2Response) {
|
||||
|
|
|
@ -17,7 +17,7 @@ caches
|
|||
"add() should throw TypeError for invalid scheme"
|
||||
);
|
||||
return cache.addAll([
|
||||
"http://example.com/valid" + context,
|
||||
"https://example.com/valid" + context,
|
||||
"ftp://example.com/invalid" + context,
|
||||
]);
|
||||
})
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
let cache;
|
||||
let url = "foo.html";
|
||||
let redirectURL = "http://example.com/foo-bar.html";
|
||||
let redirectURL = "https://example.com/foo-bar.html";
|
||||
caches
|
||||
.open("redirect-" + context)
|
||||
.then(c => {
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
["dom.caches.testing.enabled", true]],
|
||||
}, function() {
|
||||
// attach to a different origin's CacheStorage
|
||||
var url = "http://example.com/";
|
||||
var url = "https://example.com/";
|
||||
var storage = SpecialPowers.createChromeCache("content", url);
|
||||
|
||||
// verify we can use the other origin's CacheStorage as normal
|
||||
var req = new Request("http://example.com/index.html");
|
||||
var req = new Request("https://example.com/index.html");
|
||||
var res = new Response("hello world");
|
||||
var cache;
|
||||
storage.open("foo").then(function(c) {
|
||||
|
|
|
@ -90,7 +90,11 @@ function afterDragTests()
|
|||
sendMouseEventsForDrag("userselectnone");
|
||||
synthesizeMouse(draggable, 12, 12, { type: "mouseup" });
|
||||
|
||||
if (gExtraDragTests == 6)
|
||||
gDragInfo = { target: $("draggable_with_undraggable_descendant"), testid: "undraggable inside draggable" };
|
||||
sendMouseEventsForDrag("undraggable_inside_draggable");
|
||||
synthesizeMouse(draggable, 12, 12, { type: "mouseup" });
|
||||
|
||||
if (gExtraDragTests == 7)
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -670,5 +674,11 @@ shadow_host_containing_image.attachShadow({ mode: 'open' }).innerHTML =
|
|||
This is an unselectable, undraggable area.
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<div id="draggable_with_undraggable_descendant" draggable="true" ondragstart="onDragStartDraggable(event)">
|
||||
<a id="undraggable_inside_draggable" href="http://example.org" draggable="false" ondragstart="onDragOverDraggableFalse(event)">
|
||||
This is an undraggable link inside a draggable ancestor.
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -51,7 +51,7 @@ int64_t BaseBlobImpl::GetLastModified(ErrorResult& aRv) {
|
|||
return mLastModificationDate / PR_USEC_PER_MSEC;
|
||||
}
|
||||
|
||||
int64_t BaseBlobImpl::GetFileId() { return -1; }
|
||||
int64_t BaseBlobImpl::GetFileId() const { return -1; }
|
||||
|
||||
/* static */
|
||||
uint64_t BaseBlobImpl::NextSerialNumber() {
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
#include "mozilla/dom/BlobImpl.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class FileBlobImpl;
|
||||
|
||||
|
@ -57,24 +56,22 @@ class BaseBlobImpl : public BlobImpl {
|
|||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
virtual void GetName(nsAString& aName) const override;
|
||||
void GetName(nsAString& aName) const override;
|
||||
|
||||
virtual void GetDOMPath(nsAString& aName) const override;
|
||||
void GetDOMPath(nsAString& aPath) const override;
|
||||
|
||||
virtual void SetDOMPath(const nsAString& aName) override;
|
||||
void SetDOMPath(const nsAString& aPath) override;
|
||||
|
||||
virtual int64_t GetLastModified(ErrorResult& aRv) override;
|
||||
int64_t GetLastModified(ErrorResult& aRv) override;
|
||||
|
||||
virtual void GetMozFullPath(nsAString& aName,
|
||||
SystemCallerGuarantee /* unused */,
|
||||
ErrorResult& aRv) override;
|
||||
void GetMozFullPath(nsAString& aFileName, SystemCallerGuarantee /* unused */,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual void GetMozFullPathInternal(nsAString& aFileName,
|
||||
ErrorResult& aRv) override;
|
||||
void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) override;
|
||||
|
||||
virtual uint64_t GetSize(ErrorResult& aRv) override { return mLength; }
|
||||
uint64_t GetSize(ErrorResult& aRv) override { return mLength; }
|
||||
|
||||
virtual void GetType(nsAString& aType) override;
|
||||
void GetType(nsAString& aType) override;
|
||||
|
||||
size_t GetAllocationSize() const override { return 0; }
|
||||
|
||||
|
@ -83,29 +80,27 @@ class BaseBlobImpl : public BlobImpl {
|
|||
return GetAllocationSize();
|
||||
}
|
||||
|
||||
virtual uint64_t GetSerialNumber() const override { return mSerialNumber; }
|
||||
uint64_t GetSerialNumber() const override { return mSerialNumber; }
|
||||
|
||||
virtual already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart,
|
||||
uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) override {
|
||||
already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual const nsTArray<RefPtr<BlobImpl>>* GetSubBlobImpls() const override {
|
||||
const nsTArray<RefPtr<BlobImpl>>* GetSubBlobImpls() const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override {
|
||||
void CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) const override {
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
virtual int64_t GetFileId() override;
|
||||
int64_t GetFileId() const override;
|
||||
|
||||
virtual void SetLazyData(const nsAString& aName,
|
||||
const nsAString& aContentType, uint64_t aLength,
|
||||
int64_t aLastModifiedDate) override {
|
||||
void SetLazyData(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, int64_t aLastModifiedDate) override {
|
||||
mName = aName;
|
||||
mContentType = aContentType;
|
||||
mLength = aLength;
|
||||
|
@ -113,16 +108,16 @@ class BaseBlobImpl : public BlobImpl {
|
|||
mIsFile = !aName.IsVoid();
|
||||
}
|
||||
|
||||
virtual bool IsMemoryFile() const override { return false; }
|
||||
bool IsMemoryFile() const override { return false; }
|
||||
|
||||
virtual bool IsFile() const override { return mIsFile; }
|
||||
bool IsFile() const override { return mIsFile; }
|
||||
|
||||
virtual void GetBlobImplType(nsAString& aBlobImplType) const override {
|
||||
void GetBlobImplType(nsAString& aBlobImplType) const override {
|
||||
aBlobImplType = u"BaseBlobImpl"_ns;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~BaseBlobImpl() = default;
|
||||
~BaseBlobImpl() override = default;
|
||||
|
||||
/**
|
||||
* Returns a new, effectively-unique serial number. This should be used
|
||||
|
@ -157,7 +152,6 @@ class BaseBlobImpl : public BlobImpl {
|
|||
int64_t mLastModificationDate;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_BaseBlobImpl_h
|
||||
|
|
|
@ -161,7 +161,7 @@ already_AddRefed<File> Blob::ToFile(const nsAString& aName,
|
|||
|
||||
already_AddRefed<Blob> Blob::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
RefPtr<BlobImpl> impl =
|
||||
mImpl->CreateSlice(aStart, aLength, aContentType, aRv);
|
||||
if (aRv.Failed()) {
|
||||
|
@ -241,11 +241,11 @@ already_AddRefed<Blob> Blob::Constructor(
|
|||
return blob.forget();
|
||||
}
|
||||
|
||||
int64_t Blob::GetFileId() { return mImpl->GetFileId(); }
|
||||
int64_t Blob::GetFileId() const { return mImpl->GetFileId(); }
|
||||
|
||||
bool Blob::IsMemoryFile() const { return mImpl->IsMemoryFile(); }
|
||||
|
||||
void Blob::CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv) {
|
||||
void Blob::CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv) const {
|
||||
mImpl->CreateInputStream(aStream, aRv);
|
||||
}
|
||||
|
||||
|
@ -260,16 +260,16 @@ size_t BindingJSObjectMallocBytes(Blob* aBlob) {
|
|||
return aBlob->GetAllocationSize();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> Blob::Text(ErrorResult& aRv) {
|
||||
already_AddRefed<Promise> Blob::Text(ErrorResult& aRv) const {
|
||||
return ConsumeBody(BodyConsumer::CONSUME_TEXT, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> Blob::ArrayBuffer(ErrorResult& aRv) {
|
||||
already_AddRefed<Promise> Blob::ArrayBuffer(ErrorResult& aRv) const {
|
||||
return ConsumeBody(BodyConsumer::CONSUME_ARRAYBUFFER, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> Blob::ConsumeBody(
|
||||
BodyConsumer::ConsumeType aConsumeType, ErrorResult& aRv) {
|
||||
BodyConsumer::ConsumeType aConsumeType, ErrorResult& aRv) const {
|
||||
if (NS_WARN_IF(!mGlobal)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
|
@ -321,7 +321,7 @@ class BlobBodyStreamHolder final : public BodyStreamHolder {
|
|||
RefPtr<ReadableStream> mStream;
|
||||
|
||||
protected:
|
||||
virtual ~BlobBodyStreamHolder() { NullifyStream(); }
|
||||
~BlobBodyStreamHolder() override { NullifyStream(); }
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(BlobBodyStreamHolder)
|
||||
|
@ -350,7 +350,7 @@ NS_INTERFACE_MAP_END_INHERITING(BodyStreamHolder)
|
|||
} // anonymous namespace
|
||||
|
||||
already_AddRefed<ReadableStream> Blob::Stream(JSContext* aCx,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
CreateInputStream(getter_AddRefs(stream), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
|
|
|
@ -77,11 +77,11 @@ class Blob : public nsSupportsWeakReference, public nsWrapperCache {
|
|||
|
||||
already_AddRefed<Blob> CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv);
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
void CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv);
|
||||
void CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv) const;
|
||||
|
||||
int64_t GetFileId();
|
||||
int64_t GetFileId() const;
|
||||
|
||||
// A utility function that enforces the spec constraints on the type of a
|
||||
// blob: no codepoints outside the ASCII range (otherwise type becomes empty)
|
||||
|
@ -101,8 +101,8 @@ class Blob : public nsSupportsWeakReference, public nsWrapperCache {
|
|||
const GlobalObject& aGlobal, const Optional<Sequence<BlobPart>>& aData,
|
||||
const BlobPropertyBag& aBag, ErrorResult& aRv);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
uint64_t GetSize(ErrorResult& aRv);
|
||||
|
||||
|
@ -120,9 +120,10 @@ class Blob : public nsSupportsWeakReference, public nsWrapperCache {
|
|||
nsresult GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
||||
nsACString& aContentType, nsACString& aCharset) const;
|
||||
|
||||
already_AddRefed<ReadableStream> Stream(JSContext* aCx, ErrorResult& aRv);
|
||||
already_AddRefed<Promise> Text(ErrorResult& aRv);
|
||||
already_AddRefed<Promise> ArrayBuffer(ErrorResult& aRv);
|
||||
already_AddRefed<ReadableStream> Stream(JSContext* aCx,
|
||||
ErrorResult& aRv) const;
|
||||
already_AddRefed<Promise> Text(ErrorResult& aRv) const;
|
||||
already_AddRefed<Promise> ArrayBuffer(ErrorResult& aRv) const;
|
||||
|
||||
protected:
|
||||
// File constructor should never be used directly. Use Blob::Create instead.
|
||||
|
@ -132,7 +133,7 @@ class Blob : public nsSupportsWeakReference, public nsWrapperCache {
|
|||
virtual bool HasFileInterface() const { return false; }
|
||||
|
||||
already_AddRefed<Promise> ConsumeBody(BodyConsumer::ConsumeType aConsumeType,
|
||||
ErrorResult& aRv);
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
// The member is the real backend implementation of this File/Blob.
|
||||
// It's thread-safe and not CC-able and it's the only element that is moved
|
||||
|
|
|
@ -78,14 +78,14 @@ class BlobImpl : public nsISupports {
|
|||
virtual already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart,
|
||||
uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) = 0;
|
||||
ErrorResult& aRv) const = 0;
|
||||
|
||||
virtual const nsTArray<RefPtr<BlobImpl>>* GetSubBlobImpls() const = 0;
|
||||
|
||||
virtual void CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) = 0;
|
||||
ErrorResult& aRv) const = 0;
|
||||
|
||||
virtual int64_t GetFileId() = 0;
|
||||
virtual int64_t GetFileId() const = 0;
|
||||
|
||||
nsresult GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
||||
nsACString& aContentType, nsACString& aCharset);
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class BlobImpl;
|
||||
|
||||
|
@ -31,7 +30,6 @@ class BlobSet final {
|
|||
FallibleTArray<RefPtr<BlobImpl>> mBlobImpls;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_BlobSet_h
|
||||
|
|
|
@ -11,14 +11,14 @@ namespace mozilla::dom {
|
|||
|
||||
already_AddRefed<BlobImpl> EmptyBlobImpl::CreateSlice(
|
||||
uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
MOZ_ASSERT(!aStart && !aLength);
|
||||
RefPtr<BlobImpl> impl = new EmptyBlobImpl(aContentType);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void EmptyBlobImpl::CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
if (NS_WARN_IF(!aStream)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
|
||||
#include "BaseBlobImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class EmptyBlobImpl final : public BaseBlobImpl {
|
||||
public:
|
||||
|
@ -20,11 +19,12 @@ class EmptyBlobImpl final : public BaseBlobImpl {
|
|||
explicit EmptyBlobImpl(const nsAString& aContentType)
|
||||
: BaseBlobImpl(aContentType, 0 /* aLength */) {}
|
||||
|
||||
void CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv) override;
|
||||
void CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) override;
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
bool IsMemoryFile() const override { return true; }
|
||||
|
||||
|
@ -33,10 +33,9 @@ class EmptyBlobImpl final : public BaseBlobImpl {
|
|||
}
|
||||
|
||||
private:
|
||||
~EmptyBlobImpl() = default;
|
||||
~EmptyBlobImpl() override = default;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_EmptyBlobImpl_h
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
class nsIFile;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
struct ChromeFilePropertyBag;
|
||||
struct FilePropertyBag;
|
||||
|
@ -56,8 +55,8 @@ class File final : public Blob {
|
|||
|
||||
// WebIDL methods
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* cx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
JSObject* WrapObject(JSContext* cx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// File constructor
|
||||
static already_AddRefed<File> Constructor(const GlobalObject& aGlobal,
|
||||
|
@ -68,17 +67,17 @@ class File final : public Blob {
|
|||
|
||||
// ChromeOnly
|
||||
static already_AddRefed<Promise> CreateFromFileName(
|
||||
const GlobalObject& aGlobal, const nsAString& aFilePath,
|
||||
const GlobalObject& aGlobal, const nsAString& aPath,
|
||||
const ChromeFilePropertyBag& aBag, SystemCallerGuarantee aGuarantee,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// ChromeOnly
|
||||
static already_AddRefed<Promise> CreateFromNsIFile(
|
||||
const GlobalObject& aGlobal, nsIFile* aFile,
|
||||
const GlobalObject& aGlobal, nsIFile* aData,
|
||||
const ChromeFilePropertyBag& aBag, SystemCallerGuarantee aGuarantee,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void GetName(nsAString& aName) const;
|
||||
void GetName(nsAString& aFileName) const;
|
||||
|
||||
int64_t GetLastModified(ErrorResult& aRv);
|
||||
|
||||
|
@ -87,19 +86,18 @@ class File final : public Blob {
|
|||
void GetMozFullPath(nsAString& aFilename, SystemCallerGuarantee aGuarantee,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void GetMozFullPathInternal(nsAString& aName, ErrorResult& aRv);
|
||||
void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
virtual bool HasFileInterface() const override { return true; }
|
||||
bool HasFileInterface() const override { return true; }
|
||||
|
||||
private:
|
||||
// File constructor should never be used directly. Use Blob::Create or
|
||||
// File::Create.
|
||||
File(nsIGlobalObject* aGlobal, BlobImpl* aImpl);
|
||||
~File();
|
||||
~File() override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_File_h
|
||||
|
|
|
@ -110,7 +110,7 @@ FileBlobImpl::FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
|
|||
|
||||
already_AddRefed<BlobImpl> FileBlobImpl::CreateSlice(
|
||||
uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
RefPtr<FileBlobImpl> impl =
|
||||
new FileBlobImpl(this, aStart, aLength, aContentType);
|
||||
return impl.forget();
|
||||
|
@ -178,7 +178,7 @@ class FileBlobImpl::GetTypeRunnable final : public WorkerMainThreadRunnable {
|
|||
}
|
||||
|
||||
private:
|
||||
~GetTypeRunnable() = default;
|
||||
~GetTypeRunnable() override = default;
|
||||
|
||||
RefPtr<FileBlobImpl> mBlobImpl;
|
||||
const MutexAutoLock& mProofOfLock;
|
||||
|
@ -263,7 +263,7 @@ const uint32_t sFileStreamFlags =
|
|||
nsIFileInputStream::DEFER_OPEN | nsIFileInputStream::SHARE_DELETE;
|
||||
|
||||
void FileBlobImpl::CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
aRv = NS_NewLocalFileInputStream(getter_AddRefs(stream), mFile, -1, -1,
|
||||
sFileStreamFlags);
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
class nsIFile;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class FileBlobImpl : public BlobImpl {
|
||||
public:
|
||||
|
@ -68,7 +67,7 @@ class FileBlobImpl : public BlobImpl {
|
|||
|
||||
void GetType(nsAString& aType) override;
|
||||
|
||||
virtual void GetBlobImplType(nsAString& aBlobImplType) const override;
|
||||
void GetBlobImplType(nsAString& aBlobImplType) const override;
|
||||
|
||||
size_t GetAllocationSize() const override { return 0; }
|
||||
|
||||
|
@ -83,10 +82,10 @@ class FileBlobImpl : public BlobImpl {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void CreateInputStream(nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv) override;
|
||||
void CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
int64_t GetFileId() override { return mFileId; }
|
||||
int64_t GetFileId() const override { return mFileId; }
|
||||
|
||||
void SetLazyData(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, int64_t aLastModifiedDate) override {
|
||||
|
@ -116,7 +115,7 @@ class FileBlobImpl : public BlobImpl {
|
|||
}
|
||||
|
||||
protected:
|
||||
~FileBlobImpl() = default;
|
||||
~FileBlobImpl() override = default;
|
||||
|
||||
// Create slice
|
||||
FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart, uint64_t aLength,
|
||||
|
@ -124,7 +123,7 @@ class FileBlobImpl : public BlobImpl {
|
|||
|
||||
already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) override;
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
class GetTypeRunnable;
|
||||
void GetTypeInternal(nsAString& aType, const MutexAutoLock& aProofOfLock);
|
||||
|
@ -153,7 +152,6 @@ class FileBlobImpl : public BlobImpl {
|
|||
bool mWholeFile;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_FileBlobImpl_h
|
||||
|
|
|
@ -36,8 +36,8 @@ class FileList final : public nsISupports, public nsWrapperCache {
|
|||
|
||||
explicit FileList(nsISupports* aParent);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsISupports* GetParentObject() { return mParent; }
|
||||
|
||||
|
|
|
@ -23,8 +23,7 @@
|
|||
class nsITimer;
|
||||
class nsIEventTarget;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class Blob;
|
||||
class DOMException;
|
||||
|
@ -67,8 +66,8 @@ class FileReader final : public DOMEventTargetHelper,
|
|||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(FileReader,
|
||||
DOMEventTargetHelper)
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// WebIDL
|
||||
static already_AddRefed<FileReader> Constructor(const GlobalObject& aGlobal);
|
||||
|
@ -121,7 +120,7 @@ class FileReader final : public DOMEventTargetHelper,
|
|||
void InitialAsyncWait();
|
||||
|
||||
private:
|
||||
virtual ~FileReader();
|
||||
~FileReader() override;
|
||||
|
||||
// This must be in sync with dom/webidl/FileReader.webidl
|
||||
enum eReadyState { EMPTY = 0, LOADING = 1, DONE = 2 };
|
||||
|
@ -202,7 +201,6 @@ class FileReader final : public DOMEventTargetHelper,
|
|||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(FileReader, FILEREADER_ID)
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_FileReader_h
|
||||
|
|
|
@ -334,7 +334,7 @@ class ReadReadyRunnable final : public WorkerSyncRunnable {
|
|||
}
|
||||
|
||||
private:
|
||||
~ReadReadyRunnable() = default;
|
||||
~ReadReadyRunnable() override = default;
|
||||
};
|
||||
|
||||
// This class implements nsIInputStreamCallback and it will be called when the
|
||||
|
|
|
@ -48,14 +48,14 @@ nsresult MemoryBlobImpl::DataOwnerAdapter::Create(DataOwner* aDataOwner,
|
|||
|
||||
already_AddRefed<BlobImpl> MemoryBlobImpl::CreateSlice(
|
||||
uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
RefPtr<BlobImpl> impl =
|
||||
new MemoryBlobImpl(this, aStart, aLength, aContentType);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void MemoryBlobImpl::CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
if (mLength >= INT32_MAX) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
#include "nsIIPCSerializableInputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class MemoryBlobImpl final : public BaseBlobImpl {
|
||||
public:
|
||||
|
@ -44,11 +43,12 @@ class MemoryBlobImpl final : public BaseBlobImpl {
|
|||
MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data");
|
||||
}
|
||||
|
||||
void CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv) override;
|
||||
void CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) override;
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
bool IsMemoryFile() const override { return true; }
|
||||
|
||||
|
@ -123,7 +123,7 @@ class MemoryBlobImpl final : public BaseBlobImpl {
|
|||
size_t SizeOfExcludingThisEvenIfShared(MallocSizeOf) override { return 0; }
|
||||
|
||||
private:
|
||||
~DataOwnerAdapter() = default;
|
||||
~DataOwnerAdapter() override = default;
|
||||
|
||||
DataOwnerAdapter(DataOwner* aDataOwner, Span<const char> aData)
|
||||
: mDataOwner(aDataOwner), mData(aData) {}
|
||||
|
@ -149,13 +149,12 @@ class MemoryBlobImpl final : public BaseBlobImpl {
|
|||
MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data");
|
||||
}
|
||||
|
||||
~MemoryBlobImpl() = default;
|
||||
~MemoryBlobImpl() override = default;
|
||||
|
||||
// Used when backed by a memory store
|
||||
RefPtr<DataOwner> mDataOwner;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_MemoryBlobImpl_h
|
||||
|
|
|
@ -52,7 +52,7 @@ already_AddRefed<MultipartBlobImpl> MultipartBlobImpl::Create(
|
|||
}
|
||||
|
||||
void MultipartBlobImpl::CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
*aStream = nullptr;
|
||||
|
||||
uint32_t length = mBlobImpls.Length();
|
||||
|
@ -106,7 +106,7 @@ void MultipartBlobImpl::CreateInputStream(nsIInputStream** aStream,
|
|||
|
||||
already_AddRefed<BlobImpl> MultipartBlobImpl::CreateSlice(
|
||||
uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
// If we clamped to nothing we create an empty blob
|
||||
nsTArray<RefPtr<BlobImpl>> blobImpls;
|
||||
|
||||
|
|
|
@ -56,12 +56,12 @@ class MultipartBlobImpl final : public BaseBlobImpl {
|
|||
|
||||
already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) override;
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
uint64_t GetSize(ErrorResult& aRv) override { return mLength; }
|
||||
|
||||
void CreateInputStream(nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv) override;
|
||||
void CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>* GetSubBlobImpls() const override {
|
||||
return mBlobImpls.Length() ? &mBlobImpls : nullptr;
|
||||
|
@ -71,7 +71,7 @@ class MultipartBlobImpl final : public BaseBlobImpl {
|
|||
|
||||
size_t GetAllocationSize() const override;
|
||||
size_t GetAllocationSize(
|
||||
FallibleTArray<BlobImpl*>& aVisitedBlobImpls) const override;
|
||||
FallibleTArray<BlobImpl*>& aVisitedBlobs) const override;
|
||||
|
||||
void GetBlobImplType(nsAString& aBlobImplType) const override;
|
||||
|
||||
|
@ -91,7 +91,7 @@ class MultipartBlobImpl final : public BaseBlobImpl {
|
|||
: BaseBlobImpl(aContentType, MULTIPARTBLOBIMPL_UNKNOWN_LENGTH),
|
||||
mBlobImpls(std::move(aBlobImpls)) {}
|
||||
|
||||
~MultipartBlobImpl() = default;
|
||||
~MultipartBlobImpl() override = default;
|
||||
|
||||
void SetLengthAndModifiedDate(const Maybe<bool>& aCrossOriginIsolated,
|
||||
ErrorResult& aRv);
|
||||
|
|
|
@ -54,7 +54,7 @@ class BlobCreationDoneRunnable final : public Runnable {
|
|||
}
|
||||
|
||||
private:
|
||||
~BlobCreationDoneRunnable() {
|
||||
~BlobCreationDoneRunnable() override {
|
||||
MOZ_ASSERT(mBlobStorage);
|
||||
// If something when wrong, we still have to release these objects in the
|
||||
// correct thread.
|
||||
|
@ -147,7 +147,7 @@ class WriteRunnable final : public Runnable {
|
|||
MOZ_ASSERT(aData);
|
||||
}
|
||||
|
||||
~WriteRunnable() { free(mData); }
|
||||
~WriteRunnable() override { free(mData); }
|
||||
|
||||
RefPtr<MutableBlobStorage> mBlobStorage;
|
||||
void* mData;
|
||||
|
@ -170,7 +170,7 @@ class CloseFileRunnable final : public Runnable {
|
|||
}
|
||||
|
||||
private:
|
||||
~CloseFileRunnable() {
|
||||
~CloseFileRunnable() override {
|
||||
if (mFD) {
|
||||
PR_Close(mFD);
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ class CreateBlobRunnable final : public Runnable,
|
|||
}
|
||||
|
||||
private:
|
||||
~CreateBlobRunnable() {
|
||||
~CreateBlobRunnable() override {
|
||||
MOZ_ASSERT(mBlobStorage);
|
||||
// If something when wrong, we still have to release data in the correct
|
||||
// thread.
|
||||
|
@ -258,7 +258,7 @@ class LastRunnable final : public Runnable {
|
|||
}
|
||||
|
||||
private:
|
||||
~LastRunnable() {
|
||||
~LastRunnable() override {
|
||||
MOZ_ASSERT(mBlobStorage);
|
||||
// If something when wrong, we still have to release data in the correct
|
||||
// thread.
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
|
||||
class nsIEventTarget;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class MutableBlobStreamListener final
|
||||
: public nsIStreamListener,
|
||||
|
@ -26,10 +25,10 @@ class MutableBlobStreamListener final
|
|||
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
MutableBlobStreamListener(MutableBlobStorage::MutableBlobStorageType aType,
|
||||
const nsACString& aContentType,
|
||||
MutableBlobStorageCallback* aCallback,
|
||||
nsIEventTarget* aEventTarget = nullptr);
|
||||
MutableBlobStreamListener(
|
||||
MutableBlobStorage::MutableBlobStorageType aStorageType,
|
||||
const nsACString& aContentType, MutableBlobStorageCallback* aCallback,
|
||||
nsIEventTarget* aEventTarget = nullptr);
|
||||
|
||||
private:
|
||||
~MutableBlobStreamListener();
|
||||
|
@ -46,7 +45,6 @@ class MutableBlobStreamListener final
|
|||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_MutableBlobStreamListener_h
|
||||
|
|
|
@ -126,7 +126,7 @@ StreamBlobImpl::~StreamBlobImpl() {
|
|||
}
|
||||
|
||||
void StreamBlobImpl::CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
if (!mInputStream) {
|
||||
// We failed to clone the input stream in EnsureCloneableStream.
|
||||
*aStream = nullptr;
|
||||
|
@ -148,7 +148,7 @@ void StreamBlobImpl::CreateInputStream(nsIInputStream** aStream,
|
|||
|
||||
already_AddRefed<BlobImpl> StreamBlobImpl::CreateSlice(
|
||||
uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
if (!aLength) {
|
||||
RefPtr<BlobImpl> impl = new EmptyBlobImpl(aContentType);
|
||||
return impl.forget();
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
#include "nsIMemoryReporter.h"
|
||||
#include "nsICloneableInputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class StreamBlobImpl final : public BaseBlobImpl, public nsIMemoryReporter {
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
|
||||
|
@ -34,15 +33,16 @@ class StreamBlobImpl final : public BaseBlobImpl, public nsIMemoryReporter {
|
|||
const nsAString& aContentType, int64_t aLastModifiedDate,
|
||||
uint64_t aLength, const nsAString& aBlobImplType);
|
||||
|
||||
void CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv) override;
|
||||
void CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) override;
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
bool IsMemoryFile() const override { return true; }
|
||||
|
||||
int64_t GetFileId() override { return mFileId; }
|
||||
int64_t GetFileId() const override { return mFileId; }
|
||||
|
||||
void SetFileId(int64_t aFileId) { mFileId = aFileId; }
|
||||
|
||||
|
@ -77,7 +77,7 @@ class StreamBlobImpl final : public BaseBlobImpl, public nsIMemoryReporter {
|
|||
int64_t aLastModifiedDate, uint64_t aLength,
|
||||
const nsAString& aBlobImplType);
|
||||
|
||||
~StreamBlobImpl();
|
||||
~StreamBlobImpl() override;
|
||||
|
||||
void MaybeRegisterMemoryReporter();
|
||||
|
||||
|
@ -90,7 +90,6 @@ class StreamBlobImpl final : public BaseBlobImpl, public nsIMemoryReporter {
|
|||
int64_t mFileId;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_StreamBlobImpl_h
|
||||
|
|
|
@ -27,14 +27,14 @@ StringBlobImpl::~StringBlobImpl() { UnregisterWeakMemoryReporter(this); }
|
|||
|
||||
already_AddRefed<BlobImpl> StringBlobImpl::CreateSlice(
|
||||
uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
RefPtr<BlobImpl> impl =
|
||||
new StringBlobImpl(Substring(mData, aStart, aLength), aContentType);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void StringBlobImpl::CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
aRv = NS_NewCStringInputStream(aStream, mData);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
#include "BaseBlobImpl.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class StringBlobImpl final : public BaseBlobImpl, public nsIMemoryReporter {
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
|
||||
|
@ -23,11 +22,12 @@ class StringBlobImpl final : public BaseBlobImpl, public nsIMemoryReporter {
|
|||
static already_AddRefed<StringBlobImpl> Create(const nsACString& aData,
|
||||
const nsAString& aContentType);
|
||||
|
||||
void CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv) override;
|
||||
void CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) override;
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
size_t GetAllocationSize() const override { return mData.Length(); }
|
||||
|
||||
|
@ -43,12 +43,11 @@ class StringBlobImpl final : public BaseBlobImpl, public nsIMemoryReporter {
|
|||
private:
|
||||
StringBlobImpl(const nsACString& aData, const nsAString& aContentType);
|
||||
|
||||
~StringBlobImpl();
|
||||
~StringBlobImpl() override;
|
||||
|
||||
nsCString mData;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_StringBlobImpl_h
|
||||
|
|
|
@ -75,7 +75,7 @@ class TemporaryFileInputStream final : public nsFileInputStream {
|
|||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
}
|
||||
|
||||
~TemporaryFileInputStream() {
|
||||
~TemporaryFileInputStream() override {
|
||||
// Let's delete the file on the RemoteLazyInputStream Thread.
|
||||
RefPtr<RemoteLazyInputStreamThread> thread =
|
||||
RemoteLazyInputStreamThread::GetOrCreate();
|
||||
|
@ -114,13 +114,13 @@ TemporaryFileBlobImpl::~TemporaryFileBlobImpl() {
|
|||
|
||||
already_AddRefed<BlobImpl> TemporaryFileBlobImpl::CreateSlice(
|
||||
uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
MOZ_CRASH("This BlobImpl is not meant to be sliced!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TemporaryFileBlobImpl::CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) {
|
||||
ErrorResult& aRv) const {
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!mInputStreamCreated);
|
||||
// CreateInputStream can be called only once.
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
|
||||
#include "FileBlobImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
// This class is meant to be used by TemporaryIPCBlobParent only.
|
||||
// Don't use it for anything else, please!
|
||||
|
@ -20,30 +19,29 @@ namespace dom {
|
|||
// IPCBlobUtils.
|
||||
class TemporaryFileBlobImpl final : public FileBlobImpl {
|
||||
#ifdef DEBUG
|
||||
bool mInputStreamCreated;
|
||||
mutable bool mInputStreamCreated;
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit TemporaryFileBlobImpl(nsIFile* aFile, const nsAString& aContentType);
|
||||
|
||||
// Overrides
|
||||
void CreateInputStream(nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv) override;
|
||||
void CreateInputStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
void GetBlobImplType(nsAString& aBlobImplType) const override {
|
||||
aBlobImplType = u"TemporaryFileBlobImpl"_ns;
|
||||
}
|
||||
|
||||
protected:
|
||||
~TemporaryFileBlobImpl();
|
||||
~TemporaryFileBlobImpl() override;
|
||||
|
||||
private:
|
||||
already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv) override;
|
||||
ErrorResult& aRv) const override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_TemporaryFileBlobImpl_h
|
||||
|
|
|
@ -9,15 +9,14 @@
|
|||
|
||||
#include "mozilla/dom/PFileCreatorChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class FileCreatorChild final : public mozilla::dom::PFileCreatorChild {
|
||||
friend class mozilla::dom::PFileCreatorChild;
|
||||
|
||||
public:
|
||||
FileCreatorChild();
|
||||
~FileCreatorChild();
|
||||
~FileCreatorChild() override;
|
||||
|
||||
void SetPromise(Promise* aPromise);
|
||||
|
||||
|
@ -29,7 +28,6 @@ class FileCreatorChild final : public mozilla::dom::PFileCreatorChild {
|
|||
RefPtr<Promise> mPromise;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_FileCreatorChild_h
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
class nsIFile;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class BlobImpl;
|
||||
|
||||
|
@ -28,7 +27,7 @@ class FileCreatorParent final : public mozilla::dom::PFileCreatorParent {
|
|||
const bool& aIsFromNsIFile);
|
||||
|
||||
private:
|
||||
~FileCreatorParent();
|
||||
~FileCreatorParent() override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
|
@ -41,7 +40,6 @@ class FileCreatorParent final : public mozilla::dom::PFileCreatorParent {
|
|||
bool mIPCActive;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_FileCreatorParent_h
|
||||
|
|
|
@ -70,7 +70,7 @@ class RemoteLazyInputStreamChild final : public PRemoteLazyInputStreamChild {
|
|||
void Migrated();
|
||||
|
||||
private:
|
||||
~RemoteLazyInputStreamChild();
|
||||
~RemoteLazyInputStreamChild() override;
|
||||
|
||||
// Raw pointers because these streams keep this actor alive. When the last
|
||||
// stream is unregister, the actor will be deleted. This list is protected by
|
||||
|
|
|
@ -89,7 +89,7 @@ class RemoteLazyInputStreamParent final : public PRemoteLazyInputStreamParent {
|
|||
RemoteLazyInputStreamParent(const nsID& aID, uint64_t aSize,
|
||||
mozilla::net::SocketProcessParent* aManager);
|
||||
|
||||
~RemoteLazyInputStreamParent() = default;
|
||||
~RemoteLazyInputStreamParent() override = default;
|
||||
|
||||
const nsID mID;
|
||||
const uint64_t mSize;
|
||||
|
|
|
@ -32,21 +32,22 @@ mozilla::ipc::IPCResult TemporaryIPCBlobChild::RecvFileDesc(
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult TemporaryIPCBlobChild::Recv__delete__(
|
||||
const IPCBlobOrError& aData) {
|
||||
const IPCBlobOrError& aBlobOrError) {
|
||||
mActive = false;
|
||||
mMutableBlobStorage = nullptr;
|
||||
|
||||
if (aData.type() == IPCBlobOrError::TIPCBlob) {
|
||||
if (aBlobOrError.type() == IPCBlobOrError::TIPCBlob) {
|
||||
// This must be always deserialized.
|
||||
RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aData.get_IPCBlob());
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
IPCBlobUtils::Deserialize(aBlobOrError.get_IPCBlob());
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
if (mCallback) {
|
||||
mCallback->OperationSucceeded(blobImpl);
|
||||
}
|
||||
} else if (mCallback) {
|
||||
MOZ_ASSERT(aData.type() == IPCBlobOrError::Tnsresult);
|
||||
mCallback->OperationFailed(aData.get_nsresult());
|
||||
MOZ_ASSERT(aBlobOrError.type() == IPCBlobOrError::Tnsresult);
|
||||
mCallback->OperationFailed(aBlobOrError.get_nsresult());
|
||||
}
|
||||
|
||||
mCallback = nullptr;
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
#include "mozilla/dom/PTemporaryIPCBlob.h"
|
||||
#include "mozilla/dom/PTemporaryIPCBlobChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class BlobImpl;
|
||||
class MutableBlobStorage;
|
||||
|
@ -30,13 +29,13 @@ class TemporaryIPCBlobChild final : public PTemporaryIPCBlobChild {
|
|||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(TemporaryIPCBlobChild)
|
||||
|
||||
explicit TemporaryIPCBlobChild(MutableBlobStorage* aMutableBlobStorage);
|
||||
explicit TemporaryIPCBlobChild(MutableBlobStorage* aStorage);
|
||||
|
||||
void AskForBlob(TemporaryIPCBlobChildCallback* aCallback,
|
||||
const nsACString& aContentType, PRFileDesc* aFD);
|
||||
|
||||
private:
|
||||
~TemporaryIPCBlobChild();
|
||||
~TemporaryIPCBlobChild() override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvFileDesc(const FileDescriptor& aFD);
|
||||
|
||||
|
@ -49,7 +48,6 @@ class TemporaryIPCBlobChild final : public PTemporaryIPCBlobChild {
|
|||
bool mActive;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_TemporaryIPCBlobChild_h
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
|
||||
class nsIFile;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class TemporaryIPCBlobParent final : public PTemporaryIPCBlobParent {
|
||||
friend class PTemporaryIPCBlobParent;
|
||||
|
@ -24,7 +23,7 @@ class TemporaryIPCBlobParent final : public PTemporaryIPCBlobParent {
|
|||
mozilla::ipc::IPCResult CreateAndShareFile();
|
||||
|
||||
private:
|
||||
~TemporaryIPCBlobParent();
|
||||
~TemporaryIPCBlobParent() override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvOperationFailed();
|
||||
|
||||
|
@ -39,7 +38,6 @@ class TemporaryIPCBlobParent final : public PTemporaryIPCBlobParent {
|
|||
bool mActive;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_TemporaryIPCBlobParent_h
|
||||
|
|
|
@ -36,8 +36,7 @@ inline NS_DEFINE_CID(kHOSTOBJECTURICID, NS_HOSTOBJECTURI_CID);
|
|||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIBlobURLMutator, NS_IBLOBURLMUTATOR_IID)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
/**
|
||||
* These URIs refer to host objects with "blob" scheme.
|
||||
|
@ -51,17 +50,15 @@ class BlobURL final : public mozilla::net::nsSimpleURI {
|
|||
NS_DECL_NSISERIALIZABLE
|
||||
|
||||
// Override CloneInternal() and EqualsInternal()
|
||||
virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
|
||||
const nsACString& newRef,
|
||||
nsIURI** aClone) override;
|
||||
virtual nsresult EqualsInternal(nsIURI* aOther,
|
||||
RefHandlingEnum aRefHandlingMode,
|
||||
bool* aResult) override;
|
||||
nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
|
||||
const nsACString& newRef, nsIURI** aClone) override;
|
||||
nsresult EqualsInternal(nsIURI* aOther, RefHandlingEnum aRefHandlingMode,
|
||||
bool* aResult) override;
|
||||
NS_IMETHOD_(void) Serialize(mozilla::ipc::URIParams& aParams) override;
|
||||
|
||||
// Override StartClone to hand back a BlobURL
|
||||
virtual mozilla::net::nsSimpleURI* StartClone(
|
||||
RefHandlingEnum refHandlingMode, const nsACString& newRef) override {
|
||||
mozilla::net::nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode,
|
||||
const nsACString& newRef) override {
|
||||
BlobURL* url = new BlobURL();
|
||||
SetRefOnClone(url, refHandlingMode, newRef);
|
||||
return url;
|
||||
|
@ -72,7 +69,7 @@ class BlobURL final : public mozilla::net::nsSimpleURI {
|
|||
NS_IMETHOD Mutate(nsIURIMutator** _retval) override;
|
||||
|
||||
private:
|
||||
virtual ~BlobURL() = default;
|
||||
~BlobURL() override = default;
|
||||
|
||||
nsresult SetScheme(const nsACString& aProtocol) override;
|
||||
bool Deserialize(const mozilla::ipc::URIParams&);
|
||||
|
@ -121,7 +118,6 @@ class BlobURL final : public mozilla::net::nsSimpleURI {
|
|||
} \
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif /* mozilla_dom_BlobURL_h */
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class BlobImpl;
|
||||
|
||||
|
@ -23,7 +22,7 @@ class BlobURLChannel final : public nsBaseChannel {
|
|||
BlobURLChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo);
|
||||
|
||||
private:
|
||||
~BlobURLChannel();
|
||||
~BlobURLChannel() override;
|
||||
|
||||
nsresult OpenContentStream(bool aAsync, nsIInputStream** aResult,
|
||||
nsIChannel** aChannel) override;
|
||||
|
@ -31,7 +30,6 @@ class BlobURLChannel final : public nsBaseChannel {
|
|||
bool mContentStreamOpened;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif /* mozilla_dom_BlobURLChannel_h */
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIInputStreamLength.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class BlobURL;
|
||||
class BlobURLChannel;
|
||||
|
@ -77,8 +76,6 @@ class BlobURLInputStream final : public nsIAsyncInputStream,
|
|||
nsCOMPtr<nsIEventTarget> mAsyncLengthWaitTarget;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif /* mozilla_dom_BlobURLInputStream_h */
|
||||
|
|
|
@ -468,7 +468,7 @@ class ReleasingTimerHolder final : public Runnable,
|
|||
explicit ReleasingTimerHolder(const nsACString& aURI)
|
||||
: Runnable("ReleasingTimerHolder"), mURI(aURI) {}
|
||||
|
||||
~ReleasingTimerHolder() = default;
|
||||
~ReleasingTimerHolder() override = default;
|
||||
|
||||
void RevokeURI() {
|
||||
// Remove the shutting down blocker
|
||||
|
|
|
@ -76,7 +76,7 @@ class BlobURLProtocolHandler final : public nsIProtocolHandler,
|
|||
nsIPrincipal* aTriggeringPrincipal,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t aInnerWindowId,
|
||||
const Maybe<nsID>& blobAgentClusterId,
|
||||
const Maybe<nsID>& aAgentClusterId,
|
||||
bool aAlsoIfRevoked = false);
|
||||
|
||||
static void Traverse(const nsACString& aUri,
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
|
||||
#define FONTTABLEURI_SCHEME "moz-fonttable"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
class FontTableURIProtocolHandler final
|
||||
: public nsIProtocolHandler,
|
||||
|
@ -37,7 +36,6 @@ inline bool IsFontTableURI(nsIURI* aUri) {
|
|||
return aUri->SchemeIs(FONTTABLEURI_SCHEME);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif /* FontTableURIProtocolHandler_h */
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче