Home | History | Annotate | Download | only in front-end
      1 /*
      2  * Copyright (C) 2008 Apple 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
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 WebInspector.CallStackSidebarPane = function(model)
     27 {
     28     WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack"));
     29     this._model = model;
     30 
     31     this.bodyElement.addEventListener("contextmenu", this._contextMenu.bind(this), true);
     32 }
     33 
     34 WebInspector.CallStackSidebarPane.prototype = {
     35     update: function(callFrames, details)
     36     {
     37         this.bodyElement.removeChildren();
     38 
     39         this.placards = [];
     40 
     41         if (!callFrames) {
     42             var infoElement = document.createElement("div");
     43             infoElement.className = "info";
     44             infoElement.textContent = WebInspector.UIString("Not Paused");
     45             this.bodyElement.appendChild(infoElement);
     46             return;
     47         }
     48 
     49         for (var i = 0; i < callFrames.length; ++i) {
     50             var callFrame = callFrames[i];
     51             var title = callFrame.functionName || WebInspector.UIString("(anonymous function)");
     52 
     53             var subtitle;
     54             if (!callFrame.isInternalScript)
     55                 subtitle = WebInspector.displayNameForURL(callFrame.url);
     56             else
     57                 subtitle = WebInspector.UIString("(internal script)");
     58 
     59             var placard = new WebInspector.Placard(title, subtitle);
     60             placard.callFrame = callFrame;
     61             placard.element.addEventListener("click", this._placardSelected.bind(this, placard), false);
     62 
     63             function didGetSourceLine(placard, sourceFileId, lineNumber)
     64             {
     65                 if (placard.subtitle)
     66                     placard.subtitle += ":" + (lineNumber + 1);
     67                 else
     68                     placard.subtitle = WebInspector.UIString("line %d", lineNumber + 1);
     69                 placard._text = WebInspector.UIString("%s() at %s", placard.title, placard.subtitle);
     70             }
     71             callFrame.sourceLine(didGetSourceLine.bind(this, placard));
     72 
     73             this.placards.push(placard);
     74             this.bodyElement.appendChild(placard.element);
     75         }
     76     },
     77 
     78     set selectedCallFrame(x)
     79     {
     80         for (var i = 0; i < this.placards.length; ++i) {
     81             var placard = this.placards[i];
     82             placard.selected = (placard.callFrame === x);
     83         }
     84     },
     85 
     86     handleShortcut: function(event)
     87     {
     88         var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
     89         var handler = this._shortcuts[shortcut];
     90         if (handler) {
     91             handler(event);
     92             event.handled = true;
     93         }
     94     },
     95 
     96     _selectNextCallFrameOnStack: function()
     97     {
     98         var index = this._selectedCallFrameIndex();
     99         if (index == -1)
    100             return;
    101         this._selectedPlacardByIndex(index + 1);
    102     },
    103 
    104     _selectPreviousCallFrameOnStack: function()
    105     {
    106         var index = this._selectedCallFrameIndex();
    107         if (index == -1)
    108             return;
    109         this._selectedPlacardByIndex(index - 1);
    110     },
    111 
    112     _selectedPlacardByIndex: function(index)
    113     {
    114         if (index < 0 || index >= this.placards.length)
    115             return;
    116         var placard = this.placards[index];
    117         this.selectedCallFrame = placard.callFrame
    118     },
    119 
    120     _selectedCallFrameIndex: function()
    121     {
    122         if (!this._model.selectedCallFrame)
    123             return -1;
    124         for (var i = 0; i < this.placards.length; ++i) {
    125             var placard = this.placards[i];
    126             if (placard.callFrame === this._model.selectedCallFrame)
    127                 return i;
    128         }
    129         return -1;
    130     },
    131 
    132     _placardSelected: function(placard, event)
    133     {
    134         this._model.selectedCallFrame = placard.callFrame;
    135     },
    136 
    137     _contextMenu: function(event)
    138     {
    139         if (!this.placards.length)
    140             return;
    141 
    142         var contextMenu = new WebInspector.ContextMenu();
    143         contextMenu.appendItem(WebInspector.UIString("Copy Stack Trace"), this._copyStackTrace.bind(this));
    144         contextMenu.show(event);
    145     },
    146 
    147     _copyStackTrace: function()
    148     {
    149         var text = "";
    150         for (var i = 0; i < this.placards.length; ++i)
    151             text += this.placards[i]._text;
    152         InspectorFrontendHost.copyText(text);
    153     },
    154 
    155     registerShortcuts: function(section)
    156     {
    157         this._shortcuts = {};
    158 
    159         var nextCallFrame = WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Period,
    160             WebInspector.KeyboardShortcut.Modifiers.Ctrl);
    161         this._shortcuts[nextCallFrame.key] = this._selectNextCallFrameOnStack.bind(this);
    162 
    163         var prevCallFrame = WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Comma,
    164             WebInspector.KeyboardShortcut.Modifiers.Ctrl);
    165         this._shortcuts[prevCallFrame.key] = this._selectPreviousCallFrameOnStack.bind(this);
    166 
    167         section.addRelatedKeys([ nextCallFrame.name, prevCallFrame.name ], WebInspector.UIString("Next/previous call frame"));
    168     },
    169 
    170     setStatus: function(status)
    171     {
    172         var statusMessageElement = document.createElement("div");
    173         statusMessageElement.className = "info";
    174         if (typeof status === "string")
    175             statusMessageElement.textContent = status;
    176         else
    177             statusMessageElement.appendChild(status);
    178         this.bodyElement.appendChild(statusMessageElement);
    179     }
    180 }
    181 
    182 WebInspector.CallStackSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
    183