--- a/browser/base/content/browser-pageActions.js
+++ b/browser/base/content/browser-pageActions.js
@@ -941,79 +941,31 @@ var BrowserPageActions = {
onLocationChange() {
for (let action of PageActions.actions) {
action.onLocationChange(window);
}
},
};
-var BrowserPageActionFeedback = {
- /**
- * The feedback page action panel DOM node (DOM node)
- */
- get panelNode() {
- delete this.panelNode;
- return this.panelNode = document.getElementById("pageActionFeedback");
- },
-
- get feedbackAnimationBox() {
- delete this.feedbackAnimationBox;
- return this.feedbackAnimationBox = document.getElementById("pageActionFeedbackAnimatableBox");
- },
-
- get feedbackLabel() {
- delete this.feedbackLabel;
- return this.feedbackLabel = document.getElementById("pageActionFeedbackMessage");
- },
+/**
+ * Shows the feedback popup for an action.
+ *
+ * @param action (PageActions.Action, required)
+ * The action associated with the feedback.
+ * @param event (DOM event, optional)
+ * The event that triggered the feedback.
+ * @param messageId (string, optional)
+ * Can be used to set a message id that is different from the action id.
+ */
+function showBrowserPageActionFeedback(action, event = null, messageId = null) {
+ let anchor = BrowserPageActions.panelAnchorNodeForAction(action, event);
- /**
- * Shows the feedback popup for an action.
- *
- * @param action (PageActions.Action, required)
- * The action associated with the feedback.
- * @param opts (object, optional)
- * An object with the following optional properties:
- * - event (DOM event): The event that triggered the feedback.
- * - textAttributeOverride (string): Normally the feedback text is
- * taken from an attribute on the feedback panel. The attribute's
- * name is `${action.id}Feedback`. Use this to override the
- * action.id part of the name.
- * - text (string): The text string. If not given, an attribute on
- * panel is assumed to contain the text, as described above.
- */
- show(action, opts = {}) {
- this.feedbackLabel.textContent =
- opts.text ||
- this.panelNode.getAttribute((opts.textAttributeOverride || action.id) +
- "Feedback");
- this.panelNode.hidden = false;
-
- let event = opts.event || null;
- let anchor = BrowserPageActions.panelAnchorNodeForAction(action, event);
- PanelMultiView.openPopup(this.panelNode, anchor, {
- position: "bottomcenter topright",
- triggerEvent: event,
- }).catch(Cu.reportError);
-
- this.panelNode.addEventListener("popupshown", () => {
- this.feedbackAnimationBox.setAttribute("animate", "true");
-
- // The timeout value used here allows the panel to stay open for
- // 1 second after the text transition (duration=120ms) has finished.
- setTimeout(() => {
- this.panelNode.hidePopup(true);
- }, Services.prefs.getIntPref("browser.pageActions.feedbackTimeoutMS", 1120));
- }, {once: true});
- this.panelNode.addEventListener("popuphidden", () => {
- this.feedbackAnimationBox.removeAttribute("animate");
- }, {once: true});
- },
-};
-
+ ConfirmationHint.show(anchor, messageId || action.id, {event, hideArrow: true});
+}
// built-in actions below //////////////////////////////////////////////////////
// bookmark
BrowserPageActions.bookmark = {
onShowingInPanel(buttonNode) {
// Update the button label via the bookmark observer.
BookmarkingUI.updateBookmarkPageMenuItem();
@@ -1033,19 +985,17 @@ BrowserPageActions.copyURL = {
},
onCommand(event, buttonNode) {
PanelMultiView.hidePopup(BrowserPageActions.panelNode);
Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper)
.copyString(gURLBar.makeURIReadable(gBrowser.selectedBrowser.currentURI).displaySpec);
let action = PageActions.actionForID("copyURL");
- BrowserPageActionFeedback.show(action, {
- event,
- });
+ showBrowserPageActionFeedback(action, event);
},
};
// email link
BrowserPageActions.emailLink = {
onPlacedInPanel(buttonNode) {
let action = PageActions.actionForID("emailLink");
BrowserPageActions.takeActionTitleFromPanel(action);
@@ -1112,21 +1062,18 @@ BrowserPageActions.sendToDevice = {
item.addEventListener("command", event => {
if (panelNode) {
PanelMultiView.hidePopup(panelNode);
}
// There are items in the subview that don't represent devices: "Sign
// in", "Learn about Sync", etc. Device items will be .sendtab-target.
if (event.target.classList.contains("sendtab-target")) {
let action = PageActions.actionForID("sendToDevice");
- let textAttributeOverride = gSync.offline && "sendToDeviceOffline";
- BrowserPageActionFeedback.show(action, {
- event,
- textAttributeOverride,
- });
+ let messageId = gSync.offline && "sendToDeviceOffline";
+ showBrowserPageActionFeedback(action, event, messageId);
}
});
return item;
});
bodyNode.removeAttribute("state");
// In the first ~10 sec after startup, Sync may not be loaded and the list
// of devices will be empty.
@@ -1228,19 +1175,17 @@ BrowserPageActions.addSearchEngine = {
// above.)
let engine = this.engines[0];
this._installEngine(engine.uri, engine.icon);
},
_installEngine(uri, image) {
Services.search.addEngine(uri, null, image, false, {
onSuccess: engine => {
- BrowserPageActionFeedback.show(this.action, {
- text: this.strings.GetStringFromName("searchAddedFoundEngine2"),
- });
+ showBrowserPageActionFeedback(this.action);
},
onError(errorCode) {
if (errorCode != Ci.nsISearchInstallCallback.ERROR_DUPLICATE_ENGINE) {
// Download error is shown by the search service
return;
}
const kSearchBundleURI = "chrome://global/locale/search/search.properties";
let searchBundle = Services.strings.createBundle(kSearchBundleURI);
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -114,16 +114,17 @@ var StarUI = {
PlacesTransactions.undo().catch(Cu.reportError);
break;
}
// Remove all bookmarks for the bookmark's url, this also removes
// the tags for the url.
PlacesTransactions.Remove(guidsForRemoval)
.transact().catch(Cu.reportError);
} else if (this._isNewBookmark) {
+ this._showConfirmation();
LibraryUI.triggerLibraryAnimation("bookmark");
}
if (!removeBookmarksOnPopupHidden) {
this._storeRecentlyUsedFolder(selectedFolderGuid).catch(console.error);
}
}
break;
@@ -398,16 +399,36 @@ var StarUI = {
lastUsedFolderGuids.unshift(selectedFolderGuid);
}
if (lastUsedFolderGuids.length > 5) {
lastUsedFolderGuids.pop();
}
await PlacesUtils.metadata.set(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY,
lastUsedFolderGuids);
+ },
+
+ _showConfirmation() {
+ let anchor;
+ if (window.toolbar.visible) {
+ for (let id of ["library-button", "bookmarks-menu-button"]) {
+ let element = document.getElementById(id);
+ if (element &&
+ element.getAttribute("cui-areatype") != "menu-panel" &&
+ element.getAttribute("overflowedItem") != "true") {
+ anchor = element;
+ break;
+ }
+ }
+ }
+ if (!anchor) {
+ anchor = document.getElementById("PanelUI-menu-button");
+ }
+
+ ConfirmationHint.show(anchor, "pageBookmarked");
}
};
var PlacesCommandHook = {
/**
* Adds a bookmark to the page loaded in the given browser.
*
* @param aBrowser
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -8517,8 +8517,76 @@ TabModalPromptBox.prototype = {
get browser() {
let browser = this._weakBrowserRef.get();
if (!browser) {
throw "Stale promptbox! The associated browser is gone.";
}
return browser;
},
};
+
+var ConfirmationHint = {
+ /**
+ * Shows a transient, non-interactive confirmation hint anchored to an
+ * element, usually used in response to a user action to reaffirm that it was
+ * successful and potentially provide extra context. Examples for such hints:
+ * - "Saved to Library!" after bookmarking a page
+ * - "Sent!" after sending a tab to another device
+ * - "Queued (offline)" when attempting to send a tab to another device
+ * while offline
+ *
+ * @param anchor (DOM node, required)
+ * The anchor for the panel.
+ * @param messageId (string, required)
+ * For getting the message string from browser.properties:
+ * confirmationHint.<messageId>.label
+ * @param options (object, optional)
+ * An object with the following optional properties:
+ * - event (DOM event): The event that triggered the feedback.
+ * - hideArrow (boolean): Optionally hide the arrow.
+ */
+ show(anchor, messageId, options = {}) {
+ this._message.textContent =
+ gBrowserBundle.GetStringFromName("confirmationHint." + messageId + ".label");
+
+ if (options.hideArrow) {
+ this._panel.setAttribute("hidearrow", "true");
+ }
+
+ this._panel.addEventListener("popupshown", () => {
+ this._animationBox.setAttribute("animate", "true");
+
+ // The timeout value used here allows the panel to stay open for
+ // X second after the text transition (duration=120ms) has finished.
+ const DURATION = 1500;
+ setTimeout(() => {
+ this._panel.hidePopup(true);
+ }, DURATION + 120);
+ }, {once: true});
+
+ this._panel.addEventListener("popuphidden", () => {
+ this._panel.removeAttribute("hidearrow");
+ this._animationBox.removeAttribute("animate");
+ }, {once: true});
+
+ this._panel.hidden = false;
+ this._panel.openPopup(anchor, {
+ position: "bottomcenter topright",
+ triggerEvent: options.event,
+ });
+ },
+
+ get _panel() {
+ delete this._panel;
+ return this._panel = document.getElementById("confirmation-hint");
+ },
+
+ get _animationBox() {
+ delete this._animationBox;
+ return this._animationBox = document.getElementById("confirmation-hint-checkmark-animation-container");
+ },
+
+ get _message() {
+ delete this._message;
+ return this._message = document.getElementById("confirmation-hint-message");
+ },
+};
+
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -459,31 +459,29 @@
viewCacheId="appMenu-viewCache">
<panelview id="pageActionPanelMainView"
context="pageActionContextMenu"
class="PanelUI-subView">
<vbox class="panel-subview-body"/>
</panelview>
</panelmultiview>
</panel>
- <panel id="pageActionFeedback"
+
+ <panel id="confirmation-hint"
role="alert"
type="arrow"
hidden="true"
flip="slide"
position="bottomcenter topright"
tabspecific="true"
- noautofocus="true"
- copyURLFeedback="©URLFeedback.label;"
- sendToDeviceFeedback="&sendToDeviceFeedback.label;"
- sendToDeviceOfflineFeedback="&sendToDeviceOfflineFeedback.label;">
- <hbox id="pageActionFeedbackAnimatableBox">
- <image id="pageActionFeedbackAnimatableImage"/>
+ noautofocus="true">
+ <hbox id="confirmation-hint-checkmark-animation-container">
+ <image id="confirmation-hint-checkmark-image"/>
</hbox>
- <label id="pageActionFeedbackMessage"/>
+ <label id="confirmation-hint-message"/>
</panel>
<menupopup id="pageActionContextMenu"
onpopupshowing="BrowserPageActions.onContextMenuShowing(event, this);">
<menuitem class="pageActionContextMenuItem builtInUnpinned"
label="&pageAction.addToUrlbar.label;"
oncommand="BrowserPageActions.togglePinningForContextAction();"/>
<menuitem class="pageActionContextMenuItem builtInPinned"
--- a/browser/base/content/test/urlbar/browser_page_action_menu.js
+++ b/browser/base/content/test/urlbar/browser_page_action_menu.js
@@ -132,21 +132,21 @@ add_task(async function copyURLFromPanel
Assert.ok(true, "page action panel opened");
let copyURLButton =
document.getElementById("pageAction-panel-copyURL");
let hiddenPromise = promisePageActionPanelHidden();
EventUtils.synthesizeMouseAtCenter(copyURLButton, {});
await hiddenPromise;
- let feedbackPanel = document.getElementById("pageActionFeedback");
+ let feedbackPanel = document.getElementById("confirmation-hint");
let feedbackShownPromise = BrowserTestUtils.waitForEvent(feedbackPanel, "popupshown");
await feedbackShownPromise;
Assert.equal(feedbackPanel.anchorNode.id, "pageActionButton", "Feedback menu should be anchored on the main Page Action button");
- let feedbackHiddenPromise = promisePanelHidden("pageActionFeedback");
+ let feedbackHiddenPromise = promisePanelHidden("confirmation-hint");
await feedbackHiddenPromise;
action.pinnedToUrlbar = false;
});
});
add_task(async function copyURLFromURLBar() {
// Open an actionable page so that the main page action button appears. (It
@@ -155,23 +155,23 @@ add_task(async function copyURLFromURLBa
await BrowserTestUtils.withNewTab(url, async () => {
// Add action to URL bar.
let action = PageActions._builtInActions.find(a => a.id == "copyURL");
action.pinnedToUrlbar = true;
registerCleanupFunction(() => action.pinnedToUrlbar = false);
let copyURLButton =
document.getElementById("pageAction-urlbar-copyURL");
- let feedbackShownPromise = promisePanelShown("pageActionFeedback");
+ let feedbackShownPromise = promisePanelShown("confirmation-hint");
EventUtils.synthesizeMouseAtCenter(copyURLButton, {});
await feedbackShownPromise;
- let panel = document.getElementById("pageActionFeedback");
+ let panel = document.getElementById("confirmation-hint");
Assert.equal(panel.anchorNode.id, "pageAction-urlbar-copyURL", "Feedback menu should be anchored on the main URL bar button");
- let feedbackHiddenPromise = promisePanelHidden("pageActionFeedback");
+ let feedbackHiddenPromise = promisePanelHidden("confirmation-hint");
await feedbackHiddenPromise;
action.pinnedToUrlbar = false;
});
});
add_task(async function sendToDevice_nonSendable() {
// Open a tab that's not sendable but where the page action buttons still
@@ -612,23 +612,23 @@ add_task(async function sendToDevice_inU
info("Waiting for Send to Device panel to close after clicking a device");
await hiddenPromise;
Assert.ok(!urlbarButton.hasAttribute("open"),
"URL bar button no longer has open attribute");
// And then the "Sent!" notification panel should open and close by itself
// after a moment.
info("Waiting for the Sent! notification panel to open");
- await promisePanelShown(BrowserPageActionFeedback.panelNode.id);
+ await promisePanelShown(ConfirmationHint._panel.id);
Assert.equal(
- BrowserPageActionFeedback.panelNode.anchorNode.id,
+ ConfirmationHint._panel.anchorNode.id,
urlbarButton.id
);
info("Waiting for the Sent! notification panel to close");
- await promisePanelHidden(BrowserPageActionFeedback.panelNode.id);
+ await promisePanelHidden(ConfirmationHint._panel.id);
// Remove Send to Device from the urlbar.
action.pinnedToUrlbar = false;
cleanUp();
});
});
--- a/browser/base/content/test/urlbar/browser_page_action_menu_add_search_engine.js
+++ b/browser/base/content/test/urlbar/browser_page_action_menu_add_search_engine.js
@@ -44,17 +44,17 @@ add_task(async function one() {
let enginePromise =
promiseEngine("engine-added", "page_action_menu_add_search_engine_0");
let hiddenPromise = promisePageActionPanelHidden();
let feedbackPromise = promiseFeedbackPanelShownAndHidden();
EventUtils.synthesizeMouseAtCenter(button, {});
await hiddenPromise;
let engine = await enginePromise;
let feedbackText = await feedbackPromise;
- Assert.equal(feedbackText, "Added Search Engine");
+ Assert.equal(feedbackText, "Search engine added!");
// Open the panel again.
await promisePageActionPanelOpen();
EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
await promisePageActionPanelHidden();
// The action should be gone.
actions = PageActions.actionsInPanel(window);
@@ -133,17 +133,17 @@ add_task(async function many() {
let hiddenPromise = promisePageActionPanelHidden();
let feedbackPromise = promiseFeedbackPanelShownAndHidden();
EventUtils.synthesizeMouseAtCenter(body.childNodes[0], {});
await hiddenPromise;
let engines = [];
let engine = await enginePromise;
engines.push(engine);
let feedbackText = await feedbackPromise;
- Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+ Assert.equal(feedbackText, "Search engine added!", "Feedback text");
// Open the panel and show the subview again. The installed engine should
// be gone.
await promisePageActionPanelOpen();
viewPromise = promisePageActionViewShown();
EventUtils.synthesizeMouseAtCenter(button, {});
await viewPromise;
Assert.deepEqual(
@@ -160,17 +160,17 @@ add_task(async function many() {
promiseEngine("engine-added", "page_action_menu_add_search_engine_1");
hiddenPromise = promisePageActionPanelHidden();
feedbackPromise = promiseFeedbackPanelShownAndHidden();
EventUtils.synthesizeMouseAtCenter(body.childNodes[0], {});
await hiddenPromise;
engine = await enginePromise;
engines.push(engine);
feedbackText = await feedbackPromise;
- Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+ Assert.equal(feedbackText, "Search engine added!", "Feedback text");
// Open the panel again. This time the action button should show the one
// remaining engine.
await promisePageActionPanelOpen();
actions = PageActions.actionsInPanel(window);
action = actions.find(a => a.id == "addSearchEngine");
Assert.ok(action, "Action should be present in panel");
expectedTitle = "Add Search Engine";
@@ -186,17 +186,17 @@ add_task(async function many() {
promiseEngine("engine-added", "page_action_menu_add_search_engine_2");
hiddenPromise = promisePageActionPanelHidden();
feedbackPromise = promiseFeedbackPanelShownAndHidden();
EventUtils.synthesizeMouseAtCenter(button, {});
await hiddenPromise;
engine = await enginePromise;
engines.push(engine);
feedbackText = await feedbackPromise;
- Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+ Assert.equal(feedbackText, "Search engine added!", "Feedback text");
// All engines are installed at this point. Open the panel and make sure
// the action is gone.
await promisePageActionPanelOpen();
EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
await promisePageActionPanelHidden();
actions = PageActions.actionsInPanel(window);
action = actions.find(a => a.id == "addSearchEngine");
@@ -305,17 +305,17 @@ add_task(async function urlbarOne() {
// Click the action's button.
let enginePromise =
promiseEngine("engine-added", "page_action_menu_add_search_engine_0");
let feedbackPromise = promiseFeedbackPanelShownAndHidden();
EventUtils.synthesizeMouseAtCenter(button, {});
let engine = await enginePromise;
let feedbackText = await feedbackPromise;
- Assert.equal(feedbackText, "Added Search Engine");
+ Assert.equal(feedbackText, "Search engine added!");
// The action should be gone.
actions = PageActions.actionsInUrlbar(window);
action = actions.find(a => a.id == "addSearchEngine");
Assert.ok(!action, "Action should not be present in urlbar");
button = BrowserPageActions.urlbarButtonNodeForActionID("addSearchEngine");
Assert.ok(!button, "Action button should not be in urlbar");
@@ -384,17 +384,17 @@ add_task(async function urlbarMany() {
promisePanelHidden(BrowserPageActions.activatedActionPanelNode);
let feedbackPromise = promiseFeedbackPanelShownAndHidden();
EventUtils.synthesizeMouseAtCenter(body.childNodes[0], {});
await hiddenPromise;
let engines = [];
let engine = await enginePromise;
engines.push(engine);
let feedbackText = await feedbackPromise;
- Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+ Assert.equal(feedbackText, "Search engine added!", "Feedback text");
// Open the panel again. The installed engine should be gone.
EventUtils.synthesizeMouseAtCenter(button, {});
view = await waitForActivatedActionPanel();
body = view.firstChild;
Assert.deepEqual(
Array.map(body.childNodes, n => n.label),
[
@@ -410,28 +410,28 @@ add_task(async function urlbarMany() {
hiddenPromise =
promisePanelHidden(BrowserPageActions.activatedActionPanelNode);
feedbackPromise = promiseFeedbackPanelShownAndHidden();
EventUtils.synthesizeMouseAtCenter(body.childNodes[0], {});
await hiddenPromise;
engine = await enginePromise;
engines.push(engine);
feedbackText = await feedbackPromise;
- Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+ Assert.equal(feedbackText, "Search engine added!", "Feedback text");
// Now there's only one engine left, so clicking the button should simply
// install it instead of opening the activated-action panel.
enginePromise =
promiseEngine("engine-added", "page_action_menu_add_search_engine_2");
feedbackPromise = promiseFeedbackPanelShownAndHidden();
EventUtils.synthesizeMouseAtCenter(button, {});
engine = await enginePromise;
engines.push(engine);
feedbackText = await feedbackPromise;
- Assert.equal(feedbackText, "Added Search Engine", "Feedback text");
+ Assert.equal(feedbackText, "Search engine added!", "Feedback text");
// All engines are installed at this point. The action should be gone.
actions = PageActions.actionsInUrlbar(window);
action = actions.find(a => a.id == "addSearchEngine");
Assert.ok(!action, "Action should be gone");
button = BrowserPageActions.urlbarButtonNodeForActionID("addSearchEngine");
Assert.ok(!button, "Button should not be in urlbar");
@@ -516,20 +516,20 @@ function promiseEngine(expectedData, exp
info(`Got engine ${engine.wrappedJSObject.name} ${data}`);
return expectedData == data &&
expectedEngineName == engine.wrappedJSObject.name;
}).then(([engine, data]) => engine);
}
function promiseFeedbackPanelShownAndHidden() {
info("Waiting for feedback panel popupshown");
- return BrowserTestUtils.waitForEvent(BrowserPageActionFeedback.panelNode, "popupshown").then(() => {
+ return BrowserTestUtils.waitForEvent(ConfirmationHint._panel, "popupshown").then(() => {
info("Got feedback panel popupshown. Now waiting for popuphidden");
- return BrowserTestUtils.waitForEvent(BrowserPageActionFeedback.panelNode, "popuphidden")
- .then(() => BrowserPageActionFeedback.feedbackLabel.textContent);
+ return BrowserTestUtils.waitForEvent(ConfirmationHint._panel, "popuphidden")
+ .then(() => ConfirmationHint._message.textContent);
});
}
function promisePlacedInUrlbar() {
let action = PageActions.actionForID("addSearchEngine");
return new Promise(resolve => {
let onPlaced = action._onPlacedInUrlbar;
action._onPlacedInUrlbar = button => {
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -47,18 +47,16 @@ can reach it easily. -->
<!ENTITY unpinTab.label "Unpin Tab">
<!ENTITY unpinTab.accesskey "b">
<!ENTITY sendTabToDevice.label "Send Tab to Device">
<!ENTITY sendTabToDevice.accesskey "n">
<!ENTITY sendPageToDevice.label "Send Page to Device">
<!ENTITY sendPageToDevice.accesskey "n">
<!ENTITY sendLinkToDevice.label "Send Link to Device">
<!ENTITY sendLinkToDevice.accesskey "n">
-<!ENTITY sendToDeviceFeedback.label "Sent!">
-<!ENTITY sendToDeviceOfflineFeedback.label "Queued (offline)">
<!ENTITY moveToNewWindow.label "Move to New Window">
<!ENTITY moveToNewWindow.accesskey "W">
<!ENTITY reopenInContainer.label "Reopen in Container">
<!ENTITY reopenInContainer.accesskey "e">
<!ENTITY bookmarkAllTabs.label "Bookmark All Tabs…">
<!ENTITY bookmarkAllTabs.accesskey "T">
<!ENTITY undoCloseTab.label "Undo Close Tab">
<!ENTITY undoCloseTab.accesskey "U">
@@ -575,17 +573,16 @@ These should match what Safari and other
<!ENTITY setDesktopBackgroundCmd.accesskey "S">
<!ENTITY bookmarkPageCmd2.label "Bookmark This Page">
<!ENTITY bookmarkPageCmd2.accesskey "m">
<!ENTITY bookmarkThisLinkCmd.label "Bookmark This Link">
<!ENTITY bookmarkThisLinkCmd.accesskey "L">
<!ENTITY bookmarkThisFrameCmd.label "Bookmark This Frame">
<!ENTITY bookmarkThisFrameCmd.accesskey "m">
<!ENTITY pageAction.copyLink.label "Copy Link">
-<!ENTITY copyURLFeedback.label "Copied!">
<!ENTITY emailPageCmd.label "Email Link…">
<!ENTITY emailPageCmd.accesskey "E">
<!ENTITY savePageCmd.label "Save Page As…">
<!ENTITY savePageCmd.accesskey "A">
<!-- alternate for content area context menu -->
<!ENTITY savePageCmd.accesskey2 "P">
<!ENTITY savePageCmd.commandkey "s">
<!ENTITY saveFrameCmd.label "Save Frame As…">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -965,8 +965,14 @@ autoplay.DontAllow.accesskey = n
autoplay.remember = Remember this decision
# LOCALIZATION NOTE (autoplay.message): %S is the name of the site URL (https://...) trying to autoplay media
autoplay.message = Will you allow %S to autoplay media with sound?
autoplay.messageWithFile = Will you allow this file to autoplay media with sound?
# LOCALIZATION NOTE (panel.back):
# This is used by screen readers to label the "back" button in various browser
# popup panels, including the sliding subviews of the main menu.
panel.back = Back
+
+confirmationHint.sendToDevice.label = Sent!
+confirmationHint.sendToDeviceOffline.label = Queued (offline)
+confirmationHint.copyURL.label = Copied to clipboard!
+confirmationHint.pageBookmarked.label = Saved to Library!
+confirmationHint.addSearchEngine.label = Search engine added!
--- a/browser/locales/en-US/chrome/browser/search.properties
+++ b/browser/locales/en-US/chrome/browser/search.properties
@@ -29,17 +29,16 @@ cmd_showSuggestions_accesskey=S
cmd_addFoundEngine=Add “%S”
# LOCALIZATION NOTE (cmd_addFoundEngineMenu): When more than 5 engines
# are offered by a web page, instead of listing all of them in the
# search panel using the cmd_addFoundEngine string, they will be
# grouped in a submenu using cmd_addFoundEngineMenu as a label.
cmd_addFoundEngineMenu=Add search engine
searchAddFoundEngine2=Add Search Engine
-searchAddedFoundEngine2=Added Search Engine
# LOCALIZATION NOTE (searchForSomethingWith2):
# This string is used to build the header above the list of one-click
# search providers: "Search for <user-typed string> with:"
searchForSomethingWith2=Search for %S with:
# LOCALIZATION NOTE (searchWithHeader):
# The wording of this string should be as close as possible to
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -214,88 +214,90 @@ panel[photon] > .panel-arrowcontainer >
#wrapper-zoom-controls:-moz-any([place="palette"],[place="menu-panel"]) > #zoom-controls {
margin-inline-start: 0;
}
#BMB_bookmarksPopup {
max-width: @standaloneSubviewWidth@;
}
-#pageActionFeedback > .panel-arrowcontainer > .panel-arrowbox {
+#confirmation-hint {
+ --arrowpanel-background: #058b00;
+ --arrowpanel-border-color: #046b00;
+ --arrowpanel-color: #fff;
+}
+
+#confirmation-hint[hidearrow] > .panel-arrowcontainer > .panel-arrowbox {
/* Don't display the arrow but keep the popup at the same vertical
offset as other arrow panels. */
visibility: hidden;
}
-#pageActionFeedback > .panel-arrowcontainer > .panel-arrowcontent {
- background-color: #058b00;
- background-image: none;
- border-radius: 2px;
- color: #fff;
+#confirmation-hint > .panel-arrowcontainer > .panel-arrowcontent {
font-weight: 400;
font-size: 1.1rem;
-moz-box-align: center;
padding: 6px 10px;
}
-#pageActionFeedbackAnimatableBox {
+#confirmation-hint-checkmark-animation-container {
position: relative;
overflow: hidden;
width: 14px;
height: 14px;
}
-#pageActionFeedbackAnimatableBox[animate] > #pageActionFeedbackAnimatableImage {
+#confirmation-hint-checkmark-animation-container[animate] > #confirmation-hint-checkmark-image {
position: absolute;
background-image: url(chrome://browser/skin/check-animation.svg);
background-repeat: no-repeat;
min-width: 266px;
max-width: 266px;
min-height: 14px;
max-height: 14px;
- animation-name: page-action-feedback-animation;
+ animation-name: confirmation-hint-checkmark-animation;
animation-duration: 300ms;
animation-delay: 60ms;
animation-fill-mode: forwards;
animation-timing-function: steps(18);
}
-#pageActionFeedbackAnimatableBox[animate] > #pageActionFeedbackAnimatableImage:-moz-locale-dir(rtl) {
- animation-name: page-action-feedback-animation-rtl;
+#confirmation-hint-checkmark-animation-container[animate] > #confirmation-hint-checkmark-image:-moz-locale-dir(rtl) {
+ animation-name: confirmation-hint-checkmark-animation-rtl;
transform: translateX(252px);
}
-@keyframes page-action-feedback-animation {
+@keyframes confirmation-hint-checkmark-animation {
from {
transform: translateX(0);
}
to {
transform: translateX(-252px);
}
}
-@keyframes page-action-feedback-animation-rtl {
+@keyframes confirmation-hint-checkmark-animation-rtl {
from {
transform: translateX(252px);
}
to {
transform: translateX(0);
}
}
-#pageActionFeedbackMessage {
+#confirmation-hint-message {
margin-inline-start: 7px;
margin-inline-end: 0;
transform: scale(.8);
opacity: 0;
transition: transform 120ms cubic-bezier(.25,1.27,.35,1.18),
opacity 60ms linear;
}
-#pageActionFeedbackAnimatableBox[animate] + #pageActionFeedbackMessage {
+#confirmation-hint-checkmark-animation-container[animate] + #confirmation-hint-message {
transform: scale(1);
opacity: 1;
}
.cui-widget-panel[viewId^=PanelUI-webext-] > .panel-arrowcontainer > .panel-arrowcontent {
padding: 0;
}