tor-browser

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

browser_rules_keybindings.js (9573B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // Test keyboard navigation in the rule view
      7 
      8 add_task(async function () {
      9  await pushPref("devtools.inspector.rule-view.focusNextOnEnter", false);
     10  const tab = await addTab(`data:text/html;charset=utf-8,
     11    <style>h1 {}</style>
     12    <h1>Some header text</h1>`);
     13  let { inspector, view } = await openRuleView();
     14  await selectNode("h1", inspector);
     15 
     16  info("Getting the ruleclose brace element for the `h1` rule");
     17  const brace = view.styleDocument.querySelectorAll(".ruleview-ruleclose")[1];
     18 
     19  info("Focus the new property editable field to create a color property");
     20  const ruleEditor = getRuleViewRuleEditor(view, 1);
     21  await focusNewRuleViewProperty(ruleEditor);
     22  EventUtils.sendString("color");
     23 
     24  info("Typing ENTER to focus the next field: property value");
     25  let onFocus = once(brace.parentNode, "focus", true);
     26  let onRuleViewChanged = view.once("ruleview-changed");
     27 
     28  EventUtils.sendKey("Return");
     29 
     30  await onFocus;
     31  await onRuleViewChanged;
     32  ok(true, "The value field was focused");
     33 
     34  info("Entering a property value");
     35  EventUtils.sendString("tomato");
     36 
     37  info("Typing Tab again should focus a new property name");
     38  onFocus = once(brace.parentNode, "focus", true);
     39  onRuleViewChanged = view.once("ruleview-changed");
     40  EventUtils.sendKey("Tab");
     41  await onFocus;
     42  await onRuleViewChanged;
     43  ok(true, "The new property name field was focused");
     44 
     45  info(
     46    "Filling new property name with background-color and hit Tab to focus value input"
     47  );
     48  EventUtils.sendString("background-color");
     49  onRuleViewChanged = view.once("ruleview-changed");
     50  EventUtils.sendKey("Tab");
     51  await onRuleViewChanged;
     52 
     53  ok(true, "The value field was focused");
     54 
     55  info("Entering a background color value");
     56  EventUtils.sendString("gold");
     57 
     58  info("Typing Enter should close the input and focus the value span");
     59  onRuleViewChanged = view.once("ruleview-changed");
     60  EventUtils.sendKey("Return");
     61  await onRuleViewChanged;
     62 
     63  info("Wait until the swatch for the color is created");
     64  const colorSwatchEl = await waitFor(() =>
     65    getRuleViewProperty(
     66      view,
     67      "h1",
     68      "background-color"
     69    )?.valueSpan?.querySelector(".inspector-colorswatch")
     70  );
     71 
     72  is(
     73    view.styleDocument.activeElement.textContent,
     74    "gold",
     75    "Value span is focused after pressing Enter"
     76  );
     77 
     78  info("Type Tab should focus the color swatch");
     79  EventUtils.sendKey("Tab");
     80  is(
     81    view.styleDocument.activeElement,
     82    colorSwatchEl,
     83    "Focused was moved to color swatch"
     84  );
     85 
     86  info("Press Shift Tab");
     87  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
     88  is(
     89    view.styleDocument.activeElement.textContent,
     90    "gold",
     91    "Focus is moved back to property value"
     92  );
     93 
     94  info("Press Shift Tab again");
     95  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
     96  is(
     97    view.styleDocument.activeElement.textContent,
     98    "background-color",
     99    "Focus is moved back to property name"
    100  );
    101 
    102  info("Press Shift Tab once more");
    103  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
    104  ok(
    105    view.styleDocument.activeElement.matches(
    106      "input[type=checkbox].ruleview-enableproperty"
    107    ),
    108    "Focus is moved to the prop toggle checkbox"
    109  );
    110  const toggleEl = view.styleDocument.activeElement;
    111  ok(toggleEl.checked, "Checkbox is checked by default");
    112  is(
    113    toggleEl.getAttribute("title"),
    114    "Enable background-color property",
    115    "checkbox has expected label"
    116  );
    117 
    118  info("Press Space to uncheck checkbox");
    119  let onRuleViewRefreshed = view.once("ruleview-changed");
    120  EventUtils.sendKey("Space");
    121  await onRuleViewRefreshed;
    122  ok(!toggleEl.checked, "Checkbox is now unchecked");
    123 
    124  info("Press Space to check checkbox back");
    125  onRuleViewRefreshed = view.once("ruleview-changed");
    126  EventUtils.sendKey("Space");
    127  await onRuleViewRefreshed;
    128  ok(toggleEl.checked, "Checkbox is checked again");
    129 
    130  info("Re-start the toolbox");
    131  await gDevTools.closeToolboxForTab(tab);
    132  ({ view } = await openRuleView());
    133 });
    134 
    135 // The `element` have specific behavior, so we want to test that keyboard navigation
    136 // also works fine on them.
    137 
    138 add_task(async function testKeyboardNavigationInElementRule() {
    139  await pushPref("devtools.inspector.rule-view.focusNextOnEnter", false);
    140  await addTab("data:text/html;charset=utf-8,<h1>Some header text</h1>");
    141  const { inspector, view } = await openRuleView();
    142  await selectNode("h1", inspector);
    143 
    144  info("Getting the ruleclose brace element");
    145  const brace = view.styleDocument.querySelector(".ruleview-ruleclose");
    146 
    147  info("Focus the new property editable field to create a color property");
    148  const ruleEditor = getRuleViewRuleEditor(view, 0);
    149  let editor = await focusNewRuleViewProperty(ruleEditor);
    150  editor.input.value = "color";
    151 
    152  info("Typing ENTER to focus the next field: property value");
    153  let onFocus = once(brace.parentNode, "focus", true);
    154  let onRuleViewChanged = view.once("ruleview-changed");
    155  let onStyleAttributeMutation = waitForStyleAttributeMutation(view, `color: `);
    156 
    157  EventUtils.sendKey("Return");
    158 
    159  await onFocus;
    160  await onRuleViewChanged;
    161  await onStyleAttributeMutation;
    162  ok(true, "The value field was focused");
    163 
    164  info("Entering a property value");
    165  onStyleAttributeMutation = waitForStyleAttributeMutation(
    166    view,
    167    `color: green;`
    168  );
    169  editor = getCurrentInplaceEditor(view);
    170  editor.input.value = "green";
    171 
    172  info("Typing Tab again should focus a new property name");
    173  onFocus = once(brace.parentNode, "focus", true);
    174  onRuleViewChanged = view.once("ruleview-changed");
    175  EventUtils.sendKey("Tab");
    176  await onFocus;
    177  await onRuleViewChanged;
    178  await onStyleAttributeMutation;
    179  ok(true, "The new property name field was focused");
    180 
    181  info(
    182    "Filling new property name with background-color and hit Tab to focus value input"
    183  );
    184 
    185  EventUtils.sendString("background-color");
    186 
    187  onRuleViewChanged = view.once("ruleview-changed");
    188  onStyleAttributeMutation = waitForStyleAttributeMutation(
    189    view,
    190    `background-color:`
    191  );
    192  EventUtils.sendKey("Tab");
    193  await onRuleViewChanged;
    194  await onStyleAttributeMutation;
    195 
    196  ok(true, "The value field was focused");
    197 
    198  info("Entering a background color value");
    199  onStyleAttributeMutation = waitForStyleAttributeMutation(
    200    view,
    201    `background-color: tomato;`
    202  );
    203 
    204  EventUtils.sendString("tomato", view.styleWindow);
    205 
    206  info("Typing Enter should close the input and focus the value span");
    207  const onValueDone = view.once("ruleview-changed");
    208  // The element rule is reset when a property is added, which impacts how we deal
    209  // with the focused element.
    210  const onRuleEditorFocusReset = view.once("rule-editor-focus-reset");
    211  EventUtils.sendKey("Return");
    212 
    213  await onValueDone;
    214  await onRuleEditorFocusReset;
    215  await onStyleAttributeMutation;
    216 
    217  is(
    218    view.styleDocument.activeElement,
    219    getRuleViewProperty(view, "element", "background-color").valueSpan,
    220    `background-color value span ("tomato") is focused after pressing Enter`
    221  );
    222  is(
    223    view.styleDocument.activeElement.textContent,
    224    "tomato",
    225    `focused element has expected text`
    226  );
    227 });
    228 
    229 // Test keyboard navigation in the rule view when
    230 // devtools.inspector.rule-view.focusNextOnEnter is set to true
    231 
    232 add_task(async function () {
    233  await pushPref("devtools.inspector.rule-view.focusNextOnEnter", true);
    234  await addTab(`data:text/html;charset=utf-8,
    235    <style>h1 {}</style>
    236    <h1>Some header text</h1>`);
    237  const { inspector, view } = await openRuleView();
    238  await selectNode("h1", inspector);
    239 
    240  info("Getting the ruleclose brace element for the `h1` rule");
    241  const brace = view.styleDocument.querySelectorAll(".ruleview-ruleclose")[1];
    242 
    243  info("Focus the new property editable field to create a color property");
    244  const ruleEditor = getRuleViewRuleEditor(view, 1);
    245  await focusNewRuleViewProperty(ruleEditor);
    246  EventUtils.sendString("color");
    247 
    248  info("Typing ENTER to focus the next field: property value");
    249  let onFocus = once(brace.parentNode, "focus", true);
    250  let onRuleViewChanged = view.once("ruleview-changed");
    251 
    252  EventUtils.sendKey("Return");
    253 
    254  await onFocus;
    255  await onRuleViewChanged;
    256  ok(true, "The value field was focused");
    257 
    258  info("Entering a property value");
    259  EventUtils.sendString("tomato");
    260 
    261  info("Typing Enter again should focus a new property name");
    262  onFocus = once(brace.parentNode, "focus", true);
    263  onRuleViewChanged = view.once("ruleview-changed");
    264  EventUtils.sendKey("Return");
    265  await onFocus;
    266  await onRuleViewChanged;
    267 
    268  const activeElement = view.styleDocument.activeElement;
    269  is(
    270    `${activeElement.tagName}${[...activeElement.classList]
    271      .map(cls => `.${cls}`)
    272      .join("")}`,
    273    "input.styleinspector-propertyeditor",
    274    "The new property name field was focused"
    275  );
    276 });
    277 
    278 function waitForStyleAttributeMutation(view, expectedAttributeValue) {
    279  return new Promise(r => {
    280    view.inspector.walker.on(
    281      "mutations",
    282      function onWalkerMutations(mutations) {
    283        // Wait until we receive a mutation which updates the style attribute
    284        // with the expected value.
    285        const receivedLastMutation = mutations.find(
    286          mut =>
    287            mut.attributeName === "style" &&
    288            mut.newValue.includes(expectedAttributeValue)
    289        );
    290        if (receivedLastMutation) {
    291          view.inspector.walker.off("mutations", onWalkerMutations);
    292          r();
    293        }
    294      }
    295    );
    296  });
    297 }
    298 
    299 function getCurrentInplaceEditor(view) {
    300  return inplaceEditor(view.styleDocument.activeElement);
    301 }