Bug 913955 - Avoid race conditions and inserting in middle of text in inplace-editor. r=mratcliffe, a=lsblakk
authorGirish Sharma <scrapmachines@gmail.com>
Tue, 25 Mar 2014 20:43:44 +0530
changeset 192934 a89216cc58e04ab138e9e9eb31a6bde8d7e2d9c7
parent 192933 d429abe1d569266e5fc8737edce7d52b28364d98
child 192935 dd5fc2e348bb4855d64c9e5aca88363587dba18d
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmratcliffe, lsblakk
bugs913955
milestone30.0a2
Bug 913955 - Avoid race conditions and inserting in middle of text in inplace-editor. r=mratcliffe, a=lsblakk
browser/devtools/shared/inplace-editor.js
browser/devtools/styleinspector/test/browser_bug893965_css_property_completion_existing_property.js
--- a/browser/devtools/shared/inplace-editor.js
+++ b/browser/devtools/shared/inplace-editor.js
@@ -1003,38 +1003,54 @@ InplaceEditor.prototype = {
 
   /**
    * Handles displaying suggestions based on the current input.
    *
    * @param {boolean} aNoAutoInsert
    *        true if you don't want to automatically insert the first suggestion
    */
   _maybeSuggestCompletion: function(aNoAutoInsert) {
+    // Input can be null in cases when you intantaneously switch out of it.
+    if (!this.input) {
+      return;
+    }
+    let preTimeoutQuery = this.input.value;
     // Since we are calling this method from a keypress event handler, the
     // |input.value| does not include currently typed character. Thus we perform
     // this method async.
     this.doc.defaultView.setTimeout(() => {
       if (this._preventSuggestions) {
         this._preventSuggestions = false;
         return;
       }
       if (this.contentType == CONTENT_TYPES.PLAIN_TEXT) {
         return;
       }
-
+      if (!this.input) {
+        return;
+      }
       let input = this.input;
-      // Input can be null in cases when you intantaneously switch out of it.
-      if (!input) {
+      // The length of input.value should be increased by 1
+      if (input.value.length - preTimeoutQuery.length > 1) {
         return;
       }
       let query = input.value.slice(0, input.selectionStart);
       let startCheckQuery = query;
       if (query == null) {
         return;
       }
+      // If nothing is selected and there is a non-space character after the
+      // cursor, do not autocomplete.
+      if (input.selectionStart == input.selectionEnd &&
+          input.selectionStart < input.value.length &&
+          input.value.slice(input.selectionStart)[0] != " ") {
+        // This emit is mainly to make the test flow simpler.
+        this.emit("after-suggest", "nothing to autocomplete");
+        return;
+      }
       let list = [];
       if (this.contentType == CONTENT_TYPES.CSS_PROPERTY) {
         list = CSSPropertyList;
       } else if (this.contentType == CONTENT_TYPES.CSS_VALUE) {
         // Get the last query to be completed before the caret.
         let match = /([^\s,.\/]+$)/.exec(query);
         if (match) {
           startCheckQuery = match[0];
--- a/browser/devtools/styleinspector/test/browser_bug893965_css_property_completion_existing_property.js
+++ b/browser/devtools/styleinspector/test/browser_bug893965_css_property_completion_existing_property.js
@@ -43,16 +43,19 @@ let testData = [
   ["i", "direction", 0, 2],
   ["s", "display", -1, 0],
   ["VK_BACK_SPACE", "dis", -1, 0],
   ["VK_BACK_SPACE", "di", -1, 0],
   ["VK_BACK_SPACE", "d", -1, 0],
   ["VK_BACK_SPACE", "", -1, 0],
   ["f", "fill", 0, MAX_ENTRIES],
   ["i", "fill", 0, 4],
+  ["VK_LEFT", "fill", -1, 0],
+  ["VK_LEFT", "fill", -1, 0],
+  ["i", "fiill", -1, 0],
   ["VK_ESCAPE", null, -1, 0],
 ];
 
 function openRuleView()
 {
   var target = TargetFactory.forTab(gBrowser.selectedTab);
   gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
     inspector = toolbox.getCurrentPanel();
@@ -85,17 +88,17 @@ function checkStateAndMoveOn(index) {
     return;
   }
 
   let [key] = testData[index];
   state = index;
 
   info("pressing key " + key + " to get result: [" + testData[index].slice(1) +
        "] for state " + state);
-  if (/(right|back_space|escape)/ig.test(key)) {
+  if (/(left|right|back_space|escape)/ig.test(key)) {
     info("added event listener for right|back_space|escape keys");
     editor.input.addEventListener("keypress", function onKeypress() {
       if (editor.input) {
         editor.input.removeEventListener("keypress", onKeypress);
       }
       info("inside event listener");
       checkState();
     });