Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / elements / StylesSidebarPane.js
index cc2659a..be7d22d 100644 (file)
@@ -49,6 +49,11 @@ WebInspector.StylesSidebarPane = function(computedStylePane, setPseudoClassCallb
     addButton.title = WebInspector.UIString("New Style Rule");
     addButton.addEventListener("click", this._createNewRuleInViaInspectorStyleSheet.bind(this), false);
     this.titleElement.appendChild(addButton);
+    addButton.createChild("div", "long-click-glyph fill");
+
+    this._addButtonLongClickController = new WebInspector.LongClickController(addButton);
+    this._addButtonLongClickController.addEventListener(WebInspector.LongClickController.Events.LongClick, this._onAddButtonLongClick.bind(this));
+    this._addButtonLongClickController.enable();
 
     this._computedStylePane = computedStylePane;
     computedStylePane.setHostingPane(this);
@@ -56,6 +61,7 @@ WebInspector.StylesSidebarPane = function(computedStylePane, setPseudoClassCallb
     this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true);
     WebInspector.settings.colorFormat.addChangeListener(this._colorFormatSettingChanged.bind(this));
     WebInspector.settings.showUserAgentStyles.addChangeListener(this._showUserAgentStylesSettingChanged.bind(this));
+    WebInspector.settings.showInheritedComputedStyleProperties.addChangeListener(this._showInheritedComputedStyleChanged.bind(this));
 
     this._createElementStatePane();
     this.bodyElement.appendChild(this._elementStatePane);
@@ -85,6 +91,14 @@ WebInspector.StylesSidebarPane.PseudoIdNames = [
 WebInspector.StylesSidebarPane._colorRegex = /((?:rgb|hsl)a?\([^)]+\)|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}|\b\w+\b(?!-))/g;
 
 /**
+ * @enum {string}
+ */
+WebInspector.StylesSidebarPane.Events = {
+    SelectorEditingStarted: "SelectorEditingStarted",
+    SelectorEditingEnded: "SelectorEditingEnded"
+};
+
+/**
  * @param {!WebInspector.CSSProperty} property
  * @return {!Element}
  */
@@ -155,6 +169,102 @@ WebInspector.StylesSidebarPane._ignoreErrorsForProperty = function(property) {
 }
 
 WebInspector.StylesSidebarPane.prototype = {
+    _showInheritedComputedStyleChanged: function()
+    {
+        if (!this.sections || !this.sections[0])
+            return;
+        for (var i = 0; i < this.sections[0].length; ++i) {
+            var section = this.sections[0][i];
+            if (section instanceof WebInspector.ComputedStylePropertiesSection)
+                section.onShowInheritedChanged();
+        }
+    },
+
+    /**
+     * @param {!WebInspector.Event} event
+     */
+    _onAddButtonLongClick: function(event)
+    {
+        this._addButtonLongClickController.reset();
+        var cssModel = this._target.cssModel;
+        var headers = cssModel.styleSheetHeaders().filter(styleSheetResourceHeader);
+
+        /** @type {!Array.<{text: string, handler: function()}>} */
+        var contextMenuDescriptors = [];
+        for (var i = 0; i < headers.length; ++i) {
+            var header = headers[i];
+            var handler = this._createNewRuleInStyleSheet.bind(this, header);
+            contextMenuDescriptors.push({
+                text: WebInspector.displayNameForURL(header.resourceURL()),
+                handler: handler
+            });
+        }
+
+        contextMenuDescriptors.sort(compareDescriptors);
+
+        var contextMenu = new WebInspector.ContextMenu(/** @type {!Event} */(event.data));
+        for (var i = 0; i < contextMenuDescriptors.length; ++i) {
+            var descriptor = contextMenuDescriptors[i];
+            contextMenu.appendItem(descriptor.text, descriptor.handler);
+        }
+        if (!contextMenu.isEmpty())
+            contextMenu.appendSeparator();
+        contextMenu.appendItem("inspector-stylesheet", this._createNewRuleInViaInspectorStyleSheet.bind(this));
+        contextMenu.show();
+
+        /**
+         * @param {!{text: string, handler: function()}} descriptor1
+         * @param {!{text: string, handler: function()}} descriptor2
+         * @return {number}
+         */
+        function compareDescriptors(descriptor1, descriptor2)
+        {
+            return String.naturalOrderComparator(descriptor1.text, descriptor2.text);
+        }
+
+        /**
+         * @param {!WebInspector.CSSStyleSheetHeader} header
+         */
+        function styleSheetResourceHeader(header)
+        {
+            return !header.isViaInspector() && !header.isInline && header.resourceURL();
+        }
+    },
+
+    /**
+     * @param {!WebInspector.DOMNode} node
+     */
+    updateEditingSelectorForNode: function(node)
+    {
+        var selectorText = WebInspector.DOMPresentationUtils.simpleSelector(node);
+        if (!selectorText)
+            return;
+        this._editingSelectorSection.setSelectorText(selectorText);
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isEditingSelector: function()
+    {
+        return !!this._editingSelectorSection;
+    },
+
+    /**
+     * @param {!WebInspector.StylePropertiesSection} section
+     */
+    _startEditingSelector: function(section)
+    {
+        this._editingSelectorSection = section;
+        this.dispatchEventToListeners(WebInspector.StylesSidebarPane.Events.SelectorEditingStarted);
+    },
+
+    _finishEditingSelector: function()
+    {
+        delete this._editingSelectorSection;
+        this.dispatchEventToListeners(WebInspector.StylesSidebarPane.Events.SelectorEditingEnded);
+    },
+
     /**
      * @param {!WebInspector.CSSRule} editedRule
      * @param {!WebInspector.TextRange} oldRange
@@ -162,9 +272,15 @@ WebInspector.StylesSidebarPane.prototype = {
      */
     _styleSheetRuleEdited: function(editedRule, oldRange, newRange)
     {
-        var styleRuleSections = this.sections[0];
-        for (var i = 1; i < styleRuleSections.length; ++i)
-            styleRuleSections[i]._styleSheetRuleEdited(editedRule, oldRange, newRange);
+        for (var pseudoId in this.sections) {
+            var styleRuleSections = this.sections[pseudoId];
+            for (var i = 0; i < styleRuleSections.length; ++i) {
+                var section = styleRuleSections[i];
+                if (section.computedStyle)
+                    continue;
+                section._styleSheetRuleEdited(editedRule, oldRange, newRange);
+            }
+        }
     },
 
     /**
@@ -391,6 +507,8 @@ WebInspector.StylesSidebarPane.prototype = {
                 this._rebuildUpdate();
                 return;
             }
+            if (matchedResult && this._node === node)
+                this._nodeStylesUpdatedForTest(node, true);
         }
 
         /**
@@ -526,7 +644,6 @@ WebInspector.StylesSidebarPane.prototype = {
 
         if (this._filterRegex)
             this._updateFilter(false);
-        this._nodeStylesUpdatedForTest(node, true);
     },
 
     _nodeStylesUpdatedForTest: function(node, rebuild)
@@ -723,7 +840,7 @@ WebInspector.StylesSidebarPane.prototype = {
                 separatorElement.className = "sidebar-separator";
                 if (styleRule.node) {
                     var link = WebInspector.DOMPresentationUtils.linkifyNodeReference(styleRule.node);
-                    separatorElement.appendChild(document.createTextNode(WebInspector.UIString("Inherited from") + " "));
+                    separatorElement.createTextChild(WebInspector.UIString("Inherited from") + " ");
                     separatorElement.appendChild(link);
                     if (!sections.inheritedPropertiesSeparatorElement)
                         sections.inheritedPropertiesSeparatorElement = separatorElement;
@@ -788,27 +905,25 @@ WebInspector.StylesSidebarPane.prototype = {
      */
     _createNewRuleInViaInspectorStyleSheet: function(event)
     {
-        event.consume();
         var cssModel = this._target.cssModel;
-        cssModel.requestViaInspectorStylesheet(this._node, viaInspectorCallback.bind(this));
+        cssModel.requestViaInspectorStylesheet(this._node, this._createNewRuleInStyleSheet.bind(this));
+    },
 
-        /**
-         * @param {?WebInspector.CSSStyleSheetHeader} styleSheetHeader
-         * @this {WebInspector.StylesSidebarPane}
-         */
-        function viaInspectorCallback(styleSheetHeader)
-        {
-            if (!styleSheetHeader)
-                return;
-            styleSheetHeader.requestContent(onViaInspectorContent.bind(this, styleSheetHeader.id));
-        }
+    /**
+     * @param {?WebInspector.CSSStyleSheetHeader} styleSheetHeader
+     */
+    _createNewRuleInStyleSheet: function(styleSheetHeader)
+    {
+        if (!styleSheetHeader)
+            return;
+        styleSheetHeader.requestContent(onStyleSheetContent.bind(this, styleSheetHeader.id));
 
         /**
          * @param {string} styleSheetId
          * @param {string} text
          * @this {WebInspector.StylesSidebarPane}
          */
-        function onViaInspectorContent(styleSheetId, text)
+        function onStyleSheetContent(styleSheetId, text)
         {
             var lines = text.split("\n");
             var range = WebInspector.TextRange.createFromLocation(lines.length - 1, lines[lines.length - 1].length);
@@ -892,7 +1007,7 @@ WebInspector.StylesSidebarPane.prototype = {
             input.addEventListener("click", clickListener.bind(this), false);
             inputs.push(input);
             label.appendChild(input);
-            label.appendChild(document.createTextNode(":" + state));
+            label.createTextChild(":" + state);
             td.appendChild(label);
             return td;
         }
@@ -1199,14 +1314,14 @@ WebInspector.StylePropertiesSection.prototype = {
     },
 
     /**
-     * @param {!Object} styleRule
+     * @param {?Array.<!WebInspector.CSSMedia>} mediaRules
      */
-    _createMediaList: function(styleRule)
+    _createMediaList: function(mediaRules)
     {
-        if (!styleRule.media)
+        if (!mediaRules)
             return;
-        for (var i = styleRule.media.length - 1; i >= 0; --i) {
-            var media = styleRule.media[i];
+        for (var i = mediaRules.length - 1; i >= 0; --i) {
+            var media = mediaRules[i];
             var mediaDataElement = this._mediaListElement.createChild("div", "media");
             var mediaText;
             switch (media.source) {
@@ -1238,7 +1353,7 @@ WebInspector.StylePropertiesSection.prototype = {
     _updateMediaList: function()
     {
         this._mediaListElement.removeChildren();
-        this._createMediaList(this.styleRule);
+        this._createMediaList(this.styleRule.media);
     },
 
     collapse: function()
@@ -1358,9 +1473,14 @@ WebInspector.StylePropertiesSection.prototype = {
         if (this._afterUpdate) {
             this._afterUpdate(this);
             delete this._afterUpdate;
+            this._afterUpdateFinishedForTest();
         }
     },
 
+    _afterUpdateFinishedForTest: function()
+    {
+    },
+
     onpopulate: function()
     {
         var style = this.styleRule.style;
@@ -1463,7 +1583,7 @@ WebInspector.StylePropertiesSection.prototype = {
         var currentMatch = 0;
         for (var i = 0; i < selectors.length ; ++i) {
             if (i)
-                fragment.appendChild(document.createTextNode(", "));
+                fragment.createTextChild(", ");
             var isSelectorMatching = matchingSelectors[currentMatch] === i;
             if (isSelectorMatching)
                 ++currentMatch;
@@ -1503,8 +1623,10 @@ WebInspector.StylePropertiesSection.prototype = {
     {
         if (this._checkWillCancelEditing() || !this.editable)
             return;
-        if (event.target === this._selectorContainer)
+        if (event.target === this._selectorContainer) {
             this.addNewBlankProperty(0).startEditing();
+            event.consume(true);
+        }
     },
 
     /**
@@ -1531,19 +1653,6 @@ WebInspector.StylePropertiesSection.prototype = {
      */
     _createRuleOriginNode: function(rule, ruleLocation)
     {
-        /**
-         * @param {string} url
-         * @param {number} line
-         */
-        function linkifyUncopyable(url, line)
-        {
-            var link = WebInspector.linkifyResourceAsNode(url, line, "", url + ":" + (line + 1));
-            link.classList.add("webkit-html-resource-link");
-            link.setAttribute("data-uncopyable", link.textContent);
-            link.textContent = "";
-            return link;
-        }
-
         if (!rule)
             return document.createTextNode("");
 
@@ -1552,30 +1661,44 @@ WebInspector.StylePropertiesSection.prototype = {
             ruleLocation = rule.selectors[firstMatchingIndex].range;
         }
 
-        var sourceURL = rule.resourceURL();
-        if (sourceURL && ruleLocation && rule.styleSheetId) {
-            var styleSheetHeader = this._parentPane._target.cssModel.styleSheetHeaderForId(rule.styleSheetId);
-            var lineNumber = styleSheetHeader.lineNumberInSource(ruleLocation.startLine);
-            var columnNumber = styleSheetHeader.columnNumberInSource(ruleLocation.startLine, ruleLocation.startColumn);
-            var matchingSelectorLocation = new WebInspector.CSSLocation(this._parentPane._target, rule.styleSheetId, sourceURL, lineNumber, columnNumber);
-            return this._parentPane._linkifier.linkifyCSSLocation(matchingSelectorLocation) || linkifyUncopyable(sourceURL, 0);
-        }
+        if (ruleLocation && rule.styleSheetId)
+            return this._linkifyRuleLocation(rule.styleSheetId, ruleLocation);
 
         if (rule.isUserAgent)
             return document.createTextNode(WebInspector.UIString("user agent stylesheet"));
         if (rule.isUser)
             return document.createTextNode(WebInspector.UIString("user stylesheet"));
         if (rule.isViaInspector)
-            return this._createRuleViaInspectorOriginNode();
+            return document.createTextNode(WebInspector.UIString("via inspector"));
         return document.createTextNode("");
     },
 
     /**
+     * @param {string} styleSheetId
+     * @param {!WebInspector.TextRange} ruleLocation
      * @return {!Node}
      */
-    _createRuleViaInspectorOriginNode: function()
+    _linkifyRuleLocation: function(styleSheetId, ruleLocation)
     {
-        return document.createTextNode(WebInspector.UIString("via inspector"));
+        /**
+         * @param {string} url
+         * @param {number} line
+         */
+        function linkifyUncopyable(url, line)
+        {
+            var link = WebInspector.linkifyResourceAsNode(url, line, "", url + ":" + (line + 1));
+            link.classList.add("webkit-html-resource-link");
+            link.setAttribute("data-uncopyable", link.textContent);
+            link.textContent = "";
+            return link;
+        }
+
+        var styleSheetHeader = this._parentPane._target.cssModel.styleSheetHeaderForId(styleSheetId);
+        var sourceURL = styleSheetHeader.resourceURL();
+        var lineNumber = styleSheetHeader.lineNumberInSource(ruleLocation.startLine);
+        var columnNumber = styleSheetHeader.columnNumberInSource(ruleLocation.startLine, ruleLocation.startColumn);
+        var matchingSelectorLocation = new WebInspector.CSSLocation(this._parentPane._target, styleSheetId, sourceURL, lineNumber, columnNumber);
+        return this._parentPane._linkifier.linkifyCSSLocation(matchingSelectorLocation) || linkifyUncopyable(sourceURL, 0);
     },
 
     _handleEmptySpaceMouseDown: function()
@@ -1600,6 +1723,7 @@ WebInspector.StylePropertiesSection.prototype = {
         }
         this.expand();
         this.addNewBlankProperty().startEditing();
+        event.consume(true)
     },
 
     _handleSelectorClick: function(event)
@@ -1643,11 +1767,37 @@ WebInspector.StylePropertiesSection.prototype = {
         element.scrollIntoViewIfNeeded(false);
         element.textContent = element.textContent; // Reset selector marks in group.
 
-        var config = new WebInspector.InplaceEditor.Config(this.editingSelectorCommitted.bind(this), this.editingSelectorCancelled.bind(this));
+        var config = new WebInspector.InplaceEditor.Config(this.editingSelectorCommitted.bind(this), this.editingSelectorCancelled.bind(this), undefined, this._editingSelectorBlurHandler.bind(this));
         WebInspector.InplaceEditor.startEditing(this._selectorElement, config);
 
         window.getSelection().setBaseAndExtent(element, 0, element, 1);
         this._parentPane._isEditingStyle = true;
+        this._parentPane._startEditingSelector(this);
+    },
+
+    /**
+     * @param {string} text
+     */
+    setSelectorText: function(text)
+    {
+        this._selectorElement.textContent = text;
+        window.getSelection().setBaseAndExtent(this._selectorElement, 0, this._selectorElement, 1);
+    },
+
+    /**
+     * @param {!Element} editor
+     * @param {!Event} blurEvent
+     * @return {boolean}
+     */
+    _editingSelectorBlurHandler: function(editor, blurEvent)
+    {
+        if (!blurEvent.relatedTarget)
+            return true;
+        var elementTreeOutline = blurEvent.relatedTarget.enclosingNodeOrSelfWithClass("elements-tree-outline");
+        if (!elementTreeOutline)
+            return true;
+        editor.focus();
+        return false;
     },
 
     _moveEditorFromSelector: function(moveDirection)
@@ -1688,8 +1838,6 @@ WebInspector.StylePropertiesSection.prototype = {
             return;
         }
 
-        var selectedNode = this._parentPane._node;
-
         /**
          * @param {!WebInspector.CSSRule} newRule
          * @this {WebInspector.StylePropertiesSection}
@@ -1709,7 +1857,7 @@ WebInspector.StylePropertiesSection.prototype = {
             this.rule = newRule;
             this.styleRule = { section: this, style: newRule.style, selectorText: newRule.selectorText, media: newRule.media, rule: newRule };
 
-            this._parentPane.update(selectedNode);
+            this._parentPane._refreshUpdate(this, false);
             this._parentPane._styleSheetRuleEdited(this.rule, oldSelectorRange, this.rule.selectorRange);
 
             finishOperationAndMoveEditor.call(this, moveDirection);
@@ -1726,6 +1874,7 @@ WebInspector.StylePropertiesSection.prototype = {
 
         // This gets deleted in finishOperationAndMoveEditor(), which is called both on success and failure.
         this._parentPane._userOperation = true;
+        var selectedNode = this._parentPane._node;
         this._parentPane._target.cssModel.setRuleSelector(this.rule, selectedNode ? selectedNode.id : 0, newContent, successCallback.bind(this), finishOperationAndMoveEditor.bind(this, moveDirection));
     },
 
@@ -1738,6 +1887,7 @@ WebInspector.StylePropertiesSection.prototype = {
     _editingSelectorEnded: function()
     {
         delete this._parentPane._isEditingStyle;
+        this._parentPane._finishEditingSelector();
     },
 
     editingSelectorCancelled: function()
@@ -1765,19 +1915,8 @@ WebInspector.ComputedStylePropertiesSection = function(stylesPane, styleRule, us
     this._hasFreshContent = false;
     this.element.className = "styles-section monospace read-only computed-style";
 
-    var showInheritedCheckbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Show inherited properties"), WebInspector.settings.showInheritedComputedStyleProperties, true);
-    showInheritedCheckbox.classList.add("checkbox-with-label");
-    this.headerElement.appendChild(showInheritedCheckbox);
-    WebInspector.settings.showInheritedComputedStyleProperties.addChangeListener(showInheritedChanged.bind(this));
-    showInheritedChanged.call(this);
-
-    /**
-     * @this {WebInspector.ComputedStylePropertiesSection}
-     */
-    function showInheritedChanged()
-    {
-        this.element.classList.toggle("styles-show-inherited", WebInspector.settings.showInheritedComputedStyleProperties.get());
-    }
+    this.headerElement.appendChild(WebInspector.ComputedStylePropertiesSection._showInheritedCheckbox());
+    this.onShowInheritedChanged();
 
     this._stylesPane = stylesPane;
     this.styleRule = styleRule;
@@ -1788,7 +1927,24 @@ WebInspector.ComputedStylePropertiesSection = function(stylesPane, styleRule, us
     this._expandedPropertyNames = {};
 }
 
+/**
+ * @return {!Element}
+ */
+WebInspector.ComputedStylePropertiesSection._showInheritedCheckbox = function()
+{
+    if (!WebInspector.ComputedStylePropertiesSection._showInheritedCheckboxElement) {
+        WebInspector.ComputedStylePropertiesSection._showInheritedCheckboxElement = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Show inherited properties"), WebInspector.settings.showInheritedComputedStyleProperties, true);
+        WebInspector.ComputedStylePropertiesSection._showInheritedCheckboxElement.classList.add("checkbox-with-label");
+    }
+    return WebInspector.ComputedStylePropertiesSection._showInheritedCheckboxElement;
+}
+
 WebInspector.ComputedStylePropertiesSection.prototype = {
+    onShowInheritedChanged: function()
+    {
+        this.element.classList.toggle("styles-show-inherited", WebInspector.settings.showInheritedComputedStyleProperties.get());
+    },
+
     collapse: function(dontRememberState)
     {
         // Overriding with empty body.
@@ -1866,7 +2022,7 @@ WebInspector.ComputedStylePropertiesSection.prototype = {
                     var selector = fragment.createChild("span");
                     selector.style.color = "gray";
                     selector.textContent = section.styleRule.selectorText;
-                    fragment.appendChild(document.createTextNode(" - " + property.value + " "));
+                    fragment.createTextChild(" - " + property.value + " ");
                     var subtitle = fragment.createChild("span");
                     subtitle.style.float = "right";
                     subtitle.appendChild(section._createRuleOriginNode(section.rule));
@@ -1910,12 +2066,9 @@ WebInspector.BlankStylePropertiesSection = function(stylesPane, defaultSelectorT
     this._ruleLocation = ruleLocation;
     this._styleSheetId = styleSheetId;
     this._selectorRefElement.removeChildren();
-    if (insertAfterRule) {
-        this._selectorRefElement.appendChild(this._createRuleOriginNode(insertAfterRule, this._actualRuleLocation()));
-        this._createMediaList(insertAfterRule);
-    } else {
-        this._selectorRefElement.appendChild(this._createRuleViaInspectorOriginNode());
-    }
+    this._selectorRefElement.appendChild(this._linkifyRuleLocation(styleSheetId, this._actualRuleLocation()));
+    if (insertAfterRule)
+        this._createMediaList(insertAfterRule.media);
     this.element.classList.add("blank-section");
 }
 
@@ -2189,7 +2342,7 @@ WebInspector.StylePropertyTreeElementBase.prototype = {
                     if (nextProcessor)
                         container.appendChild(nextProcessor(items[i]));
                     else
-                        container.appendChild(document.createTextNode(items[i]));
+                        container.createTextChild(items[i]);
                 } else {
                     var processedNode = processor(items[i]);
                     if (processedNode)
@@ -2212,7 +2365,7 @@ WebInspector.StylePropertyTreeElementBase.prototype = {
             if (match)
                 hrefUrl = match[1];
             var container = document.createDocumentFragment();
-            container.appendChild(document.createTextNode("url("));
+            container.createTextChild("url(");
             if (this._styleRule.rule && this._styleRule.rule.resourceURL())
                 hrefUrl = WebInspector.ParsedURL.completeURL(this._styleRule.rule.resourceURL(), hrefUrl);
             else if (this.node())
@@ -2220,7 +2373,7 @@ WebInspector.StylePropertyTreeElementBase.prototype = {
             var hasResource = hrefUrl && !!WebInspector.resourceForURL(hrefUrl);
             // FIXME: WebInspector.linkifyURLAsNode() should really use baseURI.
             container.appendChild(WebInspector.linkifyURLAsNode(hrefUrl || url, url, undefined, !hasResource));
-            container.appendChild(document.createTextNode(")"));
+            container.createTextChild(")");
             return container;
         }
 
@@ -2239,10 +2392,10 @@ WebInspector.StylePropertyTreeElementBase.prototype = {
         if (this.disabled)
             this.listItemElement.createChild("span", "styles-clipboard-only").createTextChild("/* ");
         this.listItemElement.appendChild(nameElement);
-        this.listItemElement.appendChild(document.createTextNode(": "));
+        this.listItemElement.createTextChild(": ");
         this.listItemElement.appendChild(this._expandElement);
         this.listItemElement.appendChild(valueElement);
-        this.listItemElement.appendChild(document.createTextNode(";"));
+        this.listItemElement.createTextChild(";");
         if (this.disabled)
             this.listItemElement.createChild("span", "styles-clipboard-only").createTextChild(" */");
 
@@ -2531,8 +2684,12 @@ WebInspector.StylePropertyTreeElement = function(stylesPane, styleRule, style, p
     WebInspector.StylePropertyTreeElementBase.call(this, styleRule, style, property, inherited, overloaded, isShorthand);
     this._parentPane = stylesPane;
     this.isShorthand = isShorthand;
+    this._applyStyleThrottler = new WebInspector.Throttler(0);
 }
 
+/** @typedef {{expanded: boolean, hasChildren: boolean, isEditingName: boolean, previousContent: string}} */
+WebInspector.StylePropertyTreeElement.Context;
+
 WebInspector.StylePropertyTreeElement.prototype = {
     /**
      * @return {?WebInspector.DOMNode}
@@ -2795,6 +2952,7 @@ WebInspector.StylePropertyTreeElement.prototype = {
             return splitFieldValue.join("");
         }
 
+        /** @type {!WebInspector.StylePropertyTreeElement.Context} */
         var context = {
             expanded: this.expanded,
             hasChildren: this.hasChildren,
@@ -2810,6 +2968,8 @@ WebInspector.StylePropertyTreeElement.prototype = {
         selectElement.textContent = selectElement.textContent; // remove color swatch and the like
 
         /**
+         * @param {!WebInspector.StylePropertyTreeElement.Context} context
+         * @param {!Event} event
          * @this {WebInspector.StylePropertyTreeElement}
          */
         function pasteHandler(context, event)
@@ -2840,6 +3000,8 @@ WebInspector.StylePropertyTreeElement.prototype = {
         }
 
         /**
+         * @param {!WebInspector.StylePropertyTreeElement.Context} context
+         * @param {!Event} event
          * @this {WebInspector.StylePropertyTreeElement}
          */
         function blurListener(context, event)
@@ -2861,7 +3023,7 @@ WebInspector.StylePropertyTreeElement.prototype = {
         if (selectElement.parentElement)
             selectElement.parentElement.scrollIntoViewIfNeeded(false);
 
-        var applyItemCallback = !isEditingName ? this._applyFreeFlowStyleTextEdit.bind(this, true) : undefined;
+        var applyItemCallback = !isEditingName ? this._applyFreeFlowStyleTextEdit.bind(this) : undefined;
         this._prompt = new WebInspector.StylesSidebarPane.CSSPropertyPrompt(isEditingName ? WebInspector.CSSMetadata.cssPropertiesMetainfo : WebInspector.CSSMetadata.keywordsForProperty(this.nameElement.textContent), this, isEditingName);
         if (applyItemCallback) {
             this._prompt.addEventListener(WebInspector.TextPrompt.Events.ItemApplied, applyItemCallback, this);
@@ -2869,20 +3031,24 @@ WebInspector.StylePropertyTreeElement.prototype = {
         }
         var proxyElement = this._prompt.attachAndStartEditing(selectElement, blurListener.bind(this, context));
 
-        proxyElement.addEventListener("keydown", this.editingNameValueKeyDown.bind(this, context), false);
-        proxyElement.addEventListener("keypress", this.editingNameValueKeyPress.bind(this, context), false);
+        proxyElement.addEventListener("keydown", this._editingNameValueKeyDown.bind(this, context), false);
+        proxyElement.addEventListener("keypress", this._editingNameValueKeyPress.bind(this, context), false);
+        proxyElement.addEventListener("input", this._editingNameValueInput.bind(this, context), false);
         if (isEditingName)
             proxyElement.addEventListener("paste", pasteHandler.bind(this, context), false);
 
         window.getSelection().setBaseAndExtent(selectElement, 0, selectElement, 1);
     },
 
-    editingNameValueKeyDown: function(context, event)
+    /**
+     * @param {!WebInspector.StylePropertyTreeElement.Context} context
+     * @param {!Event} event
+     */
+    _editingNameValueKeyDown: function(context, event)
     {
         if (event.handled)
             return;
 
-        var isEditingName = context.isEditingName;
         var result;
 
         if (isEnterKey(event)) {
@@ -2890,7 +3056,7 @@ WebInspector.StylePropertyTreeElement.prototype = {
             result = "forward";
         } else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.keyIdentifier === "U+001B")
             result = "cancel";
-        else if (!isEditingName && this._newProperty && event.keyCode === WebInspector.KeyboardShortcut.Keys.Backspace.code) {
+        else if (!context.isEditingName && this._newProperty && event.keyCode === WebInspector.KeyboardShortcut.Keys.Backspace.code) {
             // For a new property, when Backspace is pressed at the beginning of new property value, move back to the property name.
             var selection = window.getSelection();
             if (selection.isCollapsed && !selection.focusOffset) {
@@ -2916,12 +3082,13 @@ WebInspector.StylePropertyTreeElement.prototype = {
             event.consume();
             return;
         }
-
-        if (!isEditingName)
-            this._applyFreeFlowStyleTextEdit(false);
     },
 
-    editingNameValueKeyPress: function(context, event)
+    /**
+     * @param {!WebInspector.StylePropertyTreeElement.Context} context
+     * @param {!Event} event
+     */
+    _editingNameValueKeyPress: function(context, event)
     {
         function shouldCommitValueSemicolon(text, cursorPosition)
         {
@@ -2949,36 +3116,31 @@ WebInspector.StylePropertyTreeElement.prototype = {
         }
     },
 
-    _applyFreeFlowStyleTextEdit: function(now)
+    /**
+     * @param {!WebInspector.StylePropertyTreeElement.Context} context
+     * @param {!Event} event
+     */
+    _editingNameValueInput: function(context, event)
     {
-        if (this._applyFreeFlowStyleTextEditTimer)
-            clearTimeout(this._applyFreeFlowStyleTextEditTimer);
+        if (!context.isEditingName)
+            this._applyFreeFlowStyleTextEdit();
+    },
 
-        /**
-         * @this {WebInspector.StylePropertyTreeElement}
-         */
-        function apply()
-        {
-            var valueText = this.valueElement.textContent;
-            if (valueText.indexOf(";") === -1)
-                this.applyStyleText(this.nameElement.textContent + ": " + valueText, false, false, false);
-        }
-        if (now)
-            apply.call(this);
-        else
-            this._applyFreeFlowStyleTextEditTimer = setTimeout(apply.bind(this), 100);
+    _applyFreeFlowStyleTextEdit: function()
+    {
+        var valueText = this.valueElement.textContent;
+        if (valueText.indexOf(";") === -1)
+            this.applyStyleText(this.nameElement.textContent + ": " + valueText, false, false, false);
     },
 
     kickFreeFlowStyleEditForTest: function()
     {
-        this._applyFreeFlowStyleTextEdit(true);
+        this._applyFreeFlowStyleTextEdit();
     },
 
     editingEnded: function(context)
     {
         this._resetMouseDownElement();
-        if (this._applyFreeFlowStyleTextEditTimer)
-            clearTimeout(this._applyFreeFlowStyleTextEditTimer);
 
         this.hasChildren = context.hasChildren;
         if (context.expanded)
@@ -3164,12 +3326,35 @@ WebInspector.StylePropertyTreeElement.prototype = {
     {
     },
 
+    /**
+     * @param {string} styleText
+     * @param {boolean} updateInterface
+     * @param {boolean} majorChange
+     * @param {boolean} isRevert
+     */
     applyStyleText: function(styleText, updateInterface, majorChange, isRevert)
     {
+        this._applyStyleThrottler.schedule(this._innerApplyStyleText.bind(this, styleText, updateInterface, majorChange, isRevert));
+    },
+
+    /**
+     * @param {string} styleText
+     * @param {boolean} updateInterface
+     * @param {boolean} majorChange
+     * @param {boolean} isRevert
+     * @param {!WebInspector.Throttler.FinishCallback} finishedCallback
+     */
+    _innerApplyStyleText: function(styleText, updateInterface, majorChange, isRevert, finishedCallback)
+    {
+        /**
+         * @param {!WebInspector.StylesSidebarPane} parentPane
+         * @param {boolean} updateInterface
+         */
         function userOperationFinishedCallback(parentPane, updateInterface)
         {
             if (updateInterface)
                 delete parentPane._userOperation;
+            finishedCallback();
         }
 
         // Leave a way to cancel editing after incremental changes.
@@ -3210,6 +3395,7 @@ WebInspector.StylePropertyTreeElement.prototype = {
                     this._revertStyleUponEditingCanceled(originalPropertyText);
                 }
                 userCallback();
+                this.styleTextAppliedForTest();
                 return;
             }
             this._applyNewStyle(newStyle);
@@ -3236,7 +3422,11 @@ WebInspector.StylePropertyTreeElement.prototype = {
         if (styleText.length && !/;\s*$/.test(styleText))
             styleText += ";";
         var overwriteProperty = !!(!this._newProperty || this._newPropertyInStyle);
-        this.property.setText(styleText, majorChange, overwriteProperty, callback.bind(this, userOperationFinishedCallback.bind(null, this._parentPane, updateInterface), this.originalPropertyText));
+        var boundCallback = callback.bind(this, userOperationFinishedCallback.bind(null, this._parentPane, updateInterface), this.originalPropertyText);
+        if (overwriteProperty && styleText === this.property.propertyText)
+            boundCallback.call(null, this.property.ownerStyle)
+        else
+            this.property.setText(styleText, majorChange, overwriteProperty, boundCallback);
     },
 
     /**