Web Inspector: Move a few remaining global WI settings to WI.settings
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / TextResourceContentView.js
1 /*
2  * Copyright (C) 2013, 2015 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WI.TextResourceContentView = class TextResourceContentView extends WI.ResourceContentView
27 {
28     constructor(resource)
29     {
30         super(resource, "text");
31
32         resource.addEventListener(WI.SourceCode.Event.ContentDidChange, this._sourceCodeContentDidChange, this);
33
34         var toolTip = WI.UIString("Pretty print");
35         var activatedToolTip = WI.UIString("Original formatting");
36         this._prettyPrintButtonNavigationItem = new WI.ActivateButtonNavigationItem("pretty-print", toolTip, activatedToolTip, "Images/NavigationItemCurleyBraces.svg", 13, 13);
37         this._prettyPrintButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._togglePrettyPrint, this);
38         this._prettyPrintButtonNavigationItem.enabled = false; // Enabled when the text editor is populated with content.
39         this._prettyPrintButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
40
41         var toolTipTypes = WI.UIString("Show type information");
42         var activatedToolTipTypes = WI.UIString("Hide type information");
43         this._showTypesButtonNavigationItem = new WI.ActivateButtonNavigationItem("show-types", toolTipTypes, activatedToolTipTypes, "Images/NavigationItemTypes.svg", 13, 14);
44         this._showTypesButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._toggleTypeAnnotations, this);
45         this._showTypesButtonNavigationItem.enabled = false;
46         this._showTypesButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
47         WI.settings.showJavaScriptTypeInformation.addEventListener(WI.Setting.Event.Changed, this._showJavaScriptTypeInformationSettingChanged, this);
48
49         let toolTipCodeCoverage = WI.UIString("Fade unexecuted code");
50         let activatedToolTipCodeCoverage = WI.UIString("Do not fade unexecuted code");
51         this._codeCoverageButtonNavigationItem = new WI.ActivateButtonNavigationItem("code-coverage", toolTipCodeCoverage, activatedToolTipCodeCoverage, "Images/NavigationItemCodeCoverage.svg", 13, 14);
52         this._codeCoverageButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._toggleUnexecutedCodeHighlights, this);
53         this._codeCoverageButtonNavigationItem.enabled = false;
54         this._codeCoverageButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
55         WI.settings.enableControlFlowProfiler.addEventListener(WI.Setting.Event.Changed, this._enableControlFlowProfilerSettingChanged, this);
56
57         this._textEditor = new WI.SourceCodeTextEditor(resource);
58         this._textEditor.addEventListener(WI.TextEditor.Event.ExecutionLineNumberDidChange, this._executionLineNumberDidChange, this);
59         this._textEditor.addEventListener(WI.TextEditor.Event.NumberOfSearchResultsDidChange, this._numberOfSearchResultsDidChange, this);
60         this._textEditor.addEventListener(WI.TextEditor.Event.ContentDidChange, this._textEditorContentDidChange, this);
61         this._textEditor.addEventListener(WI.TextEditor.Event.FormattingDidChange, this._textEditorFormattingDidChange, this);
62         this._textEditor.addEventListener(WI.TextEditor.Event.MIMETypeChanged, this._handleTextEditorMIMETypeChanged, this);
63         this._textEditor.addEventListener(WI.SourceCodeTextEditor.Event.ContentWillPopulate, this._contentWillPopulate, this);
64         this._textEditor.addEventListener(WI.SourceCodeTextEditor.Event.ContentDidPopulate, this._contentDidPopulate, this);
65         this._textEditor.readOnly = !this._shouldBeEditable();
66
67         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ProbeSetAdded, this._probeSetsChanged, this);
68         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ProbeSetRemoved, this._probeSetsChanged, this);
69     }
70
71     // Public
72
73     get navigationItems()
74     {
75         return [this._prettyPrintButtonNavigationItem, this._showTypesButtonNavigationItem, this._codeCoverageButtonNavigationItem];
76     }
77
78     get managesOwnIssues()
79     {
80         // SourceCodeTextEditor manages the issues, we don't need ResourceContentView doing it.
81         return true;
82     }
83
84     get textEditor()
85     {
86         return this._textEditor;
87     }
88
89     get supplementalRepresentedObjects()
90     {
91         let objects = WI.debuggerManager.probeSets.filter(function(probeSet) {
92             return this._resource.contentIdentifier === probeSet.breakpoint.contentIdentifier;
93         }, this);
94
95         // If the SourceCodeTextEditor has an executionLineNumber, we can assume
96         // it is always the active call frame.
97         if (!isNaN(this._textEditor.executionLineNumber))
98             objects.push(WI.debuggerManager.activeCallFrame);
99
100         return objects;
101     }
102
103     revealPosition(position, textRangeToSelect, forceUnformatted)
104     {
105         this._textEditor.revealPosition(position, textRangeToSelect, forceUnformatted);
106     }
107
108     shown()
109     {
110         super.shown();
111
112         this._textEditor.shown();
113     }
114
115     hidden()
116     {
117         super.hidden();
118
119         this._textEditor.hidden();
120     }
121
122     closed()
123     {
124         super.closed();
125
126         this.resource.removeEventListener(null, null, this);
127         WI.debuggerManager.removeEventListener(null, null, this);
128         WI.settings.showJavaScriptTypeInformation.removeEventListener(null, null, this);
129         WI.settings.enableControlFlowProfiler.removeEventListener(null, null, this);
130
131         this._textEditor.close();
132     }
133
134     contentAvailable(content, base64Encoded)
135     {
136         // Do nothing.
137     }
138
139     get supportsSave()
140     {
141         return super.supportsSave || this.resource instanceof WI.CSSStyleSheet;
142     }
143
144     get saveData()
145     {
146         if (this.resource instanceof WI.CSSStyleSheet)
147             return {url: "web-inspector:///InspectorStyleSheet.css", content: this._textEditor.string, forceSaveAs: true};
148         return {url: this.resource.url, content: this._textEditor.string};
149     }
150
151     get supportsSearch()
152     {
153         return true;
154     }
155
156     get numberOfSearchResults()
157     {
158         return this._textEditor.numberOfSearchResults;
159     }
160
161     get hasPerformedSearch()
162     {
163         return this._textEditor.currentSearchQuery !== null;
164     }
165
166     set automaticallyRevealFirstSearchResult(reveal)
167     {
168         this._textEditor.automaticallyRevealFirstSearchResult = reveal;
169     }
170
171     performSearch(query)
172     {
173         this._textEditor.performSearch(query);
174     }
175
176     searchCleared()
177     {
178         this._textEditor.searchCleared();
179     }
180
181     searchQueryWithSelection()
182     {
183         return this._textEditor.searchQueryWithSelection();
184     }
185
186     revealPreviousSearchResult(changeFocus)
187     {
188         this._textEditor.revealPreviousSearchResult(changeFocus);
189     }
190
191     revealNextSearchResult(changeFocus)
192     {
193         this._textEditor.revealNextSearchResult(changeFocus);
194     }
195
196     // Private
197
198     _contentWillPopulate(event)
199     {
200         if (this._textEditor.parentView === this)
201             return;
202
203         this.removeLoadingIndicator();
204
205         this.addSubview(this._textEditor);
206     }
207
208     _contentDidPopulate(event)
209     {
210         this._prettyPrintButtonNavigationItem.enabled = this._textEditor.canBeFormatted();
211
212         this._showTypesButtonNavigationItem.enabled = this._textEditor.canShowTypeAnnotations();
213         this._showTypesButtonNavigationItem.activated = WI.settings.showJavaScriptTypeInformation.value;
214
215         this._codeCoverageButtonNavigationItem.enabled = this._textEditor.canShowCoverageHints();
216         this._codeCoverageButtonNavigationItem.activated = WI.settings.enableControlFlowProfiler.value;
217
218         if (!this._textEditor.string)
219             this.showGenericNoContentMessage();
220     }
221
222     _togglePrettyPrint(event)
223     {
224         var activated = !this._prettyPrintButtonNavigationItem.activated;
225         this._textEditor.updateFormattedState(activated);
226     }
227
228     _toggleTypeAnnotations(event)
229     {
230         this._showTypesButtonNavigationItem.enabled = false;
231         this._textEditor.toggleTypeAnnotations().then(() => {
232             this._showTypesButtonNavigationItem.enabled = true;
233         });
234     }
235
236     _toggleUnexecutedCodeHighlights(event)
237     {
238         this._codeCoverageButtonNavigationItem.enabled = false;
239         this._textEditor.toggleUnexecutedCodeHighlights().then(() => {
240             this._codeCoverageButtonNavigationItem.enabled = true;
241         });
242     }
243
244     _showJavaScriptTypeInformationSettingChanged(event)
245     {
246         this._showTypesButtonNavigationItem.activated = WI.settings.showJavaScriptTypeInformation.value;
247     }
248
249     _enableControlFlowProfilerSettingChanged(event)
250     {
251         this._codeCoverageButtonNavigationItem.activated = WI.settings.enableControlFlowProfiler.value;
252     }
253
254     _textEditorFormattingDidChange(event)
255     {
256         this._prettyPrintButtonNavigationItem.activated = this._textEditor.formatted;
257     }
258
259     _handleTextEditorMIMETypeChanged(event)
260     {
261         this._prettyPrintButtonNavigationItem.enabled = this._textEditor.canBeFormatted();
262     }
263
264     _sourceCodeContentDidChange(event)
265     {
266         if (this._ignoreSourceCodeContentDidChangeEvent)
267             return;
268
269         this._textEditor.string = this.resource.currentRevision.content;
270     }
271
272     _textEditorContentDidChange(event)
273     {
274         this._ignoreSourceCodeContentDidChangeEvent = true;
275         WI.branchManager.currentBranch.revisionForRepresentedObject(this.resource).content = this._textEditor.string;
276         delete this._ignoreSourceCodeContentDidChangeEvent;
277     }
278
279     _executionLineNumberDidChange(event)
280     {
281         this.dispatchEventToListeners(WI.ContentView.Event.SupplementalRepresentedObjectsDidChange);
282     }
283
284     _numberOfSearchResultsDidChange(event)
285     {
286         this.dispatchEventToListeners(WI.ContentView.Event.NumberOfSearchResultsDidChange);
287     }
288
289     _probeSetsChanged(event)
290     {
291         var breakpoint = event.data.probeSet.breakpoint;
292         if (breakpoint.sourceCodeLocation.sourceCode === this.resource)
293             this.dispatchEventToListeners(WI.ContentView.Event.SupplementalRepresentedObjectsDidChange);
294     }
295
296     _shouldBeEditable()
297     {
298         if (this.resource instanceof WI.CSSStyleSheet)
299             return true;
300
301         // Check the MIME-type for CSS since Resource.Type.Stylesheet also includes XSL, which we can't edit yet.
302         if (this.resource.type === WI.Resource.Type.Stylesheet && this.resource.syntheticMIMEType === "text/css")
303             return true;
304
305         // Allow editing any local file since edits can be saved and reloaded right from the Inspector.
306         if (this.resource.urlComponents.scheme === "file")
307             return true;
308
309         return false;
310     }
311 };