Home | History | Annotate | Download | only in front-end
      1 /*
      2  * Copyright (C) 2009 Google Inc. All rights reserved.
      3  * Copyright (C) 2009 Joseph Pecoraro
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *     * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 WebInspector.DOMNode = function(doc, payload) {
     33     this.ownerDocument = doc;
     34 
     35     this.id = payload.id;
     36     // injectedScriptId is a node is for DOM nodes which should be converted
     37     // to corresponding InjectedScript by the inspector backend. We indicate
     38     // this by making injectedScriptId negative.
     39     this.injectedScriptId = -payload.id;
     40     this.nodeType = payload.nodeType;
     41     this.nodeName = payload.nodeName;
     42     this.localName = payload.localName;
     43     this._nodeValue = payload.nodeValue;
     44     this.textContent = this.nodeValue;
     45 
     46     this.attributes = [];
     47     this._attributesMap = {};
     48     if (payload.attributes)
     49         this._setAttributesPayload(payload.attributes);
     50 
     51     this._childNodeCount = payload.childNodeCount;
     52     this.children = null;
     53 
     54     this.nextSibling = null;
     55     this.prevSibling = null;
     56     this.firstChild = null;
     57     this.lastChild = null;
     58     this.parentNode = null;
     59 
     60     if (payload.children)
     61         this._setChildrenPayload(payload.children);
     62 
     63     this._computedStyle = null;
     64     this.style = null;
     65     this._matchedCSSRules = [];
     66 
     67     if (this.nodeType === Node.ELEMENT_NODE) {
     68         // HTML and BODY from internal iframes should not overwrite top-level ones.
     69         if (!this.ownerDocument.documentElement && this.nodeName === "HTML")
     70             this.ownerDocument.documentElement = this;
     71         if (!this.ownerDocument.body && this.nodeName === "BODY")
     72             this.ownerDocument.body = this;
     73         if (payload.documentURL)
     74             this.documentURL = payload.documentURL;
     75     } else if (this.nodeType === Node.DOCUMENT_TYPE_NODE) {
     76         this.publicId = payload.publicId;
     77         this.systemId = payload.systemId;
     78         this.internalSubset = payload.internalSubset;
     79     } else if (this.nodeType === Node.DOCUMENT_NODE)
     80         this.documentURL = payload.documentURL;
     81 }
     82 
     83 WebInspector.DOMNode.prototype = {
     84     hasAttributes: function()
     85     {
     86         return this.attributes.length > 0;
     87     },
     88 
     89     hasChildNodes: function()  {
     90         return this._childNodeCount > 0;
     91     },
     92 
     93     get nodeValue() {
     94         return this._nodeValue;
     95     },
     96 
     97     set nodeValue(value) {
     98         if (this.nodeType != Node.TEXT_NODE)
     99             return;
    100         var self = this;
    101         var callback = function()
    102         {
    103             self._nodeValue = value;
    104             self.textContent = value;
    105         };
    106         this.ownerDocument._domAgent.setTextNodeValueAsync(this, value, callback);
    107     },
    108 
    109     getAttribute: function(name)
    110     {
    111         var attr = this._attributesMap[name];
    112         return attr ? attr.value : undefined;
    113     },
    114 
    115     setAttribute: function(name, value)
    116     {
    117         var self = this;
    118         var callback = function()
    119         {
    120             var attr = self._attributesMap[name];
    121             if (attr)
    122                 attr.value = value;
    123             else
    124                 attr = self._addAttribute(name, value);
    125         };
    126         this.ownerDocument._domAgent.setAttributeAsync(this, name, value, callback);
    127     },
    128 
    129     removeAttribute: function(name)
    130     {
    131         var self = this;
    132         var callback = function()
    133         {
    134             delete self._attributesMap[name];
    135             for (var i = 0;  i < self.attributes.length; ++i) {
    136                 if (self.attributes[i].name == name) {
    137                     self.attributes.splice(i, 1);
    138                     break;
    139                 }
    140             }
    141         };
    142         this.ownerDocument._domAgent.removeAttributeAsync(this, name, callback);
    143     },
    144 
    145     _setAttributesPayload: function(attrs)
    146     {
    147         this.attributes = [];
    148         this._attributesMap = {};
    149         for (var i = 0; i < attrs.length; i += 2)
    150             this._addAttribute(attrs[i], attrs[i + 1]);
    151     },
    152 
    153     _insertChild: function(prev, payload)
    154     {
    155         var node = new WebInspector.DOMNode(this.ownerDocument, payload);
    156         if (!prev)
    157             // First node
    158             this.children = [ node ];
    159         else
    160             this.children.splice(this.children.indexOf(prev) + 1, 0, node);
    161         this._renumber();
    162         return node;
    163     },
    164 
    165     removeChild_: function(node)
    166     {
    167         this.children.splice(this.children.indexOf(node), 1);
    168         node.parentNode = null;
    169         this._renumber();
    170     },
    171 
    172     _setChildrenPayload: function(payloads)
    173     {
    174         this.children = [];
    175         for (var i = 0; i < payloads.length; ++i) {
    176             var payload = payloads[i];
    177             var node = new WebInspector.DOMNode(this.ownerDocument, payload);
    178             this.children.push(node);
    179         }
    180         this._renumber();
    181     },
    182 
    183     _renumber: function()
    184     {
    185         this._childNodeCount = this.children.length;
    186         if (this._childNodeCount == 0) {
    187             this.firstChild = null;
    188             this.lastChild = null;
    189             return;
    190         }
    191         this.firstChild = this.children[0];
    192         this.lastChild = this.children[this._childNodeCount - 1];
    193         for (var i = 0; i < this._childNodeCount; ++i) {
    194             var child = this.children[i];
    195             child.index = i;
    196             child.nextSibling = i + 1 < this._childNodeCount ? this.children[i + 1] : null;
    197             child.prevSibling = i - 1 >= 0 ? this.children[i - 1] : null;
    198             child.parentNode = this;
    199         }
    200     },
    201 
    202     _addAttribute: function(name, value)
    203     {
    204         var attr = {
    205             "name": name,
    206             "value": value,
    207             "_node": this
    208         };
    209         this._attributesMap[name] = attr;
    210         this.attributes.push(attr);
    211     },
    212 
    213     _setStyles: function(computedStyle, inlineStyle, styleAttributes, matchedCSSRules)
    214     {
    215         this._computedStyle = new WebInspector.CSSStyleDeclaration(computedStyle);
    216         this.style = new WebInspector.CSSStyleDeclaration(inlineStyle);
    217 
    218         for (var name in styleAttributes) {
    219             if (this._attributesMap[name])
    220                 this._attributesMap[name].style = new WebInspector.CSSStyleDeclaration(styleAttributes[name]);
    221         }
    222 
    223         this._matchedCSSRules = [];
    224         for (var i = 0; i < matchedCSSRules.length; i++)
    225             this._matchedCSSRules.push(WebInspector.CSSStyleDeclaration.parseRule(matchedCSSRules[i]));
    226     },
    227 
    228     _clearStyles: function()
    229     {
    230         this.computedStyle = null;
    231         this.style = null;
    232         for (var name in this._attributesMap)
    233             this._attributesMap[name].style = null;
    234         this._matchedCSSRules = null;
    235     }
    236 }
    237 
    238 WebInspector.DOMDocument = function(domAgent, defaultView, payload)
    239 {
    240     WebInspector.DOMNode.call(this, this, payload);
    241     this._listeners = {};
    242     this._domAgent = domAgent;
    243     this.defaultView = defaultView;
    244 }
    245 
    246 WebInspector.DOMDocument.prototype = {
    247 
    248     addEventListener: function(name, callback)
    249     {
    250         var listeners = this._listeners[name];
    251         if (!listeners) {
    252             listeners = [];
    253             this._listeners[name] = listeners;
    254         }
    255         listeners.push(callback);
    256     },
    257 
    258     removeEventListener: function(name, callback)
    259     {
    260         var listeners = this._listeners[name];
    261         if (!listeners)
    262             return;
    263 
    264         var index = listeners.indexOf(callback);
    265         if (index != -1)
    266             listeners.splice(index, 1);
    267     },
    268 
    269     _fireDomEvent: function(name, event)
    270     {
    271         var listeners = this._listeners[name];
    272         if (!listeners)
    273             return;
    274 
    275         for (var i = 0; i < listeners.length; ++i) {
    276             var listener = listeners[i];
    277             listener.call(this, event);
    278         }
    279     }
    280 }
    281 
    282 WebInspector.DOMDocument.prototype.__proto__ = WebInspector.DOMNode.prototype;
    283 
    284 
    285 WebInspector.DOMWindow = function(domAgent)
    286 {
    287     this._domAgent = domAgent;
    288 }
    289 
    290 WebInspector.DOMWindow.prototype = {
    291     get document()
    292     {
    293         return this._domAgent.document;
    294     },
    295 
    296     get Node()
    297     {
    298         return WebInspector.DOMNode;
    299     },
    300 
    301     get Element()
    302     {
    303         return WebInspector.DOMNode;
    304     },
    305 
    306     Object: function()
    307     {
    308     },
    309 
    310     getComputedStyle: function(node)
    311     {
    312         return node._computedStyle;
    313     },
    314 
    315     getMatchedCSSRules: function(node, pseudoElement, authorOnly)
    316     {
    317         return node._matchedCSSRules;
    318     }
    319 }
    320 
    321 WebInspector.DOMAgent = function() {
    322     this._window = new WebInspector.DOMWindow(this);
    323     this._idToDOMNode = null;
    324     this.document = null;
    325 }
    326 
    327 WebInspector.DOMAgent.prototype = {
    328     get domWindow()
    329     {
    330         return this._window;
    331     },
    332 
    333     getChildNodesAsync: function(parent, callback)
    334     {
    335         var children = parent.children;
    336         if (children) {
    337             callback(children);
    338             return;
    339         }
    340         function mycallback() {
    341             callback(parent.children);
    342         }
    343         var callId = WebInspector.Callback.wrap(mycallback);
    344         InspectorBackend.getChildNodes(callId, parent.id);
    345     },
    346 
    347     setAttributeAsync: function(node, name, value, callback)
    348     {
    349         var mycallback = this._didApplyDomChange.bind(this, node, callback);
    350         InspectorBackend.setAttribute(WebInspector.Callback.wrap(mycallback), node.id, name, value);
    351     },
    352 
    353     removeAttributeAsync: function(node, name, callback)
    354     {
    355         var mycallback = this._didApplyDomChange.bind(this, node, callback);
    356         InspectorBackend.removeAttribute(WebInspector.Callback.wrap(mycallback), node.id, name);
    357     },
    358 
    359     setTextNodeValueAsync: function(node, text, callback)
    360     {
    361         var mycallback = this._didApplyDomChange.bind(this, node, callback);
    362         InspectorBackend.setTextNodeValue(WebInspector.Callback.wrap(mycallback), node.id, text);
    363     },
    364 
    365     _didApplyDomChange: function(node, callback, success)
    366     {
    367         if (!success)
    368             return;
    369         callback();
    370         // TODO(pfeldman): Fix this hack.
    371         var elem = WebInspector.panels.elements.treeOutline.findTreeElement(node);
    372         if (elem)
    373             elem.updateTitle();
    374     },
    375 
    376     _attributesUpdated: function(nodeId, attrsArray)
    377     {
    378         var node = this._idToDOMNode[nodeId];
    379         node._setAttributesPayload(attrsArray);
    380         var event = {target: node};
    381         this.document._fireDomEvent("DOMAttrModified", event);
    382     },
    383 
    384     nodeForId: function(nodeId) {
    385         return this._idToDOMNode[nodeId];
    386     },
    387 
    388     _setDocument: function(payload)
    389     {
    390         this._idToDOMNode = {};
    391         if (payload && "id" in payload) {
    392             this.document = new WebInspector.DOMDocument(this, this._window, payload);
    393             this._idToDOMNode[payload.id] = this.document;
    394             this._bindNodes(this.document.children);
    395         } else
    396             this.document = null;
    397         WebInspector.panels.elements.setDocument(this.document);
    398     },
    399 
    400     _setDetachedRoot: function(payload)
    401     {
    402         var root = new WebInspector.DOMNode(this.document, payload);
    403         this._idToDOMNode[payload.id] = root;
    404     },
    405 
    406     _setChildNodes: function(parentId, payloads)
    407     {
    408         var parent = this._idToDOMNode[parentId];
    409         parent._setChildrenPayload(payloads);
    410         this._bindNodes(parent.children);
    411     },
    412 
    413     _bindNodes: function(children)
    414     {
    415         for (var i = 0; i < children.length; ++i) {
    416             var child = children[i];
    417             this._idToDOMNode[child.id] = child;
    418             if (child.children)
    419                 this._bindNodes(child.children);
    420         }
    421     },
    422 
    423     _childNodeCountUpdated: function(nodeId, newValue)
    424     {
    425         var node = this._idToDOMNode[nodeId];
    426         node._childNodeCount = newValue;
    427         var outline = WebInspector.panels.elements.treeOutline;
    428         var treeElement = outline.findTreeElement(node);
    429         if (treeElement)
    430             treeElement.hasChildren = newValue;
    431     },
    432 
    433     _childNodeInserted: function(parentId, prevId, payload)
    434     {
    435         var parent = this._idToDOMNode[parentId];
    436         var prev = this._idToDOMNode[prevId];
    437         var node = parent._insertChild(prev, payload);
    438         this._idToDOMNode[node.id] = node;
    439         var event = { target : node, relatedNode : parent };
    440         this.document._fireDomEvent("DOMNodeInserted", event);
    441     },
    442 
    443     _childNodeRemoved: function(parentId, nodeId)
    444     {
    445         var parent = this._idToDOMNode[parentId];
    446         var node = this._idToDOMNode[nodeId];
    447         parent.removeChild_(node);
    448         var event = { target : node, relatedNode : parent };
    449         this.document._fireDomEvent("DOMNodeRemoved", event);
    450         delete this._idToDOMNode[nodeId];
    451     }
    452 }
    453 
    454 WebInspector.Cookies = {}
    455 
    456 WebInspector.Cookies.getCookiesAsync = function(callback)
    457 {
    458     function mycallback(cookies, cookiesString) {
    459         if (cookiesString)
    460             callback(WebInspector.Cookies.buildCookiesFromString(cookiesString), false);
    461         else
    462             callback(cookies, true);
    463     }
    464     var callId = WebInspector.Callback.wrap(mycallback);
    465     InspectorBackend.getCookies(callId);
    466 }
    467 
    468 WebInspector.Cookies.buildCookiesFromString = function(rawCookieString)
    469 {
    470     var rawCookies = rawCookieString.split(/;\s*/);
    471     var cookies = [];
    472 
    473     if (!(/^\s*$/.test(rawCookieString))) {
    474         for (var i = 0; i < rawCookies.length; ++i) {
    475             var cookie = rawCookies[i];
    476             var delimIndex = cookie.indexOf("=");
    477             var name = cookie.substring(0, delimIndex);
    478             var value = cookie.substring(delimIndex + 1);
    479             var size = name.length + value.length;
    480             cookies.push({ name: name, value: value, size: size });
    481         }
    482     }
    483 
    484     return cookies;
    485 }
    486 
    487 WebInspector.Cookies.cookieMatchesResourceURL = function(cookie, resourceURL)
    488 {
    489     var match = resourceURL.match(WebInspector.URLRegExp);
    490     if (!match)
    491         return false;
    492     // See WebInspector.URLRegExp for definitions of the group index constants.
    493     if (!this.cookieDomainMatchesResourceDomain(cookie.domain, match[2]))
    494         return false;
    495     var resourcePort = match[3] ? match[3] : undefined;
    496     var resourcePath = match[4] ? match[4] : '/';
    497     return (resourcePath.indexOf(cookie.path) === 0
    498         && (!cookie.port || resourcePort == cookie.port)
    499         && (!cookie.secure || match[1].toLowerCase() === 'https'));
    500 }
    501 
    502 WebInspector.Cookies.cookieDomainMatchesResourceDomain = function(cookieDomain, resourceDomain)
    503 {
    504     if (cookieDomain.charAt(0) !== '.')
    505         return resourceDomain === cookieDomain;
    506     return !!resourceDomain.match(new RegExp("^([^\\.]+\\.)?" + cookieDomain.substring(1).escapeForRegExp() + "$"), "i");
    507 }
    508 
    509 WebInspector.EventListeners = {}
    510 
    511 WebInspector.EventListeners.getEventListenersForNodeAsync = function(node, callback)
    512 {
    513     if (!node)
    514         return;
    515 
    516     var callId = WebInspector.Callback.wrap(callback);
    517     InspectorBackend.getEventListenersForNode(callId, node.id);
    518 }
    519 
    520 WebInspector.CSSStyleDeclaration = function(payload)
    521 {
    522     this.id = payload.id;
    523     this.injectedScriptId = payload.injectedScriptId;
    524     this.width = payload.width;
    525     this.height = payload.height;
    526     this.__disabledProperties = payload.__disabledProperties;
    527     this.__disabledPropertyValues = payload.__disabledPropertyValues;
    528     this.__disabledPropertyPriorities = payload.__disabledPropertyPriorities;
    529     this.uniqueStyleProperties = payload.uniqueStyleProperties;
    530     this._shorthandValues = payload.shorthandValues;
    531     this._propertyMap = {};
    532     this._longhandProperties = {};
    533     this.length = payload.properties.length;
    534 
    535     for (var i = 0; i < this.length; ++i) {
    536         var property = payload.properties[i];
    537         var name = property.name;
    538         this[i] = name;
    539         this._propertyMap[name] = property;
    540     }
    541 
    542     // Index longhand properties.
    543     for (var i = 0; i < this.uniqueStyleProperties.length; ++i) {
    544         var name = this.uniqueStyleProperties[i];
    545         var property = this._propertyMap[name];
    546         if (property.shorthand) {
    547             var longhands = this._longhandProperties[property.shorthand];
    548             if (!longhands) {
    549                 longhands = [];
    550                 this._longhandProperties[property.shorthand] = longhands;
    551             }
    552             longhands.push(name);
    553         }
    554     }
    555 }
    556 
    557 WebInspector.CSSStyleDeclaration.parseStyle = function(payload)
    558 {
    559     return new WebInspector.CSSStyleDeclaration(payload);
    560 }
    561 
    562 WebInspector.CSSStyleDeclaration.parseRule = function(payload)
    563 {
    564     var rule = {};
    565     rule.id = payload.id;
    566     rule.injectedScriptId = payload.injectedScriptId;
    567     rule.selectorText = payload.selectorText;
    568     rule.style = new WebInspector.CSSStyleDeclaration(payload.style);
    569     rule.style.parentRule = rule;
    570     rule.isUserAgent = payload.isUserAgent;
    571     rule.isUser = payload.isUser;
    572     rule.isViaInspector = payload.isViaInspector;
    573     if (payload.parentStyleSheet)
    574         rule.parentStyleSheet = { href: payload.parentStyleSheet.href };
    575 
    576     return rule;
    577 }
    578 
    579 WebInspector.CSSStyleDeclaration.prototype = {
    580     getPropertyValue: function(name)
    581     {
    582         var property = this._propertyMap[name];
    583         return property ? property.value : "";
    584     },
    585 
    586     getPropertyPriority: function(name)
    587     {
    588         var property = this._propertyMap[name];
    589         return property ? property.priority : "";
    590     },
    591 
    592     getPropertyShorthand: function(name)
    593     {
    594         var property = this._propertyMap[name];
    595         return property ? property.shorthand : "";
    596     },
    597 
    598     isPropertyImplicit: function(name)
    599     {
    600         var property = this._propertyMap[name];
    601         return property ? property.implicit : "";
    602     },
    603 
    604     styleTextWithShorthands: function()
    605     {
    606         var cssText = "";
    607         var foundProperties = {};
    608         for (var i = 0; i < this.length; ++i) {
    609             var individualProperty = this[i];
    610             var shorthandProperty = this.getPropertyShorthand(individualProperty);
    611             var propertyName = (shorthandProperty || individualProperty);
    612 
    613             if (propertyName in foundProperties)
    614                 continue;
    615 
    616             if (shorthandProperty) {
    617                 var value = this.getPropertyValue(shorthandProperty);
    618                 var priority = this.getShorthandPriority(shorthandProperty);
    619             } else {
    620                 var value = this.getPropertyValue(individualProperty);
    621                 var priority = this.getPropertyPriority(individualProperty);
    622             }
    623 
    624             foundProperties[propertyName] = true;
    625 
    626             cssText += propertyName + ": " + value;
    627             if (priority)
    628                 cssText += " !" + priority;
    629             cssText += "; ";
    630         }
    631 
    632         return cssText;
    633     },
    634 
    635     getLonghandProperties: function(name)
    636     {
    637         return this._longhandProperties[name] || [];
    638     },
    639 
    640     getShorthandValue: function(shorthandProperty)
    641     {
    642         return this._shorthandValues[shorthandProperty];
    643     },
    644 
    645     getShorthandPriority: function(shorthandProperty)
    646     {
    647         var priority = this.getPropertyPriority(shorthandProperty);
    648         if (priority)
    649             return priority;
    650 
    651         var longhands = this._longhandProperties[shorthandProperty];
    652         return longhands ? this.getPropertyPriority(longhands[0]) : null;
    653     }
    654 }
    655 
    656 WebInspector.attributesUpdated = function()
    657 {
    658     this.domAgent._attributesUpdated.apply(this.domAgent, arguments);
    659 }
    660 
    661 WebInspector.setDocument = function()
    662 {
    663     this.domAgent._setDocument.apply(this.domAgent, arguments);
    664 }
    665 
    666 WebInspector.setDetachedRoot = function()
    667 {
    668     this.domAgent._setDetachedRoot.apply(this.domAgent, arguments);
    669 }
    670 
    671 WebInspector.setChildNodes = function()
    672 {
    673     this.domAgent._setChildNodes.apply(this.domAgent, arguments);
    674 }
    675 
    676 WebInspector.childNodeCountUpdated = function()
    677 {
    678     this.domAgent._childNodeCountUpdated.apply(this.domAgent, arguments);
    679 }
    680 
    681 WebInspector.childNodeInserted = function()
    682 {
    683     this.domAgent._childNodeInserted.apply(this.domAgent, arguments);
    684 }
    685 
    686 WebInspector.childNodeRemoved = function()
    687 {
    688     this.domAgent._childNodeRemoved.apply(this.domAgent, arguments);
    689 }
    690 
    691 WebInspector.didGetCookies = WebInspector.Callback.processCallback;
    692 WebInspector.didGetChildNodes = WebInspector.Callback.processCallback;
    693 WebInspector.didPerformSearch = WebInspector.Callback.processCallback;
    694 WebInspector.didApplyDomChange = WebInspector.Callback.processCallback;
    695 WebInspector.didRemoveAttribute = WebInspector.Callback.processCallback;
    696 WebInspector.didSetTextNodeValue = WebInspector.Callback.processCallback;
    697 WebInspector.didGetEventListenersForNode = WebInspector.Callback.processCallback;
    698