Bug 1270494 - fix autocomplete popup offset for multiple values input;r=pbro
authorJulian Descottes <jdescottes@mozilla.com>
Mon, 06 Jun 2016 12:10:13 +0200
changeset 301185 daadc8567a11c6165986c05719fa44a7ed8af839
parent 301184 5753eb3ec41884030a12d9df006ee8fced481ca5
child 301186 fcd8a5d33cb63d088911f02c601145f2829106ec
push id78241
push userkwierso@gmail.com
push dateThu, 09 Jun 2016 00:09:10 +0000
treeherdermozilla-inbound@2c66b75bbb7f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspbro
bugs1270494, 1168246
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1270494 - fix autocomplete popup offset for multiple values input;r=pbro Fixed regression from Bug 1168246 and added a unit test to loosely check that the autocomplete popup moves along with autocompleted query. MozReview-Commit-ID: H7t5WjkwBE4
devtools/client/shared/inplace-editor.js
devtools/client/shared/test/browser.ini
devtools/client/shared/test/browser_inplace-editor_autocomplete_01.js
devtools/client/shared/test/browser_inplace-editor_autocomplete_02.js
devtools/client/shared/test/browser_inplace-editor_autocomplete_offset.js
--- a/devtools/client/shared/inplace-editor.js
+++ b/devtools/client/shared/inplace-editor.js
@@ -1426,17 +1426,17 @@ InplaceEditor.prototype = {
         input.setSelectionRange(query.length, query.length + item.length -
                                               startCheckQuery.length);
         this._updateSize();
       }
 
       // Display the list of suggestions if there are more than one.
       if (finalList.length > 1) {
         // Calculate the popup horizontal offset.
-        let indent = this.input.selectionStart - query.length;
+        let indent = this.input.selectionStart - startCheckQuery.length;
         let offset = indent * this.inputCharDimensions.width;
         offset = this._isSingleLine() ? offset : 0;
 
         // Select the most relevantItem if autoInsert is allowed
         let selectedIndex = autoInsert ? index : -1;
 
         // Open the suggestions popup.
         this.popup.setItems(finalList);
--- a/devtools/client/shared/test/browser.ini
+++ b/devtools/client/shared/test/browser.ini
@@ -119,16 +119,17 @@ skip-if = e10s # Bug 1221911, bug 122228
 [browser_html_tooltip-04.js]
 [browser_html_tooltip-05.js]
 [browser_html_tooltip_arrow-01.js]
 [browser_html_tooltip_arrow-02.js]
 [browser_inplace-editor-01.js]
 [browser_inplace-editor-02.js]
 [browser_inplace-editor_autocomplete_01.js]
 [browser_inplace-editor_autocomplete_02.js]
+[browser_inplace-editor_autocomplete_offset.js]
 [browser_inplace-editor_maxwidth.js]
 [browser_key_shortcuts.js]
 [browser_layoutHelpers.js]
 skip-if = e10s # Layouthelpers test should not run in a content page.
 [browser_layoutHelpers-getBoxQuads.js]
 skip-if = e10s # Layouthelpers test should not run in a content page.
 [browser_mdn-docs-01.js]
 [browser_mdn-docs-02.js]
--- a/devtools/client/shared/test/browser_inplace-editor_autocomplete_01.js
+++ b/devtools/client/shared/test/browser_inplace-editor_autocomplete_01.js
@@ -8,16 +8,23 @@
 const { InplaceEditor } = require("devtools/client/shared/inplace-editor");
 const { AutocompletePopup } = require("devtools/client/shared/autocomplete-popup");
 loadHelperScript("helper_inplace_editor.js");
 
 // Test the inplace-editor autocomplete popup for CSS properties suggestions.
 // Using a mocked list of CSS properties to avoid test failures linked to
 // engine changes (new property, removed property, ...).
 
+// format :
+//  [
+//    what key to press,
+//    expected input box value after keypress,
+//    selected suggestion index (-1 if popup is hidden),
+//    number of suggestions in the popup (0 if popup is hidden),
+//  ]
 const testData = [
   ["b", "border", 1, 3],
   ["VK_DOWN", "box-sizing", 2, 3],
   ["VK_DOWN", "background", 0, 3],
   ["VK_DOWN", "border", 1, 3],
   ["VK_BACK_SPACE", "b", -1, 0],
   ["VK_BACK_SPACE", "", -1, 0],
   ["VK_DOWN", "background", 0, 6],
--- a/devtools/client/shared/test/browser_inplace-editor_autocomplete_02.js
+++ b/devtools/client/shared/test/browser_inplace-editor_autocomplete_02.js
@@ -8,16 +8,23 @@
 const { InplaceEditor } = require("devtools/client/shared/inplace-editor");
 const { AutocompletePopup } = require("devtools/client/shared/autocomplete-popup");
 loadHelperScript("helper_inplace_editor.js");
 
 // Test the inplace-editor autocomplete popup for CSS values suggestions.
 // Using a mocked list of CSS properties to avoid test failures linked to
 // engine changes (new property, removed property, ...).
 
+// format :
+//  [
+//    what key to press,
+//    expected input box value after keypress,
+//    selected suggestion index (-1 if popup is hidden),
+//    number of suggestions in the popup (0 if popup is hidden),
+//  ]
 const testData = [
   ["b", "block", -1, 0],
   ["VK_BACK_SPACE", "b", -1, 0],
   ["VK_BACK_SPACE", "", -1, 0],
   ["i", "inline", 0, 2],
   ["VK_DOWN", "inline-block", 1, 2],
   ["VK_DOWN", "inline", 0, 2],
   ["VK_LEFT", "inline", -1, 0],
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/test/browser_inplace-editor_autocomplete_offset.js
@@ -0,0 +1,111 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+/* import-globals-from helper_inplace_editor.js */
+
+"use strict";
+
+const { InplaceEditor } = require("devtools/client/shared/inplace-editor");
+const { AutocompletePopup } = require("devtools/client/shared/autocomplete-popup");
+loadHelperScript("helper_inplace_editor.js");
+
+// Test the inplace-editor autocomplete popup is aligned with the completed query.
+// Which means when completing "style=display:flex; color:" the popup will aim to be
+// aligned with the ":" next to "color".
+
+// format :
+//  [
+//    what key to press,
+//    expected input box value after keypress,
+//    selected suggestion index (-1 if popup is hidden),
+//    number of suggestions in the popup (0 if popup is hidden),
+//  ]
+// or
+//  ["checkPopupOffset"]
+// to measure and test the autocomplete popup left offset.
+const testData = [
+  ["VK_RIGHT", "style=", -1, 0],
+  ["d", "style=display", 1, 2],
+  ["checkPopupOffset"],
+  ["VK_RIGHT", "style=display", -1, 0],
+  [":", "style=display:block", 0, 3],
+  ["checkPopupOffset"],
+  ["f", "style=display:flex", -1, 0],
+  ["VK_RIGHT", "style=display:flex", -1, 0],
+  [";", "style=display:flex;", -1, 0],
+  ["c", "style=display:flex;color", 1, 2],
+  ["checkPopupOffset"],
+  ["VK_RIGHT", "style=display:flex;color", -1, 0],
+  [":", "style=display:flex;color:blue", 0, 2],
+  ["checkPopupOffset"],
+];
+
+const mockGetCSSPropertyList = function () {
+  return [
+    "clear",
+    "color",
+    "direction",
+    "display",
+  ];
+};
+
+const mockGetCSSValuesForPropertyName = function (propertyName) {
+  let values = {
+    "color": ["blue", "red"],
+    "display": ["block", "flex", "none"]
+  };
+  return values[propertyName] || [];
+};
+
+add_task(function* () {
+  yield addTab("data:text/html;charset=utf-8,inplace editor CSS value autocomplete");
+  let [host, win, doc] = yield createHost();
+
+  let xulDocument = win.top.document;
+  let popup = new AutocompletePopup(xulDocument, { autoSelect: true });
+
+  info("Create a CSS_MIXED type autocomplete");
+  yield new Promise(resolve => {
+    createInplaceEditorAndClick({
+      initial: "style=",
+      start: runAutocompletionTest,
+      contentType: InplaceEditor.CONTENT_TYPES.CSS_MIXED,
+      done: resolve,
+      popup: popup
+    }, doc);
+  });
+
+  host.destroy();
+  gBrowser.removeCurrentTab();
+});
+
+let runAutocompletionTest = Task.async(function* (editor) {
+  info("Starting autocomplete test for inplace-editor popup offset");
+  editor._getCSSPropertyList = mockGetCSSPropertyList;
+  editor._getCSSValuesForPropertyName = mockGetCSSValuesForPropertyName;
+
+  let previousOffset = -1;
+  for (let data of testData) {
+    if (data[0] === "checkPopupOffset") {
+      info("Check the popup offset has been modified");
+      // We are not testing hard coded offset values here, which could be fragile. We only
+      // want to ensure the popup tries to match the position of the query in the editor
+      // input.
+      let offset = getPopupOffset(editor);
+      ok(offset > previousOffset, "New popup offset is greater than the previous one");
+      previousOffset = offset;
+    } else {
+      yield testCompletion(data, editor);
+    }
+  }
+
+  EventUtils.synthesizeKey("VK_RETURN", {}, editor.input.defaultView);
+});
+
+/**
+ * Get the autocomplete panel left offset, relative to the provided input's left offset.
+ */
+function getPopupOffset({popup, input}) {
+  let popupQuads = popup._panel.getBoxQuads({relativeTo: input});
+  return popupQuads[0].bounds.left;
+}