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     this.reset();
     35 }
     36 
     37 WebInspector.WatchExpressionsSidebarPane.prototype = {
     38     reset: 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)
     94         {
     95             var property = new WebInspector.RemoteObjectProperty(expression, result);
     96             property.watchIndex = watchIndex;
     97 
     98             // To clarify what's going on here:
     99             // In the outer function, we calculate the number of properties
    100             // that we're going to be updating, and set that in the
    101             // propertyCount variable.
    102             // In this function, we test to see when we are processing the
    103             // last property, and then call the superclass's updateProperties()
    104             // method to get all the properties refreshed at once.
    105             properties.push(property);
    106 
    107             if (properties.length == propertyCount) {
    108                 this.updateProperties(properties, WebInspector.WatchExpressionTreeElement, WebInspector.WatchExpressionsSection.CompareProperties);
    109 
    110                 // check to see if we just added a new watch expression,
    111                 // which will always be the last property
    112                 if (this._newExpressionAdded) {
    113                     delete this._newExpressionAdded;
    114 
    115                     treeElement = this.findAddedTreeElement();
    116                     if (treeElement)
    117                         treeElement.startEditing();
    118                 }
    119             }
    120         }
    121 
    122         // TODO: pass exact injected script id.
    123         RuntimeAgent.releaseObjectGroup(this._watchObjectGroupId)
    124         var properties = [];
    125 
    126         // Count the properties, so we known when to call this.updateProperties()
    127         // in appendResult()
    128         var propertyCount = 0;
    129         for (var i = 0; i < this.watchExpressions.length; ++i) {
    130             if (!this.watchExpressions[i])
    131                 continue;
    132             ++propertyCount;
    133         }
    134 
    135         // Now process all the expressions, since we have the actual count,
    136         // which is checked in the appendResult inner function.
    137         for (var i = 0; i < this.watchExpressions.length; ++i) {
    138             var expression = this.watchExpressions[i];
    139             if (!expression)
    140                 continue;
    141 
    142             WebInspector.console.evalInInspectedWindow("(" + expression + ")", this._watchObjectGroupId, false, appendResult.bind(this, expression, i));
    143         }
    144 
    145         // note this is setting the expansion of the tree, not the section;
    146         // with no expressions, and expanded tree, we get some extra vertical
    147         // white space
    148         // FIXME: should change to use header buttons instead of the buttons
    149         // at the bottom of the section, then we can add a "No Watch Expressions
    150         // element when there are no watch expressions, and this issue should
    151         // go away.
    152         this.expanded = (propertyCount != 0);
    153     },
    154 
    155     addExpression: function()
    156     {
    157         this._newExpressionAdded = true;
    158         this.watchExpressions.push(WebInspector.WatchExpressionsSection.NewWatchExpression);
    159         this.update();
    160     },
    161 
    162     updateExpression: function(element, value)
    163     {
    164         this.watchExpressions[element.property.watchIndex] = value;
    165         this.saveExpressions();
    166         this.update();
    167     },
    168 
    169     findAddedTreeElement: function()
    170     {
    171         var children = this.propertiesTreeOutline.children;
    172         for (var i = 0; i < children.length; ++i)
    173             if (children[i].property.name === WebInspector.WatchExpressionsSection.NewWatchExpression)
    174                 return children[i];
    175     },
    176 
    177     saveExpressions: function()
    178     {
    179         var toSave = [];
    180         for (var i = 0; i < this.watchExpressions.length; i++)
    181             if (this.watchExpressions[i])
    182                 toSave.push(this.watchExpressions[i]);
    183 
    184         WebInspector.settings.watchExpressions = toSave;
    185         return toSave.length;
    186     }
    187 }
    188 
    189 WebInspector.WatchExpressionsSection.prototype.__proto__ = WebInspector.ObjectPropertiesSection.prototype;
    190 
    191 WebInspector.WatchExpressionsSection.CompareProperties = function(propertyA, propertyB)
    192 {
    193     if (propertyA.watchIndex == propertyB.watchIndex)
    194         return 0;
    195     else if (propertyA.watchIndex < propertyB.watchIndex)
    196         return -1;
    197     else
    198         return 1;
    199 }
    200 
    201 WebInspector.WatchExpressionTreeElement = function(property)
    202 {
    203     WebInspector.ObjectPropertyTreeElement.call(this, property);
    204 }
    205 
    206 WebInspector.WatchExpressionTreeElement.prototype = {
    207     update: function()
    208     {
    209         WebInspector.ObjectPropertyTreeElement.prototype.update.call(this);
    210 
    211         if (this.property.value.isError())
    212             this.valueElement.addStyleClass("watch-expressions-error-level");
    213 
    214         var deleteButton = document.createElement("input");
    215         deleteButton.type = "button";
    216         deleteButton.title = WebInspector.UIString("Delete watch expression.");
    217         deleteButton.addStyleClass("enabled-button");
    218         deleteButton.addStyleClass("delete-button");
    219         deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false);
    220 
    221         this.listItemElement.insertBefore(deleteButton, this.listItemElement.firstChild);
    222     },
    223 
    224     _deleteButtonClicked: function()
    225     {
    226         this.treeOutline.section.updateExpression(this, null);
    227     },
    228 
    229     startEditing: function()
    230     {
    231         if (WebInspector.isBeingEdited(this.nameElement) || !this.treeOutline.section.editable)
    232             return;
    233 
    234         this.nameElement.textContent = this.property.name.trim();
    235 
    236         var context = { expanded: this.expanded };
    237 
    238         // collapse temporarily, if required
    239         this.hasChildren = false;
    240 
    241         this.listItemElement.addStyleClass("editing-sub-part");
    242 
    243         WebInspector.startEditing(this.nameElement, {
    244             context: context,
    245             commitHandler: this.editingCommitted.bind(this),
    246             cancelHandler: this.editingCancelled.bind(this)
    247         });
    248     },
    249 
    250     editingCancelled: function(element, context)
    251     {
    252         if (!this.nameElement.textContent)
    253             this.treeOutline.section.updateExpression(this, null);
    254 
    255         this.update();
    256         this.editingEnded(context);
    257     },
    258 
    259     applyExpression: function(expression, updateInterface)
    260     {
    261         expression = expression.trim();
    262 
    263         if (!expression)
    264             expression = null;
    265 
    266         this.property.name = expression;
    267         this.treeOutline.section.updateExpression(this, expression);
    268     }
    269 }
    270 
    271 WebInspector.WatchExpressionTreeElement.prototype.__proto__ = WebInspector.ObjectPropertyTreeElement.prototype;
    272