Home | History | Annotate | Download | only in sources
      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  * 1. Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *
     11  * 2. 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  *
     16  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
     17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
     20  * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /**
     30  * @constructor
     31  * @extends {WebInspector.SourceFrame}
     32  * @param {!WebInspector.UISourceCode} uiSourceCode
     33  */
     34 WebInspector.UISourceCodeFrame = function(uiSourceCode)
     35 {
     36     this._uiSourceCode = uiSourceCode;
     37     WebInspector.SourceFrame.call(this, this._uiSourceCode);
     38     WebInspector.settings.textEditorAutocompletion.addChangeListener(this._enableAutocompletionIfNeeded, this);
     39     this._enableAutocompletionIfNeeded();
     40 
     41     this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._onWorkingCopyChanged, this);
     42     this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._onWorkingCopyCommitted, this);
     43     this._updateStyle();
     44 }
     45 
     46 WebInspector.UISourceCodeFrame.prototype = {
     47     /**
     48      * @return {!WebInspector.UISourceCode}
     49      */
     50     uiSourceCode: function()
     51     {
     52         return this._uiSourceCode;
     53     },
     54 
     55     _enableAutocompletionIfNeeded: function()
     56     {
     57         this.textEditor.setCompletionDictionary(WebInspector.settings.textEditorAutocompletion.get() ? new WebInspector.SampleCompletionDictionary() : null);
     58     },
     59 
     60     wasShown: function()
     61     {
     62         WebInspector.SourceFrame.prototype.wasShown.call(this);
     63         this._boundWindowFocused = this._windowFocused.bind(this);
     64         window.addEventListener("focus", this._boundWindowFocused, false);
     65         this._checkContentUpdated();
     66     },
     67 
     68     willHide: function()
     69     {
     70         WebInspector.SourceFrame.prototype.willHide.call(this);
     71         window.removeEventListener("focus", this._boundWindowFocused, false);
     72         delete this._boundWindowFocused;
     73         this._uiSourceCode.removeWorkingCopyGetter();
     74     },
     75 
     76     /**
     77      * @return {boolean}
     78      */
     79     canEditSource: function()
     80     {
     81         var projectType = this._uiSourceCode.project().type();
     82         if (projectType === WebInspector.projectTypes.Debugger || projectType === WebInspector.projectTypes.Formatter)
     83             return false;
     84         if (projectType === WebInspector.projectTypes.Network && this._uiSourceCode.contentType() === WebInspector.resourceTypes.Document)
     85             return false;
     86         return true;
     87     },
     88 
     89     _windowFocused: function(event)
     90     {
     91         this._checkContentUpdated();
     92     },
     93 
     94     _checkContentUpdated: function()
     95     {
     96         if (!this.loaded || !this.isShowing())
     97             return;
     98         this._uiSourceCode.checkContentUpdated();
     99     },
    100 
    101     commitEditing: function()
    102     {
    103         if (!this._uiSourceCode.isDirty())
    104             return;
    105 
    106         this._muteSourceCodeEvents = true;
    107         this._uiSourceCode.commitWorkingCopy();
    108         delete this._muteSourceCodeEvents;
    109     },
    110 
    111     onTextChanged: function(oldRange, newRange)
    112     {
    113         WebInspector.SourceFrame.prototype.onTextChanged.call(this, oldRange, newRange);
    114         if (this._isSettingContent)
    115             return;
    116         this._muteSourceCodeEvents = true;
    117         if (this._textEditor.isClean())
    118             this._uiSourceCode.resetWorkingCopy();
    119         else
    120             this._uiSourceCode.setWorkingCopyGetter(this._textEditor.text.bind(this._textEditor));
    121         delete this._muteSourceCodeEvents;
    122     },
    123 
    124     /**
    125      * @param {!WebInspector.Event} event
    126      */
    127     _onWorkingCopyChanged: function(event)
    128     {
    129         if (this._muteSourceCodeEvents)
    130             return;
    131         this._innerSetContent(this._uiSourceCode.workingCopy());
    132         this.onUISourceCodeContentChanged();
    133     },
    134 
    135     /**
    136      * @param {!WebInspector.Event} event
    137      */
    138     _onWorkingCopyCommitted: function(event)
    139     {
    140         if (!this._muteSourceCodeEvents) {
    141             this._innerSetContent(this._uiSourceCode.workingCopy());
    142             this.onUISourceCodeContentChanged();
    143         }
    144         this._textEditor.markClean();
    145         this._updateStyle();
    146         WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
    147             action: WebInspector.UserMetrics.UserActionNames.FileSaved,
    148             url: this._uiSourceCode.url
    149         });
    150     },
    151 
    152     _updateStyle: function()
    153     {
    154         this.element.classList.toggle("source-frame-unsaved-committed-changes", this._uiSourceCode.hasUnsavedCommittedChanges());
    155     },
    156 
    157     onUISourceCodeContentChanged: function()
    158     {
    159     },
    160 
    161     /**
    162      * @param {string} content
    163      */
    164     _innerSetContent: function(content)
    165     {
    166         this._isSettingContent = true;
    167         this.setContent(content);
    168         delete this._isSettingContent;
    169     },
    170 
    171     populateTextAreaContextMenu: function(contextMenu, lineNumber)
    172     {
    173         WebInspector.SourceFrame.prototype.populateTextAreaContextMenu.call(this, contextMenu, lineNumber);
    174         contextMenu.appendApplicableItems(this._uiSourceCode);
    175         contextMenu.appendSeparator();
    176     },
    177 
    178     /**
    179      * @param {!Array.<!WebInspector.UISourceCodeFrame.Infobar|undefined>} infobars
    180      */
    181     attachInfobars: function(infobars)
    182     {
    183         for (var i = infobars.length - 1; i >= 0; --i) {
    184             var infobar = infobars[i];
    185             if (!infobar)
    186                 continue;
    187             this.element.insertBefore(infobar.element, this.element.children[0]);
    188             infobar._attached(this);
    189         }
    190         this.doResize();
    191     },
    192 
    193     dispose: function()
    194     {
    195         WebInspector.settings.textEditorAutocompletion.removeChangeListener(this._enableAutocompletionIfNeeded, this);
    196         this._textEditor.dispose();
    197         this.detach();
    198     },
    199 
    200     __proto__: WebInspector.SourceFrame.prototype
    201 }
    202 
    203 /**
    204  * @constructor
    205  * @param {!WebInspector.UISourceCodeFrame.Infobar.Level} level
    206  * @param {string} message
    207  */
    208 WebInspector.UISourceCodeFrame.Infobar = function(level, message)
    209 {
    210     this.element = document.createElementWithClass("div", "source-frame-infobar source-frame-infobar-" + level);
    211     this._mainRow = this.element.createChild("div", "source-frame-infobar-main-row");
    212     this._detailsContainer = this.element.createChild("span", "source-frame-infobar-details-container");
    213 
    214     this._mainRow.createChild("span", "source-frame-infobar-icon");
    215     this._mainRow.createChild("span", "source-frame-infobar-row-message").textContent = message;
    216 
    217     this._toggleElement = this._mainRow.createChild("div", "source-frame-infobar-toggle source-frame-infobar-link");
    218     this._toggleElement.addEventListener("click", this._onToggleDetails.bind(this), false);
    219 
    220     this._closeElement = this._mainRow.createChild("div", "close-button");
    221     this._closeElement.addEventListener("click", this._onClose.bind(this), false);
    222 
    223     this._updateToggleElement();
    224 }
    225 
    226 /**
    227  * @enum {string}
    228  */
    229 WebInspector.UISourceCodeFrame.Infobar.Level = {
    230     Info: "info",
    231     Warning: "warning",
    232     Error: "error",
    233 };
    234 
    235 WebInspector.UISourceCodeFrame.Infobar.prototype = {
    236     _onResize: function()
    237     {
    238         if (this._uiSourceCodeFrame)
    239             this._uiSourceCodeFrame.doResize();
    240     },
    241 
    242     _onToggleDetails: function()
    243     {
    244         this._toggled = !this._toggled;
    245         this._updateToggleElement();
    246         this._onResize();
    247     },
    248 
    249     _onClose: function()
    250     {
    251         this.dispose();
    252     },
    253 
    254     _updateToggleElement: function()
    255     {
    256         this._toggleElement.textContent = this._toggled ? WebInspector.UIString("less") : WebInspector.UIString("more");
    257         this._detailsContainer.classList.toggle("hidden", !this._toggled);
    258     },
    259 
    260     /**
    261      * @param {!WebInspector.UISourceCodeFrame} uiSourceCodeFrame
    262      */
    263     _attached: function(uiSourceCodeFrame)
    264     {
    265         this._uiSourceCodeFrame = uiSourceCodeFrame;
    266     },
    267 
    268     /**
    269      * @param {string=} message
    270      * @return {!Element}
    271      */
    272     createDetailsRowMessage: function(message)
    273     {
    274         var infobarDetailsRow = this._detailsContainer.createChild("div", "source-frame-infobar-details-row");
    275         var detailsRowMessage = infobarDetailsRow.createChild("span", "source-frame-infobar-row-message");
    276         detailsRowMessage.textContent = message || "";
    277         return detailsRowMessage;
    278     },
    279 
    280     dispose: function()
    281     {
    282         this.element.remove();
    283         this._onResize();
    284         delete this._uiSourceCodeFrame;
    285     }
    286 }
    287