Web Inspector: convert workers inspection into capability
[WebKit-https.git] / Source / WebCore / inspector / front-end / Settings.js
1 /*
2  * Copyright (C) 2009 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 var Preferences = {
33     maxInlineTextChildLength: 80,
34     minConsoleHeight: 75,
35     minSidebarWidth: 100,
36     minSidebarHeight: 75,
37     minElementsSidebarWidth: 200,
38     minElementsSidebarHeight: 200,
39     minScriptsSidebarWidth: 200,
40     styleRulesExpandedState: {},
41     showMissingLocalizedStrings: false,
42     useLowerCaseMenuTitlesOnWindows: false,
43     sharedWorkersDebugNote: undefined,
44     localizeUI: true,
45     exposeDisableCache: false,
46     applicationTitle: "Web Inspector - %s",
47     showDockToRight: false,
48     exposeFileSystemInspection: false,
49     experimentsEnabled: true
50 }
51
52 var Capabilities = {
53     samplingCPUProfiler: false,
54     debuggerCausesRecompilation: true,
55     separateScriptCompilationAndExecutionEnabled: false,
56     profilerCausesRecompilation: true,
57     heapProfilerPresent: false,
58     canOverrideDeviceMetrics: false,
59     timelineSupportsFrameInstrumentation: false,
60     timelineCanMonitorMainThread: false,
61     canOverrideGeolocation: false,
62     canOverrideDeviceOrientation: false,
63     canShowDebugBorders: false,
64     canShowFPSCounter: false,
65     canContinuouslyPaint: false,
66     canInspectWorkers: false
67 }
68
69 /**
70  * @constructor
71  */
72 WebInspector.Settings = function()
73 {
74     this._eventSupport = new WebInspector.Object();
75
76     this.colorFormat = this.createSetting("colorFormat", "original");
77     this.consoleHistory = this.createSetting("consoleHistory", []);
78     this.debuggerEnabled = this.createSetting("debuggerEnabled", false);
79     this.domWordWrap = this.createSetting("domWordWrap", true);
80     this.profilerEnabled = this.createSetting("profilerEnabled", false);
81     this.eventListenersFilter = this.createSetting("eventListenersFilter", "all");
82     this.lastActivePanel = this.createSetting("lastActivePanel", "elements");
83     this.lastViewedScriptFile = this.createSetting("lastViewedScriptFile", "application");
84     this.monitoringXHREnabled = this.createSetting("monitoringXHREnabled", false);
85     this.preserveConsoleLog = this.createSetting("preserveConsoleLog", false);
86     this.resourcesLargeRows = this.createSetting("resourcesLargeRows", true);
87     this.resourcesSortOptions = this.createSetting("resourcesSortOptions", {timeOption: "responseTime", sizeOption: "transferSize"});
88     this.resourceViewTab = this.createSetting("resourceViewTab", "preview");
89     this.showInheritedComputedStyleProperties = this.createSetting("showInheritedComputedStyleProperties", false);
90     this.showUserAgentStyles = this.createSetting("showUserAgentStyles", true);
91     this.watchExpressions = this.createSetting("watchExpressions", []);
92     this.breakpoints = this.createSetting("breakpoints", []);
93     this.eventListenerBreakpoints = this.createSetting("eventListenerBreakpoints", []);
94     this.domBreakpoints = this.createSetting("domBreakpoints", []);
95     this.xhrBreakpoints = this.createSetting("xhrBreakpoints", []);
96     this.sourceMapsEnabled = this.createSetting("sourceMapsEnabled", false);
97     this.cacheDisabled = this.createSetting("cacheDisabled", false);
98     this.overrideUserAgent = this.createSetting("overrideUserAgent", "");
99     this.userAgent = this.createSetting("userAgent", "");
100     this.deviceMetrics = this.createSetting("deviceMetrics", "");
101     this.deviceFitWindow = this.createSetting("deviceFitWindow", false);
102     this.emulateTouchEvents = this.createSetting("emulateTouchEvents", false);
103     this.showPaintRects = this.createSetting("showPaintRects", false);
104     this.continuousPainting = this.createSetting("continuousPainting", false);
105     this.showDebugBorders = this.createSetting("showDebugBorders", false);
106     this.showFPSCounter = this.createSetting("showFPSCounter", false);
107     this.showShadowDOM = this.createSetting("showShadowDOM", false);
108     this.zoomLevel = this.createSetting("zoomLevel", 0);
109     this.savedURLs = this.createSetting("savedURLs", {});
110     this.javaScriptDisabled = this.createSetting("javaScriptDisabled", false);
111     this.geolocationOverride = this.createSetting("geolocationOverride", "");
112     this.deviceOrientationOverride = this.createSetting("deviceOrientationOverride", "");
113     this.showHeapSnapshotObjectsHiddenProperties = this.createSetting("showHeaSnapshotObjectsHiddenProperties", false);
114     this.showNativeSnapshotUninstrumentedSize = this.createSetting("showNativeSnapshotUninstrumentedSize", false);
115     this.searchInContentScripts = this.createSetting("searchInContentScripts", false);
116     this.textEditorIndent = this.createSetting("textEditorIndent", "    ");
117     this.lastDockState = this.createSetting("lastDockState", "");
118     this.cssReloadEnabled = this.createSetting("cssReloadEnabled", false);
119     this.cssReloadTimeout = this.createSetting("cssReloadTimeout", 1000);
120     this.showCpuOnTimelineRuler = this.createSetting("showCpuOnTimelineRuler", false);
121     this.showMetricsRulers = this.createSetting("showMetricsRulers", false);
122     this.emulatedCSSMedia = this.createSetting("emulatedCSSMedia", "print");
123     this.showToolbarIcons = this.createSetting("showToolbarIcons", false);
124     this.workerInspectorWidth = this.createSetting("workerInspectorWidth", 600);
125     this.workerInspectorHeight = this.createSetting("workerInspectorHeight", 600);
126     this.messageURLFilters = this.createSetting("messageURLFilters", {});
127     this.splitVerticallyWhenDockedToRight = this.createSetting("splitVerticallyWhenDockedToRight", true);
128 }
129
130 WebInspector.Settings.prototype = {
131     /**
132      * @return {WebInspector.Setting}
133      */
134     createSetting: function(key, defaultValue)
135     {
136         return new WebInspector.Setting(key, defaultValue, this._eventSupport);
137     }
138 }
139
140 /**
141  * @constructor
142  */
143 WebInspector.Setting = function(name, defaultValue, eventSupport)
144 {
145     this._name = name;
146     this._defaultValue = defaultValue;
147     this._eventSupport = eventSupport;
148 }
149
150 WebInspector.Setting.prototype = {
151     addChangeListener: function(listener, thisObject)
152     {
153         this._eventSupport.addEventListener(this._name, listener, thisObject);
154     },
155
156     removeChangeListener: function(listener, thisObject)
157     {
158         this._eventSupport.removeEventListener(this._name, listener, thisObject);
159     },
160
161     get name()
162     {
163         return this._name;
164     },
165
166     get: function()
167     {
168         if (typeof this._value !== "undefined")
169             return this._value;
170
171         this._value = this._defaultValue;
172         if (window.localStorage != null && this._name in window.localStorage) {
173             try {
174                 this._value = JSON.parse(window.localStorage[this._name]);
175             } catch(e) {
176                 window.localStorage.removeItem(this._name);
177             }
178         }
179         return this._value;
180     },
181
182     set: function(value)
183     {
184         this._value = value;
185         if (window.localStorage != null) {
186             try {
187                 window.localStorage[this._name] = JSON.stringify(value);
188             } catch(e) {
189                 console.error("Error saving setting with name:" + this._name);
190             }
191         }
192         this._eventSupport.dispatchEventToListeners(this._name, value);
193     }
194 }
195
196 /**
197  * @constructor
198  */
199 WebInspector.ExperimentsSettings = function()
200 {
201     this._setting = WebInspector.settings.createSetting("experiments", {});
202     this._experiments = [];
203     this._enabledForTest = {};
204     
205     // Add currently running experiments here.
206     this.snippetsSupport = this._createExperiment("snippetsSupport", "Snippets support");
207     this.nativeMemorySnapshots = this._createExperiment("nativeMemorySnapshots", "Native memory profiling");
208     this.nativeMemoryTimeline = this._createExperiment("nativeMemoryTimeline", "Native memory timeline");
209     this.fileSystemInspection = this._createExperiment("fileSystemInspection", "FileSystem inspection");
210     this.canvasInspection = this._createExperiment("canvasInspection ", "Canvas inspection");
211     this.sass = this._createExperiment("sass", "Support for Sass");
212     this.codemirror = this._createExperiment("codemirror", "Use CodeMirror editor");
213     this.aceTextEditor = this._createExperiment("aceTextEditor", "Use Ace editor");
214     this.cssRegions = this._createExperiment("cssRegions", "CSS Regions Support");
215     this.showOverridesInDrawer = this._createExperiment("showOverridesInDrawer", "Show Overrides in drawer");
216     this.fileSystemProject = this._createExperiment("fileSystemProject", "File system folders in Sources Panel");
217     this.showWhitespaceInEditor = this._createExperiment("showWhitespaceInEditor", "Show whitespace characters in editor");
218     this.textEditorSmartBraces = this._createExperiment("textEditorSmartBraces", "Enable smart braces in text editor");
219     this.separateProfilers = this._createExperiment("separateProfilers", "Separate profiler tools");
220     this.cpuFlameChart = this._createExperiment("cpuFlameChart", "Show Flame Chart in CPU Profiler");
221
222     this._cleanUpSetting();
223 }
224
225 WebInspector.ExperimentsSettings.prototype = {
226     /**
227      * @return {Array.<WebInspector.Experiment>}
228      */
229     get experiments()
230     {
231         return this._experiments.slice();
232     },
233     
234     /**
235      * @return {boolean}
236      */
237     get experimentsEnabled()
238     {
239         return Preferences.experimentsEnabled || ("experiments" in WebInspector.queryParamsObject);
240     },
241     
242     /**
243      * @param {string} experimentName
244      * @param {string} experimentTitle
245      * @return {WebInspector.Experiment}
246      */
247     _createExperiment: function(experimentName, experimentTitle)
248     {
249         var experiment = new WebInspector.Experiment(this, experimentName, experimentTitle);
250         this._experiments.push(experiment);
251         return experiment;
252     },
253     
254     /**
255      * @param {string} experimentName
256      * @return {boolean}
257      */
258     isEnabled: function(experimentName)
259     {
260         if (this._enabledForTest[experimentName])
261             return true;
262
263         if (!this.experimentsEnabled)
264             return false;
265         
266         var experimentsSetting = this._setting.get();
267         return experimentsSetting[experimentName];
268     },
269     
270     /**
271      * @param {string} experimentName
272      * @param {boolean} enabled
273      */
274     setEnabled: function(experimentName, enabled)
275     {
276         var experimentsSetting = this._setting.get();
277         experimentsSetting[experimentName] = enabled;
278         this._setting.set(experimentsSetting);
279     },
280
281     /**
282      * @param {string} experimentName
283      */
284     _enableForTest: function(experimentName)
285     {
286         this._enabledForTest[experimentName] = true;
287     },
288
289     _cleanUpSetting: function()
290     {
291         var experimentsSetting = this._setting.get();
292         var cleanedUpExperimentSetting = {};
293         for (var i = 0; i < this._experiments.length; ++i) {
294             var experimentName = this._experiments[i].name;
295             if (experimentsSetting[experimentName])
296                 cleanedUpExperimentSetting[experimentName] = true;
297         }
298         this._setting.set(cleanedUpExperimentSetting);
299     }
300 }
301
302 /**
303  * @constructor
304  * @param {WebInspector.ExperimentsSettings} experimentsSettings
305  * @param {string} name
306  * @param {string} title
307  */
308 WebInspector.Experiment = function(experimentsSettings, name, title)
309 {
310     this._name = name;
311     this._title = title;
312     this._experimentsSettings = experimentsSettings;
313 }
314
315 WebInspector.Experiment.prototype = {
316     /**
317      * @return {string}
318      */
319     get name()
320     {
321         return this._name;
322     },
323     
324     /**
325      * @return {string}
326      */
327     get title()
328     {
329         return this._title;
330     },
331     
332     /**
333      * @return {boolean}
334      */
335     isEnabled: function()
336     {
337         return this._experimentsSettings.isEnabled(this._name);
338     },
339     
340     /**
341      * @param {boolean} enabled
342      */
343     setEnabled: function(enabled)
344     {
345         return this._experimentsSettings.setEnabled(this._name, enabled);
346     },
347
348     enableForTest: function()
349     {
350         this._experimentsSettings._enableForTest(this._name);
351     }
352 }
353
354 /**
355  * @constructor
356  */
357 WebInspector.VersionController = function()
358 {
359 }
360
361 WebInspector.VersionController.currentVersion = 2;
362
363 WebInspector.VersionController.prototype = {
364     updateVersion: function()
365     {
366         var versionSetting = WebInspector.settings.createSetting("inspectorVersion", 0);
367         var currentVersion = WebInspector.VersionController.currentVersion;
368         var oldVersion = versionSetting.get();
369         var methodsToRun = this._methodsToRunToUpdateVersion(oldVersion, currentVersion);
370         for (var i = 0; i < methodsToRun.length; ++i)
371             this[methodsToRun[i]].call(this);
372         versionSetting.set(currentVersion);
373     },
374
375     /**
376      * @param {number} oldVersion
377      * @param {number} currentVersion
378      */
379     _methodsToRunToUpdateVersion: function(oldVersion, currentVersion)
380     {
381         var result = [];
382         for (var i = oldVersion; i < currentVersion; ++i)
383             result.push("_updateVersionFrom" + i + "To" + (i + 1));
384         return result;
385     },
386
387     _updateVersionFrom0To1: function()
388     {
389         this._clearBreakpointsWhenTooMany(WebInspector.settings.breakpoints, 500000);
390     },
391
392     _updateVersionFrom1To2: function()
393     {
394         var versionSetting = WebInspector.settings.createSetting("previouslyViewedFiles", []);
395         versionSetting.set([]);
396     },
397
398     /**
399      * @param {WebInspector.Setting} breakpointsSetting
400      * @param {number} maxBreakpointsCount
401      */
402     _clearBreakpointsWhenTooMany: function(breakpointsSetting, maxBreakpointsCount)
403     {
404         // If there are too many breakpoints in a storage, it is likely due to a recent bug that caused
405         // periodical breakpoints duplication leading to inspector slowness.
406         if (breakpointsSetting.get().length > maxBreakpointsCount)
407             breakpointsSetting.set([]);
408     }
409 }
410
411 WebInspector.settings = new WebInspector.Settings();
412 WebInspector.experimentsSettings = new WebInspector.ExperimentsSettings();