Loading Cargo.lock +170 −164 File changed.Preview size limit exceeded, changes collapsed. Show changes Cargo.toml +3 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,9 @@ vcpkg = { path = "build/rust/vcpkg" } # Helper crate for integration in the gecko build system. mozbuild = { path = "build/rust/mozbuild" } # Patch itoa 0.4 to 1.0. itoa = { path = "build/rust/itoa" } # Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30 autocfg = { path = "third_party/rust/autocfg" } Loading browser/components/firefoxview/tabs-pickup.js +18 −9 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ const { switchToTabHavingURI } = window.docShell.chromeEventHandler.ownerGlobal; const { XPCOMUtils } = ChromeUtils.import( "resource://gre/modules/XPCOMUtils.jsm" ); const SYNC_TABS_PREF = "services.sync.engine.tabs"; const tabsSetupFlowManager = new (class { constructor() { Loading @@ -28,6 +29,17 @@ const tabsSetupFlowManager = new (class { "resource://services-sync/UIState.jsm" ); // this.syncTabsPrefEnabled will track the value of the tabs pref XPCOMUtils.defineLazyPreferenceGetter( this, "syncTabsPrefEnabled", SYNC_TABS_PREF, false, () => { this.maybeUpdateUI(); } ); this.registerSetupState({ uiStateIndex: 0, name: "not-signed-in", Loading @@ -47,9 +59,7 @@ const tabsSetupFlowManager = new (class { uiStateIndex: 2, name: "disabled-tab-sync", exitConditions: () => { // Bug 1763139 - Implement the actual logic to advance to next step // This will basically be a check for the pref to enable tab-syncing return false; return this.syncTabsPrefEnabled; }, }); this.registerSetupState({ Loading @@ -62,7 +72,7 @@ const tabsSetupFlowManager = new (class { }); this.registerSetupState({ uiStateIndex: 4, name: "show-synced-tabs-agreement", name: "show-synced-tabs-loading", exitConditions: () => { // Bug 1763139 - Implement the actual logic to advance to next step return false; Loading Loading @@ -165,15 +175,14 @@ const tabsSetupFlowManager = new (class { switchToTabHavingURI(url, true); } syncOpenTabs(containerElem) { // Bug 1763139 - Implement the actual logic to advance to next step this.elem.updateSetupState( this.setupState.get("synced-tabs-not-ready").uiStateIndex ); // Flip the pref on. // The observer should trigger re-evaluating state and advance to next step this.Services.prefs.setBoolPref(SYNC_TABS_PREF, true); } confirmSetupComplete(containerElem) { // Bug 1763139 - Implement the actual logic to advance to next step this.elem.updateSetupState( this.setupState.get("show-synced-tabs-agreement").uiStateIndex this.setupState.get("show-synced-tabs-loading").uiStateIndex ); } })(); Loading browser/components/firefoxview/tests/browser/browser_setup_state.js +99 −37 Original line number Diff line number Diff line Loading @@ -30,19 +30,34 @@ function setupMocks({ fxaDevices = null, state = UIState.STATUS_SIGNED_IN }) { return sandbox; } function testSetupState(browser, expected) { async function waitForVisibleStep(browser, expected) { const { document } = browser.contentWindow; for (let [selector, shouldBeVisible] of Object.entries( expected.expectedVisible )) { const elem = document.querySelector(selector); if (shouldBeVisible) { const deck = document.querySelector(".sync-setup-container"); const nextStepElem = deck.querySelector(expected.expectedVisible); const stepElems = deck.querySelectorAll(".setup-step"); await BrowserTestUtils.waitForMutationCondition( deck, { attributeFilter: ["selected-view"], }, () => { return BrowserTestUtils.is_visible(nextStepElem); } ); for (let elem of stepElems) { if (elem == nextStepElem) { ok( BrowserTestUtils.is_visible(elem), `Expected ${selector} to be visible` `Expected ${elem.id || elem.className} to be visible` ); } else { ok(BrowserTestUtils.is_hidden(elem), `Expected ${selector} to be hidden`); ok( BrowserTestUtils.is_hidden(elem), `Expected ${elem.id || elem.className} to be hidden` ); } } } Loading @@ -58,6 +73,11 @@ add_setup(async function() { ); registerCleanupFunction(async function() { BrowserTestUtils.removeTab(tab); Services.prefs.clearUserPref("services.sync.engine.tabs"); }); // set tab sync false so we don't skip setup states await SpecialPowers.pushPrefEnv({ set: [["services.sync.engine.tabs", false]], }); }); Loading @@ -66,13 +86,8 @@ add_task(async function test_unconfigured_initial_state() { 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, }, await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view0", }); sandbox.restore(); Loading @@ -91,16 +106,11 @@ add_task(async function test_signed_in() { }, ], }); 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, }, await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view1", }); is(fxAccounts.device.recentDeviceList?.length, 1, "Just 1 device connected"); sandbox.restore(); Loading @@ -126,14 +136,10 @@ add_task(async function test_2nd_desktop_connected() { }); 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, }, await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view1", }); is(fxAccounts.device.recentDeviceList?.length, 2, "2 devices connected"); ok( fxAccounts.device.recentDeviceList?.every( Loading Loading @@ -163,16 +169,17 @@ add_task(async function test_mobile_connected() { }, ], }); // ensure tab sync is false so we don't skip onto next step ok( !Services.prefs.getBoolPref("services.sync.engine.tabs", false), "services.sync.engine.tabs is initially false" ); 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, }, await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view2", }); is(fxAccounts.device.recentDeviceList?.length, 2, "2 devices connected"); ok( fxAccounts.device.recentDeviceList?.some( Loading @@ -183,3 +190,58 @@ add_task(async function test_mobile_connected() { sandbox.restore(); }); add_task(async function test_tab_sync_enabled() { 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); // test initial state, with the pref not enabled await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view2", }); // test with the pref toggled on await SpecialPowers.pushPrefEnv({ set: [["services.sync.engine.tabs", true]], }); await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view3", }); // reset and test clicking the action button await SpecialPowers.popPrefEnv(); await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view2", }); const actionButton = browser.contentWindow.document.querySelector( "#tabpickup-steps-view2 button.primary" ); actionButton.click(); await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view3", }); ok( Services.prefs.getBoolPref("services.sync.engine.tabs", false), "tab sync pref should be enabled after button click" ); sandbox.restore(); Services.prefs.clearUserPref("services.sync.engine.tabs"); }); browser/components/urlbar/UrlbarInput.jsm +28 −11 Original line number Diff line number Diff line Loading @@ -377,22 +377,39 @@ class UrlbarInput { const previousSelectionStart = this.selectionStart; const previousSelectionEnd = this.selectionEnd; let isDifferentValidValue = valid && value != this.untrimmedValue; this.value = value; this.valueIsTyped = !valid; this.removeAttribute("usertyping"); if (isDifferentValidValue) { // If the caret is at the end of the input or its position is beyond the // end of the new value, keep it at the end. Otherwise keep its current // position. const isCaretPositionEnd = previousUntrimmedValue.length === previousSelectionEnd || value.length <= previousSelectionEnd; if (isCaretPositionEnd) { this.selectionStart = this.selectionEnd = value.length; } else { if (!this.focused) { // When setURI is called while the input is not focused, reset the caret. this.selectionStart = this.selectionEnd = 0; } else if (value != previousUntrimmedValue) { if ( previousSelectionStart != previousSelectionEnd && value.substring(previousSelectionStart, previousSelectionEnd) === previousUntrimmedValue.substring( previousSelectionStart, previousSelectionEnd ) ) { // If the same text is in the same place as the previously selected text, // the selection is kept. this.selectionStart = previousSelectionStart; this.selectionEnd = previousSelectionEnd; } else if ( previousSelectionEnd && (previousUntrimmedValue.length === previousSelectionEnd || value.length <= previousSelectionEnd) ) { // If the previous end caret is not 0 and the caret is at the end of the // input or its position is beyond the end of the new value, keep the // position at the end. this.selectionStart = this.selectionEnd = value.length; } else { // Otherwise clear selection and set the caret position to the previous // caret end position. this.selectionStart = this.selectionEnd = previousSelectionEnd; } } Loading Loading
Cargo.toml +3 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,9 @@ vcpkg = { path = "build/rust/vcpkg" } # Helper crate for integration in the gecko build system. mozbuild = { path = "build/rust/mozbuild" } # Patch itoa 0.4 to 1.0. itoa = { path = "build/rust/itoa" } # Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30 autocfg = { path = "third_party/rust/autocfg" } Loading
browser/components/firefoxview/tabs-pickup.js +18 −9 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ const { switchToTabHavingURI } = window.docShell.chromeEventHandler.ownerGlobal; const { XPCOMUtils } = ChromeUtils.import( "resource://gre/modules/XPCOMUtils.jsm" ); const SYNC_TABS_PREF = "services.sync.engine.tabs"; const tabsSetupFlowManager = new (class { constructor() { Loading @@ -28,6 +29,17 @@ const tabsSetupFlowManager = new (class { "resource://services-sync/UIState.jsm" ); // this.syncTabsPrefEnabled will track the value of the tabs pref XPCOMUtils.defineLazyPreferenceGetter( this, "syncTabsPrefEnabled", SYNC_TABS_PREF, false, () => { this.maybeUpdateUI(); } ); this.registerSetupState({ uiStateIndex: 0, name: "not-signed-in", Loading @@ -47,9 +59,7 @@ const tabsSetupFlowManager = new (class { uiStateIndex: 2, name: "disabled-tab-sync", exitConditions: () => { // Bug 1763139 - Implement the actual logic to advance to next step // This will basically be a check for the pref to enable tab-syncing return false; return this.syncTabsPrefEnabled; }, }); this.registerSetupState({ Loading @@ -62,7 +72,7 @@ const tabsSetupFlowManager = new (class { }); this.registerSetupState({ uiStateIndex: 4, name: "show-synced-tabs-agreement", name: "show-synced-tabs-loading", exitConditions: () => { // Bug 1763139 - Implement the actual logic to advance to next step return false; Loading Loading @@ -165,15 +175,14 @@ const tabsSetupFlowManager = new (class { switchToTabHavingURI(url, true); } syncOpenTabs(containerElem) { // Bug 1763139 - Implement the actual logic to advance to next step this.elem.updateSetupState( this.setupState.get("synced-tabs-not-ready").uiStateIndex ); // Flip the pref on. // The observer should trigger re-evaluating state and advance to next step this.Services.prefs.setBoolPref(SYNC_TABS_PREF, true); } confirmSetupComplete(containerElem) { // Bug 1763139 - Implement the actual logic to advance to next step this.elem.updateSetupState( this.setupState.get("show-synced-tabs-agreement").uiStateIndex this.setupState.get("show-synced-tabs-loading").uiStateIndex ); } })(); Loading
browser/components/firefoxview/tests/browser/browser_setup_state.js +99 −37 Original line number Diff line number Diff line Loading @@ -30,19 +30,34 @@ function setupMocks({ fxaDevices = null, state = UIState.STATUS_SIGNED_IN }) { return sandbox; } function testSetupState(browser, expected) { async function waitForVisibleStep(browser, expected) { const { document } = browser.contentWindow; for (let [selector, shouldBeVisible] of Object.entries( expected.expectedVisible )) { const elem = document.querySelector(selector); if (shouldBeVisible) { const deck = document.querySelector(".sync-setup-container"); const nextStepElem = deck.querySelector(expected.expectedVisible); const stepElems = deck.querySelectorAll(".setup-step"); await BrowserTestUtils.waitForMutationCondition( deck, { attributeFilter: ["selected-view"], }, () => { return BrowserTestUtils.is_visible(nextStepElem); } ); for (let elem of stepElems) { if (elem == nextStepElem) { ok( BrowserTestUtils.is_visible(elem), `Expected ${selector} to be visible` `Expected ${elem.id || elem.className} to be visible` ); } else { ok(BrowserTestUtils.is_hidden(elem), `Expected ${selector} to be hidden`); ok( BrowserTestUtils.is_hidden(elem), `Expected ${elem.id || elem.className} to be hidden` ); } } } Loading @@ -58,6 +73,11 @@ add_setup(async function() { ); registerCleanupFunction(async function() { BrowserTestUtils.removeTab(tab); Services.prefs.clearUserPref("services.sync.engine.tabs"); }); // set tab sync false so we don't skip setup states await SpecialPowers.pushPrefEnv({ set: [["services.sync.engine.tabs", false]], }); }); Loading @@ -66,13 +86,8 @@ add_task(async function test_unconfigured_initial_state() { 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, }, await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view0", }); sandbox.restore(); Loading @@ -91,16 +106,11 @@ add_task(async function test_signed_in() { }, ], }); 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, }, await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view1", }); is(fxAccounts.device.recentDeviceList?.length, 1, "Just 1 device connected"); sandbox.restore(); Loading @@ -126,14 +136,10 @@ add_task(async function test_2nd_desktop_connected() { }); 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, }, await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view1", }); is(fxAccounts.device.recentDeviceList?.length, 2, "2 devices connected"); ok( fxAccounts.device.recentDeviceList?.every( Loading Loading @@ -163,16 +169,17 @@ add_task(async function test_mobile_connected() { }, ], }); // ensure tab sync is false so we don't skip onto next step ok( !Services.prefs.getBoolPref("services.sync.engine.tabs", false), "services.sync.engine.tabs is initially false" ); 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, }, await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view2", }); is(fxAccounts.device.recentDeviceList?.length, 2, "2 devices connected"); ok( fxAccounts.device.recentDeviceList?.some( Loading @@ -183,3 +190,58 @@ add_task(async function test_mobile_connected() { sandbox.restore(); }); add_task(async function test_tab_sync_enabled() { 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); // test initial state, with the pref not enabled await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view2", }); // test with the pref toggled on await SpecialPowers.pushPrefEnv({ set: [["services.sync.engine.tabs", true]], }); await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view3", }); // reset and test clicking the action button await SpecialPowers.popPrefEnv(); await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view2", }); const actionButton = browser.contentWindow.document.querySelector( "#tabpickup-steps-view2 button.primary" ); actionButton.click(); await waitForVisibleStep(browser, { expectedVisible: "#tabpickup-steps-view3", }); ok( Services.prefs.getBoolPref("services.sync.engine.tabs", false), "tab sync pref should be enabled after button click" ); sandbox.restore(); Services.prefs.clearUserPref("services.sync.engine.tabs"); });
browser/components/urlbar/UrlbarInput.jsm +28 −11 Original line number Diff line number Diff line Loading @@ -377,22 +377,39 @@ class UrlbarInput { const previousSelectionStart = this.selectionStart; const previousSelectionEnd = this.selectionEnd; let isDifferentValidValue = valid && value != this.untrimmedValue; this.value = value; this.valueIsTyped = !valid; this.removeAttribute("usertyping"); if (isDifferentValidValue) { // If the caret is at the end of the input or its position is beyond the // end of the new value, keep it at the end. Otherwise keep its current // position. const isCaretPositionEnd = previousUntrimmedValue.length === previousSelectionEnd || value.length <= previousSelectionEnd; if (isCaretPositionEnd) { this.selectionStart = this.selectionEnd = value.length; } else { if (!this.focused) { // When setURI is called while the input is not focused, reset the caret. this.selectionStart = this.selectionEnd = 0; } else if (value != previousUntrimmedValue) { if ( previousSelectionStart != previousSelectionEnd && value.substring(previousSelectionStart, previousSelectionEnd) === previousUntrimmedValue.substring( previousSelectionStart, previousSelectionEnd ) ) { // If the same text is in the same place as the previously selected text, // the selection is kept. this.selectionStart = previousSelectionStart; this.selectionEnd = previousSelectionEnd; } else if ( previousSelectionEnd && (previousUntrimmedValue.length === previousSelectionEnd || value.length <= previousSelectionEnd) ) { // If the previous end caret is not 0 and the caret is at the end of the // input or its position is beyond the end of the new value, keep the // position at the end. this.selectionStart = this.selectionEnd = value.length; } else { // Otherwise clear selection and set the caret position to the previous // caret end position. this.selectionStart = this.selectionEnd = previousSelectionEnd; } } Loading