tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_inplace-editor_autocomplete_02.js (9670B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 /* import-globals-from helper_inplace_editor.js */
      4 
      5 "use strict";
      6 
      7 const AutocompletePopup = require("resource://devtools/client/shared/autocomplete-popup.js");
      8 const {
      9  InplaceEditor,
     10 } = require("resource://devtools/client/shared/inplace-editor.js");
     11 loadHelperScript("helper_inplace_editor.js");
     12 
     13 // Test the inplace-editor autocomplete popup for CSS values suggestions.
     14 // Using a mocked list of CSS properties to avoid test failures linked to
     15 // engine changes (new property, removed property, ...).
     16 
     17 const mockValues = {
     18  "background-image": [
     19    "linear-gradient",
     20    "radial-gradient",
     21    "repeating-radial-gradient",
     22  ],
     23  color: ["blue", "red", "rgb"],
     24  display: ["block", "flex", "inline", "inline-block", "none"],
     25  "grid-template-areas": ["unset", "inherits"],
     26 };
     27 
     28 add_task(async function () {
     29  await addTab(
     30    "data:text/html;charset=utf-8," + "inplace editor CSS value autocomplete"
     31  );
     32  const { host, win, doc } = await createHost();
     33 
     34  info("Test for css property completion");
     35  await createEditorAndRunCompletionTest(doc, win, "display", [
     36    ["b", "block", -1, []],
     37    ["VK_BACK_SPACE", "b", -1, []],
     38    ["VK_BACK_SPACE", "", -1, []],
     39    ["i", "inline", 0, ["inline", "inline-block"]],
     40    ["VK_DOWN", "inline-block", 1, ["inline", "inline-block"]],
     41    ["VK_DOWN", "inline", 0, ["inline", "inline-block"]],
     42    ["VK_LEFT", "inline", -1, []],
     43    // Shift + navigation key shouldn't trigger autocomplete (Bug 1184538)
     44    [{ key: "VK_UP", shiftKey: true }, "inline", -1, [], null, false, true],
     45    [{ key: "VK_DOWN", shiftKey: true }, "inline", -1, [], null, false, true],
     46    [{ key: "VK_LEFT", shiftKey: true }, "inline", -1, [], null, false, true],
     47    [{ key: "VK_RIGHT", shiftKey: true }, "inline", -1, [], null, false, true],
     48    [{ key: "VK_HOME", shiftKey: true }, "inline", -1, [], null, false, true],
     49    [{ key: "VK_END", shiftKey: true }, "inline", -1, [], null, false, true],
     50    // "Select All" keyboard shortcut shouldn't trigger autocomplete
     51    [
     52      {
     53        key: "a",
     54        [AppConstants.platform == "macosx" ? "metaKey" : "ctrlKey"]: true,
     55      },
     56      "inline",
     57      -1,
     58      [],
     59      null,
     60      false,
     61      true,
     62    ],
     63  ]);
     64 
     65  info("Test for css property completion after css comment");
     66  await createEditorAndRunCompletionTest(doc, win, "display", [
     67    ["/", "/", -1, []],
     68    ["*", "/*", -1, []],
     69    // "/*/" is still an unclosed comment
     70    ["/", "/*/", -1, []],
     71    [" ", "/*/ ", -1, []],
     72    ["h", "/*/ h", -1, []],
     73    ["i", "/*/ hi", -1, []],
     74    [" ", "/*/ hi ", -1, []],
     75    ["*", "/*/ hi *", -1, []],
     76    // note that !important is not displayed here
     77    ["/", "/*/ hi */block", 0, mockValues.display],
     78    ["b", "/*/ hi */block", -1, []],
     79    ["VK_BACK_SPACE", "/*/ hi */b", -1, []],
     80    ["VK_BACK_SPACE", "/*/ hi */", -1, []],
     81    ["i", "/*/ hi */inline", 0, ["inline", "inline-block"]],
     82    ["VK_DOWN", "/*/ hi */inline-block", 1, ["inline", "inline-block"]],
     83    ["VK_DOWN", "/*/ hi */inline", 0, ["inline", "inline-block"]],
     84    ["VK_LEFT", "/*/ hi */inline", -1, []],
     85  ]);
     86 
     87  info("Test that !important is only added when we want");
     88  await createEditorAndRunCompletionTest(doc, win, "display", [
     89    // !important doesn't get displayed if there's only whitespace before the cursor
     90    [" ", " block", 0, mockValues.display],
     91    // !important doesn't get displayed if there's no meaningful char before
     92    ["!", " !", -1, []],
     93    ["i", " !i", -1, []],
     94    ["m", " !im", -1, []],
     95    // deleting `!im`
     96    ["VK_BACK_SPACE", " !i", -1, []],
     97    ["VK_BACK_SPACE", " !", -1, []],
     98    ["VK_BACK_SPACE", " ", -1, []],
     99    ["b", " block", -1, []],
    100    ["VK_RIGHT", " block", -1, []],
    101    // !important is displayed after a space
    102    [" ", " block block", 0, [...mockValues.display, "!important"]],
    103    [" ", " block  block", 0, [...mockValues.display, "!important"]],
    104    ["!", " block  !important", -1, []],
    105    ["VK_BACK_SPACE", " block  !", -1, []],
    106    ["VK_BACK_SPACE", " block  ", -1, []],
    107    ["VK_LEFT", " block  ", -1, []],
    108    // !important is displayed even if there is a space after the cursor
    109    [" ", " block  block ", 0, [...mockValues.display, "!important"]],
    110    // Add a char that doesn't match anything, and place the cursor before it
    111    ["x", " block  x ", -1, []],
    112    ["VK_LEFT", " block  x ", -1, []],
    113    // cursor is now between block and x: block | x (where | is the cursor)
    114    ["VK_LEFT", " block  x ", -1, []],
    115    // trigger the autocomplete, and check that !important is not in it
    116    [" ", " block  block x ", 0, mockValues.display],
    117    // cancel autocomplete
    118    ["VK_BACK_SPACE", " block   x ", -1, []],
    119    // Move to the end
    120    ...Array.from({ length: 3 }).map(() => ["VK_RIGHT", " block   x ", -1, []]),
    121    // Autocomplete !important
    122    ["!", " block   x !important", -1, []],
    123    // Accept autocomplete
    124    ["VK_RIGHT", " block   x !important", -1, []],
    125    // Check that no autocomplete appears when adding a space after !important
    126    [" ", " block   x !important ", -1, []],
    127    // And that we don't try to autocomplete another !important keyword
    128    ["!", " block   x !important !", -1, []],
    129  ]);
    130 
    131  info("Test for css property completion in gradient function");
    132  await createEditorAndRunCompletionTest(doc, win, "background-image", [
    133    [
    134      `r`,
    135      `radial-gradient`,
    136      0,
    137      ["radial-gradient", "repeating-radial-gradient"],
    138    ],
    139    // accept the completion
    140    [`VK_RIGHT`, `radial-gradient`, -1, []],
    141    // entering the opening bracket opens the autocomplete poup
    142    [`(`, `radial-gradient(blue)`, 0, ["blue", "red", "rgb"]],
    143    // the list gets properly filtered
    144    [`r`, `radial-gradient(red)`, 0, ["red", "rgb"]],
    145    // accept selected value
    146    [`VK_RIGHT`, `radial-gradient(red)`, -1, []],
    147    // entering a comma does trigger the autocomplete
    148    [`,`, `radial-gradient(red,blue)`, 0, ["blue", "red", "rgb"]],
    149    // entering a numerical value makes the autocomplete go away
    150    [`1`, `radial-gradient(red,1)`, -1, []],
    151    [`0`, `radial-gradient(red,10)`, -1, []],
    152    [`%`, `radial-gradient(red,10%)`, -1, []],
    153    // entering a space after the numerical value does trigger the autocomplete
    154    [` `, `radial-gradient(red,10% blue)`, 0, ["blue", "red", "rgb"]],
    155    [`r`, `radial-gradient(red,10% red)`, 0, ["red", "rgb"]],
    156    [`g`, `radial-gradient(red,10% rgb)`, -1, []],
    157    [`VK_RIGHT`, `radial-gradient(red,10% rgb)`, -1, []],
    158    // there is no autocomplete for "rgb()"
    159    [`(`, `radial-gradient(red,10% rgb())`, -1, []],
    160    [`0`, `radial-gradient(red,10% rgb(0))`, -1, []],
    161    [`,`, `radial-gradient(red,10% rgb(0,))`, -1, []],
    162    [`1`, `radial-gradient(red,10% rgb(0,1))`, -1, []],
    163    [`,`, `radial-gradient(red,10% rgb(0,1,))`, -1, []],
    164    [`2`, `radial-gradient(red,10% rgb(0,1,2))`, -1, []],
    165    // entering the closing parenthesis for rgb does not add a new one,
    166    // but reuse the one that was automatically inserted
    167    [`)`, `radial-gradient(red,10% rgb(0,1,2))`, -1, []],
    168    // entering a comma does trigger the autocomplete again after rgb() is closed
    169    [
    170      `,`,
    171      `radial-gradient(red,10% rgb(0,1,2),blue)`,
    172      0,
    173      ["blue", "red", "rgb"],
    174    ],
    175    // cancel adding a new argument in radial-gradient
    176    ["VK_BACK_SPACE", "radial-gradient(red,10% rgb(0,1,2),)", -1, []],
    177    ["VK_BACK_SPACE", "radial-gradient(red,10% rgb(0,1,2))", -1, []],
    178    // entering the closing parenthesis for radial-gradient does not add a new one,
    179    // but reuse the one that was automatically inserted
    180    [")", "radial-gradient(red,10% rgb(0,1,2))", -1, []],
    181    // entering a comma does trigger the autocomplete for the property again
    182    [
    183      ",",
    184      "radial-gradient(red,10% rgb(0,1,2)),linear-gradient",
    185      0,
    186      // we don't show !important here
    187      ["linear-gradient", "radial-gradient", "repeating-radial-gradient"],
    188    ],
    189    // don't go further, we covered everything
    190  ]);
    191 
    192  info("Test for no completion in string value");
    193  await createEditorAndRunCompletionTest(doc, win, "grid-template-areas", [
    194    [`"`, `"`, -1, 0],
    195    [`a`, `"a`, -1, 0],
    196    [` `, `"a `, -1, 0],
    197    [`.`, `"a .`, -1, 0],
    198    [`"`, `"a ."`, -1, 0],
    199  ]);
    200 
    201  host.destroy();
    202  gBrowser.removeCurrentTab();
    203 });
    204 
    205 /**
    206 *
    207 * @param {Document} doc
    208 * @param {Window} win
    209 * @param {string} property - The property name
    210 * @param {Array} testData - The data passed to helper_inplace_editor.js `testComplation`.
    211 *         format :
    212 *         [
    213 *           what key to press,
    214 *           expected input box value after keypress,
    215 *           selected suggestion index (-1 if popup is hidden),
    216 *           number of suggestions in the popup (0 if popup is hidden), or the array of items label
    217 *         ]
    218 */
    219 async function createEditorAndRunCompletionTest(doc, win, property, testData) {
    220  const xulDocument = win.top.document;
    221  const popup = new AutocompletePopup(xulDocument, { autoSelect: true });
    222 
    223  await new Promise(resolve => {
    224    createInplaceEditorAndClick(
    225      {
    226        start: async editor => {
    227          for (const data of testData) {
    228            await testCompletion(data, editor);
    229          }
    230 
    231          EventUtils.synthesizeKey("VK_RETURN", {}, editor.input.defaultView);
    232        },
    233        contentType: InplaceEditor.CONTENT_TYPES.CSS_VALUE,
    234        property: {
    235          name: property,
    236        },
    237        cssProperties: {
    238          getNames: () => Object.keys(mockValues),
    239          getValues: propertyName => mockValues[propertyName] || [],
    240        },
    241        done: resolve,
    242        popup,
    243      },
    244      doc
    245    );
    246  });
    247  popup.destroy();
    248 }