Home | History | Annotate | Download | only in bindings
      1 /*
      2  * Copyright (C) 2012 Google Inc. 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 Google Inc. 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 /**
     32  * @constructor
     33  * @param {!WebInspector.Workspace} workspace
     34  */
     35 WebInspector.PresentationConsoleMessageHelper = function(workspace)
     36 {
     37     this._workspace = workspace;
     38 
     39     /** @type {!Object.<string, !Array.<!WebInspector.ConsoleMessage>>} */
     40     this._pendingConsoleMessages = {};
     41 
     42     /** @type {!Array.<!WebInspector.PresentationConsoleMessage>} */
     43     this._presentationConsoleMessages = [];
     44 
     45     /** @type {!Map.<!WebInspector.UISourceCode, !Array.<!WebInspector.PresentationConsoleMessage>>} */
     46     this._uiSourceCodeToMessages = new Map();
     47 
     48     /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.Object>} */
     49     this._uiSourceCodeToEventTarget = new Map();
     50 
     51     workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
     52     workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemoved, this._projectRemoved, this);
     53     WebInspector.multitargetConsoleModel.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this);
     54     WebInspector.multitargetConsoleModel.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._onConsoleMessageAdded, this);
     55     WebInspector.multitargetConsoleModel.messages().forEach(this._consoleMessageAdded, this);
     56     WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this);
     57     WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.FailedToParseScriptSource, this._parsedScriptSource, this);
     58     WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
     59 }
     60 
     61 /**
     62  * @enum {string}
     63  */
     64 WebInspector.PresentationConsoleMessageHelper.Events = {
     65     ConsoleMessageAdded: "ConsoleMessageAdded",
     66     ConsoleMessageRemoved: "ConsoleMessageRemoved",
     67     ConsoleMessagesCleared: "ConsoleMessagesCleared",
     68 }
     69 
     70 WebInspector.PresentationConsoleMessageHelper.prototype = {
     71     /**
     72      * @param {!WebInspector.PresentationConsoleMessageHelper.Events} eventType
     73      * @param {!WebInspector.UISourceCode} uiSourceCode
     74      * @param {function(!WebInspector.Event)} listener
     75      * @param {!Object=} thisObject
     76      */
     77     addConsoleMessageEventListener: function(eventType, uiSourceCode, listener, thisObject)
     78     {
     79         var target = this._uiSourceCodeToEventTarget.get(uiSourceCode);
     80         if (!target) {
     81             target = new WebInspector.Object();
     82             this._uiSourceCodeToEventTarget.set(uiSourceCode, target);
     83         }
     84         target.addEventListener(eventType, listener, thisObject);
     85     },
     86 
     87     /**
     88      * @param {!WebInspector.PresentationConsoleMessageHelper.Events} eventType
     89      * @param {!WebInspector.UISourceCode} uiSourceCode
     90      * @param {function(!WebInspector.Event)} listener
     91      * @param {!Object=} thisObject
     92      */
     93     removeConsoleMessageEventListener: function(eventType, uiSourceCode, listener, thisObject)
     94     {
     95         var target = this._uiSourceCodeToEventTarget.get(uiSourceCode);
     96         if (!target)
     97             return;
     98         target.removeEventListener(eventType, listener, thisObject);
     99     },
    100 
    101     /**
    102      * @param {!WebInspector.UISourceCode} uiSourceCode
    103      * @return {!Array.<!WebInspector.PresentationConsoleMessage>}
    104      */
    105     consoleMessages: function(uiSourceCode)
    106     {
    107         return this._uiSourceCodeToMessages.get(uiSourceCode) || [];
    108     },
    109 
    110     /**
    111      * @param {!WebInspector.PresentationConsoleMessageHelper.Events} eventType
    112      * @param {!WebInspector.UISourceCode} uiSourceCode
    113      * @param {!WebInspector.PresentationConsoleMessage=} message
    114      */
    115     _dispatchConsoleEvent: function(eventType, uiSourceCode, message)
    116     {
    117         var target = this._uiSourceCodeToEventTarget.get(uiSourceCode);
    118         if (!target)
    119             return;
    120         target.dispatchEventToListeners(eventType, message);
    121     },
    122 
    123     /**
    124      * @param {!WebInspector.Event} event
    125      */
    126     _uiSourceCodeRemoved: function(event)
    127     {
    128         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
    129         this._uiSourceCodeToEventTarget.remove(uiSourceCode);
    130         this._uiSourceCodeToMessages.remove(uiSourceCode);
    131     },
    132 
    133     /**
    134      * @param {!WebInspector.Event} event
    135      */
    136     _projectRemoved: function(event)
    137     {
    138         var project = /** @type {!WebInspector.Project} */ (event.data);
    139         var uiSourceCodes = project.uiSourceCodes();
    140         for (var i = 0; i < uiSourceCodes.length; ++i) {
    141             this._uiSourceCodeToEventTarget.remove(uiSourceCodes[i]);
    142             this._uiSourceCodeToMessages.remove(uiSourceCodes[i]);
    143         }
    144     },
    145 
    146     /**
    147      * @param {!WebInspector.Event} event
    148      */
    149     _onConsoleMessageAdded: function(event)
    150     {
    151         var message = /** @type {!WebInspector.ConsoleMessage} */ (event.data);
    152         this._consoleMessageAdded(message)
    153     },
    154 
    155     /**
    156      * @param {!WebInspector.ConsoleMessage} message
    157      */
    158     _consoleMessageAdded: function(message)
    159     {
    160         if (!message.url || !message.isErrorOrWarning())
    161             return;
    162 
    163         var rawLocation = this._rawLocation(message);
    164         if (rawLocation)
    165             this._addConsoleMessageToScript(message, rawLocation);
    166         else
    167             this._addPendingConsoleMessage(message);
    168     },
    169 
    170     /**
    171      * @param {!WebInspector.ConsoleMessage} message
    172      * @return {?WebInspector.DebuggerModel.Location}
    173      */
    174     _rawLocation: function(message)
    175     {
    176         // FIXME(62725): stack trace line/column numbers are one-based.
    177         var lineNumber = message.stackTrace ? message.stackTrace[0].lineNumber - 1 : message.line - 1;
    178         var columnNumber = message.stackTrace && message.stackTrace[0].columnNumber ? message.stackTrace[0].columnNumber - 1 : 0;
    179         if (message.scriptId)
    180             return message.target().debuggerModel.createRawLocationByScriptId(message.scriptId, message.url || "", lineNumber, columnNumber);
    181         return message.target().debuggerModel.createRawLocationByURL(message.url || "", lineNumber, columnNumber);
    182     },
    183 
    184     /**
    185      * @param {!WebInspector.ConsoleMessage} message
    186      * @param {!WebInspector.DebuggerModel.Location} rawLocation
    187      */
    188     _addConsoleMessageToScript: function(message, rawLocation)
    189     {
    190         this._presentationConsoleMessages.push(new WebInspector.PresentationConsoleMessage(message, rawLocation));
    191     },
    192 
    193     /**
    194      * @param {!WebInspector.ConsoleMessage} message
    195      */
    196     _addPendingConsoleMessage: function(message)
    197     {
    198         if (!message.url)
    199             return;
    200         if (!this._pendingConsoleMessages[message.url])
    201             this._pendingConsoleMessages[message.url] = [];
    202         this._pendingConsoleMessages[message.url].push(message);
    203     },
    204 
    205     /**
    206      * @param {!WebInspector.Event} event
    207      */
    208     _parsedScriptSource: function(event)
    209     {
    210         var script = /** @type {!WebInspector.Script} */ (event.data);
    211 
    212         var messages = this._pendingConsoleMessages[script.sourceURL];
    213         if (!messages)
    214             return;
    215 
    216         var pendingMessages = [];
    217         for (var i = 0; i < messages.length; i++) {
    218             var message = messages[i];
    219             var rawLocation = this._rawLocation(message);
    220             if (script.target() === message.target() && script.scriptId === rawLocation.scriptId)
    221                 this._addConsoleMessageToScript(message, rawLocation);
    222             else
    223                 pendingMessages.push(message);
    224         }
    225 
    226         if (pendingMessages.length)
    227             this._pendingConsoleMessages[script.sourceURL] = pendingMessages;
    228         else
    229             delete this._pendingConsoleMessages[script.sourceURL];
    230     },
    231 
    232     /**
    233      * @param {!WebInspector.PresentationConsoleMessage} message
    234      */
    235     _presentationConsoleMessageAdded: function(message)
    236     {
    237         var uiSourceCode = message._uiLocation.uiSourceCode;
    238         var messages = this._uiSourceCodeToMessages.get(uiSourceCode);
    239         if (!messages) {
    240             messages = [];
    241             this._uiSourceCodeToMessages.set(uiSourceCode, messages);
    242         }
    243         messages.push(message);
    244         this._dispatchConsoleEvent(WebInspector.PresentationConsoleMessageHelper.Events.ConsoleMessageAdded, uiSourceCode, message);
    245     },
    246 
    247     /**
    248      * @param {!WebInspector.PresentationConsoleMessage} message
    249      */
    250     _presentationConsoleMessageRemoved: function(message)
    251     {
    252         var uiSourceCode = message._uiLocation.uiSourceCode;
    253         var messages = this._uiSourceCodeToMessages.get(uiSourceCode);
    254         if (!messages)
    255             return;
    256         messages.remove(message);
    257         this._dispatchConsoleEvent(WebInspector.PresentationConsoleMessageHelper.Events.ConsoleMessageRemoved, uiSourceCode, message);
    258     },
    259 
    260     _consoleCleared: function()
    261     {
    262         this._pendingConsoleMessages = {};
    263         for (var i = 0; i < this._presentationConsoleMessages.length; ++i)
    264             this._presentationConsoleMessages[i].dispose();
    265         this._presentationConsoleMessages = [];
    266         var targets = this._uiSourceCodeToEventTarget.values();
    267         for (var i = 0; i < targets.length; ++i)
    268             targets[i].dispatchEventToListeners(WebInspector.PresentationConsoleMessageHelper.Events.ConsoleMessagesCleared);
    269         this._uiSourceCodeToMessages.clear();
    270     },
    271 
    272     _debuggerReset: function()
    273     {
    274         this._pendingConsoleMessages = {};
    275         this._presentationConsoleMessages = [];
    276     }
    277 }
    278 
    279 /**
    280  * @constructor
    281  * @param {!WebInspector.ConsoleMessage} message
    282  * @param {!WebInspector.DebuggerModel.Location} rawLocation
    283  */
    284 WebInspector.PresentationConsoleMessage = function(message, rawLocation)
    285 {
    286     this.originalMessage = message;
    287     this._liveLocation = WebInspector.debuggerWorkspaceBinding.createLiveLocation(rawLocation, this._updateLocation.bind(this));
    288 }
    289 
    290 WebInspector.PresentationConsoleMessage.prototype = {
    291     /**
    292      * @param {!WebInspector.UILocation} uiLocation
    293      */
    294     _updateLocation: function(uiLocation)
    295     {
    296         if (this._uiLocation)
    297             WebInspector.presentationConsoleMessageHelper._presentationConsoleMessageRemoved(this);
    298         this._uiLocation = uiLocation;
    299         WebInspector.presentationConsoleMessageHelper._presentationConsoleMessageAdded(this);
    300     },
    301 
    302     get lineNumber()
    303     {
    304         return this._uiLocation.lineNumber;
    305     },
    306 
    307     dispose: function()
    308     {
    309         this._liveLocation.dispose();
    310     }
    311 }
    312 
    313 /** @type {!WebInspector.PresentationConsoleMessageHelper} */
    314 WebInspector.presentationConsoleMessageHelper;