Home | History | Annotate | Download | only in front-end
      1 /*
      2  * Copyright (C) 2007 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2009 Joseph Pecoraro
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1.  Redistributions of source code must retain the above copyright
     10  *     notice, this list of conditions and the following disclaimer.
     11  * 2.  Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15  *     its contributors may be used to endorse or promote products derived
     16  *     from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 WebInspector.StylesSidebarPane = function()
     31 {
     32     WebInspector.SidebarPane.call(this, WebInspector.UIString("Styles"));
     33 
     34     this.settingsSelectElement = document.createElement("select");
     35 
     36     var option = document.createElement("option");
     37     option.value = "hex";
     38     option.action = this._changeColorFormat.bind(this);
     39     option.label = WebInspector.UIString("Hex Colors");
     40     this.settingsSelectElement.appendChild(option);
     41 
     42     option = document.createElement("option");
     43     option.value = "rgb";
     44     option.action = this._changeColorFormat.bind(this);
     45     option.label = WebInspector.UIString("RGB Colors");
     46     this.settingsSelectElement.appendChild(option);
     47 
     48     option = document.createElement("option");
     49     option.value = "hsl";
     50     option.action = this._changeColorFormat.bind(this);
     51     option.label = WebInspector.UIString("HSL Colors");
     52     this.settingsSelectElement.appendChild(option);
     53 
     54     this.settingsSelectElement.appendChild(document.createElement("hr"));
     55 
     56     option = document.createElement("option");
     57     option.action = this._createNewRule.bind(this);
     58     option.label = WebInspector.UIString("New Style Rule");
     59     this.settingsSelectElement.appendChild(option);
     60 
     61     this.settingsSelectElement.addEventListener("click", function(event) { event.stopPropagation() }, false);
     62     this.settingsSelectElement.addEventListener("change", this._changeSetting.bind(this), false);
     63     WebInspector.settings.addEventListener("loaded", this._settingsLoaded, this);
     64 
     65     this.titleElement.appendChild(this.settingsSelectElement);
     66 }
     67 
     68 WebInspector.StylesSidebarPane.prototype = {
     69     _settingsLoaded: function()
     70     {
     71         var format = WebInspector.settings.colorFormat;
     72         if (format === "hex")
     73             this.settingsSelectElement[0].selected = true;
     74         if (format === "rgb")
     75             this.settingsSelectElement[1].selected = true;
     76         if (format === "hsl")
     77             this.settingsSelectElement[2].selected = true;
     78     },
     79 
     80     update: function(node, editedSection, forceUpdate)
     81     {
     82         var refresh = false;
     83 
     84         if (forceUpdate)
     85             delete this.node;
     86 
     87         if (!forceUpdate && (!node || node === this.node))
     88             refresh = true;
     89 
     90         if (node && node.nodeType === Node.TEXT_NODE && node.parentNode)
     91             node = node.parentNode;
     92 
     93         if (node && node.nodeType !== Node.ELEMENT_NODE)
     94             node = null;
     95 
     96         if (node)
     97             this.node = node;
     98         else
     99             node = this.node;
    100 
    101         var body = this.bodyElement;
    102 
    103         if (!node) {
    104             body.removeChildren();
    105             this.sections = [];
    106             return;
    107         }
    108 
    109         var self = this;
    110         function callback(styles)
    111         {
    112             if (!styles)
    113                 return;
    114             node._setStyles(styles.computedStyle, styles.inlineStyle, styles.styleAttributes, styles.matchedCSSRules);
    115             self._update(refresh, body, node, editedSection, forceUpdate);
    116         }
    117 
    118         InjectedScriptAccess.get(node.injectedScriptId).getStyles(node.id, !WebInspector.settings.showUserAgentStyles, callback);
    119     },
    120 
    121     _update: function(refresh, body, node, editedSection, forceUpdate)
    122     {
    123         if (!refresh) {
    124             body.removeChildren();
    125             this.sections = [];
    126         }
    127 
    128         var styleRules = [];
    129 
    130         if (refresh) {
    131             for (var i = 0; i < this.sections.length; ++i) {
    132                 var section = this.sections[i];
    133                 if (section instanceof WebInspector.BlankStylePropertiesSection)
    134                     continue;
    135                 if (section.computedStyle)
    136                     section.styleRule.style = node.ownerDocument.defaultView.getComputedStyle(node);
    137                 var styleRule = { section: section, style: section.styleRule.style, computedStyle: section.computedStyle, rule: section.rule };
    138                 styleRules.push(styleRule);
    139             }
    140         } else {
    141             var computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
    142             styleRules.push({ computedStyle: true, selectorText: WebInspector.UIString("Computed Style"), style: computedStyle, editable: false });
    143 
    144             var nodeName = node.nodeName.toLowerCase();
    145             for (var i = 0; i < node.attributes.length; ++i) {
    146                 var attr = node.attributes[i];
    147                 if (attr.style) {
    148                     var attrStyle = { style: attr.style, editable: false };
    149                     attrStyle.subtitle = WebInspector.UIString("elements %s attribute", attr.name);
    150                     attrStyle.selectorText = nodeName + "[" + attr.name;
    151                     if (attr.value.length)
    152                         attrStyle.selectorText += "=" + attr.value;
    153                     attrStyle.selectorText += "]";
    154                     styleRules.push(attrStyle);
    155                 }
    156             }
    157 
    158             // Always Show element's Style Attributes
    159             if (node.nodeType === Node.ELEMENT_NODE) {
    160                 var inlineStyle = { selectorText: WebInspector.UIString("Style Attribute"), style: node.style, isAttribute: true };
    161                 inlineStyle.subtitle = WebInspector.UIString("elements %s attribute", "style");
    162                 styleRules.push(inlineStyle);
    163             }
    164 
    165             var matchedStyleRules = node.ownerDocument.defaultView.getMatchedCSSRules(node, "", !WebInspector.settings.showUserAgentStyles);
    166             if (matchedStyleRules) {
    167                 // Add rules in reverse order to match the cascade order.
    168                 for (var i = (matchedStyleRules.length - 1); i >= 0; --i) {
    169                     var rule = matchedStyleRules[i];
    170                     styleRules.push({ style: rule.style, selectorText: rule.selectorText, parentStyleSheet: rule.parentStyleSheet, rule: rule });
    171                 }
    172             }
    173         }
    174 
    175         function deleteDisabledProperty(style, name)
    176         {
    177             if (!style || !name)
    178                 return;
    179             if (style.__disabledPropertyValues)
    180                 delete style.__disabledPropertyValues[name];
    181             if (style.__disabledPropertyPriorities)
    182                 delete style.__disabledPropertyPriorities[name];
    183             if (style.__disabledProperties)
    184                 delete style.__disabledProperties[name];
    185         }
    186 
    187         var usedProperties = {};
    188         var disabledComputedProperties = {};
    189         var priorityUsed = false;
    190 
    191         // Walk the style rules and make a list of all used and overloaded properties.
    192         for (var i = 0; i < styleRules.length; ++i) {
    193             var styleRule = styleRules[i];
    194             if (styleRule.computedStyle)
    195                 continue;
    196             if (styleRule.section && styleRule.section.noAffect)
    197                 continue;
    198 
    199             styleRule.usedProperties = {};
    200 
    201             var style = styleRule.style;
    202             for (var j = 0; j < style.length; ++j) {
    203                 var name = style[j];
    204 
    205                 if (!priorityUsed && style.getPropertyPriority(name).length)
    206                     priorityUsed = true;
    207 
    208                 // If the property name is already used by another rule then this rule's
    209                 // property is overloaded, so don't add it to the rule's usedProperties.
    210                 if (!(name in usedProperties))
    211                     styleRule.usedProperties[name] = true;
    212 
    213                 if (name === "font") {
    214                     // The font property is not reported as a shorthand. Report finding the individual
    215                     // properties so they are visible in computed style.
    216                     // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15598 is fixed.
    217                     styleRule.usedProperties["font-family"] = true;
    218                     styleRule.usedProperties["font-size"] = true;
    219                     styleRule.usedProperties["font-style"] = true;
    220                     styleRule.usedProperties["font-variant"] = true;
    221                     styleRule.usedProperties["font-weight"] = true;
    222                     styleRule.usedProperties["line-height"] = true;
    223                 }
    224 
    225                 // Delete any disabled properties, since the property does exist.
    226                 // This prevents it from showing twice.
    227                 deleteDisabledProperty(style, name);
    228                 deleteDisabledProperty(style, style.getPropertyShorthand(name));
    229             }
    230 
    231             // Add all the properties found in this style to the used properties list.
    232             // Do this here so only future rules are affect by properties used in this rule.
    233             for (var name in styleRules[i].usedProperties)
    234                 usedProperties[name] = true;
    235 
    236             // Remember all disabled properties so they show up in computed style.
    237             if (style.__disabledProperties)
    238                 for (var name in style.__disabledProperties)
    239                     disabledComputedProperties[name] = true;
    240         }
    241 
    242         if (priorityUsed) {
    243             // Walk the properties again and account for !important.
    244             var foundPriorityProperties = [];
    245 
    246             // Walk in reverse to match the order !important overrides.
    247             for (var i = (styleRules.length - 1); i >= 0; --i) {
    248                 if (styleRules[i].computedStyle)
    249                     continue;
    250 
    251                 var style = styleRules[i].style;
    252                 var uniqueProperties = style.uniqueStyleProperties;
    253                 for (var j = 0; j < uniqueProperties.length; ++j) {
    254                     var name = uniqueProperties[j];
    255                     if (style.getPropertyPriority(name).length) {
    256                         if (!(name in foundPriorityProperties))
    257                             styleRules[i].usedProperties[name] = true;
    258                         else
    259                             delete styleRules[i].usedProperties[name];
    260                         foundPriorityProperties[name] = true;
    261                     } else if (name in foundPriorityProperties)
    262                         delete styleRules[i].usedProperties[name];
    263                 }
    264             }
    265         }
    266 
    267         if (refresh) {
    268             // Walk the style rules and update the sections with new overloaded and used properties.
    269             for (var i = 0; i < styleRules.length; ++i) {
    270                 var styleRule = styleRules[i];
    271                 var section = styleRule.section;
    272                 if (styleRule.computedStyle)
    273                     section.disabledComputedProperties = disabledComputedProperties;
    274                 section._usedProperties = (styleRule.usedProperties || usedProperties);
    275                 section.update((section === editedSection) || styleRule.computedStyle);
    276             }
    277         } else {
    278             // Make a property section for each style rule.
    279             for (var i = 0; i < styleRules.length; ++i) {
    280                 var styleRule = styleRules[i];
    281                 var subtitle = styleRule.subtitle;
    282                 delete styleRule.subtitle;
    283 
    284                 var computedStyle = styleRule.computedStyle;
    285                 delete styleRule.computedStyle;
    286 
    287                 var ruleUsedProperties = styleRule.usedProperties;
    288                 delete styleRule.usedProperties;
    289 
    290                 var editable = styleRule.editable;
    291                 delete styleRule.editable;
    292 
    293                 var isAttribute = styleRule.isAttribute;
    294                 delete styleRule.isAttribute;
    295 
    296                 // Default editable to true if it was omitted.
    297                 if (typeof editable === "undefined")
    298                     editable = true;
    299 
    300                 var section = new WebInspector.StylePropertiesSection(styleRule, subtitle, computedStyle, (ruleUsedProperties || usedProperties), editable);
    301                 if (computedStyle)
    302                     section.disabledComputedProperties = disabledComputedProperties;
    303                 section.pane = this;
    304 
    305                 if (Preferences.styleRulesExpandedState && section.identifier in Preferences.styleRulesExpandedState)
    306                     section.expanded = Preferences.styleRulesExpandedState[section.identifier];
    307                 else if (computedStyle)
    308                     section.collapse(true);
    309                 else if (isAttribute && styleRule.style.length === 0)
    310                     section.collapse(true);
    311                 else
    312                     section.expand(true);
    313 
    314                 body.appendChild(section.element);
    315                 this.sections.push(section);
    316             }
    317         }
    318     },
    319 
    320     _changeSetting: function(event)
    321     {
    322         var options = this.settingsSelectElement.options;
    323         var selectedOption = options[this.settingsSelectElement.selectedIndex];
    324         selectedOption.action(event);
    325 
    326         // Select the correct color format setting again, since it needs to be selected.
    327         var selectedIndex = 0;
    328         for (var i = 0; i < options.length; ++i) {
    329             if (options[i].value === WebInspector.settings.colorFormat) {
    330                 selectedIndex = i;
    331                 break;
    332             }
    333         }
    334 
    335         this.settingsSelectElement.selectedIndex = selectedIndex;
    336     },
    337 
    338     _changeColorFormat: function(event)
    339     {
    340         var selectedOption = this.settingsSelectElement[this.settingsSelectElement.selectedIndex];
    341         WebInspector.settings.colorFormat = selectedOption.value;
    342 
    343         for (var i = 0; i < this.sections.length; ++i)
    344             this.sections[i].update(true);
    345     },
    346 
    347     _createNewRule: function(event)
    348     {
    349         this.addBlankSection().startEditingSelector();
    350     },
    351 
    352     addBlankSection: function()
    353     {
    354         var blankSection = new WebInspector.BlankStylePropertiesSection(appropriateSelectorForNode(this.node, true));
    355         blankSection.pane = this;
    356 
    357         var elementStyleSection = this.sections[1];
    358         this.bodyElement.insertBefore(blankSection.element, elementStyleSection.element.nextSibling);
    359 
    360         this.sections.splice(2, 0, blankSection);
    361 
    362         return blankSection;
    363     },
    364 
    365     removeSection: function(section)
    366     {
    367         var index = this.sections.indexOf(section);
    368         if (index === -1)
    369             return;
    370         this.sections.splice(index, 1);
    371         if (section.element.parentNode)
    372             section.element.parentNode.removeChild(section.element);
    373     }
    374 }
    375 
    376 WebInspector.StylesSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
    377 
    378 WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyle, usedProperties, editable)
    379 {
    380     WebInspector.PropertiesSection.call(this, styleRule.selectorText);
    381 
    382     this.titleElement.addEventListener("click", this._clickSelector.bind(this), false);
    383     this.titleElement.addEventListener("dblclick", this._dblclickSelector.bind(this), false);
    384     this.element.addEventListener("dblclick", this._dblclickEmptySpace.bind(this), false);
    385 
    386     this.styleRule = styleRule;
    387     this.rule = this.styleRule.rule;
    388     this.computedStyle = computedStyle;
    389     this.editable = (editable && !computedStyle);
    390 
    391     // Prevent editing the user agent and user rules.
    392     var isUserAgent = this.rule && this.rule.isUserAgent;
    393     var isUser = this.rule && this.rule.isUser;
    394     var isViaInspector = this.rule && this.rule.isViaInspector;
    395 
    396     if (isUserAgent || isUser)
    397         this.editable = false;
    398 
    399     this._usedProperties = usedProperties;
    400 
    401     if (computedStyle) {
    402         this.element.addStyleClass("computed-style");
    403 
    404         if (WebInspector.settings.showInheritedComputedStyleProperties)
    405             this.element.addStyleClass("show-inherited");
    406 
    407         var showInheritedLabel = document.createElement("label");
    408         var showInheritedInput = document.createElement("input");
    409         showInheritedInput.type = "checkbox";
    410         showInheritedInput.checked = WebInspector.settings.showInheritedComputedStyleProperties;
    411 
    412         var computedStyleSection = this;
    413         var showInheritedToggleFunction = function(event) {
    414             WebInspector.settings.showInheritedComputedStyleProperties = showInheritedInput.checked;
    415             if (WebInspector.settings.showInheritedComputedStyleProperties)
    416                 computedStyleSection.element.addStyleClass("show-inherited");
    417             else
    418                 computedStyleSection.element.removeStyleClass("show-inherited");
    419             event.stopPropagation();
    420         };
    421 
    422         showInheritedLabel.addEventListener("click", showInheritedToggleFunction, false);
    423 
    424         showInheritedLabel.appendChild(showInheritedInput);
    425         showInheritedLabel.appendChild(document.createTextNode(WebInspector.UIString("Show inherited")));
    426         this.subtitleElement.appendChild(showInheritedLabel);
    427     } else {
    428         if (!subtitle) {
    429             if (this.styleRule.parentStyleSheet && this.styleRule.parentStyleSheet.href) {
    430                 var url = this.styleRule.parentStyleSheet.href;
    431                 subtitle = WebInspector.linkifyURL(url, WebInspector.displayNameForURL(url));
    432                 this.subtitleElement.addStyleClass("file");
    433             } else if (isUserAgent)
    434                 subtitle = WebInspector.UIString("user agent stylesheet");
    435             else if (isUser)
    436                 subtitle = WebInspector.UIString("user stylesheet");
    437             else if (isViaInspector)
    438                 subtitle = WebInspector.UIString("via inspector");
    439             else
    440                 subtitle = WebInspector.UIString("inline stylesheet");
    441         }
    442 
    443         this.subtitle = subtitle;
    444     }
    445 
    446     this.identifier = styleRule.selectorText;
    447     if (this.subtitle)
    448         this.identifier += ":" + this.subtitleElement.textContent;
    449 }
    450 
    451 WebInspector.StylePropertiesSection.prototype = {
    452     get usedProperties()
    453     {
    454         return this._usedProperties || {};
    455     },
    456 
    457     set usedProperties(x)
    458     {
    459         this._usedProperties = x;
    460         this.update();
    461     },
    462 
    463     expand: function(dontRememberState)
    464     {
    465         WebInspector.PropertiesSection.prototype.expand.call(this);
    466         if (dontRememberState)
    467             return;
    468 
    469         if (!Preferences.styleRulesExpandedState)
    470             Preferences.styleRulesExpandedState = {};
    471         Preferences.styleRulesExpandedState[this.identifier] = true;
    472     },
    473 
    474     collapse: function(dontRememberState)
    475     {
    476         WebInspector.PropertiesSection.prototype.collapse.call(this);
    477         if (dontRememberState)
    478             return;
    479 
    480         if (!Preferences.styleRulesExpandedState)
    481             Preferences.styleRulesExpandedState = {};
    482         Preferences.styleRulesExpandedState[this.identifier] = false;
    483     },
    484 
    485     isPropertyInherited: function(property)
    486     {
    487         if (!this.computedStyle || !this._usedProperties || this.noAffect)
    488             return false;
    489         // These properties should always show for Computed Style.
    490         var alwaysShowComputedProperties = { "display": true, "height": true, "width": true };
    491         return !(property in this.usedProperties) && !(property in alwaysShowComputedProperties) && !(property in this.disabledComputedProperties);
    492     },
    493 
    494     isPropertyOverloaded: function(property, shorthand)
    495     {
    496         if (this.computedStyle || !this._usedProperties || this.noAffect)
    497             return false;
    498 
    499         var used = (property in this.usedProperties);
    500         if (used || !shorthand)
    501             return !used;
    502 
    503         // Find out if any of the individual longhand properties of the shorthand
    504         // are used, if none are then the shorthand is overloaded too.
    505         var longhandProperties = this.styleRule.style.getLonghandProperties(property);
    506         for (var j = 0; j < longhandProperties.length; ++j) {
    507             var individualProperty = longhandProperties[j];
    508             if (individualProperty in this.usedProperties)
    509                 return false;
    510         }
    511 
    512         return true;
    513     },
    514 
    515     isInspectorStylesheet: function()
    516     {
    517         return (this.styleRule.parentStyleSheet === WebInspector.panels.elements.stylesheet);
    518     },
    519 
    520     update: function(full)
    521     {
    522         if (full || this.computedStyle) {
    523             this.propertiesTreeOutline.removeChildren();
    524             this.populated = false;
    525         } else {
    526             var child = this.propertiesTreeOutline.children[0];
    527             while (child) {
    528                 child.overloaded = this.isPropertyOverloaded(child.name, child.shorthand);
    529                 child = child.traverseNextTreeElement(false, null, true);
    530             }
    531         }
    532 
    533         this.afterUpdate();
    534     },
    535 
    536     afterUpdate: function()
    537     {
    538         if (this._afterUpdate) {
    539             this._afterUpdate(this);
    540             delete this._afterUpdate;
    541         }
    542     },
    543 
    544     onpopulate: function()
    545     {
    546         var style = this.styleRule.style;
    547 
    548         var foundShorthands = {};
    549         var uniqueProperties = style.uniqueStyleProperties;
    550         var disabledProperties = style.__disabledPropertyValues || {};
    551 
    552         for (var name in disabledProperties)
    553             uniqueProperties.push(name);
    554 
    555         uniqueProperties.sort();
    556 
    557         for (var i = 0; i < uniqueProperties.length; ++i) {
    558             var name = uniqueProperties[i];
    559             var disabled = name in disabledProperties;
    560             if (!disabled && this.disabledComputedProperties && !(name in this.usedProperties) && name in this.disabledComputedProperties)
    561                 disabled = true;
    562 
    563             var shorthand = !disabled ? style.getPropertyShorthand(name) : null;
    564 
    565             if (shorthand && shorthand in foundShorthands)
    566                 continue;
    567 
    568             if (shorthand) {
    569                 foundShorthands[shorthand] = true;
    570                 name = shorthand;
    571             }
    572 
    573             var isShorthand = (shorthand ? true : false);
    574             var inherited = this.isPropertyInherited(name);
    575             var overloaded = this.isPropertyOverloaded(name, isShorthand);
    576 
    577             var item = new WebInspector.StylePropertyTreeElement(this.styleRule, style, name, isShorthand, inherited, overloaded, disabled);
    578             this.propertiesTreeOutline.appendChild(item);
    579         }
    580     },
    581 
    582     findTreeElementWithName: function(name)
    583     {
    584         var treeElement = this.propertiesTreeOutline.children[0];
    585         while (treeElement) {
    586             if (treeElement.name === name)
    587                 return treeElement;
    588             treeElement = treeElement.traverseNextTreeElement(true, null, true);
    589         }
    590         return null;
    591     },
    592 
    593     addNewBlankProperty: function()
    594     {
    595         var item = new WebInspector.StylePropertyTreeElement(this.styleRule, this.styleRule.style, "", false, false, false, false);
    596         this.propertiesTreeOutline.appendChild(item);
    597         item.listItemElement.textContent = "";
    598         item._newProperty = true;
    599         return item;
    600     },
    601 
    602     _clickSelector: function(event)
    603     {
    604         event.stopPropagation();
    605 
    606         // Don't search "Computed Styles", "Style Attribute", or Mapped Attributes.
    607         if (this.computedStyle || !this.rule || this.rule.isUser)
    608             return;
    609 
    610         var searchElement = document.getElementById("search");
    611         searchElement.value = this.styleRule.selectorText;
    612         WebInspector.performSearch({ target: searchElement });
    613     },
    614 
    615     _dblclickEmptySpace: function(event)
    616     {
    617         this.expand();
    618         this.addNewBlankProperty().startEditing();
    619     },
    620 
    621     _dblclickSelector: function(event)
    622     {
    623         if (!this.editable)
    624             return;
    625 
    626         if (!this.rule && this.propertiesTreeOutline.children.length === 0) {
    627             this.expand();
    628             this.addNewBlankProperty().startEditing();
    629             return;
    630         }
    631 
    632         if (!this.rule)
    633             return;
    634 
    635         this.startEditingSelector();
    636         event.stopPropagation();
    637     },
    638 
    639     startEditingSelector: function()
    640     {
    641         var element = this.titleElement;
    642         if (WebInspector.isBeingEdited(element))
    643             return;
    644 
    645         WebInspector.startEditing(this.titleElement, this.editingSelectorCommitted.bind(this), this.editingSelectorCancelled.bind(this), null);
    646         window.getSelection().setBaseAndExtent(element, 0, element, 1);
    647     },
    648 
    649     editingSelectorCommitted: function(element, newContent, oldContent, context, moveDirection)
    650     {
    651         function moveToNextIfNeeded() {
    652             if (!moveDirection || moveDirection !== "forward")
    653                 return;
    654 
    655             this.expand();
    656             if (this.propertiesTreeOutline.children.length === 0)
    657                 this.addNewBlankProperty().startEditing();
    658             else {
    659                 var item = this.propertiesTreeOutline.children[0]
    660                 item.startEditing(item.valueElement);
    661             }
    662         }
    663 
    664         if (newContent === oldContent)
    665             return moveToNextIfNeeded.call(this);
    666 
    667         var self = this;
    668         function callback(result)
    669         {
    670             if (!result) {
    671                 // Invalid Syntax for a Selector
    672                 moveToNextIfNeeded.call(self);
    673                 return;
    674             }
    675 
    676             var newRulePayload = result[0];
    677             var doesAffectSelectedNode = result[1];
    678             if (!doesAffectSelectedNode) {
    679                 self.noAffect = true;
    680                 self.element.addStyleClass("no-affect");
    681             } else {
    682                 delete self.noAffect;
    683                 self.element.removeStyleClass("no-affect");
    684             }
    685 
    686             var newRule = WebInspector.CSSStyleDeclaration.parseRule(newRulePayload);
    687             self.rule = newRule;
    688             self.styleRule = { section: self, style: newRule.style, selectorText: newRule.selectorText, parentStyleSheet: newRule.parentStyleSheet, rule: newRule };
    689 
    690             var oldIdentifier = this.identifier;
    691             self.identifier = newRule.selectorText + ":" + self.subtitleElement.textContent;
    692 
    693             self.pane.update();
    694 
    695             WebInspector.panels.elements.renameSelector(oldIdentifier, this.identifier, oldContent, newContent);
    696 
    697             moveToNextIfNeeded.call(self);
    698         }
    699 
    700         InjectedScriptAccess.get(this.rule.injectedScriptId).applyStyleRuleText(this.rule.id, newContent, this.pane.node.id, callback);
    701     },
    702 
    703     editingSelectorCancelled: function()
    704     {
    705         // Do nothing, this is overridden by BlankStylePropertiesSection.
    706     }
    707 }
    708 
    709 WebInspector.StylePropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype;
    710 
    711 WebInspector.BlankStylePropertiesSection = function(defaultSelectorText)
    712 {
    713     WebInspector.StylePropertiesSection.call(this, {selectorText: defaultSelectorText, rule: {isViaInspector: true}}, "", false, {}, false);
    714 
    715     this.element.addStyleClass("blank-section");
    716 }
    717 
    718 WebInspector.BlankStylePropertiesSection.prototype = {
    719     expand: function()
    720     {
    721         // Do nothing, blank sections are not expandable.
    722     },
    723 
    724     editingSelectorCommitted: function(element, newContent, oldContent, context)
    725     {
    726         var self = this;
    727         function callback(result)
    728         {
    729             if (!result) {
    730                 // Invalid Syntax for a Selector
    731                 self.editingSelectorCancelled();
    732                 return;
    733             }
    734 
    735             var rule = result[0];
    736             var doesSelectorAffectSelectedNode = result[1];
    737 
    738             var styleRule = WebInspector.CSSStyleDeclaration.parseRule(rule);
    739             styleRule.rule = rule;
    740 
    741             self.makeNormal(styleRule);
    742 
    743             if (!doesSelectorAffectSelectedNode) {
    744                 self.noAffect = true;
    745                 self.element.addStyleClass("no-affect");
    746             }
    747 
    748             self.subtitleElement.textContent = WebInspector.UIString("via inspector");
    749             self.expand();
    750 
    751             self.addNewBlankProperty().startEditing();
    752         }
    753 
    754         InjectedScriptAccess.get(this.pane.node.injectedScriptId).addStyleSelector(newContent, this.pane.node.id, callback);
    755     },
    756 
    757     editingSelectorCancelled: function()
    758     {
    759         this.pane.removeSection(this);
    760     },
    761 
    762     makeNormal: function(styleRule)
    763     {
    764         this.element.removeStyleClass("blank-section");
    765 
    766         this.styleRule = styleRule;
    767         this.rule = styleRule.rule;
    768         this.computedStyle = false;
    769         this.editable = true;
    770         this.identifier = styleRule.selectorText + ":via inspector";
    771 
    772         this.__proto__ = WebInspector.StylePropertiesSection.prototype;
    773     }
    774 }
    775 
    776 WebInspector.BlankStylePropertiesSection.prototype.__proto__ = WebInspector.StylePropertiesSection.prototype;
    777 
    778 WebInspector.StylePropertyTreeElement = function(styleRule, style, name, shorthand, inherited, overloaded, disabled)
    779 {
    780     this._styleRule = styleRule;
    781     this.style = style;
    782     this.name = name;
    783     this.shorthand = shorthand;
    784     this._inherited = inherited;
    785     this._overloaded = overloaded;
    786     this._disabled = disabled;
    787 
    788     // Pass an empty title, the title gets made later in onattach.
    789     TreeElement.call(this, "", null, shorthand);
    790 }
    791 
    792 WebInspector.StylePropertyTreeElement.prototype = {
    793     get inherited()
    794     {
    795         return this._inherited;
    796     },
    797 
    798     set inherited(x)
    799     {
    800         if (x === this._inherited)
    801             return;
    802         this._inherited = x;
    803         this.updateState();
    804     },
    805 
    806     get overloaded()
    807     {
    808         return this._overloaded;
    809     },
    810 
    811     set overloaded(x)
    812     {
    813         if (x === this._overloaded)
    814             return;
    815         this._overloaded = x;
    816         this.updateState();
    817     },
    818 
    819     get disabled()
    820     {
    821         return this._disabled;
    822     },
    823 
    824     set disabled(x)
    825     {
    826         if (x === this._disabled)
    827             return;
    828         this._disabled = x;
    829         this.updateState();
    830     },
    831 
    832     get priority()
    833     {
    834         if (this.disabled && this.style.__disabledPropertyPriorities && this.name in this.style.__disabledPropertyPriorities)
    835             return this.style.__disabledPropertyPriorities[this.name];
    836         return (this.shorthand ? this.style.getShorthandPriority(this.name) : this.style.getPropertyPriority(this.name));
    837     },
    838 
    839     get value()
    840     {
    841         if (this.disabled && this.style.__disabledPropertyValues && this.name in this.style.__disabledPropertyValues)
    842             return this.style.__disabledPropertyValues[this.name];
    843         return (this.shorthand ? this.style.getShorthandValue(this.name) : this.style.getPropertyValue(this.name));
    844     },
    845 
    846     onattach: function()
    847     {
    848         this.updateTitle();
    849     },
    850 
    851     updateTitle: function()
    852     {
    853         var priority = this.priority;
    854         var value = this.value;
    855 
    856         if (priority && !priority.length)
    857             delete priority;
    858         if (priority)
    859             priority = "!" + priority;
    860 
    861         this.updateState();
    862 
    863         var enabledCheckboxElement = document.createElement("input");
    864         enabledCheckboxElement.className = "enabled-button";
    865         enabledCheckboxElement.type = "checkbox";
    866         enabledCheckboxElement.checked = !this.disabled;
    867         enabledCheckboxElement.addEventListener("change", this.toggleEnabled.bind(this), false);
    868 
    869         var nameElement = document.createElement("span");
    870         nameElement.className = "name";
    871         nameElement.textContent = this.name;
    872         this.nameElement = nameElement;
    873 
    874         var valueElement = document.createElement("span");
    875         valueElement.className = "value";
    876         this.valueElement = valueElement;
    877 
    878         if (value) {
    879             function processValue(regex, processor, nextProcessor, valueText)
    880             {
    881                 var container = document.createDocumentFragment();
    882 
    883                 var items = valueText.replace(regex, "\0$1\0").split("\0");
    884                 for (var i = 0; i < items.length; ++i) {
    885                     if ((i % 2) === 0) {
    886                         if (nextProcessor)
    887                             container.appendChild(nextProcessor(items[i]));
    888                         else
    889                             container.appendChild(document.createTextNode(items[i]));
    890                     } else {
    891                         var processedNode = processor(items[i]);
    892                         if (processedNode)
    893                             container.appendChild(processedNode);
    894                     }
    895                 }
    896 
    897                 return container;
    898             }
    899 
    900             function linkifyURL(url)
    901             {
    902                 var container = document.createDocumentFragment();
    903                 container.appendChild(document.createTextNode("url("));
    904                 container.appendChild(WebInspector.linkifyURLAsNode(url, url, null, (url in WebInspector.resourceURLMap)));
    905                 container.appendChild(document.createTextNode(")"));
    906                 return container;
    907             }
    908 
    909             function processColor(text)
    910             {
    911                 try {
    912                     var color = new WebInspector.Color(text);
    913                 } catch (e) {
    914                     return document.createTextNode(text);
    915                 }
    916 
    917                 var swatchElement = document.createElement("span");
    918                 swatchElement.title = WebInspector.UIString("Click to change color format");
    919                 swatchElement.className = "swatch";
    920                 swatchElement.style.setProperty("background-color", text);
    921 
    922                 swatchElement.addEventListener("click", changeColorDisplay, false);
    923                 swatchElement.addEventListener("dblclick", function(event) { event.stopPropagation() }, false);
    924 
    925                 var format;
    926                 if (Preferences.showColorNicknames && color.nickname)
    927                     format = "nickname";
    928                 else if (WebInspector.settings.colorFormat === "rgb")
    929                     format = (color.simple ? "rgb" : "rgba");
    930                 else if (WebInspector.settings.colorFormat === "hsl")
    931                     format = (color.simple ? "hsl" : "hsla");
    932                 else if (color.simple)
    933                     format = (color.hasShortHex() ? "shorthex" : "hex");
    934                 else
    935                     format = "rgba";
    936 
    937                 var colorValueElement = document.createElement("span");
    938                 colorValueElement.textContent = color.toString(format);
    939 
    940                 function changeColorDisplay(event)
    941                 {
    942                     switch (format) {
    943                         case "rgb":
    944                             format = "hsl";
    945                             break;
    946 
    947                         case "shorthex":
    948                             format = "hex";
    949                             break;
    950 
    951                         case "hex":
    952                             format = "rgb";
    953                             break;
    954 
    955                         case "nickname":
    956                             if (color.simple) {
    957                                 if (color.hasShortHex())
    958                                     format = "shorthex";
    959                                 else
    960                                     format = "hex";
    961                                 break;
    962                             }
    963 
    964                             format = "rgba";
    965                             break;
    966 
    967                         case "hsl":
    968                             if (color.nickname)
    969                                 format = "nickname";
    970                             else if (color.hasShortHex())
    971                                 format = "shorthex";
    972                             else
    973                                 format = "hex";
    974                             break;
    975 
    976                         case "rgba":
    977                             format = "hsla";
    978                             break;
    979 
    980                         case "hsla":
    981                             if (color.nickname)
    982                                 format = "nickname";
    983                             else
    984                                 format = "rgba";
    985                             break;
    986                     }
    987 
    988                     colorValueElement.textContent = color.toString(format);
    989                 }
    990 
    991                 var container = document.createDocumentFragment();
    992                 container.appendChild(swatchElement);
    993                 container.appendChild(colorValueElement);
    994                 return container;
    995             }
    996 
    997             var colorRegex = /((?:rgb|hsl)a?\([^)]+\)|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}|\b\w+\b)/g;
    998             var colorProcessor = processValue.bind(window, colorRegex, processColor, null);
    999 
   1000             valueElement.appendChild(processValue(/url\(([^)]+)\)/g, linkifyURL, colorProcessor, value));
   1001         }
   1002 
   1003         if (priority) {
   1004             var priorityElement = document.createElement("span");
   1005             priorityElement.className = "priority";
   1006             priorityElement.textContent = priority;
   1007         }
   1008 
   1009         this.listItemElement.removeChildren();
   1010 
   1011         // Append the checkbox for root elements of an editable section.
   1012         if (this.treeOutline.section && this.treeOutline.section.editable && this.parent.root)
   1013             this.listItemElement.appendChild(enabledCheckboxElement);
   1014         this.listItemElement.appendChild(nameElement);
   1015         this.listItemElement.appendChild(document.createTextNode(": "));
   1016         this.listItemElement.appendChild(valueElement);
   1017 
   1018         if (priorityElement) {
   1019             this.listItemElement.appendChild(document.createTextNode(" "));
   1020             this.listItemElement.appendChild(priorityElement);
   1021         }
   1022 
   1023         this.listItemElement.appendChild(document.createTextNode(";"));
   1024 
   1025         this.tooltip = this.name + ": " + valueElement.textContent + (priority ? " " + priority : "");
   1026     },
   1027 
   1028     updateAll: function(updateAllRules)
   1029     {
   1030         if (updateAllRules && this.treeOutline.section && this.treeOutline.section.pane)
   1031             this.treeOutline.section.pane.update(null, this.treeOutline.section);
   1032         else if (this.treeOutline.section)
   1033             this.treeOutline.section.update(true);
   1034         else
   1035             this.updateTitle(); // FIXME: this will not show new properties. But we don't hit his case yet.
   1036     },
   1037 
   1038     toggleEnabled: function(event)
   1039     {
   1040         var disabled = !event.target.checked;
   1041 
   1042         var self = this;
   1043         function callback(newPayload)
   1044         {
   1045             if (!newPayload)
   1046                 return;
   1047 
   1048             self.style = WebInspector.CSSStyleDeclaration.parseStyle(newPayload);
   1049             self._styleRule.style = self.style;
   1050 
   1051             // Set the disabled property here, since the code above replies on it not changing
   1052             // until after the value and priority are retrieved.
   1053             self.disabled = disabled;
   1054 
   1055             if (self.treeOutline.section && self.treeOutline.section.pane)
   1056                 self.treeOutline.section.pane.dispatchEventToListeners("style property toggled");
   1057 
   1058             self.updateAll(true);
   1059         }
   1060 
   1061         InjectedScriptAccess.get(this.style.injectedScriptId).toggleStyleEnabled(this.style.id, this.name, disabled, callback);
   1062     },
   1063 
   1064     updateState: function()
   1065     {
   1066         if (!this.listItemElement)
   1067             return;
   1068 
   1069         if (this.style.isPropertyImplicit(this.name) || this.value === "initial")
   1070             this.listItemElement.addStyleClass("implicit");
   1071         else
   1072             this.listItemElement.removeStyleClass("implicit");
   1073 
   1074         if (this.inherited)
   1075             this.listItemElement.addStyleClass("inherited");
   1076         else
   1077             this.listItemElement.removeStyleClass("inherited");
   1078 
   1079         if (this.overloaded)
   1080             this.listItemElement.addStyleClass("overloaded");
   1081         else
   1082             this.listItemElement.removeStyleClass("overloaded");
   1083 
   1084         if (this.disabled)
   1085             this.listItemElement.addStyleClass("disabled");
   1086         else
   1087             this.listItemElement.removeStyleClass("disabled");
   1088     },
   1089 
   1090     onpopulate: function()
   1091     {
   1092         // Only populate once and if this property is a shorthand.
   1093         if (this.children.length || !this.shorthand)
   1094             return;
   1095 
   1096         var longhandProperties = this.style.getLonghandProperties(this.name);
   1097         for (var i = 0; i < longhandProperties.length; ++i) {
   1098             var name = longhandProperties[i];
   1099 
   1100             if (this.treeOutline.section) {
   1101                 var inherited = this.treeOutline.section.isPropertyInherited(name);
   1102                 var overloaded = this.treeOutline.section.isPropertyOverloaded(name);
   1103             }
   1104 
   1105             var item = new WebInspector.StylePropertyTreeElement(this._styleRule, this.style, name, false, inherited, overloaded);
   1106             this.appendChild(item);
   1107         }
   1108     },
   1109 
   1110     ondblclick: function(event)
   1111     {
   1112         this.startEditing(event.target);
   1113         event.stopPropagation();
   1114     },
   1115 
   1116     startEditing: function(selectElement)
   1117     {
   1118         // FIXME: we don't allow editing of longhand properties under a shorthand right now.
   1119         if (this.parent.shorthand)
   1120             return;
   1121 
   1122         if (WebInspector.isBeingEdited(this.listItemElement) || (this.treeOutline.section && !this.treeOutline.section.editable))
   1123             return;
   1124 
   1125         var context = { expanded: this.expanded, hasChildren: this.hasChildren };
   1126 
   1127         // Lie about our children to prevent expanding on double click and to collapse shorthands.
   1128         this.hasChildren = false;
   1129 
   1130         if (!selectElement)
   1131             selectElement = this.listItemElement;
   1132 
   1133         this.listItemElement.handleKeyEvent = this.editingKeyDown.bind(this);
   1134 
   1135         WebInspector.startEditing(this.listItemElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), context);
   1136         window.getSelection().setBaseAndExtent(selectElement, 0, selectElement, 1);
   1137     },
   1138 
   1139     editingKeyDown: function(event)
   1140     {
   1141         var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down");
   1142         var pageKeyPressed = (event.keyIdentifier === "PageUp" || event.keyIdentifier === "PageDown");
   1143         if (!arrowKeyPressed && !pageKeyPressed)
   1144             return;
   1145 
   1146         var selection = window.getSelection();
   1147         if (!selection.rangeCount)
   1148             return;
   1149 
   1150         var selectionRange = selection.getRangeAt(0);
   1151         if (selectionRange.commonAncestorContainer !== this.listItemElement && !selectionRange.commonAncestorContainer.isDescendant(this.listItemElement))
   1152             return;
   1153 
   1154         const styleValueDelimeters = " \t\n\"':;,/()";
   1155         var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, styleValueDelimeters, this.listItemElement);
   1156         var wordString = wordRange.toString();
   1157         var replacementString = wordString;
   1158 
   1159         var matches = /(.*?)(-?\d+(?:\.\d+)?)(.*)/.exec(wordString);
   1160         if (matches && matches.length) {
   1161             var prefix = matches[1];
   1162             var number = parseFloat(matches[2]);
   1163             var suffix = matches[3];
   1164 
   1165             // If the number is near zero or the number is one and the direction will take it near zero.
   1166             var numberNearZero = (number < 1 && number > -1);
   1167             if (number === 1 && event.keyIdentifier === "Down")
   1168                 numberNearZero = true;
   1169             else if (number === -1 && event.keyIdentifier === "Up")
   1170                 numberNearZero = true;
   1171 
   1172             if (numberNearZero && event.altKey && arrowKeyPressed) {
   1173                 if (event.keyIdentifier === "Down")
   1174                     number = Math.ceil(number - 1);
   1175                 else
   1176                     number = Math.floor(number + 1);
   1177             } else {
   1178                 // Jump by 10 when shift is down or jump by 0.1 when near zero or Alt/Option is down.
   1179                 // Also jump by 10 for page up and down, or by 100 if shift is held with a page key.
   1180                 var changeAmount = 1;
   1181                 if (event.shiftKey && pageKeyPressed)
   1182                     changeAmount = 100;
   1183                 else if (event.shiftKey || pageKeyPressed)
   1184                     changeAmount = 10;
   1185                 else if (event.altKey || numberNearZero)
   1186                     changeAmount = 0.1;
   1187 
   1188                 if (event.keyIdentifier === "Down" || event.keyIdentifier === "PageDown")
   1189                     changeAmount *= -1;
   1190 
   1191                 // Make the new number and constrain it to a precision of 6, this matches numbers the engine returns.
   1192                 // Use the Number constructor to forget the fixed precision, so 1.100000 will print as 1.1.
   1193                 number = Number((number + changeAmount).toFixed(6));
   1194             }
   1195 
   1196             replacementString = prefix + number + suffix;
   1197         } else {
   1198             // FIXME: this should cycle through known keywords for the current property name.
   1199             return;
   1200         }
   1201 
   1202         var replacementTextNode = document.createTextNode(replacementString);
   1203 
   1204         wordRange.deleteContents();
   1205         wordRange.insertNode(replacementTextNode);
   1206 
   1207         var finalSelectionRange = document.createRange();
   1208         finalSelectionRange.setStart(replacementTextNode, 0);
   1209         finalSelectionRange.setEnd(replacementTextNode, replacementString.length);
   1210 
   1211         selection.removeAllRanges();
   1212         selection.addRange(finalSelectionRange);
   1213 
   1214         event.preventDefault();
   1215         event.handled = true;
   1216 
   1217         if (!this.originalCSSText) {
   1218             // Remember the rule's original CSS text, so it can be restored
   1219             // if the editing is canceled and before each apply.
   1220             this.originalCSSText = this.style.styleTextWithShorthands();
   1221         } else {
   1222             // Restore the original CSS text before applying user changes. This is needed to prevent
   1223             // new properties from sticking around if the user adds one, then removes it.
   1224             InjectedScriptAccess.get(this.style.injectedScriptId).setStyleText(this.style.id, this.originalCSSText);
   1225         }
   1226 
   1227         this.applyStyleText(this.listItemElement.textContent);
   1228     },
   1229 
   1230     editingEnded: function(context)
   1231     {
   1232         this.hasChildren = context.hasChildren;
   1233         if (context.expanded)
   1234             this.expand();
   1235         delete this.listItemElement.handleKeyEvent;
   1236         delete this.originalCSSText;
   1237     },
   1238 
   1239     editingCancelled: function(element, context)
   1240     {
   1241         if (this._newProperty)
   1242             this.treeOutline.removeChild(this);
   1243         else if (this.originalCSSText) {
   1244             InjectedScriptAccess.get(this.style.injectedScriptId).setStyleText(this.style.id, this.originalCSSText);
   1245 
   1246             if (this.treeOutline.section && this.treeOutline.section.pane)
   1247                 this.treeOutline.section.pane.dispatchEventToListeners("style edited");
   1248 
   1249             this.updateAll();
   1250         } else
   1251             this.updateTitle();
   1252 
   1253         this.editingEnded(context);
   1254     },
   1255 
   1256     editingCommitted: function(element, userInput, previousContent, context, moveDirection)
   1257     {
   1258         this.editingEnded(context);
   1259 
   1260         // Determine where to move to before making changes
   1261         var newProperty, moveToPropertyName, moveToSelector;
   1262         var moveTo = (moveDirection === "forward" ? this.nextSibling : this.previousSibling);
   1263         if (moveTo)
   1264             moveToPropertyName = moveTo.name;
   1265         else if (moveDirection === "forward")
   1266             newProperty = true;
   1267         else if (moveDirection === "backward" && this.treeOutline.section.rule)
   1268             moveToSelector = true;
   1269 
   1270         // Make the Changes and trigger the moveToNextCallback after updating
   1271         var blankInput = /^\s*$/.test(userInput);
   1272         if (userInput !== previousContent || (this._newProperty && blankInput)) { // only if something changed, or adding a new style and it was blank
   1273             this.treeOutline.section._afterUpdate = moveToNextCallback.bind(this, this._newProperty, !blankInput);
   1274             this.applyStyleText(userInput, true);
   1275         } else
   1276             moveToNextCallback(this._newProperty, false, this.treeOutline.section, false);
   1277 
   1278         // The Callback to start editing the next property
   1279         function moveToNextCallback(alreadyNew, valueChanged, section)
   1280         {
   1281             if (!moveDirection)
   1282                 return;
   1283 
   1284             // User just tabbed through without changes
   1285             if (moveTo && moveTo.parent) {
   1286                 moveTo.startEditing(moveTo.valueElement);
   1287                 return;
   1288             }
   1289 
   1290             // User has made a change then tabbed, wiping all the original treeElements,
   1291             // recalculate the new treeElement for the same property we were going to edit next
   1292             if (moveTo && !moveTo.parent) {
   1293                 var treeElement = section.findTreeElementWithName(moveToPropertyName);
   1294                 if (treeElement)
   1295                     treeElement.startEditing(treeElement.valueElement);
   1296                 return;
   1297             }
   1298 
   1299             // Create a new attribute in this section
   1300             if (newProperty) {
   1301                 if (alreadyNew && !valueChanged)
   1302                     return;
   1303 
   1304                 section.addNewBlankProperty().startEditing();
   1305                 return;
   1306             }
   1307 
   1308             if (moveToSelector)
   1309                 section.startEditingSelector();
   1310         }
   1311     },
   1312 
   1313     applyStyleText: function(styleText, updateInterface)
   1314     {
   1315         var section = this.treeOutline.section;
   1316         var elementsPanel = WebInspector.panels.elements;
   1317         var styleTextLength = styleText.trim().length;
   1318         if (!styleTextLength && updateInterface) {
   1319             if (this._newProperty) {
   1320                 // The user deleted everything, so remove the tree element and update.
   1321                 this.parent.removeChild(this);
   1322                 section.afterUpdate();
   1323                 return;
   1324             } else {
   1325                 delete section._afterUpdate;
   1326             }
   1327         }
   1328 
   1329         var self = this;
   1330         function callback(result)
   1331         {
   1332             if (!result) {
   1333                 // The user typed something, but it didn't parse. Just abort and restore
   1334                 // the original title for this property.  If this was a new attribute and
   1335                 // we couldn't parse, then just remove it.
   1336                 if (self._newProperty) {
   1337                     self.parent.removeChild(self);
   1338                     return;
   1339                 }
   1340                 if (updateInterface)
   1341                     self.updateTitle();
   1342                 return;
   1343             }
   1344 
   1345             var newPayload = result[0];
   1346             var changedProperties = result[1];
   1347             elementsPanel.removeStyleChange(section.identifier, self.style, self.name);
   1348 
   1349             if (!styleTextLength) {
   1350                 // Do remove ourselves from UI when the property removal is confirmed.
   1351                 self.parent.removeChild(self);
   1352             } else {
   1353                 self.style = WebInspector.CSSStyleDeclaration.parseStyle(newPayload);
   1354                 for (var i = 0; i < changedProperties.length; ++i)
   1355                     elementsPanel.addStyleChange(section.identifier, self.style, changedProperties[i]);
   1356                 self._styleRule.style = self.style;
   1357             }
   1358 
   1359             if (section && section.pane)
   1360                 section.pane.dispatchEventToListeners("style edited");
   1361 
   1362             if (updateInterface)
   1363                 self.updateAll(true);
   1364 
   1365             if (!section.rule)
   1366                 WebInspector.panels.elements.treeOutline.update();
   1367         }
   1368 
   1369         InjectedScriptAccess.get(this.style.injectedScriptId).applyStyleText(this.style.id, styleText.trim(), this.name, callback);
   1370     }
   1371 }
   1372 
   1373 WebInspector.StylePropertyTreeElement.prototype.__proto__ = TreeElement.prototype;
   1374