Home | History | Annotate | Download | only in front-end
      1 /*
      2  * Copyright (C) IBM Corp. 2009  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of IBM Corp. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 WebInspector.WatchExpressionsSidebarPane = function()
     32 {
     33     WebInspector.SidebarPane.call(this, WebInspector.UIString("Watch Expressions"));
     34     WebInspector.settings.addEventListener("loaded", this._settingsLoaded, this);
     35 }
     36 
     37 WebInspector.WatchExpressionsSidebarPane.prototype = {
     38     _settingsLoaded: function()
     39     {
     40         this.bodyElement.removeChildren();
     41 
     42         this.expanded = WebInspector.settings.watchExpressions.length > 0;
     43         this.section = new WebInspector.WatchExpressionsSection();
     44         this.bodyElement.appendChild(this.section.element);
     45 
     46         var addElement = document.createElement("button");
     47         addElement.setAttribute("type", "button");
     48         addElement.textContent = WebInspector.UIString("Add");
     49         addElement.addEventListener("click", this.section.addExpression.bind(this.section), false);
     50 
     51         var refreshElement = document.createElement("button");
     52         refreshElement.setAttribute("type", "button");
     53         refreshElement.textContent = WebInspector.UIString("Refresh");
     54         refreshElement.addEventListener("click", this.section.update.bind(this.section), false);
     55 
     56         var centerElement = document.createElement("div");
     57         centerElement.addStyleClass("watch-expressions-buttons-container");
     58         centerElement.appendChild(addElement);
     59         centerElement.appendChild(refreshElement);
     60         this.bodyElement.appendChild(centerElement);
     61 
     62         this.onexpand = this.refreshExpressions.bind(this);
     63     },
     64 
     65     refreshExpressions: function()
     66     {
     67         if (this.section)
     68             this.section.update();
     69     }
     70 }
     71 
     72 WebInspector.WatchExpressionsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
     73 
     74 WebInspector.WatchExpressionsSection = function()
     75 {
     76     this._watchObjectGroupId = "watch-group";
     77 
     78     WebInspector.ObjectPropertiesSection.call(this);
     79 
     80     this.watchExpressions = WebInspector.settings.watchExpressions;
     81 
     82     this.headerElement.className = "hidden";
     83     this.editable = true;
     84     this.expanded = true;
     85     this.propertiesElement.addStyleClass("watch-expressions");
     86 }
     87 
     88 WebInspector.WatchExpressionsSection.NewWatchExpression = "\xA0";
     89 
     90 WebInspector.WatchExpressionsSection.prototype = {
     91     update: function()
     92     {
     93         function appendResult(expression, watchIndex, result, exception)
     94         {
     95             if (exception) {
     96                 // Exception results are not wrappers, but text messages.
     97                 result = WebInspector.ObjectProxy.wrapPrimitiveValue(result);
     98             } else if (result.type === "string") {
     99                 // Evaluation result is intentionally not abbreviated. However, we'd like to distinguish between null and "null"
    100                 result.description = "\"" + result.description + "\"";
    101             }
    102 
    103             var property = new WebInspector.ObjectPropertyProxy(expression, result);
    104             property.watchIndex = watchIndex;
    105             property.isException = exception;
    106 
    107             // For newly added, empty expressions, set description to "",
    108             // since otherwise you get DOMWindow
    109             if (property.name === WebInspector.WatchExpressionsSection.NewWatchExpression)
    110                 property.value.description = "";
    111 
    112             // To clarify what's going on here:
    113             // In the outer function, we calculate the number of properties
    114             // that we're going to be updating, and set that in the
    115             // propertyCount variable.
    116             // In this function, we test to see when we are processing the
    117             // last property, and then call the superclass's updateProperties()
    118             // method to get all the properties refreshed at once.
    119             properties.push(property);
    120 
    121             if (properties.length == propertyCount) {
    122                 this.updateProperties(properties, WebInspector.WatchExpressionTreeElement, WebInspector.WatchExpressionsSection.CompareProperties);
    123 
    124                 // check to see if we just added a new watch expression,
    125                 // which will always be the last property
    126                 if (this._newExpressionAdded) {
    127                     delete this._newExpressionAdded;
    128 
    129                     treeElement = this.findAddedTreeElement();
    130                     if (treeElement)
    131                         treeElement.startEditing();
    132                 }
    133             }
    134         }
    135 
    136         // TODO: pass exact injected script id.
    137         InspectorBackend.releaseWrapperObjectGroup(0, this._watchObjectGroupId)
    138         var properties = [];
    139 
    140         // Count the properties, so we known when to call this.updateProperties()
    141         // in appendResult()
    142         var propertyCount = 0;
    143         for (var i = 0; i < this.watchExpressions.length; ++i) {
    144             if (!this.watchExpressions[i])
    145                 continue;
    146             ++propertyCount;
    147         }
    148 
    149         // Now process all the expressions, since we have the actual count,
    150         // which is checked in the appendResult inner function.
    151         for (var i = 0; i < this.watchExpressions.length; ++i) {
    152             var expression = this.watchExpressions[i];
    153             if (!expression)
    154                 continue;
    155 
    156             WebInspector.console.evalInInspectedWindow("(" + expression + ")", this._watchObjectGroupId, appendResult.bind(this, expression, i));
    157         }
    158 
    159         // note this is setting the expansion of the tree, not the section;
    160         // with no expressions, and expanded tree, we get some extra vertical
    161         // white space
    162         // FIXME: should change to use header buttons instead of the buttons
    163         // at the bottom of the section, then we can add a "No Watch Expressions
    164         // element when there are no watch expressions, and this issue should
    165         // go away.
    166         this.expanded = (propertyCount != 0);
    167     },
    168 
    169     addExpression: function()
    170     {
    171         this._newExpressionAdded = true;
    172         this.watchExpressions.push(WebInspector.WatchExpressionsSection.NewWatchExpression);
    173         this.update();
    174     },
    175 
    176     updateExpression: function(element, value)
    177     {
    178         this.watchExpressions[element.property.watchIndex] = value;
    179         this.saveExpressions();
    180         this.update();
    181     },
    182 
    183     findAddedTreeElement: function()
    184     {
    185         var children = this.propertiesTreeOutline.children;
    186         for (var i = 0; i < children.length; ++i)
    187             if (children[i].property.name === WebInspector.WatchExpressionsSection.NewWatchExpression)
    188                 return children[i];
    189     },
    190 
    191     saveExpressions: function()
    192     {
    193         var toSave = [];
    194         for (var i = 0; i < this.watchExpressions.length; i++)
    195             if (this.watchExpressions[i])
    196                 toSave.push(this.watchExpressions[i]);
    197 
    198         WebInspector.settings.watchExpressions = toSave;
    199         return toSave.length;
    200     }
    201 }
    202 
    203 WebInspector.WatchExpressionsSection.prototype.__proto__ = WebInspector.ObjectPropertiesSection.prototype;
    204 
    205 WebInspector.WatchExpressionsSection.CompareProperties = function(propertyA, propertyB)
    206 {
    207     if (propertyA.watchIndex == propertyB.watchIndex)
    208         return 0;
    209     else if (propertyA.watchIndex < propertyB.watchIndex)
    210         return -1;
    211     else
    212         return 1;
    213 }
    214 
    215 WebInspector.WatchExpressionTreeElement = function(property)
    216 {
    217     WebInspector.ObjectPropertyTreeElement.call(this, property);
    218 }
    219 
    220 WebInspector.WatchExpressionTreeElement.prototype = {
    221     update: function()
    222     {
    223         WebInspector.ObjectPropertyTreeElement.prototype.update.call(this);
    224 
    225         if (this.property.isException)
    226             this.valueElement.addStyleClass("watch-expressions-error-level");
    227 
    228         var deleteButton = document.createElement("input");
    229         deleteButton.type = "button";
    230         deleteButton.title = WebInspector.UIString("Delete watch expression.");
    231         deleteButton.addStyleClass("enabled-button");
    232         deleteButton.addStyleClass("delete-button");
    233         deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false);
    234 
    235         this.listItemElement.insertBefore(deleteButton, this.listItemElement.firstChild);
    236     },
    237 
    238     _deleteButtonClicked: function()
    239     {
    240         this.treeOutline.section.updateExpression(this, null);
    241     },
    242 
    243     startEditing: function()
    244     {
    245         if (WebInspector.isBeingEdited(this.nameElement) || !this.treeOutline.section.editable)
    246             return;
    247 
    248         this.nameElement.textContent = this.property.name.trim();
    249 
    250         var context = { expanded: this.expanded };
    251 
    252         // collapse temporarily, if required
    253         this.hasChildren = false;
    254 
    255         this.listItemElement.addStyleClass("editing-sub-part");
    256 
    257         WebInspector.startEditing(this.nameElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), context);
    258     },
    259 
    260     editingCancelled: function(element, context)
    261     {
    262         if (!this.nameElement.textContent)
    263             this.treeOutline.section.updateExpression(this, null);
    264 
    265         this.update();
    266         this.editingEnded(context);
    267     },
    268 
    269     applyExpression: function(expression, updateInterface)
    270     {
    271         expression = expression.trim();
    272 
    273         if (!expression)
    274             expression = null;
    275 
    276         this.property.name = expression;
    277         this.treeOutline.section.updateExpression(this, expression);
    278     }
    279 }
    280 
    281 WebInspector.WatchExpressionTreeElement.prototype.__proto__ = WebInspector.ObjectPropertyTreeElement.prototype;
    282