Commit dea58102 authored by Oriol Brufau's avatar Oriol Brufau
Browse files

Bug 1474440 - Implement support for the 'onHighlighted' API for multiselect tabs r=mixedpuppy

MozReview-Commit-ID: 8aOmdj0AB3e

--HG--
extra : rebase_source : 5eec0163341b6621103ac4a5e43f8439a19a9c5a
parent f76978b8
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -285,6 +285,7 @@ class TabTracker extends TabTrackerBase {
    windowTracker.addListener("TabClose", this);
    windowTracker.addListener("TabOpen", this);
    windowTracker.addListener("TabSelect", this);
    windowTracker.addListener("TabMultiSelect", this);
    windowTracker.addOpenListener(this._handleWindowOpen);
    windowTracker.addCloseListener(this._handleWindowClose);

@@ -456,6 +457,16 @@ class TabTracker extends TabTrackerBase {
          this.emitActivated(nativeTab);
        });
        break;

      case "TabMultiSelect":
        if (this.has("tabs-highlighted")) {
          // Because we are delaying calling emitCreated above, we also need to
          // delay sending this event because it shouldn't fire before onCreated.
          Promise.resolve().then(() => {
            this.emitHighlighted(event.target.ownerGlobal);
          });
        }
        break;
    }
  }

@@ -514,6 +525,9 @@ class TabTracker extends TabTrackerBase {

      // emitActivated to trigger tab.onActivated/tab.onHighlighted for a newly opened window.
      this.emitActivated(window.gBrowser.tabs[0]);
      if (this.has("tabs-highlighted")) {
        this.emitHighlighted(window);
      }
    }
  }

@@ -548,6 +562,19 @@ class TabTracker extends TabTrackerBase {
      windowId: windowTracker.getId(nativeTab.ownerGlobal)});
  }

  /**
   * Emits a "tabs-highlighted" event for the given tab element.
   *
   * @param {ChromeWindow} window
   *        The window in which the active tab or the set of multiselected tabs changed.
   * @private
   */
  emitHighlighted(window) {
    let tabIds = window.gBrowser.selectedTabs.map(tab => this.getId(tab));
    let windowId = windowTracker.getId(window);
    this.emit("tabs-highlighted", {tabIds, windowId});
  }

  /**
   * Emits a "tab-attached" event for the given tab element.
   *
+3 −9
Original line number Diff line number Diff line
@@ -411,23 +411,17 @@ this.tabs = class extends ExtensionAPI {
          },
        }).api(),

        /**
         * Since multiple tabs currently can't be highlighted, onHighlighted
         * essentially acts an alias for self.tabs.onActivated but returns
         * the tabId in an array to match the API.
         * @see  https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onHighlighted
        */
        onHighlighted: new EventManager({
          context,
          name: "tabs.onHighlighted",
          register: fire => {
            let listener = (eventName, event) => {
              fire.async({tabIds: [event.tabId], windowId: event.windowId});
              fire.async(event);
            };

            tabTracker.on("tab-activated", listener);
            tabTracker.on("tabs-highlighted", listener);
            return () => {
              tabTracker.off("tab-activated", listener);
              tabTracker.off("tabs-highlighted", listener);
            };
          },
        }).api(),
+1 −0
Original line number Diff line number Diff line
@@ -198,6 +198,7 @@ skip-if = (verify && !debug && (os == 'mac'))
[browser_ext_tabs_move_window.js]
[browser_ext_tabs_move_window_multiple.js]
[browser_ext_tabs_move_window_pinned.js]
[browser_ext_tabs_onHighlighted.js]
[browser_ext_tabs_onUpdated.js]
[browser_ext_tabs_onUpdated_filter.js]
[browser_ext_tabs_opener.js]
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ add_task(async function test_highlighted() {
        let highlightedTabs = await browser.tabs.query({currentWindow: true, highlighted: true});
        browser.test.assertEq(
          highlightedIndices.concat(activeIndex).sort((a, b) => a - b).join(),
          highlightedTabs.map(tab => tab.index).sort((a, b) => a - b).join(),
          highlightedTabs.map(tab => tab.index).join(),
          "Check tabs.query with highlighted:true provides the expected tabs");
      }

+122 −0
Original line number Diff line number Diff line
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
/* eslint-disable mozilla/no-arbitrary-setTimeout */
"use strict";

add_task(async function test_onHighlighted() {
  await SpecialPowers.pushPrefEnv({
    set: [
      ["browser.tabs.multiselect", true],
    ],
  });

  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      "permissions": ["tabs"],
    },

    background: async function() {
      async function expectHighlighted(fn, action) {
        let resolve;
        let promise = new Promise((r) => {
          resolve = r;
        });
        let expected;
        let events = [];
        let listener = (highlightInfo) => {
          events.push(highlightInfo);
          if (expected && expected.length >= events.length) {
            resolve();
          }
        };
        browser.tabs.onHighlighted.addListener(listener);
        expected = await fn() || [];
        if (events.length < expected.length) {
          await promise;
        }
        let unexpected = events.splice(expected.length);
        browser.test.assertEq(
          JSON.stringify(expected), JSON.stringify(events),
          `Should get ${expected.length} expected onHighlighted events when ${action}`);
        if (unexpected.length) {
          browser.test.fail(
            `${unexpected.length} unexpected onHighlighted events when ${action}: ` +
            JSON.stringify(unexpected));
        }
        browser.tabs.onHighlighted.removeListener(listener);
      }

      let [{id, windowId}] = await browser.tabs.query({active: true, currentWindow: true});
      let windows = [windowId];
      let tabs = [id];

      await expectHighlighted(async () => {
        let tab = await browser.tabs.create({active: true, url: "about:blank?1"});
        tabs.push(tab.id);
        return [{tabIds: [tabs[1]], windowId: windows[0]}];
      }, "creating a new active tab");

      await expectHighlighted(async () => {
        await browser.tabs.update(tabs[0], {active: true});
        return [{tabIds: [tabs[0]], windowId: windows[0]}];
      }, "selecting former tab");

      await expectHighlighted(async () => {
        await browser.tabs.highlight({tabs: [0, 1]});
        return [{tabIds: [tabs[0], tabs[1]], windowId: windows[0]}];
      }, "highlighting both tabs");

      await expectHighlighted(async () => {
        await browser.tabs.highlight({tabs: [1, 0]});
        return [{tabIds: [tabs[0], tabs[1]], windowId: windows[0]}];
      }, "highlighting same tabs but changing selected one");

      await expectHighlighted(async () => {
        let tab = await browser.tabs.create({active: false, url: "about:blank?2"});
        tabs.push(tab.id);
      }, "create a new inactive tab");

      await expectHighlighted(async () => {
        await browser.tabs.highlight({tabs: [2, 0, 1]});
        return [{tabIds: [tabs[0], tabs[1], tabs[2]], windowId: windows[0]}];
      }, "highlighting all tabs");

      await expectHighlighted(async () => {
        await browser.tabs.move(tabs[1], {index: 0});
      }, "reordering tabs");

      await expectHighlighted(async () => {
        await browser.tabs.highlight({tabs: [0]});
        return [{tabIds: [tabs[1]], windowId: windows[0]}];
      }, "highlighting moved tab");

      await expectHighlighted(async () => {
        await browser.tabs.highlight({tabs: [0]});
      }, "highlighting again");

      await expectHighlighted(async () => {
        await browser.tabs.highlight({tabs: [2, 1, 0]});
        return [{tabIds: [tabs[1], tabs[0], tabs[2]], windowId: windows[0]}];
      }, "highlighting all tabs");

      await expectHighlighted(async () => {
        await browser.tabs.highlight({tabs: [2, 0, 1]});
      }, "highlighting same tabs with different order");

      await expectHighlighted(async () => {
        let window = await browser.windows.create({tabId: tabs[2]});
        windows.push(window.id);
        // Bug 1481185: on Chrome it's [tabs[1], tabs[0]] instead of [tabs[0]]
        return [{tabIds: [tabs[0]], windowId: windows[0]},
                {tabIds: [tabs[2]], windowId: windows[1]}];
      }, "moving selected tab into a new window");

      await browser.tabs.remove(tabs.slice(1));
      browser.test.notifyPass("test-finished");
    },
  });

  await extension.startup();
  await extension.awaitFinish("test-finished");
  await extension.unload();
});
Loading