Update textarea patch
This commit is contained in:
parent
0365593990
commit
f01e178c00
|
@ -1,119 +1,576 @@
|
|||
diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp
|
||||
index 3a336b25278ae..448a96fb0ae9b 100644
|
||||
--- a/layout/generic/nsIFrame.cpp
|
||||
+++ b/layout/generic/nsIFrame.cpp
|
||||
@@ -8879,6 +8879,60 @@ nsresult nsIFrame::PeekOffsetForParagraph(PeekOffsetStruct* aPos) {
|
||||
return NS_OK;
|
||||
}
|
||||
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
|
||||
index b3a09ea31391c..e16bc4df9606b 100644
|
||||
--- a/browser/base/content/browser.js
|
||||
+++ b/browser/base/content/browser.js
|
||||
@@ -72,7 +72,7 @@ ChromeUtils.defineESModuleGetters(this, {
|
||||
SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs",
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
ShoppingSidebarParent: "resource:///actors/ShoppingSidebarParent.sys.mjs",
|
||||
- ShoppingUtils: "resource:///modules/ShoppingUtils.sys.mjs",
|
||||
+ ShoppingSidebarManager: "resource:///actors/ShoppingSidebarParent.sys.mjs",
|
||||
ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs",
|
||||
SiteDataManager: "resource:///modules/SiteDataManager.sys.mjs",
|
||||
SitePermissions: "resource:///modules/SitePermissions.sys.mjs",
|
||||
@@ -2079,7 +2079,7 @@ var gBrowserInit = {
|
||||
|
||||
+nsresult nsIFrame::PeekOffsetForLineEdgeLogical(PeekOffsetStruct* aPos) {
|
||||
+ nsIFrame* frame = this;
|
||||
+ nsContentAndOffset blockFrameOrBR;
|
||||
+ blockFrameOrBR.mContent = nullptr;
|
||||
+ bool reachedLimit = frame->IsBlockOutside() || IsEditingHost(frame);
|
||||
CaptivePortalWatcher.delayedStartup();
|
||||
|
||||
- ShoppingSidebarManager.init();
|
||||
+ ShoppingSidebarManager.ensureInitialized();
|
||||
|
||||
SessionStore.promiseAllWindowsRestored.then(() => {
|
||||
this._schedulePerWindowIdleTasks();
|
||||
@@ -2506,8 +2506,6 @@ var gBrowserInit = {
|
||||
|
||||
FirefoxViewHandler.uninit();
|
||||
|
||||
- ShoppingSidebarManager.uninit();
|
||||
-
|
||||
// Now either cancel delayedStartup, or clean up the services initialized from
|
||||
// it.
|
||||
if (this._boundDelayedStartup) {
|
||||
@@ -10082,208 +10080,3 @@ var FirefoxViewHandler = {
|
||||
this.button?.toggleAttribute("attention", shouldShow);
|
||||
},
|
||||
};
|
||||
-
|
||||
-var ShoppingSidebarManager = {
|
||||
- init() {
|
||||
- this._updateVisibility = this._updateVisibility.bind(this);
|
||||
- NimbusFeatures.shopping2023.onUpdate(this._updateVisibility);
|
||||
- XPCOMUtils.defineLazyPreferenceGetter(
|
||||
- this,
|
||||
- "optedInPref",
|
||||
- "browser.shopping.experience2023.optedIn",
|
||||
- null,
|
||||
- this._updateVisibility
|
||||
- );
|
||||
- XPCOMUtils.defineLazyPreferenceGetter(
|
||||
- this,
|
||||
- "isActive",
|
||||
- ShoppingSidebarParent.SHOPPING_ACTIVE_PREF,
|
||||
- true,
|
||||
- this._updateVisibility
|
||||
- );
|
||||
- this._updateVisibility();
|
||||
-
|
||||
- gBrowser.tabContainer.addEventListener("TabSelect", this);
|
||||
- window.addEventListener("visibilitychange", this);
|
||||
- },
|
||||
-
|
||||
- uninit() {
|
||||
- NimbusFeatures.shopping2023.offUpdate(this._updateVisibility);
|
||||
- },
|
||||
-
|
||||
- _updateVisibility() {
|
||||
- if (window.closed) {
|
||||
- return;
|
||||
- }
|
||||
- let isPBM = PrivateBrowsingUtils.isWindowPrivate(window);
|
||||
-
|
||||
- // We are forced to cache this value because otherwise we access the pref
|
||||
- // too many times.
|
||||
- this.inEnabledBranch = NimbusFeatures.shopping2023.getVariable("enabled");
|
||||
- this._enabled = this.inEnabledBranch && !isPBM;
|
||||
-
|
||||
- if (!this.isActive) {
|
||||
- document.querySelectorAll("shopping-sidebar").forEach(sidebar => {
|
||||
- sidebar.hidden = true;
|
||||
- });
|
||||
- }
|
||||
-
|
||||
- this._maybeToggleButton();
|
||||
-
|
||||
- if (!this._enabled) {
|
||||
- document.querySelectorAll("shopping-sidebar").forEach(sidebar => {
|
||||
- sidebar.remove();
|
||||
- });
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- let { selectedBrowser, currentURI } = gBrowser;
|
||||
- this._maybeToggleSidebar(selectedBrowser, currentURI, 0);
|
||||
- },
|
||||
-
|
||||
- /**
|
||||
- * Called by TabsProgressListener whenever any browser navigates from one
|
||||
- * URL to another.
|
||||
- * Note that this includes hash changes / pushState navigations, because
|
||||
- * those can be significant for us.
|
||||
- */
|
||||
- onLocationChange(aBrowser, aLocationURI, aFlags) {
|
||||
- ShoppingUtils.maybeRecordExposure(aLocationURI, aFlags);
|
||||
-
|
||||
- this._maybeToggleButton();
|
||||
- this._maybeToggleSidebar(aBrowser, aLocationURI, aFlags);
|
||||
- },
|
||||
-
|
||||
- // The strange signature is because this function was formerly the
|
||||
- // onLocationChange function, but we needed to differentiate between
|
||||
- // calls triggered by actual location changes and calls triggered by
|
||||
- // TabSelect. We will refactor this code in bug 1845842.
|
||||
- _maybeToggleSidebar(aBrowser, aLocationURI, aFlags) {
|
||||
- if (!this._enabled) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- let browserPanel = gBrowser.getPanel(aBrowser);
|
||||
- let sidebar = browserPanel.querySelector("shopping-sidebar");
|
||||
- let actor;
|
||||
- if (sidebar) {
|
||||
- let { browsingContext } = sidebar.querySelector("browser");
|
||||
- let global = browsingContext.currentWindowGlobal;
|
||||
- actor = global.getExistingActor("ShoppingSidebar");
|
||||
- }
|
||||
- let isProduct = isProductURL(aLocationURI);
|
||||
- if (isProduct && this.isActive) {
|
||||
- if (!sidebar) {
|
||||
- sidebar = document.createXULElement("shopping-sidebar");
|
||||
- sidebar.setAttribute("style", "width: 320px");
|
||||
- sidebar.hidden = false;
|
||||
- browserPanel.appendChild(sidebar);
|
||||
- } else {
|
||||
- actor?.updateProductURL(aLocationURI, aFlags);
|
||||
- sidebar.hidden = false;
|
||||
- }
|
||||
- } else if (sidebar && !sidebar.hidden) {
|
||||
- actor?.updateProductURL(null);
|
||||
- sidebar.hidden = true;
|
||||
- }
|
||||
-
|
||||
- this._updateBCActiveness(aBrowser);
|
||||
- this._setShoppingButtonState(aBrowser);
|
||||
-
|
||||
- if (
|
||||
- sidebar &&
|
||||
- !sidebar.hidden &&
|
||||
- ShoppingUtils.isProductPageNavigation(aLocationURI, aFlags)
|
||||
- ) {
|
||||
- Glean.shopping.surfaceDisplayed.record();
|
||||
- }
|
||||
-
|
||||
- if (isProduct) {
|
||||
- // This is the auto-enable behavior that toggles the `active` pref. It
|
||||
- // must be at the end of this function, or 2 sidebars could be created.
|
||||
- ShoppingUtils.handleAutoActivateOnProduct();
|
||||
-
|
||||
- if (!this.isActive) {
|
||||
- ShoppingUtils.sendTrigger({
|
||||
- browser: aBrowser,
|
||||
- id: "shoppingProductPageWithSidebarClosed",
|
||||
- context: { isSidebarClosing: !!sidebar },
|
||||
- });
|
||||
- }
|
||||
- }
|
||||
- },
|
||||
-
|
||||
- _maybeToggleButton() {
|
||||
- let optedOut = this.optedInPref === 2;
|
||||
- let isPBM = PrivateBrowsingUtils.isWindowPrivate(window);
|
||||
- if (this.inEnabledBranch && !isPBM && optedOut) {
|
||||
- this._setShoppingButtonState(gBrowser.selectedBrowser);
|
||||
- }
|
||||
- },
|
||||
-
|
||||
- _updateBCActiveness(aBrowser) {
|
||||
- let browserPanel = gBrowser.getPanel(aBrowser);
|
||||
- let sidebar = browserPanel.querySelector("shopping-sidebar");
|
||||
- if (!sidebar) {
|
||||
- return;
|
||||
- }
|
||||
- let { browsingContext } = sidebar.querySelector("browser");
|
||||
- try {
|
||||
- // Tell Gecko when the sidebar visibility changes to avoid background
|
||||
- // sidebars taking more CPU / energy than needed.
|
||||
- browsingContext.isActive =
|
||||
- !document.hidden &&
|
||||
- aBrowser == gBrowser.selectedBrowser &&
|
||||
- !sidebar.hidden;
|
||||
- } catch (ex) {
|
||||
- // The setter can throw and we do need to run the rest of this
|
||||
- // code in that case.
|
||||
- console.error(ex);
|
||||
- }
|
||||
- },
|
||||
-
|
||||
- _setShoppingButtonState(aBrowser) {
|
||||
- if (aBrowser !== gBrowser.selectedBrowser) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- let button = document.getElementById("shopping-sidebar-button");
|
||||
-
|
||||
- let isCurrentBrowserProduct = isProductURL(
|
||||
- gBrowser.selectedBrowser.currentURI
|
||||
- );
|
||||
-
|
||||
- // Only record if the state of the icon will change from hidden to visible.
|
||||
- if (button.hidden && isCurrentBrowserProduct) {
|
||||
- Glean.shopping.addressBarIconDisplayed.record();
|
||||
- }
|
||||
-
|
||||
- button.hidden = !isCurrentBrowserProduct;
|
||||
- button.setAttribute("shoppingsidebaropen", !!this.isActive);
|
||||
- let l10nId = this.isActive
|
||||
- ? "shopping-sidebar-close-button2"
|
||||
- : "shopping-sidebar-open-button2";
|
||||
- document.l10n.setAttributes(button, l10nId);
|
||||
- },
|
||||
-
|
||||
- handleEvent(event) {
|
||||
- switch (event.type) {
|
||||
- case "TabSelect": {
|
||||
- if (!this._enabled) {
|
||||
- return;
|
||||
- }
|
||||
- this._updateVisibility();
|
||||
- if (event.detail?.previousTab.linkedBrowser) {
|
||||
- this._updateBCActiveness(event.detail.previousTab.linkedBrowser);
|
||||
- }
|
||||
- break;
|
||||
- }
|
||||
- case "visibilitychange": {
|
||||
- if (!this._enabled) {
|
||||
- return;
|
||||
- }
|
||||
- this._updateBCActiveness(gBrowser.selectedBrowser);
|
||||
- }
|
||||
- }
|
||||
- },
|
||||
-};
|
||||
diff --git a/browser/components/shopping/ShoppingSidebarParent.sys.mjs b/browser/components/shopping/ShoppingSidebarParent.sys.mjs
|
||||
index a3d9737afd7cf..05145b249bb33 100644
|
||||
--- a/browser/components/shopping/ShoppingSidebarParent.sys.mjs
|
||||
+++ b/browser/components/shopping/ShoppingSidebarParent.sys.mjs
|
||||
@@ -2,6 +2,18 @@
|
||||
* 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 lazy = {};
|
||||
+ChromeUtils.defineESModuleGetters(lazy, {
|
||||
+ BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
|
||||
+ EveryWindow: "resource:///modules/EveryWindow.sys.mjs",
|
||||
+ isProductURL: "chrome://global/content/shopping/ShoppingProduct.mjs",
|
||||
+ NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
|
||||
+ PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
||||
+ ShoppingUtils: "resource:///modules/ShoppingUtils.sys.mjs",
|
||||
+});
|
||||
+
|
||||
+ auto traverse = [&aPos](nsIFrame* current) {
|
||||
+ return aPos->mDirection == eDirPrevious ? current->GetPrevSibling()
|
||||
+ : current->GetNextSibling();
|
||||
+ };
|
||||
+import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
||||
+
|
||||
+ // Go through containing frames until reaching a block frame.
|
||||
+ // In each step, search the previous (or next) siblings for the closest
|
||||
+ // "stop frame" (a block frame or a BRFrame).
|
||||
+ // If found, set it to be the selection boundary and abort.
|
||||
+ while (!reachedLimit) {
|
||||
+ nsIFrame* parent = frame->GetParent();
|
||||
+ // Treat a frame associated with the root content as if it were a block
|
||||
+ // frame.
|
||||
+ if (!frame->mContent || !frame->mContent->GetParent()) {
|
||||
+ reachedLimit = true;
|
||||
+ break;
|
||||
export class ShoppingSidebarParent extends JSWindowActorParent {
|
||||
static SHOPPING_ACTIVE_PREF = "browser.shopping.experience2023.active";
|
||||
static SHOPPING_OPTED_IN_PREF = "browser.shopping.experience2023.optedIn";
|
||||
@@ -74,3 +86,251 @@ export class ShoppingSidebarParent extends JSWindowActorParent {
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+class ShoppingSidebarManagerClass {
|
||||
+ #initialized = false;
|
||||
+ #everyWindowCallbackId = `shopping-${Services.uuid.generateUUID()}`;
|
||||
+
|
||||
+ ensureInitialized() {
|
||||
+ if (this.#initialized) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (aPos->mDirection == eDirNext) {
|
||||
+ // Try to find our own line-break before looking at our siblings.
|
||||
+ blockFrameOrBR = FindLineBreakInText(frame, eDirNext);
|
||||
+ }
|
||||
+ this.updateSidebarVisibility = this.updateSidebarVisibility.bind(this);
|
||||
+ lazy.NimbusFeatures.shopping2023.onUpdate(this.updateSidebarVisibility);
|
||||
+ XPCOMUtils.defineLazyPreferenceGetter(
|
||||
+ this,
|
||||
+ "optedInPref",
|
||||
+ "browser.shopping.experience2023.optedIn",
|
||||
+ null,
|
||||
+ this.updateSidebarVisibility
|
||||
+ );
|
||||
+ XPCOMUtils.defineLazyPreferenceGetter(
|
||||
+ this,
|
||||
+ "isActive",
|
||||
+ ShoppingSidebarParent.SHOPPING_ACTIVE_PREF,
|
||||
+ true,
|
||||
+ this.updateSidebarVisibility
|
||||
+ );
|
||||
+ this.updateSidebarVisibility();
|
||||
+
|
||||
+ nsIFrame* sibling = traverse(frame);
|
||||
+ while (sibling && !blockFrameOrBR.mContent) {
|
||||
+ blockFrameOrBR = FindLineBreakingFrame(sibling, aPos->mDirection);
|
||||
+ sibling = traverse(sibling);
|
||||
+ }
|
||||
+ if (blockFrameOrBR.mContent) {
|
||||
+ aPos->mResultContent = blockFrameOrBR.mContent;
|
||||
+ aPos->mContentOffset = blockFrameOrBR.mOffset;
|
||||
+ break;
|
||||
+ }
|
||||
+ frame = parent;
|
||||
+ reachedLimit = frame && (frame->IsBlockOutside() || IsEditingHost(frame));
|
||||
+ lazy.EveryWindow.registerCallback(
|
||||
+ this.#everyWindowCallbackId,
|
||||
+ window => {
|
||||
+ let isPBM = lazy.PrivateBrowsingUtils.isWindowPrivate(window);
|
||||
+ if (isPBM) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ window.gBrowser.tabContainer.addEventListener("TabSelect", this);
|
||||
+ window.addEventListener("visibilitychange", this);
|
||||
+ },
|
||||
+ window => {
|
||||
+ let isPBM = lazy.PrivateBrowsingUtils.isWindowPrivate(window);
|
||||
+ if (isPBM) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ window.gBrowser.tabContainer.removeEventListener("TabSelect", this);
|
||||
+ window.removeEventListener("visibilitychange", this);
|
||||
+ }
|
||||
+ );
|
||||
+
|
||||
+ this.#initialized = true;
|
||||
+ }
|
||||
+
|
||||
+ if (reachedLimit) { // no "stop frame" found
|
||||
+ aPos->mResultContent = frame->GetContent();
|
||||
+ if (aPos->mDirection == eDirPrevious) {
|
||||
+ aPos->mContentOffset = 0;
|
||||
+ } else if (aPos->mResultContent) {
|
||||
+ aPos->mContentOffset = aPos->mResultContent->GetChildCount();
|
||||
+ updateSidebarVisibility() {
|
||||
+ this.enabled = lazy.NimbusFeatures.shopping2023.getVariable("enabled");
|
||||
+
|
||||
+ for (let window of lazy.BrowserWindowTracker.orderedWindows) {
|
||||
+ this.updateSidebarVisibilityForWindow(window);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ updateSidebarVisibilityForWindow(window) {
|
||||
+ if (window.closed) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ let document = window.document;
|
||||
+ if (document.visibilityState === "hidden") {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!this.isActive) {
|
||||
+ document.querySelectorAll("shopping-sidebar").forEach(sidebar => {
|
||||
+ sidebar.hidden = true;
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ this._maybeToggleButton(window.gBrowser);
|
||||
+
|
||||
+ if (!this.enabled) {
|
||||
+ document.querySelectorAll("shopping-sidebar").forEach(sidebar => {
|
||||
+ sidebar.remove();
|
||||
+ });
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ let { selectedBrowser, currentURI } = window.gBrowser;
|
||||
+ this._maybeToggleSidebar(selectedBrowser, currentURI, 0);
|
||||
+ }
|
||||
+
|
||||
+ _maybeToggleSidebar(aBrowser, aLocationURI, aFlags) {
|
||||
+ let gBrowser = aBrowser.getTabBrowser();
|
||||
+ let document = aBrowser.ownerDocument;
|
||||
+ if (!this.enabled) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ let browserPanel = gBrowser.getPanel(aBrowser);
|
||||
+ let sidebar = browserPanel.querySelector("shopping-sidebar");
|
||||
+ let actor;
|
||||
+ if (sidebar) {
|
||||
+ let { browsingContext } = sidebar.querySelector("browser");
|
||||
+ let global = browsingContext.currentWindowGlobal;
|
||||
+ actor = global.getExistingActor("ShoppingSidebar");
|
||||
+ }
|
||||
+ let isProduct = lazy.isProductURL(aLocationURI);
|
||||
+ if (isProduct && this.isActive) {
|
||||
+ if (!sidebar) {
|
||||
+ sidebar = document.createXULElement("shopping-sidebar");
|
||||
+ sidebar.setAttribute("style", "width: 320px");
|
||||
+ sidebar.hidden = false;
|
||||
+ browserPanel.appendChild(sidebar);
|
||||
+ } else {
|
||||
+ actor?.updateProductURL(aLocationURI, aFlags);
|
||||
+ sidebar.hidden = false;
|
||||
+ }
|
||||
+ } else if (sidebar && !sidebar.hidden) {
|
||||
+ actor?.updateProductURL(null);
|
||||
+ sidebar.hidden = true;
|
||||
+ }
|
||||
+
|
||||
+ this._updateBCActiveness(aBrowser);
|
||||
+ this._setShoppingButtonState(aBrowser);
|
||||
+
|
||||
+ if (
|
||||
+ sidebar &&
|
||||
+ !sidebar.hidden &&
|
||||
+ lazy.ShoppingUtils.isProductPageNavigation(aLocationURI, aFlags)
|
||||
+ ) {
|
||||
+ Glean.shopping.surfaceDisplayed.record();
|
||||
+ }
|
||||
+
|
||||
+ if (isProduct) {
|
||||
+ // This is the auto-enable behavior that toggles the `active` pref. It
|
||||
+ // must be at the end of this function, or 2 sidebars could be created.
|
||||
+ lazy.ShoppingUtils.handleAutoActivateOnProduct();
|
||||
+
|
||||
+ if (!this.isActive) {
|
||||
+ lazy.ShoppingUtils.sendTrigger({
|
||||
+ browser: aBrowser,
|
||||
+ id: "shoppingProductPageWithSidebarClosed",
|
||||
+ context: { isSidebarClosing: !!sidebar },
|
||||
+ });
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ _maybeToggleButton(gBrowser) {
|
||||
+ let optedOut = this.optedInPref === 2;
|
||||
+ if (this.enabled && optedOut) {
|
||||
+ this._setShoppingButtonState(gBrowser.selectedBrowser);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ _updateBCActiveness(aBrowser) {
|
||||
+ let gBrowser = aBrowser.getTabBrowser();
|
||||
+ let document = aBrowser.ownerDocument;
|
||||
+ let browserPanel = gBrowser.getPanel(aBrowser);
|
||||
+ let sidebar = browserPanel.querySelector("shopping-sidebar");
|
||||
+ if (!sidebar) {
|
||||
+ return;
|
||||
+ }
|
||||
+ let { browsingContext } = sidebar.querySelector("browser");
|
||||
+ try {
|
||||
+ // Tell Gecko when the sidebar visibility changes to avoid background
|
||||
+ // sidebars taking more CPU / energy than needed.
|
||||
+ browsingContext.isActive =
|
||||
+ !document.hidden &&
|
||||
+ aBrowser == gBrowser.selectedBrowser &&
|
||||
+ !sidebar.hidden;
|
||||
+ } catch (ex) {
|
||||
+ // The setter can throw and we do need to run the rest of this
|
||||
+ // code in that case.
|
||||
+ console.error(ex);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ _setShoppingButtonState(aBrowser) {
|
||||
+ let gBrowser = aBrowser.getTabBrowser();
|
||||
+ let document = aBrowser.ownerDocument;
|
||||
+ if (aBrowser !== gBrowser.selectedBrowser) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ let button = document.getElementById("shopping-sidebar-button");
|
||||
+
|
||||
+ let isCurrentBrowserProduct = lazy.isProductURL(
|
||||
+ gBrowser.selectedBrowser.currentURI
|
||||
+ );
|
||||
+
|
||||
+ // Only record if the state of the icon will change from hidden to visible.
|
||||
+ if (button.hidden && isCurrentBrowserProduct) {
|
||||
+ Glean.shopping.addressBarIconDisplayed.record();
|
||||
+ }
|
||||
+
|
||||
+ button.hidden = !isCurrentBrowserProduct;
|
||||
+ button.setAttribute("shoppingsidebaropen", !!this.isActive);
|
||||
+ let l10nId = this.isActive
|
||||
+ ? "shopping-sidebar-close-button2"
|
||||
+ : "shopping-sidebar-open-button2";
|
||||
+ document.l10n.setAttributes(button, l10nId);
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Called by TabsProgressListener whenever any browser navigates from one
|
||||
+ * URL to another.
|
||||
+ * Note that this includes hash changes / pushState navigations, because
|
||||
+ * those can be significant for us.
|
||||
+ */
|
||||
+ onLocationChange(aBrowser, aLocationURI, aFlags) {
|
||||
+ let isPBM = lazy.PrivateBrowsingUtils.isWindowPrivate(aBrowser.ownerGlobal);
|
||||
+ if (isPBM) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ lazy.ShoppingUtils.maybeRecordExposure(aLocationURI, aFlags);
|
||||
+
|
||||
+ this._maybeToggleButton(aBrowser.getTabBrowser());
|
||||
+ this._maybeToggleSidebar(aBrowser, aLocationURI, aFlags);
|
||||
+ }
|
||||
+
|
||||
+ handleEvent(event) {
|
||||
+ switch (event.type) {
|
||||
+ case "TabSelect": {
|
||||
+ if (!this.enabled) {
|
||||
+ return;
|
||||
+ }
|
||||
+ this.updateSidebarVisibility();
|
||||
+ if (event.detail?.previousTab.linkedBrowser) {
|
||||
+ this._updateBCActiveness(event.detail.previousTab.linkedBrowser);
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ case "visibilitychange": {
|
||||
+ if (!this.enabled) {
|
||||
+ return;
|
||||
+ }
|
||||
+ this.updateSidebarVisibilityForWindow(event.target.ownerGlobal.top);
|
||||
+ this._updateBCActiveness(
|
||||
+ event.target.ownerGlobal.top.gBrowser.selectedBrowser
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return NS_OK;
|
||||
+}
|
||||
+
|
||||
// Determine movement direction relative to frame
|
||||
static bool IsMovingInFrameDirection(const nsIFrame* frame,
|
||||
nsDirection aDirection, bool aVisual) {
|
||||
@@ -9202,7 +9256,7 @@ nsresult nsIFrame::PeekOffsetForLine(PeekOffsetStruct* aPos) {
|
||||
return result;
|
||||
}
|
||||
+const ShoppingSidebarManager = new ShoppingSidebarManagerClass();
|
||||
+export { ShoppingSidebarManager };
|
||||
diff --git a/browser/components/shopping/tests/browser/browser_private_mode.js b/browser/components/shopping/tests/browser/browser_private_mode.js
|
||||
index cf161e43c66ae..3002e602a6fe6 100644
|
||||
--- a/browser/components/shopping/tests/browser/browser_private_mode.js
|
||||
+++ b/browser/components/shopping/tests/browser/browser_private_mode.js
|
||||
@@ -6,30 +6,10 @@
|
||||
// This test verifies that the shopping sidebar is not initialized if the
|
||||
// user visits a shopping product page while in private browsing mode.
|
||||
|
||||
-nsresult nsIFrame::PeekOffsetForLineEdge(PeekOffsetStruct* aPos) {
|
||||
+nsresult nsIFrame::PeekOffsetForLineEdgeVisual(PeekOffsetStruct* aPos) {
|
||||
// Adjusted so that the caret can't get confused when content changes
|
||||
nsIFrame* frame = AdjustFrameForSelectionStyles(this);
|
||||
Element* editingHost = frame->GetContent()->GetEditingHost();
|
||||
@@ -9316,7 +9370,12 @@ nsresult nsIFrame::PeekOffset(PeekOffsetStruct* aPos) {
|
||||
return PeekOffsetForLine(aPos);
|
||||
case eSelectBeginLine:
|
||||
case eSelectEndLine:
|
||||
- return PeekOffsetForLineEdge(aPos);
|
||||
+ if (StaticPrefs::dom_input_logical_textarea_caret_movement_style()) {
|
||||
+ return PeekOffsetForLineEdgeLogical(aPos);
|
||||
+ }
|
||||
+ else {
|
||||
+ return PeekOffsetForLineEdgeVisual(aPos);
|
||||
+ }
|
||||
case eSelectParagraph:
|
||||
return PeekOffsetForParagraph(aPos);
|
||||
default: {
|
||||
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
|
||||
index 80c3504e1af36..af55881b95f95 100644
|
||||
--- a/layout/generic/nsIFrame.h
|
||||
+++ b/layout/generic/nsIFrame.h
|
||||
@@ -3867,7 +3867,8 @@ class nsIFrame : public nsQueryFrame {
|
||||
int32_t aOffset);
|
||||
nsresult PeekOffsetForWord(mozilla::PeekOffsetStruct* aPos, int32_t aOffset);
|
||||
nsresult PeekOffsetForLine(mozilla::PeekOffsetStruct* aPos);
|
||||
- nsresult PeekOffsetForLineEdge(mozilla::PeekOffsetStruct* aPos);
|
||||
+ nsresult PeekOffsetForLineEdgeLogical(mozilla::PeekOffsetStruct* aPos);
|
||||
+ nsresult PeekOffsetForLineEdgeVisual(mozilla::PeekOffsetStruct* aPos);
|
||||
-add_task(async function test_regular_window_enabled() {
|
||||
- let nonPrivateWindow = await BrowserTestUtils.openNewBrowserWindow();
|
||||
- ok(
|
||||
- nonPrivateWindow.ShoppingSidebarManager._enabled,
|
||||
- "Shopping sidebar should be enabled in a regular window"
|
||||
- );
|
||||
- await BrowserTestUtils.closeWindow(nonPrivateWindow);
|
||||
-});
|
||||
-
|
||||
add_task(async function test_private_window_disabled() {
|
||||
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({
|
||||
private: true,
|
||||
});
|
||||
- ok(
|
||||
- !privateWindow.ShoppingSidebarManager._enabled,
|
||||
- "Shopping sidebar should not be enabled in a private window"
|
||||
- );
|
||||
- await BrowserTestUtils.closeWindow(privateWindow);
|
||||
-});
|
||||
-
|
||||
-add_task(async function test_private_window_urlbar_button_hidden() {
|
||||
- let privateWindow = await BrowserTestUtils.openNewBrowserWindow({
|
||||
- private: true,
|
||||
- });
|
||||
|
||||
/**
|
||||
* Search for the first paragraph boundary before or after the given position
|
||||
diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml
|
||||
index 7ec9237d9f26d..715059de80314 100644
|
||||
--- a/modules/libpref/init/StaticPrefList.yaml
|
||||
+++ b/modules/libpref/init/StaticPrefList.yaml
|
||||
@@ -2773,6 +2773,12 @@
|
||||
value: true
|
||||
mirror: always
|
||||
let browser = privateWindow.gBrowser.selectedBrowser;
|
||||
BrowserTestUtils.startLoadingURIString(
|
||||
@@ -46,5 +26,10 @@ add_task(async function test_private_window_urlbar_button_hidden() {
|
||||
"Shopping Button should not be visible on a product page"
|
||||
);
|
||||
|
||||
+# Textarea caret movement style. Disable this to restore previous behavior (visual movement).
|
||||
+- name: dom.input.logical_textarea_caret_movement_style
|
||||
+ type: bool
|
||||
+ value: true
|
||||
+ mirror: always
|
||||
+ ok(
|
||||
+ !privateWindow.document.querySelector("shopping-sidebar"),
|
||||
+ "Shopping sidebar does not exist"
|
||||
+ );
|
||||
+
|
||||
# How often to check for CPOW timeouts (ms). CPOWs are only timed
|
||||
# out by the hang monitor.
|
||||
- name: dom.ipc.cpow.timeout
|
||||
await BrowserTestUtils.closeWindow(privateWindow);
|
||||
});
|
||||
diff --git a/browser/components/shopping/tests/browser/browser_shopping_message_triggers.js b/browser/components/shopping/tests/browser/browser_shopping_message_triggers.js
|
||||
index 61a5b2a661edd..aec555dd5246f 100644
|
||||
--- a/browser/components/shopping/tests/browser/browser_shopping_message_triggers.js
|
||||
+++ b/browser/components/shopping/tests/browser/browser_shopping_message_triggers.js
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
+ChromeUtils.defineESModuleGetters(this, {
|
||||
+ ShoppingUtils: "resource:///modules/ShoppingUtils.sys.mjs",
|
||||
+});
|
||||
+
|
||||
const { ASRouter } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/ASRouter.jsm"
|
||||
);
|
||||
|
|
119
patches/0012-textarea-behavior.patch.old
Normal file
119
patches/0012-textarea-behavior.patch.old
Normal file
|
@ -0,0 +1,119 @@
|
|||
diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp
|
||||
index 3a336b25278ae..448a96fb0ae9b 100644
|
||||
--- a/layout/generic/nsIFrame.cpp
|
||||
+++ b/layout/generic/nsIFrame.cpp
|
||||
@@ -8879,6 +8879,60 @@ nsresult nsIFrame::PeekOffsetForParagraph(PeekOffsetStruct* aPos) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
+nsresult nsIFrame::PeekOffsetForLineEdgeLogical(PeekOffsetStruct* aPos) {
|
||||
+ nsIFrame* frame = this;
|
||||
+ nsContentAndOffset blockFrameOrBR;
|
||||
+ blockFrameOrBR.mContent = nullptr;
|
||||
+ bool reachedLimit = frame->IsBlockOutside() || IsEditingHost(frame);
|
||||
+
|
||||
+ auto traverse = [&aPos](nsIFrame* current) {
|
||||
+ return aPos->mDirection == eDirPrevious ? current->GetPrevSibling()
|
||||
+ : current->GetNextSibling();
|
||||
+ };
|
||||
+
|
||||
+ // Go through containing frames until reaching a block frame.
|
||||
+ // In each step, search the previous (or next) siblings for the closest
|
||||
+ // "stop frame" (a block frame or a BRFrame).
|
||||
+ // If found, set it to be the selection boundary and abort.
|
||||
+ while (!reachedLimit) {
|
||||
+ nsIFrame* parent = frame->GetParent();
|
||||
+ // Treat a frame associated with the root content as if it were a block
|
||||
+ // frame.
|
||||
+ if (!frame->mContent || !frame->mContent->GetParent()) {
|
||||
+ reachedLimit = true;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (aPos->mDirection == eDirNext) {
|
||||
+ // Try to find our own line-break before looking at our siblings.
|
||||
+ blockFrameOrBR = FindLineBreakInText(frame, eDirNext);
|
||||
+ }
|
||||
+
|
||||
+ nsIFrame* sibling = traverse(frame);
|
||||
+ while (sibling && !blockFrameOrBR.mContent) {
|
||||
+ blockFrameOrBR = FindLineBreakingFrame(sibling, aPos->mDirection);
|
||||
+ sibling = traverse(sibling);
|
||||
+ }
|
||||
+ if (blockFrameOrBR.mContent) {
|
||||
+ aPos->mResultContent = blockFrameOrBR.mContent;
|
||||
+ aPos->mContentOffset = blockFrameOrBR.mOffset;
|
||||
+ break;
|
||||
+ }
|
||||
+ frame = parent;
|
||||
+ reachedLimit = frame && (frame->IsBlockOutside() || IsEditingHost(frame));
|
||||
+ }
|
||||
+
|
||||
+ if (reachedLimit) { // no "stop frame" found
|
||||
+ aPos->mResultContent = frame->GetContent();
|
||||
+ if (aPos->mDirection == eDirPrevious) {
|
||||
+ aPos->mContentOffset = 0;
|
||||
+ } else if (aPos->mResultContent) {
|
||||
+ aPos->mContentOffset = aPos->mResultContent->GetChildCount();
|
||||
+ }
|
||||
+ }
|
||||
+ return NS_OK;
|
||||
+}
|
||||
+
|
||||
// Determine movement direction relative to frame
|
||||
static bool IsMovingInFrameDirection(const nsIFrame* frame,
|
||||
nsDirection aDirection, bool aVisual) {
|
||||
@@ -9202,7 +9256,7 @@ nsresult nsIFrame::PeekOffsetForLine(PeekOffsetStruct* aPos) {
|
||||
return result;
|
||||
}
|
||||
|
||||
-nsresult nsIFrame::PeekOffsetForLineEdge(PeekOffsetStruct* aPos) {
|
||||
+nsresult nsIFrame::PeekOffsetForLineEdgeVisual(PeekOffsetStruct* aPos) {
|
||||
// Adjusted so that the caret can't get confused when content changes
|
||||
nsIFrame* frame = AdjustFrameForSelectionStyles(this);
|
||||
Element* editingHost = frame->GetContent()->GetEditingHost();
|
||||
@@ -9316,7 +9370,12 @@ nsresult nsIFrame::PeekOffset(PeekOffsetStruct* aPos) {
|
||||
return PeekOffsetForLine(aPos);
|
||||
case eSelectBeginLine:
|
||||
case eSelectEndLine:
|
||||
- return PeekOffsetForLineEdge(aPos);
|
||||
+ if (StaticPrefs::dom_input_logical_textarea_caret_movement_style()) {
|
||||
+ return PeekOffsetForLineEdgeLogical(aPos);
|
||||
+ }
|
||||
+ else {
|
||||
+ return PeekOffsetForLineEdgeVisual(aPos);
|
||||
+ }
|
||||
case eSelectParagraph:
|
||||
return PeekOffsetForParagraph(aPos);
|
||||
default: {
|
||||
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
|
||||
index 80c3504e1af36..af55881b95f95 100644
|
||||
--- a/layout/generic/nsIFrame.h
|
||||
+++ b/layout/generic/nsIFrame.h
|
||||
@@ -3867,7 +3867,8 @@ class nsIFrame : public nsQueryFrame {
|
||||
int32_t aOffset);
|
||||
nsresult PeekOffsetForWord(mozilla::PeekOffsetStruct* aPos, int32_t aOffset);
|
||||
nsresult PeekOffsetForLine(mozilla::PeekOffsetStruct* aPos);
|
||||
- nsresult PeekOffsetForLineEdge(mozilla::PeekOffsetStruct* aPos);
|
||||
+ nsresult PeekOffsetForLineEdgeLogical(mozilla::PeekOffsetStruct* aPos);
|
||||
+ nsresult PeekOffsetForLineEdgeVisual(mozilla::PeekOffsetStruct* aPos);
|
||||
|
||||
/**
|
||||
* Search for the first paragraph boundary before or after the given position
|
||||
diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml
|
||||
index 7ec9237d9f26d..715059de80314 100644
|
||||
--- a/modules/libpref/init/StaticPrefList.yaml
|
||||
+++ b/modules/libpref/init/StaticPrefList.yaml
|
||||
@@ -2773,6 +2773,12 @@
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
+# Textarea caret movement style. Disable this to restore previous behavior (visual movement).
|
||||
+- name: dom.input.logical_textarea_caret_movement_style
|
||||
+ type: bool
|
||||
+ value: true
|
||||
+ mirror: always
|
||||
+
|
||||
# How often to check for CPOW timeouts (ms). CPOWs are only timed
|
||||
# out by the hang monitor.
|
||||
- name: dom.ipc.cpow.timeout
|
Loading…
Reference in a new issue