/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";

const PAGE =
  "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html";

add_task(async function accesskeys() {
  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
  gBrowser.selectedTab = tab;

  async function background() {
    // description is informative.
    // title is passed to menus.create.
    // label and key are compared with the actual values.
    const TESTCASES = [
      {
        description: "Amp at start",
        title: "&accesskey",
        label: "accesskey",
        key: "a",
      },
      {
        description: "amp in between",
        title: "A& b",
        label: "A b",
        key: " ",
      },
      {
        description: "lonely amp",
        title: "&",
        label: "",
        key: "",
      },
      {
        description: "amp at end",
        title: "End &",
        label: "End ",
        key: "",
      },
      {
        description: "escaped amp",
        title: "A && B",
        label: "A & B",
        key: "",
      },
      {
        description: "amp before escaped amp",
        title: "A &T&& before",
        label: "A T& before",
        key: "T",
      },
      {
        description: "amp after escaped amp",
        title: "A &&&T after",
        label: "A &T after",
        key: "T",
      },
      {
        // Only the first amp should be used as the access key.
        description: "amp, escaped amp, amp to ignore",
        title: "First &1 comes && first &2 serves",
        label: "First 1 comes & first 2 serves",
        key: "1",
      },
      {
        description: "created with amp, updated without amp",
        title: "temp with &X", // will be updated below.
        label: "remove amp",
        key: "",
      },
      {
        description: "created without amp, update with amp",
        title: "temp without access key", // will be updated below.
        label: "add ampY",
        key: "Y",
      },
    ];

    let menuIds = TESTCASES.map(({ title }) => browser.menus.create({ title }));

    // Should clear the access key:
    await browser.menus.update(menuIds[menuIds.length - 2], {
      title: "remove amp",
    });

    // Should add an access key:
    await browser.menus.update(menuIds[menuIds.length - 1], {
      title: "add amp&Y",
    });
    // Should not clear the access key because title is not set:
    await browser.menus.update(menuIds[menuIds.length - 1], { enabled: true });

    browser.test.sendMessage("testCases", TESTCASES);
  }
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      permissions: ["menus"],
    },
    background,
  });

  await extension.startup();

  const TESTCASES = await extension.awaitMessage("testCases");
  let menu = await openExtensionContextMenu();
  let items = menu.getElementsByTagName("menuitem");
  is(items.length, TESTCASES.length, "Expected menu items for page");
  TESTCASES.forEach(({ description, label, key }, i) => {
    is(items[i].label, label, `Label for item ${i} (${description})`);
    is(items[i].accessKey, key, `Accesskey for item ${i} (${description})`);
  });

  await closeExtensionContextMenu();
  await extension.unload();
  BrowserTestUtils.removeTab(tab);
});

add_task(async function accesskeys_selection() {
  const PAGE_WITH_AMPS = "data:text/plain;charset=utf-8,PageSelection&Amp";
  let tab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    PAGE_WITH_AMPS
  );
  gBrowser.selectedTab = tab;

  async function background() {
    const TESTCASES = [
      {
        description: "Selection without amp",
        title: "percent-s: %s.",
        label: "percent-s: PageSelection&Amp.",
        key: "",
      },
      {
        description: "Selection with amp after %s",
        title: "percent-s: %s &A.",
        label: "percent-s: PageSelection&Amp A.",
        key: "A",
      },
      {
        description: "Selection with amp before %s",
        title: "percent-s: &B %s.",
        label: "percent-s: B PageSelection&Amp.",
        key: "B",
      },
      {
        description: "Amp-percent",
        title: "Amp-percent: &%.",
        label: "Amp-percent: %.",
        key: "%",
      },
      {
        // "&%s" should be treated as "%s", and "ignore this" with amps should be ignored.
        description: "Selection with amp-percent-s",
        title: "Amp-percent-s: &%s.&i&g&n&o&r&e& &t&h&i&s",
        label: "Amp-percent-s: PageSelection&Amp.ignore this",
        // Chrome uses the first character of the selection as access key.
        // Let's not copy that behavior...
        key: "",
      },
      {
        description: "Selection with amp before amp-percent-s",
        title: "Amp-percent-s: &_ &%s.",
        label: "Amp-percent-s: _ PageSelection&Amp.",
        key: "_",
      },
    ];

    let lastMenuId;
    for (let { title } of TESTCASES) {
      lastMenuId = browser.menus.create({ contexts: ["selection"], title });
    }
    // Round-trip to ensure that the menus have been registered.
    await browser.menus.update(lastMenuId, {});
    browser.test.sendMessage("testCases", TESTCASES);
  }
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      permissions: ["menus"],
    },
    background,
  });

  await extension.startup();

  // Select all
  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function (arg) {
    let doc = content.document;
    let range = doc.createRange();
    let selection = content.getSelection();
    selection.removeAllRanges();
    range.selectNodeContents(doc.body);
    selection.addRange(range);
  });

  const TESTCASES = await extension.awaitMessage("testCases");
  let menu = await openExtensionContextMenu();
  let items = menu.getElementsByTagName("menuitem");
  is(items.length, TESTCASES.length, "Expected menu items for page");
  TESTCASES.forEach(({ description, label, key }, i) => {
    is(items[i].label, label, `Label for item ${i} (${description})`);
    is(items[i].accessKey, key, `Accesskey for item ${i} (${description})`);
  });

  await closeExtensionContextMenu();
  await extension.unload();
  BrowserTestUtils.removeTab(tab);
});
