Changeset 46972 in webkit


Ignore:
Timestamp:
Aug 10, 2009 3:02:48 AM (15 years ago)
Author:
pfeldman@chromium.org
Message:

2009-08-10 Pavel Feldman <pfeldman@chromium.org>

Reviewed by Timothy Hatcher.

WebInspector: Make properties inspection serialized.

https://bugs.webkit.org/show_bug.cgi?id=28078

  • inspector/front-end/DOMAgent.js: (InspectorController.getPrototypes): (InspectorController.getProperties):
  • inspector/front-end/InjectedScript.js: (InjectedScript.getPrototypes): (InjectedScript.getProperties): (InjectedScript.setPropertyValue):
  • inspector/front-end/ObjectPropertiesSection.js: (WebInspector.ObjectRef): (WebInspector.ObjectPropertyRef): (WebInspector.ObjectPropertiesSection.prototype.onpopulate): (WebInspector.ObjectPropertiesSection.prototype.update.callback): (WebInspector.ObjectPropertiesSection.prototype.update): (WebInspector.ObjectPropertiesSection.prototype._update): (WebInspector.ObjectPropertyTreeElement.prototype.onpopulate.callback): (WebInspector.ObjectPropertyTreeElement.prototype.onpopulate): (WebInspector.ObjectPropertyTreeElement.prototype.onattach): (WebInspector.ObjectPropertyTreeElement.prototype.update):
  • inspector/front-end/PropertiesSidebarPane.js: (WebInspector.PropertiesSidebarPane.prototype.update.callback): (WebInspector.PropertiesSidebarPane.prototype.update):
Location:
trunk/WebCore
Files:
1 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r46969 r46972  
     12009-08-10  Pavel Feldman  <pfeldman@chromium.org>
     2
     3        Reviewed by Timothy Hatcher.
     4
     5        WebInspector: Make properties inspection serialized.
     6
     7        https://bugs.webkit.org/show_bug.cgi?id=28078
     8
     9        * inspector/front-end/DOMAgent.js:
     10        (InspectorController.getPrototypes):
     11        (InspectorController.getProperties):
     12        * inspector/front-end/InjectedScript.js:
     13        (InjectedScript.getPrototypes):
     14        (InjectedScript.getProperties):
     15        (InjectedScript.setPropertyValue):
     16        * inspector/front-end/ObjectPropertiesSection.js:
     17        (WebInspector.ObjectRef):
     18        (WebInspector.ObjectPropertyRef):
     19        (WebInspector.ObjectPropertiesSection.prototype.onpopulate):
     20        (WebInspector.ObjectPropertiesSection.prototype.update.callback):
     21        (WebInspector.ObjectPropertiesSection.prototype.update):
     22        (WebInspector.ObjectPropertiesSection.prototype._update):
     23        (WebInspector.ObjectPropertyTreeElement.prototype.onpopulate.callback):
     24        (WebInspector.ObjectPropertyTreeElement.prototype.onpopulate):
     25        (WebInspector.ObjectPropertyTreeElement.prototype.onattach):
     26        (WebInspector.ObjectPropertyTreeElement.prototype.update):
     27        * inspector/front-end/PropertiesSidebarPane.js:
     28        (WebInspector.PropertiesSidebarPane.prototype.update.callback):
     29        (WebInspector.PropertiesSidebarPane.prototype.update):
     30
    1312009-08-09  Nikolas Zimmermann  <nikolas.zimmermann@torchmobile.com>
    232
  • trunk/WebCore/WebCore.vcproj/WebCore.vcproj

    r46943 r46972  
    3088030880                                </File>
    3088130881                                <File
    30882                                         RelativePath="..\inspector\front-end\Console.js"
     30882                                        RelativePath="..\inspector\front-end\ChangesView.js"
     30883                                        >
     30884                                </File>
     30885                                <File
     30886                                        RelativePath="..\inspector\front-end\Color.js"
     30887                                        >
     30888                                </File>
     30889                                <File
     30890                                        RelativePath="..\inspector\front-end\ConsoleView.js"
    3088330891                                        >
    3088430892                                </File>
     
    3092030928                                </File>
    3092130929                                <File
     30930                                        RelativePath="..\inspector\front-end\Drawer.js"
     30931                                        >
     30932                                </File>
     30933                                <File
    3092230934                                        RelativePath="..\inspector\front-end\ElementsPanel.js"
    3092330935                                        >
     
    3093230944                                </File>
    3093330945                                <File
     30946                                        RelativePath="..\inspector\front-end\InjectedScript.js"
     30947                                        >
     30948                                </File>
     30949                                <File
    3093430950                                        RelativePath="..\inspector\front-end\inspector.css"
    3093530951                                        >
     
    3095330969                                <File
    3095430970                                        RelativePath="..\inspector\front-end\ObjectPropertiesSection.js"
     30971                                        >
     30972                                </File>
     30973                                <File
     30974                                        RelativePath="..\inspector\front-end\ObjectProxy.js"
    3095530975                                        >
    3095630976                                </File>
  • trunk/WebCore/inspector/front-end/ConsoleView.js

    r46886 r46972  
    514514    _formatobject: function(obj, elem)
    515515    {
    516         elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, null, null, null, true).element);
     516        elem.appendChild(new WebInspector.ObjectPropertiesSection(new WebInspector.ObjectProxy(obj), Object.describe(obj, true), null, null, true).element);
    517517    },
    518518
  • trunk/WebCore/inspector/front-end/DOMAgent.js

    r46848 r46972  
    704704    }, 0)
    705705}
     706
     707InspectorController.getPrototypes = function(objectProxy, callback) {
     708    setTimeout(function() {
     709        callback(InjectedScript.getPrototypes(objectProxy));
     710    }, 0)
     711}
     712
     713InspectorController.getProperties = function(objectProxy, ignoreHasOwnProperty, callback) {
     714    setTimeout(function() {
     715        callback(InjectedScript.getProperties(objectProxy, ignoreHasOwnProperty));
     716    }, 0)
     717}
     718
     719InspectorController.setPropertyValue = function(objectProxy, propertyName, expression, callback) {
     720    setTimeout(function() {
     721        callback(InjectedScript.setPropertyValue(objectProxy, propertyName, expression));
     722    }, 0)
     723}
     724
  • trunk/WebCore/inspector/front-end/InjectedScript.js

    r46848 r46972  
    3939    var node = InjectedScript._nodeForId(nodeId);
    4040    if (!node)
    41         return null;
     41        return false;
    4242    var matchedRules = InjectedScript._window().getMatchedCSSRules(node, "", authorOnly);
    4343    var matchedCSSRules = [];
     
    382382}
    383383
     384InjectedScript.getPrototypes = function(nodeId)
     385{
     386    var node = InjectedScript._nodeForId(nodeId);
     387    if (!node)
     388        return false;
     389
     390    var result = [];
     391    for (var prototype = node; prototype; prototype = prototype.__proto__) {
     392        var title = Object.describe(prototype);
     393        if (title.match(/Prototype$/)) {
     394            title = title.replace(/Prototype$/, "");
     395        }
     396        result.push(title);
     397    }
     398    return result;
     399}
     400
     401InjectedScript.getProperties = function(objectProxy, ignoreHasOwnProperty)
     402{
     403    var object = InjectedScript._resolveObject(objectProxy);
     404    if (!object)
     405        return false;
     406
     407    var properties = [];
     408    // Go over properties, prepare results.
     409    for (var propertyName in object) {
     410        if (!ignoreHasOwnProperty && "hasOwnProperty" in object && !object.hasOwnProperty(propertyName))
     411            continue;
     412
     413        //TODO: remove this once object becomes really remote.
     414        if (propertyName === "__treeElementIdentifier")
     415            continue;
     416        var property = {};
     417        property.name = propertyName;
     418        var isGetter = object["__lookupGetter__"] && object.__lookupGetter__(propertyName);
     419        if (!property.isGetter) {
     420            var childObject = object[propertyName];
     421            property.type = typeof childObject;
     422            property.textContent = Object.describe(childObject, true);
     423            property.parentObjectProxy = objectProxy;
     424            var parentPath = objectProxy.path.slice();
     425            property.childObjectProxy = {
     426                objectId : objectProxy.objectId,
     427                path : parentPath.splice(parentPath.length, 0, propertyName),
     428                protoDepth : objectProxy.protoDepth
     429            };
     430            if (childObject && (property.type === "object" || property.type === "function")) {
     431                for (var subPropertyName in childObject) {
     432                    if (propertyName === "__treeElementIdentifier")
     433                        continue;
     434                    property.hasChildren = true;
     435                    break;
     436                }
     437            }
     438        } else {
     439            // FIXME: this should show something like "getter" (bug 16734).
     440            property.textContent = "\u2014"; // em dash
     441            property.isGetter = true;
     442        }
     443        properties.push(property);
     444    }
     445    return properties;
     446}
     447
     448InjectedScript.setPropertyValue = function(objectProxy, propertyName, expression)
     449{
     450    var object = InjectedScript._resolveObject(objectProxy);
     451    if (!object)
     452        return false;
     453
     454    var expressionLength = expression.length;
     455    if (!expressionLength) {
     456        delete object[propertyName];
     457        return !(propertyName in object);
     458    }
     459
     460    try {
     461        // Surround the expression in parenthesis so the result of the eval is the result
     462        // of the whole expression not the last potential sub-expression.
     463
     464        // There is a regression introduced here: eval is now happening against global object,
     465        // not call frame while on a breakpoint.
     466        // TODO: bring evaluation against call frame back.
     467        var result = InjectedScript._window().eval("(" + expression + ")");
     468        // Store the result in the property.
     469        object[propertyName] = result;
     470        return true;
     471    } catch(e) {
     472        try {
     473            var result = InjectedScript._window().eval("\"" + expression.escapeCharacters("\"") + "\"");
     474            object[propertyName] = result;
     475            return true;
     476        } catch(e) {
     477            return false;
     478        }
     479    }
     480}
     481
     482InjectedScript._resolveObject = function(objectProxy)
     483{
     484    var object = InjectedScript._objectForId(objectProxy.objectId);
     485    var path = objectProxy.path;
     486    var protoDepth = objectProxy.protoDepth;
     487
     488    // Follow the property path.
     489    for (var i = 0; object && i < path.length; ++i)
     490        object = object[path[i]];
     491
     492    // Get to the necessary proto layer.
     493    for (var i = 0; object && i < protoDepth; ++i)
     494        object = object.__proto__;
     495
     496    return object;
     497}
     498
    384499InjectedScript._window = function()
    385500{
     501    // TODO: replace with 'return window;' once this script is injected into
     502    // the page's context.
    386503    return InspectorController.inspectedWindow();
    387504}
     
    389506InjectedScript._nodeForId = function(nodeId)
    390507{
     508    // TODO: replace with node lookup in the InspectorDOMAgent once DOMAgent nodes are used.
    391509    return nodeId;
    392510}
     511
     512InjectedScript._objectForId = function(objectId)
     513{
     514    // TODO: replace with node lookups for node ids and evaluation result lookups for the rest of ids.
     515    return objectId;
     516}
  • trunk/WebCore/inspector/front-end/ObjectPropertiesSection.js

    r46391 r46972  
    2727WebInspector.ObjectPropertiesSection = function(object, title, subtitle, emptyPlaceholder, ignoreHasOwnProperty, extraProperties, treeElementConstructor)
    2828{
    29     if (!title) {
    30         title = Object.describe(object);
    31         if (title.match(/Prototype$/)) {
    32             title = title.replace(/Prototype$/, "");
    33             if (!subtitle)
    34                 subtitle = WebInspector.UIString("Prototype");
    35         }
    36     }
    37 
    3829    this.emptyPlaceholder = (emptyPlaceholder || WebInspector.UIString("No Properties"));
    3930    this.object = object;
     
    5445    update: function()
    5546    {
    56         var properties = [];
    57         for (var prop in this.object)
    58             properties.push(prop);
     47        var self = this;
     48        var callback = function(properties) {
     49            if (!properties)
     50                return;
     51            self._update(properties);
     52        };
     53        InspectorController.getProperties(this.object, this.ignoreHasOwnProperty, callback);
     54    },
     55
     56    _update: function(properties)
     57    {
    5958        if (this.extraProperties)
    6059            for (var prop in this.extraProperties)
    61                 properties.push(prop);
     60                properties.push(new WebInspector.ObjectPropertyProxy(prop, this.extraProperties[prop]));
    6261        properties.sort(this._displaySort);
    6362
    6463        this.propertiesTreeOutline.removeChildren();
    6564
    66         for (var i = 0; i < properties.length; ++i) {
    67             var object = this.object;
    68             var propertyName = properties[i];
    69             if (this.extraProperties && propertyName in this.extraProperties)
    70                 object = this.extraProperties;
    71             if (propertyName === "__treeElementIdentifier")
    72                 continue;
    73             if (!this.ignoreHasOwnProperty && "hasOwnProperty" in object && !object.hasOwnProperty(propertyName))
    74                 continue;
    75             this.propertiesTreeOutline.appendChild(new this.treeElementConstructor(object, propertyName));
    76         }
     65        for (var i = 0; i < properties.length; ++i)
     66            this.propertiesTreeOutline.appendChild(new this.treeElementConstructor(properties[i]));
    7767
    7868        if (!this.propertiesTreeOutline.children.length) {
     
    8373    },
    8474
    85     _displaySort: function(a,b) {
     75    _displaySort: function(propertyA, propertyB) {
     76        var a = propertyA.name;
     77        var b = propertyB.name;
    8678
    8779        // if used elsewhere make sure to
     
    124116WebInspector.ObjectPropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype;
    125117
    126 WebInspector.ObjectPropertyTreeElement = function(parentObject, propertyName)
     118WebInspector.ObjectPropertyTreeElement = function(property)
    127119{
    128     this.parentObject = parentObject;
    129     this.propertyName = propertyName;
     120    this.property = property;
    130121
    131122    // Pass an empty title, the title gets made later in onattach.
     
    146137            return;
    147138
    148         this.removeChildren();
    149 
    150         var childObject = this.safePropertyValue(this.parentObject, this.propertyName);
    151         var properties = Object.sortedProperties(childObject, WebInspector.ObjectPropertiesSection.prototype._displaySort);
    152         for (var i = 0; i < properties.length; ++i) {
    153             var propertyName = properties[i];
    154             if (propertyName === "__treeElementIdentifier")
    155                 continue;
    156             this.appendChild(new this.treeOutline.section.treeElementConstructor(childObject, propertyName));
    157         }
     139        var self = this;
     140        var callback = function(properties) {
     141            self.removeChildren();
     142            if (!properties)
     143                return;
     144
     145            properties.sort(self._displaySort);
     146            for (var i = 0; i < properties.length; ++i) {
     147                self.appendChild(new self.treeOutline.section.treeElementConstructor(properties[i]));
     148            }
     149        };
     150        InspectorController.getProperties(this.property.childObjectProxy, false, callback);
    158151    },
    159152
     
    170163    update: function()
    171164    {
    172         var childObject = this.safePropertyValue(this.parentObject, this.propertyName);
    173         var isGetter = ("__lookupGetter__" in this.parentObject && this.parentObject.__lookupGetter__(this.propertyName));
    174 
    175165        var nameElement = document.createElement("span");
    176166        nameElement.className = "name";
    177         nameElement.textContent = this.propertyName;
     167        nameElement.textContent = this.property.name;
    178168
    179169        this.valueElement = document.createElement("span");
    180170        this.valueElement.className = "value";
    181         if (!isGetter) {
    182             this.valueElement.textContent = Object.describe(childObject, true);
    183         } else {
    184             // FIXME: this should show something like "getter" (bug 16734).
    185             this.valueElement.textContent = "\u2014"; // em dash
    186             this.valueElement.addStyleClass("dimmed");
    187         }
     171        this.valueElement.textContent = this.property.textContent;
     172        if (this.property.isGetter)
     173           this.valueElement.addStyleClass("dimmed");
    188174
    189175        this.listItemElement.removeChildren();
     
    192178        this.listItemElement.appendChild(document.createTextNode(": "));
    193179        this.listItemElement.appendChild(this.valueElement);
    194 
    195         var hasSubProperties = false;
    196         var type = typeof childObject;
    197         if (childObject && (type === "object" || type === "function")) {
    198             for (var subPropertyName in childObject) {
    199                 if (subPropertyName === "__treeElementIdentifier")
    200                     continue;
    201                 hasSubProperties = true;
    202                 break;
    203             }
    204         }
    205 
    206         this.hasChildren = hasSubProperties;
     180        this.hasChildren = this.property.hasChildren;
    207181    },
    208182
     
    254228    },
    255229
    256     evaluateExpression: function(expression, callback)
    257     {
    258         // Evaluate in the currently selected call frame if the debugger is paused.
    259         // Otherwise evaluate in against the inspected window.
    260         if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused && this.treeOutline.section.editInSelectedCallFrameWhenPaused)
    261             return WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, callback);
    262         try {
    263             var result = InspectorController.inspectedWindow().eval(expression);
    264             callback(result);
    265         } catch (e) {
    266             callback(e, true);
    267         }
    268     },
    269 
    270230    applyExpression: function(expression, updateInterface)
    271231    {
    272         var expressionLength = expression.trimWhitespace().length;
    273 
    274         if (!expressionLength) {
    275             // The user deleted everything, so try to delete the property.
    276             delete this.parentObject[this.propertyName];
    277 
    278             if (updateInterface) {
    279                 if (this.propertyName in this.parentObject) {
    280                     // The property was not deleted, so update.
    281                     this.update();
    282                 } else {
    283                     // The property was deleted, so remove this tree element.
    284                     this.parent.removeChild(this);
    285                 }
     232        expression = expression.trimWhitespace();
     233        var expressionLength = expression.length;
     234        var self = this;
     235        var callback = function(success) {
     236            if (!updateInterface)
     237                return;
     238
     239            if (!success)
     240                self.update();
     241
     242            if (!expressionLength) {
     243                // The property was deleted, so remove this tree element.
     244                self.parent.removeChild(this);
     245            } else {
     246                // Call updateSiblings since their value might be based on the value that just changed.
     247                self.updateSiblings();
    286248            }
    287 
    288             return;
    289         }
    290 
    291         try {
    292             // Surround the expression in parenthesis so the result of the eval is the result
    293             // of the whole expression not the last potential sub-expression.
    294             var result = this.evaluateExpression("(" + expression + ")");
    295 
    296             // Store the result in the property.
    297             this.parentObject[this.propertyName] = result;
    298         } catch(e) {
    299             try {
    300                 // Try to update as a string
    301                 var result = this.evaluateExpression("\"" + expression.escapeCharacters("\"") + "\"");
    302 
    303                 // Store the result in the property.
    304                 this.parentObject[this.propertyName] = result;
    305             } catch(e) {
    306                 // The expression failed so don't change the value. So just update and return.
    307                 if (updateInterface)
    308                     this.update();
    309                 return;
    310             }
    311         }
    312 
    313         if (updateInterface) {
    314             // Call updateSiblings since their value might be based on the value that just changed.
    315             this.updateSiblings();
    316         }
     249        };
     250        InspectorController.setPropertyValue(this.property.parentObjectProxy, this.property.name, expression.trimWhitespace(), callback);
    317251    }
    318252}
  • trunk/WebCore/inspector/front-end/PropertiesSidebarPane.js

    r37289 r46972  
    4444            return;
    4545
    46         for (var prototype = object; prototype; prototype = prototype.__proto__) {
    47             var section = new WebInspector.ObjectPropertiesSection(prototype);
    48             this.sections.push(section);
    49             body.appendChild(section.element);
    50         }
     46        var self = this;
     47        var callback = function(prototypes) {
     48            var body = self.bodyElement;
     49            body.removeChildren();
     50            self.sections = [];
     51
     52            // Get array of prototype user-friendly names.
     53            for (var i = 0; i < prototypes.length; ++i) {
     54                var prototype = new WebInspector.ObjectProxy(object, [], i);
     55                var section = new WebInspector.ObjectPropertiesSection(prototype, prototypes[i], WebInspector.UIString("Prototype"));
     56                self.sections.push(section);
     57                body.appendChild(section.element);
     58            }
     59        };
     60        InspectorController.getPrototypes(object, callback);
    5161    }
    5262}
  • trunk/WebCore/inspector/front-end/ScopeChainSidebarPane.js

    r37289 r46972  
    8686                subtitle = null;
    8787
    88             var section = new WebInspector.ObjectPropertiesSection(scopeObject, title, subtitle, emptyPlaceholder, true, extraProperties, WebInspector.ScopeVariableTreeElement);
     88            var section = new WebInspector.ObjectPropertiesSection(new WebInspector.ObjectProxy(scopeObject), title, subtitle, emptyPlaceholder, true, extraProperties, WebInspector.ScopeVariableTreeElement);
    8989            section.editInSelectedCallFrameWhenPaused = true;
    9090            section.pane = this;
     
    101101WebInspector.ScopeChainSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
    102102
    103 WebInspector.ScopeVariableTreeElement = function(parentObject, propertyName)
     103WebInspector.ScopeVariableTreeElement = function(property)
    104104{
    105     WebInspector.ObjectPropertyTreeElement.call(this, parentObject, propertyName);
     105    WebInspector.ObjectPropertyTreeElement.call(this, property);
    106106}
    107107
     
    143143        do {
    144144            if (result)
    145                 result = current.propertyName + "." + result;
     145                result = current.property.name + "." + result;
    146146            else
    147                 result = current.propertyName;
     147                result = current.property.name;
    148148            current = current.parent;
    149149        } while (current && !current.root);
  • trunk/WebCore/inspector/front-end/WebKit.qrc

    r46841 r46972  
    3030    <file>Object.js</file>
    3131    <file>ObjectPropertiesSection.js</file>
     32    <file>ObjectProxy.js</file>
    3233    <file>Panel.js</file>
    3334    <file>PanelEnablerView.js</file>
  • trunk/WebCore/inspector/front-end/inspector.html

    r46841 r46972  
    5656    <script type="text/javascript" src="SidebarTreeElement.js"></script>
    5757    <script type="text/javascript" src="PropertiesSection.js"></script>
     58    <script type="text/javascript" src="ObjectProxy.js"></script>
    5859    <script type="text/javascript" src="ObjectPropertiesSection.js"></script>
    5960    <script type="text/javascript" src="BreakpointsSidebarPane.js"></script>
Note: See TracChangeset for help on using the changeset viewer.