Changeset 27575 in webkit


Ignore:
Timestamp:
Nov 7, 2007 9:56:16 AM (16 years ago)
Author:
timothy@apple.com
Message:

Reviewed by Adam.

Bug 11920: Web Inspector should have Firebug-like CSS editing
http://bugs.webkit.org/show_bug.cgi?id=11920

  • css/CSSComputedStyleDeclaration.h: (WebCore::CSSComputedStyleDeclaration::isPropertyImplicit): Return false. I'm not sure why this was true, but computed style has no concept of implicit. So false makes more sense and makes the code simpler in the inspector. This function was added for the inspector, so this isn't a compatibility change.
  • page/inspector/PropertiesSection.js: Add a getter/setter to reset populated status.
  • page/inspector/StylesSidebarPane.js: Some refactoring along with the main support for style editing.
  • page/inspector/inspector.css: Style changes for propery editing and focus correctness.
  • page/inspector/inspector.js: Look for a handleKeyEvent function of the focus element before trying to call a function based on the element's id. Call focused and blurred on the focused element when currentFocusElement is changed. Use the new listItemElement getter instead of the private property.
  • page/inspector/treeoutline.js: No longer expand on double click if ondblclick is implemented. Shrink the toggle zone to 10px to better match the size of the arrow. Add an onattach call to allow generation of the title using the DOM element. Add listItemElement and childrenListElement getters.
  • page/inspector/utilities.js: Add new helper prototype methods on CSSStyleDeclaration.
  • page/inspector/DocumentPanel.js: Use the new listItemElement getter instead of the private property. Also expand the DOM node on double click now that the TreeOutline dosen't do it.
  • page/inspector/Resource.js: Use the new listItemElement and childrenListElement getters instead of the private properties.
Location:
trunk/WebCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r27569 r27575  
     12007-11-06  Timothy Hatcher  <timothy@apple.com>
     2
     3        Reviewed by Adam.
     4
     5        Bug 11920: Web Inspector should have Firebug-like CSS editing
     6        http://bugs.webkit.org/show_bug.cgi?id=11920
     7
     8        * css/CSSComputedStyleDeclaration.h:
     9          (WebCore::CSSComputedStyleDeclaration::isPropertyImplicit): Return false. I'm not sure why
     10          this was true, but computed style has no concept of implicit. So false makes more sense
     11          and makes the code simpler in the inspector. This function was added for the inspector,
     12          so this isn't a compatibility change.
     13        * page/inspector/PropertiesSection.js: Add a getter/setter to reset populated status.
     14        * page/inspector/StylesSidebarPane.js: Some refactoring along with the main support for
     15          style editing.
     16        * page/inspector/inspector.css: Style changes for propery editing and focus correctness.
     17        * page/inspector/inspector.js: Look for a handleKeyEvent function of the focus element before
     18          trying to call a function based on the element's id. Call focused and blurred on the focused
     19          element when currentFocusElement is changed. Use the new listItemElement getter instead of
     20          the private property.
     21        * page/inspector/treeoutline.js: No longer expand on double click if ondblclick is implemented.
     22          Shrink the toggle zone to 10px to better match the size of the arrow. Add an onattach call
     23          to allow generation of the title using the DOM element. Add listItemElement and
     24          childrenListElement getters.
     25        * page/inspector/utilities.js: Add new helper prototype methods on CSSStyleDeclaration.
     26        * page/inspector/DocumentPanel.js: Use the new listItemElement getter instead of the private
     27          property. Also expand the DOM node on double click now that the TreeOutline dosen't do it.
     28        * page/inspector/Resource.js: Use the new listItemElement and childrenListElement getters
     29          instead of the private properties.
     30
    1312007-11-07  Simon Hausmann  <hausmann@kde.org>
    232
  • trunk/WebCore/css/CSSComputedStyleDeclaration.h

    r26522 r27575  
    4949    virtual bool getPropertyPriority(int propertyID) const;
    5050    virtual int getPropertyShorthand(int propertyID) const { return -1; }
    51     virtual bool isPropertyImplicit(int propertyID) const { return true; }
     51    virtual bool isPropertyImplicit(int propertyID) const { return false; }
    5252
    5353    virtual PassRefPtr<CSSMutableStyleDeclaration> copy() const;
  • trunk/WebCore/page/inspector/DocumentPanel.js

    r27431 r27575  
    397397    updateSelection: function()
    398398    {
    399         if (!this._listItemNode)
     399        var listItemElement = this.listItemElement;
     400        if (!listItemElement)
    400401            return;
    401402
     
    403404            this.selectionElement = document.createElement("div");
    404405            this.selectionElement.className = "selection selected";
    405             this._listItemNode.insertBefore(this.selectionElement, this._listItemNode.firstChild);
    406         }
    407 
    408         this.selectionElement.style.height = this._listItemNode.offsetHeight + "px";
     406            listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild);
     407        }
     408
     409        this.selectionElement.style.height = listItemElement.offsetHeight + "px";
    409410    },
    410411
     
    443444    onreveal: function()
    444445    {
    445         if (!this._listItemNode || !this.treeOutline || !this.treeOutline._childrenListNode)
    446             return;
    447         var parent = this.treeOutline.panel.views.dom.treeContentElement;
    448         parent.scrollToElement(this._listItemNode);
     446        if (!this.listItemElement || !this.treeOutline)
     447            return;
     448        this.treeOutline.panel.views.dom.treeContentElement.scrollToElement(this.listItemElement);
    449449    },
    450450
     
    466466        panel.rootDOMNode = this.representedObject.parentNode;
    467467        panel.focusedDOMNode = this.representedObject;
     468
     469        if (this.hasChildren && !this.expanded)
     470            this.expand();
    468471    }
    469472}
  • trunk/WebCore/page/inspector/PropertiesSection.js

    r27431 r27575  
    100100    },
    101101
     102    get populated()
     103    {
     104        return this._populated;
     105    },
     106
     107    set populated(x)
     108    {
     109        this._populated = x;
     110        if (!x && this.onpopulate && this._expanded) {
     111            this.onpopulate(this);
     112            this._populated = true;
     113        }
     114    },
     115
    102116    expand: function()
    103117    {
     
    105119            return;
    106120        this._expanded = true;
     121        this.element.addStyleClass("expanded");
    107122
    108123        if (!this._populated && this.onpopulate) {
     
    110125            this._populated = true;
    111126        }
    112         this.element.addStyleClass("expanded");
    113127    },
    114128
  • trunk/WebCore/page/inspector/Resource.js

    r26933 r27575  
    685685WebInspector.ResourceTreeElement.revealed = function(element)
    686686{
    687     if (!element._listItemNode || !element.treeOutline || !element.treeOutline._childrenListNode)
     687    if (!element.listItemElement || !element.treeOutline || !element.treeOutline.childrenListElement)
    688688        return;
    689     element.treeOutline._childrenListNode.scrollToElement(element._listItemNode);
     689    element.treeOutline.childrenListElement.scrollToElement(element.listItemElement);
    690690}
  • trunk/WebCore/page/inspector/StylesSidebarPane.js

    r27431 r27575  
    3333
    3434WebInspector.StylesSidebarPane.prototype = {
    35     update: function(node)
    36     {
     35    update: function(node, editedSection)
     36    {
     37        var refresh = false;
     38
     39        if (!node || node === this.node)
     40            refresh = true;
     41
     42        if (node && node.nodeType === Node.TEXT_NODE && node.parentNode)
     43            node = node.parentNode;
     44
     45        if (node && node.nodeType !== Node.ELEMENT_NODE)
     46            node = null;
     47
     48        if (node)
     49            this.node = node;
     50        else
     51            node = this.node;
     52
    3753        var body = this.bodyElement;
    38 
    39         body.removeChildren();
    40 
    41         this.sections = [];
     54        if (!refresh || !node) {
     55            body.removeChildren();
     56            this.sections = [];
     57        }
    4258
    4359        if (!node)
    4460            return;
    4561
    46         if (node.nodeType === Node.TEXT_NODE && node.parentNode)
    47             node = node.parentNode;
    48 
    4962        var styleRules = [];
    50         var styleProperties = [];
    51 
    52         if (node.nodeType === Node.ELEMENT_NODE) {
    53             var propertyCount = [];
    54 
     63
     64        if (refresh) {
     65            for (var i = 0; i < this.sections.length; ++i) {
     66                var section = this.sections[i];
     67                if (section.computedStyle)
     68                    section.styleRule.style = node.ownerDocument.defaultView.getComputedStyle(node);
     69                var styleRule = { section: section, style: section.styleRule.style, computedStyle: section.computedStyle };
     70                styleRules.push(styleRule);
     71            }
     72        } else {
    5573            var computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
    56             if (computedStyle && computedStyle.length)
    57                 styleRules.push({ computedStyle: true, selectorText: "Computed Style", style: computedStyle });
     74            styleRules.push({ computedStyle: true, selectorText: "Computed Style", style: computedStyle, editable: false });
    5875
    5976            var nodeName = node.nodeName.toLowerCase();
     
    6178                var attr = node.attributes[i];
    6279                if (attr.style) {
    63                     var attrStyle = { style: attr.style };
     80                    var attrStyle = { style: attr.style, editable: false };
    6481                    attrStyle.subtitle = "element\u2019s \u201C" + attr.name + "\u201D attribute";
    6582                    attrStyle.selectorText = nodeName + "[" + attr.name;
     
    83100                    styleRules.push(matchedStyleRules[i]);
    84101            }
    85 
    86             var usedProperties = {};
    87             var priorityUsed = false;
    88 
    89             // Walk the style rules and make a list of all used and overloaded properties.
    90             for (var i = 0; i < styleRules.length; ++i) {
     102        }
     103
     104        var usedProperties = {};
     105        var priorityUsed = false;
     106
     107        // Walk the style rules and make a list of all used and overloaded properties.
     108        for (var i = 0; i < styleRules.length; ++i) {
     109            var styleRule = styleRules[i];
     110            if (styleRule.computedStyle)
     111                continue;
     112
     113            styleRule.usedProperties = {};
     114
     115            var style = styleRule.style;
     116            for (var j = 0; j < style.length; ++j) {
     117                var name = style[j];
     118
     119                if (!priorityUsed && style.getPropertyPriority(name).length)
     120                    priorityUsed = true;
     121
     122                // If the property name is already used by another rule this is rule's
     123                // property is overloaded, so don't add it to the rule's usedProperties.
     124                if (!(name in usedProperties))
     125                    styleRule.usedProperties[name] = true;
     126
     127                if (name === "font") {
     128                    // The font property is not reported as a shorthand. Report finding the individual
     129                    // properties so they are visible in computed style.
     130                    // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15598 is fixed.
     131                    styleRule.usedProperties["font-family"] = true;
     132                    styleRule.usedProperties["font-size"] = true;
     133                    styleRule.usedProperties["font-style"] = true;
     134                    styleRule.usedProperties["font-variant"] = true;
     135                    styleRule.usedProperties["font-weight"] = true;
     136                    styleRule.usedProperties["line-height"] = true;
     137                }
     138            }
     139
     140            // Add all the properties found in this style to the used properties list.
     141            // Do this here so only future rules are affect by properties used in this rule.
     142            for (var name in styleRules[i].usedProperties)
     143                usedProperties[name] = true;
     144        }
     145
     146        if (priorityUsed) {
     147            // Walk the properties again and account for !important.
     148            var foundPriorityProperties = [];
     149
     150            // Walk in reverse to match the order !important overrides.
     151            for (var i = (styleRules.length - 1); i >= 0; --i) {
    91152                if (styleRules[i].computedStyle)
    92153                    continue;
    93154
    94                 styleRules[i].overloadedProperties = {};
    95 
    96155                var foundProperties = {};
    97 
    98156                var style = styleRules[i].style;
    99157                for (var j = 0; j < style.length; ++j) {
    100158                    var name = style[j];
    101                     var shorthand = style.getPropertyShorthand(name);
    102                     var overloaded = (name in usedProperties);
    103 
    104                     if (!priorityUsed && style.getPropertyPriority(name).length)
    105                         priorityUsed = true;
    106 
    107                     if (overloaded)
    108                         styleRules[i].overloadedProperties[name] = true;
     159
     160                    // Skip duplicate properties in the same rule.
     161                    if (name in foundProperties)
     162                        continue;
    109163
    110164                    foundProperties[name] = true;
    111                     if (shorthand)
    112                         foundProperties[shorthand] = true;
    113 
    114                     if (name === "font") {
    115                         // The font property is not reported as a shorthand. Report finding the individual
    116                         // properties so they are visible in computed style.
    117                         // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15598 is fixed.
    118                         foundProperties["font-family"] = true;
    119                         foundProperties["font-size"] = true;
    120                         foundProperties["font-style"] = true;
    121                         foundProperties["font-variant"] = true;
    122                         foundProperties["font-weight"] = true;
    123                         foundProperties["line-height"] = true;
    124                     }
     165
     166                    if (style.getPropertyPriority(name).length) {
     167                        if (!(name in foundPriorityProperties))
     168                            styleRules[i].usedProperties[name] = true;
     169                        else
     170                            delete styleRules[i].usedProperties[name];
     171                        foundPriorityProperties[name] = true;
     172                    } else if (name in foundPriorityProperties)
     173                        delete styleRules[i].usedProperties[name];
    125174                }
    126 
    127                 // Add all the properties found in this style to the used properties list.
    128                 // Do this here so only future rules are affect by properties used in this rule.
    129                 for (var name in foundProperties)
    130                     usedProperties[name] = true;
    131             }
    132 
    133             if (priorityUsed) {
    134                 // Walk the properties again and account for !important.
    135                 var foundPriorityProperties = [];
    136 
    137                 // Walk in reverse to match the order !important overrides.
    138                 for (var i = (styleRules.length - 1); i >= 0; --i) {
    139                     if (styleRules[i].computedStyle)
    140                         continue;
    141 
    142                     var foundProperties = {};
    143                     var style = styleRules[i].style;
    144                     for (var j = 0; j < style.length; ++j) {
    145                         var name = style[j];
    146 
    147                         // Skip duplicate properties in the same rule.
    148                         if (name in foundProperties)
    149                             continue;
    150 
    151                         foundProperties[name] = true;
    152 
    153                         if (style.getPropertyPriority(name).length) {
    154                             if (!(name in foundPriorityProperties))
    155                                 delete styleRules[i].overloadedProperties[name];
    156                             else
    157                                 styleRules[i].overloadedProperties[name] = true;
    158                             foundPriorityProperties[name] = true;
    159                         } else if (name in foundPriorityProperties)
    160                             styleRules[i].overloadedProperties[name] = true;
    161                     }
    162                 }
    163             }
    164 
     175            }
     176        }
     177
     178        if (refresh) {
     179            // Walk the style rules and update the sections with new overloaded and used properties.
     180            for (var i = 0; i < styleRules.length; ++i) {
     181                var styleRule = styleRules[i];
     182                var section = styleRule.section;
     183                section._usedProperties = (styleRule.usedProperties || usedProperties);
     184                section.update((section === editedSection) || styleRule.computedStyle);
     185            }
     186        } else {
    165187            // Make a property section for each style rule.
    166             var styleRulesLength = styleRules.length;
    167             for (var i = 0; i < styleRulesLength; ++i) {
     188            for (var i = 0; i < styleRules.length; ++i) {
    168189                var styleRule = styleRules[i];
    169190                var subtitle = styleRule.subtitle;
     
    173194                delete styleRule.computedStyle;
    174195
    175                 var overloadedProperties = styleRule.overloadedProperties;
    176                 delete styleRule.overloadedProperties;
    177 
    178                 var section = new WebInspector.StylePropertiesSection(styleRule, subtitle, computedStyle, (overloadedProperties || usedProperties));
     196                var ruleUsedProperties = styleRule.usedProperties;
     197                delete styleRule.usedProperties;
     198
     199                var editable = styleRule.editable;
     200                delete styleRule.editable;
     201
     202                // Default editable to true if it was omitted.
     203                if (typeof editable === "undefined")
     204                    editable = true;
     205
     206                var section = new WebInspector.StylePropertiesSection(styleRule, subtitle, computedStyle, (ruleUsedProperties || usedProperties), editable);
    179207                section.expanded = true;
     208                section.pane = this;
    180209
    181210                body.appendChild(section.element);
    182211                this.sections.push(section);
    183212            }
    184         } else {
    185             // can't style this node
    186213        }
    187214    }
     
    190217WebInspector.StylesSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
    191218
    192 WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyle, overloadedOrUsedProperties)
     219WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyle, usedProperties, editable)
    193220{
    194221    WebInspector.PropertiesSection.call(this, styleRule.selectorText);
     
    196223    this.styleRule = styleRule;
    197224    this.computedStyle = computedStyle;
    198 
    199     if (computedStyle)
    200         this.usedProperties = overloadedOrUsedProperties;
    201     else
    202         this.overloadedProperties = overloadedOrUsedProperties || {};
     225    this.editable = (editable && !computedStyle);
     226
     227    // Prevent editing the user agent rules.
     228    if (this.styleRule.parentStyleSheet && !this.styleRule.parentStyleSheet.ownerNode)
     229        this.editable = false;
     230
     231    this._usedProperties = usedProperties;
    203232
    204233    if (computedStyle) {
     
    243272
    244273WebInspector.StylePropertiesSection.prototype = {
     274    get usedProperties()
     275    {
     276        return this._usedProperties || {};
     277    },
     278
     279    set usedProperties(x)
     280    {
     281        this._usedProperties = x;
     282        this.update();
     283    },
     284
     285    isPropertyInherited: function(property)
     286    {
     287        if (!this.computedStyle || !this._usedProperties)
     288            return false;
     289        // These properties should always show for Computed Style.
     290        var alwaysShowComputedProperties = { "display": true, "height": true, "width": true };
     291        return !(property in this.usedProperties) && !(property in alwaysShowComputedProperties);
     292    },
     293
     294    isPropertyOverloaded: function(property, shorthand)
     295    {
     296        if (this.computedStyle || !this._usedProperties)
     297            return false;
     298
     299        var used = (property in this.usedProperties);
     300        if (used || !shorthand)
     301            return !used;
     302
     303        // Find out if any of the individual longhand properties of the shorthand
     304        // are used, if none are then the shorthand is overloaded too.
     305        var longhandProperties = this.styleRule.style.getLonghandProperties(property);
     306        for (var j = 0; j < longhandProperties.length; ++j) {
     307            var individualProperty = longhandProperties[j];
     308            if (individualProperty in this.usedProperties)
     309                return false;
     310        }
     311
     312        return true;
     313    },
     314
     315    update: function(full)
     316    {
     317        if (full || this.computedStyle) {
     318            this.propertiesTreeOutline.removeChildren();
     319            this.populated = false;
     320        } else {
     321            var child = this.propertiesTreeOutline.children[0];
     322            while (child) {
     323                child.overloaded = this.isPropertyOverloaded(child.name, child.shorthand);
     324                child = child.traverseNextTreeElement(false, null, true);
     325            }
     326        }
     327    },
     328
    245329    onpopulate: function()
    246330    {
     
    249333            return;
    250334
    251         var foundProperties = {};
    252 
    253         // Add properties in reverse order to better match how the style
    254         // system picks the winning value for duplicate properties.
    255         for (var i = (style.length - 1); i >= 0; --i) {
    256             var name = style[i];
     335        var foundShorthands = {};
     336        var uniqueProperties = style.getUniqueProperties();
     337        uniqueProperties.sort();
     338
     339        for (var i = 0; i < uniqueProperties.length; ++i) {
     340            var name = uniqueProperties[i];
    257341            var shorthand = style.getPropertyShorthand(name);
    258342
    259             if (name in foundProperties || (shorthand && shorthand in foundProperties))
     343            if (shorthand && shorthand in foundShorthands)
    260344                continue;
    261345
    262             foundProperties[name] = true;
    263             if (shorthand)
    264                 foundProperties[shorthand] = true;
    265 
    266             if (this.computedStyle)
    267                 var inherited = (this.usedProperties && !((shorthand || name) in this.usedProperties));
    268             else {
    269                 var overloaded = ((shorthand || name) in this.overloadedProperties);
    270 
    271                 if (shorthand && !overloaded) {
    272                     // Find out if all the individual properties of a shorthand
    273                     // are overloaded and mark the shorthand as overloaded too.
    274 
    275                     var count = 0;
    276                     var overloadCount = 0;
    277                     for (var j = 0; j < style.length; ++j) {
    278                         var individualProperty = style[j];
    279                         if (style.getPropertyShorthand(individualProperty) !== shorthand)
    280                             continue;
    281                         ++count;
    282                         if (individualProperty in this.overloadedProperties)
    283                             ++overloadCount;
    284                     }
    285 
    286                     overloaded = (overloadCount >= count);
    287                 }
    288             }
    289 
    290             var item = new WebInspector.StylePropertyTreeElement(style, (shorthand || name), this.computedStyle, (shorthand ? true : false), (overloaded || inherited));
    291             this.propertiesTreeOutline.insertChild(item, 0);
     346            if (shorthand) {
     347                foundShorthands[shorthand] = true;
     348                name = shorthand;
     349            }
     350
     351            var isShorthand = (shorthand ? true : false);
     352            var inherited = this.isPropertyInherited(name);
     353            var overloaded = this.isPropertyOverloaded(name, isShorthand);
     354
     355            var item = new WebInspector.StylePropertyTreeElement(style, name, isShorthand, inherited, overloaded);
     356            this.propertiesTreeOutline.appendChild(item);
    292357        }
    293358    }
     
    296361WebInspector.StylePropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype;
    297362
    298 WebInspector.StylePropertyTreeElement = function(style, name, computedStyle, shorthand, overloadedOrInherited)
     363WebInspector.StylePropertyTreeElement = function(style, name, shorthand, inherited, overloaded)
    299364{
    300     // These properties should always show for Computed Style
    301     var alwaysShowComputedProperties = { "display": true, "height": true, "width": true };
    302 
    303     // "Nicknames" for some common values that are easier to read.
    304     var valueNicknames = {
    305         "rgb(0, 0, 0)": "black",
    306         "#000": "black",
    307         "#000000": "black",
    308         "rgb(255, 255, 255)": "white",
    309         "#fff": "white",
    310         "#ffffff": "white",
    311         "#FFF": "white",
    312         "#FFFFFF": "white",
    313         "rgba(0, 0, 0, 0)": "transparent",
    314         "rgb(255, 0, 0)": "red",
    315         "rgb(0, 255, 0)": "lime",
    316         "rgb(0, 0, 255)": "blue",
    317         "rgb(255, 255, 0)": "yellow",
    318         "rgb(255, 0, 255)": "magenta",
    319         "rgb(0, 255, 255)": "cyan"
    320     };
    321 
    322365    this.style = style;
    323366    this.name = name;
    324     this.computedStyle = computedStyle;
    325367    this.shorthand = shorthand;
    326     this.overloaded = (!computedStyle && overloadedOrInherited);
    327     this.inherited = (computedStyle && overloadedOrInherited && !(name in alwaysShowComputedProperties));
    328 
    329     var priority = style.getPropertyPriority(name);
    330     var value = style.getPropertyValue(name);
    331     var htmlValue = value;
    332 
    333     if (priority && !priority.length)
    334         delete priority;
    335 
    336     if (!priority && shorthand) {
    337         // Priority is not returned for shorthands, find the priority from an individual property.
    338         for (var i = 0; i < style.length; ++i) {
    339             var individualProperty = style[i];
    340             if (style.getPropertyShorthand(individualProperty) !== name)
    341                 continue;
    342             priority = style.getPropertyPriority(individualProperty);
    343             break;
    344         }
    345     }
    346 
    347     if (value) {
    348         var urls = value.match(/url\([^)]+\)/);
    349         if (urls) {
    350             for (var i = 0; i < urls.length; ++i) {
    351                 var url = urls[i].substring(4, urls[i].length - 1);
    352                 htmlValue = htmlValue.replace(urls[i], "url(" + WebInspector.linkifyURL(url) + ")");
    353             }
    354         } else {
    355             if (value in valueNicknames)
    356                 htmlValue = valueNicknames[value];
    357             htmlValue = htmlValue.escapeHTML();
    358         }
    359     } else if (shorthand) {
    360         // Some shorthands (like border) return a null value, so compute a shorthand value.
    361         // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15823 is fixed.
    362 
    363         value = "";
    364 
    365         var foundProperties = {};
    366         for (var i = 0; i < style.length; ++i) {
    367             var individualProperty = style[i];
    368             if (style.getPropertyShorthand(individualProperty) !== name || individualProperty in foundProperties)
    369                 continue;
    370 
    371             var individualValue = style.getPropertyValue(individualProperty);
    372             if (style.isPropertyImplicit(individualProperty) || individualValue === "initial")
    373                 continue;
    374 
    375             foundProperties[individualProperty] = true;
    376 
    377             if (value.length)
    378                 value += " ";
    379             value += individualValue;
    380         }
    381 
    382         htmlValue = value.escapeHTML();
    383     } else
    384         htmlValue = value = "";
    385 
    386     var classes = [];
    387     if (!computedStyle && (style.isPropertyImplicit(name) || value === "initial"))
    388         classes.push("implicit");
    389     if (this.inherited)
    390         classes.push("inherited");
    391     if (this.overloaded)
    392         classes.push("overloaded");
    393 
    394     var title = "";
    395     if (classes.length)
    396         title += "<span class=\"" + classes.join(" ") + "\">";
    397 
    398     title += "<span class=\"name\">" + name.escapeHTML() + "</span>: ";
    399     title += "<span class=\"value\">" + htmlValue;
    400     if (priority)
    401         title += " !" + priority;
    402     title += "</span>;";
    403 
    404     if (value) {
    405         // FIXME: this dosen't catch keyword based colors like black and white
    406         var colors = value.match(/((rgb|hsl)a?\([^)]+\))|(#[0-9a-fA-F]{6})|(#[0-9a-fA-F]{3})/g);
    407         if (colors) {
    408             var colorsLength = colors.length;
    409             for (var i = 0; i < colorsLength; ++i)
    410                 title += "<span class=\"swatch\" style=\"background-color: " + colors[i] + "\"></span>";
    411         }
    412     }
    413 
    414     if (classes.length)
    415         title += "</span>";
    416 
    417     TreeElement.call(this, title, null, shorthand);
    418 
    419     this.tooltip = name + ": " + (valueNicknames[value] || value) + (priority ? " !" + priority : "");
     368    this._inherited = inherited;
     369    this._overloaded = overloaded;
     370
     371    // Pass an empty title, the title gets made later in onattach.
     372    TreeElement.call(this, "", null, shorthand);
    420373}
    421374
    422375WebInspector.StylePropertyTreeElement.prototype = {
     376    get inherited()
     377    {
     378        return this._inherited;
     379    },
     380
     381    set inherited(x)
     382    {
     383        if (x === this._inherited)
     384            return;
     385        this._inherited = x;
     386        this.updateState();
     387    },
     388
     389    get overloaded()
     390    {
     391        return this._overloaded;
     392    },
     393
     394    set overloaded(x)
     395    {
     396        if (x === this._overloaded)
     397            return;
     398        this._overloaded = x;
     399        this.updateState();
     400    },
     401
     402    onattach: function()
     403    {
     404        this.updateTitle();
     405    },
     406
     407    updateTitle: function()
     408    {
     409        // "Nicknames" for some common values that are easier to read.
     410        var valueNicknames = {
     411            "rgb(0, 0, 0)": "black",
     412            "#000": "black",
     413            "#000000": "black",
     414            "rgb(255, 255, 255)": "white",
     415            "#fff": "white",
     416            "#ffffff": "white",
     417            "#FFF": "white",
     418            "#FFFFFF": "white",
     419            "rgba(0, 0, 0, 0)": "transparent",
     420            "rgb(255, 0, 0)": "red",
     421            "rgb(0, 255, 0)": "lime",
     422            "rgb(0, 0, 255)": "blue",
     423            "rgb(255, 255, 0)": "yellow",
     424            "rgb(255, 0, 255)": "magenta",
     425            "rgb(0, 255, 255)": "cyan"
     426        };
     427
     428        var priority = (this.shorthand ? this.style.getShorthandPriority(this.name) : this.style.getPropertyPriority(this.name));
     429        var value = (this.shorthand ? this.style.getShorthandValue(this.name) : this.style.getPropertyValue(this.name));
     430        var htmlValue = value;
     431
     432        if (priority && !priority.length)
     433            delete priority;
     434        if (priority)
     435            priority = "!" + priority;
     436
     437        if (value) {
     438            var urls = value.match(/url\([^)]+\)/);
     439            if (urls) {
     440                for (var i = 0; i < urls.length; ++i) {
     441                    var url = urls[i].substring(4, urls[i].length - 1);
     442                    htmlValue = htmlValue.replace(urls[i], "url(" + WebInspector.linkifyURL(url) + ")");
     443                }
     444            } else {
     445                if (value in valueNicknames)
     446                    htmlValue = valueNicknames[value];
     447                htmlValue = htmlValue.escapeHTML();
     448            }
     449        } else
     450            htmlValue = value = "";
     451
     452        this.updateState();
     453
     454        var nameElement = document.createElement("span");
     455        nameElement.className = "name";
     456        nameElement.textContent = this.name;
     457
     458        var valueElement = document.createElement("span");
     459        valueElement.className = "value";
     460        valueElement.innerHTML = htmlValue;
     461
     462        if (priority) {
     463            var priorityElement = document.createElement("span");
     464            priorityElement.className = "priority";
     465            priorityElement.textContent = priority;
     466        }
     467
     468        this.listItemElement.removeChildren();
     469
     470        this.listItemElement.appendChild(nameElement);
     471        this.listItemElement.appendChild(document.createTextNode(": "));
     472        this.listItemElement.appendChild(valueElement);
     473
     474        if (priorityElement) {
     475            this.listItemElement.appendChild(document.createTextNode(" "));
     476            this.listItemElement.appendChild(priorityElement);
     477        }
     478
     479        this.listItemElement.appendChild(document.createTextNode(";"));
     480
     481        if (value) {
     482            // FIXME: this dosen't catch keyword based colors like black and white
     483            var colors = value.match(/((rgb|hsl)a?\([^)]+\))|(#[0-9a-fA-F]{6})|(#[0-9a-fA-F]{3})/g);
     484            if (colors) {
     485                var colorsLength = colors.length;
     486                for (var i = 0; i < colorsLength; ++i) {
     487                    var swatchElement = document.createElement("span");
     488                    swatchElement.className = "swatch";
     489                    swatchElement.style.setProperty("background-color", colors[i]);
     490                    this.listItemElement.appendChild(swatchElement);
     491                }
     492            }
     493        }
     494
     495        this.tooltip = this.name + ": " + (valueNicknames[value] || value) + (priority ? " " + priority : "");
     496    },
     497
     498    updateState: function()
     499    {
     500        if (!this.listItemElement)
     501            return;
     502
     503        var value = (this.shorthand ? this.style.getShorthandValue(this.name) : this.style.getPropertyValue(this.name));
     504        if (this.style.isPropertyImplicit(this.name) || value === "initial")
     505            this.listItemElement.addStyleClass("implicit");
     506        else
     507            this.listItemElement.removeStyleClass("implicit");
     508
     509        if (this.inherited)
     510            this.listItemElement.addStyleClass("inherited");
     511        else
     512            this.listItemElement.removeStyleClass("inherited");
     513
     514        if (this.overloaded)
     515            this.listItemElement.addStyleClass("overloaded");
     516        else
     517            this.listItemElement.removeStyleClass("overloaded");
     518    },
     519
    423520    onpopulate: function()
    424521    {
     
    427524            return;
    428525
    429         var foundProperties = {};
    430 
    431         // Add properties in reverse order to better match how the style
    432         // system picks the winning value for duplicate properties.
    433         for (var i = (this.style.length - 1); i >= 0; --i) {
    434             var name = this.style[i];
    435             var shorthand = this.style.getPropertyShorthand(name);
    436 
    437             if (shorthand !== this.name || name in foundProperties)
    438                 continue;
    439 
    440             foundProperties[name] = true;
    441 
    442             if (this.computedStyle)
    443                 var inherited = (this.treeOutline.section.usedProperties && !(name in this.treeOutline.section.usedProperties));
     526        var longhandProperties = this.style.getLonghandProperties(this.name);
     527        for (var i = 0; i < longhandProperties.length; ++i) {
     528            var name = longhandProperties[i];
     529
     530            if (this.treeOutline.section) {
     531                var inherited = this.treeOutline.section.isPropertyInherited(name);
     532                var overloaded = this.treeOutline.section.isPropertyOverloaded(name);
     533            }
     534
     535            var item = new WebInspector.StylePropertyTreeElement(this.style, name, false, inherited, overloaded);
     536            this.appendChild(item);
     537        }
     538    },
     539
     540    ondblclick: function(element, event)
     541    {
     542        this.startEditing(event.target);
     543    },
     544
     545    startEditing: function(selectElement)
     546    {
     547        // FIXME: we don't allow editing of longhand properties under a shorthand right now.
     548        if (this.parent.shorthand)
     549            return;
     550
     551        if (this.editing || (this.treeOutline.section && !this.treeOutline.section.editable))
     552            return;
     553
     554        this.editing = true;
     555        this.previousTextContent = this.listItemElement.textContent;
     556
     557        this.listItemElement.addStyleClass("focusable");
     558        this.listItemElement.addStyleClass("editing");
     559        this.wasExpanded = this.expanded;
     560        this.collapse();
     561        // Lie about out children to prevent toggling on click.
     562        this.hasChildren = false;
     563
     564        if (!selectElement)
     565            selectElement = this.listItemElement;
     566
     567        window.getSelection().setBaseAndExtent(selectElement, 0, selectElement, 1);
     568
     569        var treeElement = this;
     570        this.listItemElement.blurred = function() { treeElement.endEditing() };
     571        this.listItemElement.handleKeyEvent = function(event) {
     572            if (event.keyIdentifier === "Enter") {
     573                treeElement.endEditing();
     574                event.preventDefault();
     575            }
     576        };
     577
     578        this.previousFocusElement = WebInspector.currentFocusElement;
     579        WebInspector.currentFocusElement = this.listItemElement;
     580    },
     581
     582    endEditing: function()
     583    {
     584        // Revert the changes done in startEditing().
     585        delete this.listItemElement.blurred;
     586        delete this.listItemElement.handleKeyEvent;
     587
     588        WebInspector.currentFocusElement = this.previousFocusElement;
     589        delete this.previousFocusElement;
     590
     591        delete this.editing;
     592
     593        this.listItemElement.removeStyleClass("focusable");
     594        this.listItemElement.removeStyleClass("editing");
     595        this.hasChildren = (this.children.length ? true : false);
     596        if (this.wasExpanded) {
     597            delete this.wasExpanded;
     598            this.expand();
     599        }
     600
     601        var previousContent = this.previousTextContent;
     602        delete this.previousTextContent;
     603
     604        var userInput = this.listItemElement.textContent;
     605        if (userInput === previousContent)
     606            return; // nothing changed, so do nothing else
     607
     608        // Remove the original property from the real style declaration, if this represents
     609        // a shorthand remove all the longhand properties.
     610        if (this.shorthand) {
     611            var longhandProperties = this.style.getLonghandProperties(this.name);
     612            for (var i = 0; i < longhandProperties.length; ++i)
     613                this.style.removeProperty(longhandProperties[i]);
     614        } else
     615            this.style.removeProperty(this.name);
     616
     617        // Create a new element to parse the user input CSS.
     618        var parseElement = document.createElement("span");
     619        parseElement.setAttribute("style", userInput);
     620
     621        var userInputStyle = parseElement.style;
     622        if (userInputStyle.length) {
     623            // Iterate of the properties on the test element's style declaration and
     624            // add them to the real style declaration. We take care to move shorthands.
     625
     626            var foundShorthands = {};
     627            var uniqueProperties = userInputStyle.getUniqueProperties();
     628
     629            for (var i = 0; i < uniqueProperties.length; ++i) {
     630                var name = uniqueProperties[i];
     631                var shorthand = userInputStyle.getPropertyShorthand(name);
     632
     633                if (shorthand && shorthand in foundShorthands)
     634                    continue;
     635
     636                if (shorthand) {
     637                    var value = userInputStyle.getShorthandValue(shorthand);
     638                    var priority = userInputStyle.getShorthandPriority(shorthand);
     639                    foundShorthands[shorthand] = true;
     640                } else {
     641                    var value = userInputStyle.getPropertyValue(name);
     642                    var priority = userInputStyle.getPropertyPriority(name);
     643                }
     644
     645                // Set the property on the real style declaration.
     646                this.style.setProperty((shorthand || name), value, priority);
     647            }
     648
     649            if (this.treeOutline.section && this.treeOutline.section.pane)
     650                this.treeOutline.section.pane.update(null, this.treeOutline.section);
     651            else if (this.treeOutline.section)
     652                this.treeOutline.section.update(true);
    444653            else
    445                 var overloaded = (name in this.treeOutline.section.overloadedProperties);
    446 
    447             var item = new WebInspector.StylePropertyTreeElement(this.style, name, this.computedStyle, false, (inherited || overloaded));
    448             this.insertChild(item, 0);
     654                this.updateTitle(); // FIXME: this will not show new properties. But we don't hit his case yet.
     655        } else {
     656            if (this.treeOutline.section && this.treeOutline.section.pane)
     657                this.treeOutline.section.pane.update();
     658            this.parent.removeChild(this);
    449659        }
    450660    }
  • trunk/WebCore/page/inspector/inspector.css

    r27371 r27575  
    10221022}
    10231023
    1024 .focused .content.tree li.selected * {
     1024body:not(.inactive) .focused .content.tree li.selected * {
    10251025    color: inherit;
    10261026}
     
    11041104    overflow: hidden;
    11051105    -webkit-user-select: text;
     1106    outline: none;
    11061107}
    11071108
     
    11401141}
    11411142
     1143.section .properties li.editing {
     1144    -webkit-box-shadow: rgba(0, 0, 0, .5) 3px 3px 4px;
     1145    outline: 1px solid rgb(66%, 66%, 66%);
     1146    background-color: white;
     1147    -webkit-user-modify: read-write-plaintext-only;
     1148    text-overflow: clip;
     1149    margin-left: 8px;
     1150    padding-left: 2px;
     1151    margin-bottom: -1px;
     1152    padding-bottom: 1px;
     1153    text-decoration: none !important;
     1154    opacity: 1.0 !important;
     1155}
     1156
     1157.section .properties li.editing.parent::before {
     1158    display: none;
     1159}
     1160
     1161.section .properties li.editing * {
     1162    color: black !important;
     1163}
     1164
    11421165.section .properties .overloaded {
    11431166    text-decoration: line-through;
    11441167}
    11451168
    1146 .section .properties .implicit {
     1169.section .properties .implicit, .section .properties .inherited {
    11471170    opacity: 0.5;
    11481171}
    11491172
    1150 .section .properties .inherited {
     1173.section:not(.show-inherited) .properties .inherited {
    11511174    display: none;
    1152     opacity: 0.5;
    1153 }
    1154 
    1155 .section.show-inherited .properties .inherited {
    1156     display: inline;
    11571175}
    11581176
     
    11631181.section .properties .number {
    11641182    color: blue;
     1183}
     1184
     1185.section .properties .priority {
     1186    color: rgb(128, 0, 0);
    11651187}
    11661188
  • trunk/WebCore/page/inspector/inspector.js

    r27266 r27575  
    8989            this._currentFocusElement.removeStyleClass("focused");
    9090            this._currentFocusElement.addStyleClass("blurred");
     91            if (this._currentFocusElement.blurred)
     92                this._currentFocusElement.blurred();
    9193        }
    9294
     
    9698            x.addStyleClass("focused");
    9799            x.removeStyleClass("blurred");
     100            if (this._currentFocusElement.focused)
     101                this._currentFocusElement.focused();
    98102        }
    99103    },
     
    320324WebInspector.documentKeypress = function(event)
    321325{
    322     if (!this.currentFocusElement || !this.currentFocusElement.id || !this.currentFocusElement.id.length)
     326    if (!this.currentFocusElement)
    323327        return;
    324     if (this.currentFocusElement.id + "Keypress" in WebInspector)
     328    if (this.currentFocusElement.handleKeyEvent)
     329        this.currentFocusElement.handleKeyEvent(event);
     330    else if (this.currentFocusElement.id && this.currentFocusElement.id.length && WebInspector[this.currentFocusElement.id + "Keypress"])
    325331        WebInspector[this.currentFocusElement.id + "Keypress"](event);
    326332}
     
    392398            else if (key === "start")
    393399                start = animation[key];
    394             else if (key == "current")
     400            else if (key === "current")
    395401                current = animation[key];
    396402            else if (key === "end")
     
    816822        WebInspector.navigateToPanel(element.representedObject.panel, "source");
    817823        element.representedObject.line.scrollIntoView(true);
    818         resultsContainer.scrollToElement(element._listItemNode);
     824        resultsContainer.scrollToElement(element.listItemElement);
    819825    }
    820826
     
    823829        WebInspector.navigateToPanel(element.representedObject.panel, "dom");
    824830        element.representedObject.panel.focusedDOMNode = element.representedObject.node;
    825         resultsContainer.scrollToElement(element._listItemNode);
     831        resultsContainer.scrollToElement(element.listItemElement);
    826832    }
    827833
  • trunk/WebCore/page/inspector/treeoutline.js

    r27431 r27575  
    402402
    403403TreeElement.prototype = {
     404    get listItemElement() {
     405        return this._listItemNode;
     406    },
     407
     408    get childrenListElement() {
     409        return this._childrenListNode;
     410    },
     411
    404412    get title() {
    405413        return this._title;
     
    475483        this._listItemNode.addEventListener("click", TreeElement.treeElementToggled, false);
    476484        this._listItemNode.addEventListener("dblclick", TreeElement.treeElementDoubleClicked, false);
     485
     486        if (this.onattach)
     487            this.onattach(this);
    477488    }
    478489
     
    500511        return;
    501512
    502     if (event.offsetX > 20 || !element.treeElement.hasChildren)
     513    if (event.offsetX > 10 || !element.treeElement.hasChildren)
    503514        element.treeElement.select();
    504515}
     
    510521        return;
    511522
    512     if (event.offsetX <= 20 && element.treeElement.hasChildren) {
     523    if (event.offsetX <= 10 && element.treeElement.hasChildren) {
    513524        if (element.treeElement.expanded) {
    514525            if (event.altKey)
     
    531542        return;
    532543
    533     if (element.treeElement.hasChildren && !element.treeElement.expanded)
     544    if (element.treeElement.ondblclick)
     545        element.treeElement.ondblclick(element.treeElement, event);
     546    else if (element.treeElement.hasChildren && !element.treeElement.expanded)
    534547        element.treeElement.expand();
    535 
    536     if (element.treeElement.ondblclick)
    537         element.treeElement.ondblclick(element.treeElement);
    538548}
    539549
     
    582592            this.onpopulate(this);
    583593
    584         for (var i = 0; i < this.children.length; ++i) {
    585             var child = this.children[i];
    586             child._attach();
    587         }
     594        for (var i = 0; i < this.children.length; ++i)
     595            this.children[i]._attach();
    588596
    589597        delete this.refreshChildren;
  • trunk/WebCore/page/inspector/utilities.js

    r26922 r27575  
    243243        result = result.replace(new RegExp("^" + baseURLDomain.escapeForRegExp(), "i"), "");
    244244    return result;
     245}
     246
     247CSSStyleDeclaration.prototype.getShorthandValue = function(shorthandProperty)
     248{
     249    var value = this.getPropertyValue(shorthandProperty);
     250    if (!value) {
     251        // Some shorthands (like border) return a null value, so compute a shorthand value.
     252        // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15823 is fixed.
     253
     254        var foundProperties = {};
     255        for (var i = 0; i < this.length; ++i) {
     256            var individualProperty = this[i];
     257            if (individualProperty in foundProperties || this.getPropertyShorthand(individualProperty) !== shorthandProperty)
     258                continue;
     259
     260            var individualValue = this.getPropertyValue(individualProperty);
     261            if (this.isPropertyImplicit(individualProperty) || individualValue === "initial")
     262                continue;
     263
     264            foundProperties[individualProperty] = true;
     265
     266            if (!value)
     267                value = "";
     268            else if (value.length)
     269                value += " ";
     270            value += individualValue;
     271        }
     272    }
     273    return value;
     274}
     275
     276CSSStyleDeclaration.prototype.getShorthandPriority = function(shorthandProperty)
     277{
     278    var priority = this.getPropertyPriority(shorthandProperty);
     279    if (!priority) {
     280        for (var i = 0; i < this.length; ++i) {
     281            var individualProperty = this[i];
     282            if (this.getPropertyShorthand(individualProperty) !== shorthandProperty)
     283                continue;
     284            priority = this.getPropertyPriority(individualProperty);
     285            break;
     286        }
     287    }
     288    return priority;
     289}
     290
     291CSSStyleDeclaration.prototype.getLonghandProperties = function(shorthandProperty)
     292{
     293    var properties = [];
     294    var foundProperties = {};
     295
     296    for (var i = 0; i < this.length; ++i) {
     297        var individualProperty = this[i];
     298        if (individualProperty in foundProperties || this.getPropertyShorthand(individualProperty) !== shorthandProperty)
     299            continue;
     300        foundProperties[individualProperty] = true;
     301        properties.push(individualProperty);
     302    }
     303
     304    return properties;
     305}
     306
     307CSSStyleDeclaration.prototype.getUniqueProperties = function()
     308{
     309    var properties = [];
     310    var foundProperties = {};
     311
     312    for (var i = 0; i < this.length; ++i) {
     313        var property = this[i];
     314        if (property in foundProperties)
     315            continue;
     316        foundProperties[property] = true;
     317        properties.push(property);
     318    }
     319
     320    return properties;
    245321}
    246322
Note: See TracChangeset for help on using the changeset viewer.