• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
32var Preferences = {
33    maxInlineTextChildLength: 80,
34    minConsoleHeight: 25,
35    minSidebarWidth: 100,
36    minSidebarHeight: 75,
37    minElementsSidebarWidth: 200,
38    minElementsSidebarHeight: 200,
39    minScriptsSidebarWidth: 200,
40    applicationTitle: "Developer Tools - %s",
41    experimentsEnabled: false
42}
43
44var Capabilities = {
45    canInspectWorkers: false,
46    canScreencast: false
47}
48
49/**
50 * @constructor
51 */
52WebInspector.Settings = function()
53{
54    this._eventSupport = new WebInspector.Object();
55    this._registry = /** @type {!Object.<string, !WebInspector.Setting>} */ ({});
56
57    this.colorFormat = this.createSetting("colorFormat", "original");
58    this.consoleHistory = this.createSetting("consoleHistory", []);
59    this.domWordWrap = this.createSetting("domWordWrap", true);
60    this.eventListenersFilter = this.createSetting("eventListenersFilter", "all");
61    this.lastViewedScriptFile = this.createSetting("lastViewedScriptFile", "application");
62    this.monitoringXHREnabled = this.createSetting("monitoringXHREnabled", false);
63    this.preserveConsoleLog = this.createSetting("preserveConsoleLog", false);
64    this.resourcesLargeRows = this.createSetting("resourcesLargeRows", true);
65    this.resourcesSortOptions = this.createSetting("resourcesSortOptions", {timeOption: "responseTime", sizeOption: "transferSize"});
66    this.resourceViewTab = this.createSetting("resourceViewTab", "preview");
67    this.showInheritedComputedStyleProperties = this.createSetting("showInheritedComputedStyleProperties", false);
68    this.showUserAgentStyles = this.createSetting("showUserAgentStyles", true);
69    this.watchExpressions = this.createSetting("watchExpressions", []);
70    this.breakpoints = this.createSetting("breakpoints", []);
71    this.eventListenerBreakpoints = this.createSetting("eventListenerBreakpoints", []);
72    this.domBreakpoints = this.createSetting("domBreakpoints", []);
73    this.xhrBreakpoints = this.createSetting("xhrBreakpoints", []);
74    this.jsSourceMapsEnabled = this.createSetting("sourceMapsEnabled", true);
75    this.cssSourceMapsEnabled = this.createSetting("cssSourceMapsEnabled", true);
76    this.cacheDisabled = this.createSetting("cacheDisabled", false);
77    this.overrideUserAgent = this.createSetting("overrideUserAgent", false);
78    this.userAgent = this.createSetting("userAgent", "");
79    this.overrideDeviceMetrics = this.createSetting("overrideDeviceMetrics", false);
80    this.deviceMetrics = this.createSetting("deviceMetrics", "");
81    this.deviceFitWindow = this.createSetting("deviceFitWindow", true);
82    this.emulateViewport = this.createSetting("emulateViewport", false);
83    this.emulateTouchEvents = this.createSetting("emulateTouchEvents", false);
84    this.showShadowDOM = this.createSetting("showShadowDOM", false);
85    this.zoomLevel = this.createSetting("zoomLevel", 0);
86    this.savedURLs = this.createSetting("savedURLs", {});
87    this.javaScriptDisabled = this.createSetting("javaScriptDisabled", false);
88    this.overrideGeolocation = this.createSetting("overrideGeolocation", false);
89    this.geolocationOverride = this.createSetting("geolocationOverride", "");
90    this.overrideDeviceOrientation = this.createSetting("overrideDeviceOrientation", false);
91    this.deviceOrientationOverride = this.createSetting("deviceOrientationOverride", "");
92    this.showAdvancedHeapSnapshotProperties = this.createSetting("showAdvancedHeapSnapshotProperties", false);
93    this.highResolutionCpuProfiling = this.createSetting("highResolutionCpuProfiling", false);
94    this.searchInContentScripts = this.createSetting("searchInContentScripts", false);
95    this.textEditorIndent = this.createSetting("textEditorIndent", "    ");
96    this.textEditorAutoDetectIndent = this.createSetting("textEditorAutoIndentIndent", true);
97    this.textEditorAutocompletion = this.createSetting("textEditorAutocompletion", true);
98    this.textEditorBracketMatching = this.createSetting("textEditorBracketMatching", true);
99    this.lastDockState = this.createSetting("lastDockState", "");
100    this.cssReloadEnabled = this.createSetting("cssReloadEnabled", false);
101    this.timelineCaptureStacks = this.createSetting("timelineCaptureStacks", true);
102    this.showMetricsRulers = this.createSetting("showMetricsRulers", false);
103    this.overrideCSSMedia = this.createSetting("overrideCSSMedia", false);
104    this.emulatedCSSMedia = this.createSetting("emulatedCSSMedia", "print");
105    this.workerInspectorWidth = this.createSetting("workerInspectorWidth", 600);
106    this.workerInspectorHeight = this.createSetting("workerInspectorHeight", 600);
107    this.messageURLFilters = this.createSetting("messageURLFilters", {});
108    this.networkHideDataURL = this.createSetting("networkHideDataURL", false);
109    this.messageLevelFilters = this.createSetting("messageLevelFilters", {});
110    this.splitVerticallyWhenDockedToRight = this.createSetting("splitVerticallyWhenDockedToRight", true);
111    this.visiblePanels = this.createSetting("visiblePanels", {});
112    this.shortcutPanelSwitch = this.createSetting("shortcutPanelSwitch", false);
113    this.showWhitespacesInEditor = this.createSetting("showWhitespacesInEditor", false);
114    this.skipStackFramesSwitch = this.createSetting("skipStackFramesSwitch", false);
115    this.skipStackFramesPattern = this.createSetting("skipStackFramesPattern", "");
116    this.screencastEnabled = this.createSetting("screencastEnabled", false);
117    this.screencastSidebarWidth = this.createSetting("screencastSidebarWidth", 300);
118    this.showEmulationViewInDrawer = this.createSetting("showEmulationViewInDrawer", true);
119    this.showRenderingViewInDrawer = this.createSetting("showRenderingViewInDrawer", true);
120    this.enableAsyncStackTraces = this.createSetting("enableAsyncStackTraces", false);
121}
122
123WebInspector.Settings.prototype = {
124    /**
125     * @param {string} key
126     * @param {*} defaultValue
127     * @return {!WebInspector.Setting}
128     */
129    createSetting: function(key, defaultValue)
130    {
131        if (!this._registry[key])
132            this._registry[key] = new WebInspector.Setting(key, defaultValue, this._eventSupport, window.localStorage);
133        return this._registry[key];
134    },
135
136    /**
137     * @param {string} key
138     * @param {*} defaultValue
139     * @param {function(*, function(string, ...))} setterCallback
140     * @return {!WebInspector.Setting}
141     */
142    createBackendSetting: function(key, defaultValue, setterCallback)
143    {
144        if (!this._registry[key])
145            this._registry[key] = new WebInspector.BackendSetting(key, defaultValue, this._eventSupport, window.localStorage, setterCallback);
146        return this._registry[key];
147    }
148}
149
150/**
151 * @constructor
152 * @param {string} name
153 * @param {*} defaultValue
154 * @param {!WebInspector.Object} eventSupport
155 * @param {?Storage} storage
156 */
157WebInspector.Setting = function(name, defaultValue, eventSupport, storage)
158{
159    this._name = name;
160    this._defaultValue = defaultValue;
161    this._eventSupport = eventSupport;
162    this._storage = storage;
163}
164
165WebInspector.Setting.prototype = {
166    /**
167     * @param {function(!WebInspector.Event)} listener
168     * @param {!Object=} thisObject
169     */
170    addChangeListener: function(listener, thisObject)
171    {
172        this._eventSupport.addEventListener(this._name, listener, thisObject);
173    },
174
175    /**
176     * @param {function(!WebInspector.Event)} listener
177     * @param {!Object=} thisObject
178     */
179    removeChangeListener: function(listener, thisObject)
180    {
181        this._eventSupport.removeEventListener(this._name, listener, thisObject);
182    },
183
184    get name()
185    {
186        return this._name;
187    },
188
189    get: function()
190    {
191        if (typeof this._value !== "undefined")
192            return this._value;
193
194        this._value = this._defaultValue;
195        if (this._storage && this._name in this._storage) {
196            try {
197                this._value = JSON.parse(this._storage[this._name]);
198            } catch(e) {
199                delete this._storage[this._name];
200            }
201        }
202        return this._value;
203    },
204
205    set: function(value)
206    {
207        this._value = value;
208        if (this._storage) {
209            try {
210                this._storage[this._name] = JSON.stringify(value);
211            } catch(e) {
212                console.error("Error saving setting with name:" + this._name);
213            }
214        }
215        this._eventSupport.dispatchEventToListeners(this._name, value);
216    }
217}
218
219/**
220 * @constructor
221 * @extends {WebInspector.Setting}
222 * @param {string} name
223 * @param {*} defaultValue
224 * @param {!WebInspector.Object} eventSupport
225 * @param {?Storage} storage
226 * @param {function(*,function(string, ...))} setterCallback
227 */
228WebInspector.BackendSetting = function(name, defaultValue, eventSupport, storage, setterCallback)
229{
230    WebInspector.Setting.call(this, name, defaultValue, eventSupport, storage);
231    this._setterCallback = setterCallback;
232    var currentValue = this.get();
233    if (currentValue !== defaultValue)
234        this.set(currentValue);
235}
236
237WebInspector.BackendSetting.prototype = {
238    set: function(value)
239    {
240        /**
241         * @param {?Protocol.Error} error
242         * @this {WebInspector.BackendSetting}
243         */
244        function callback(error)
245        {
246            if (error) {
247                WebInspector.log("Error applying setting " + this._name + ": " + error);
248                this._eventSupport.dispatchEventToListeners(this._name, this._value);
249                return;
250            }
251            WebInspector.Setting.prototype.set.call(this, value);
252        }
253        this._setterCallback(value, callback.bind(this));
254    },
255
256    __proto__: WebInspector.Setting.prototype
257};
258
259/**
260 * @constructor
261 */
262WebInspector.ExperimentsSettings = function()
263{
264    this._setting = WebInspector.settings.createSetting("experiments", {});
265    this._experiments = [];
266    this._enabledForTest = {};
267
268    // Add currently running experiments here.
269    this.asyncStackTraces = this._createExperiment("asyncStackTraces", "Enable support for async stack traces");
270    this.fileSystemInspection = this._createExperiment("fileSystemInspection", "FileSystem inspection");
271    this.canvasInspection = this._createExperiment("canvasInspection ", "Canvas inspection");
272    this.cssRegions = this._createExperiment("cssRegions", "CSS Regions Support");
273    this.frameworksDebuggingSupport = this._createExperiment("frameworksDebuggingSupport", "Enable frameworks debugging support");
274    this.layersPanel = this._createExperiment("layersPanel", "Show Layers panel");
275    this.stepIntoSelection = this._createExperiment("stepIntoSelection", "Show step-in candidates while debugging.");
276    this.doNotOpenDrawerOnEsc = this._createExperiment("doNotOpenDrawerWithEsc", "Do not open drawer on Esc");
277    this.showEditorInDrawer = this._createExperiment("showEditorInDrawer", "Show editor in drawer");
278    this.gpuTimeline = this._createExperiment("gpuTimeline", "Show GPU data on timeline");
279    this.applyCustomStylesheet = this._createExperiment("applyCustomStylesheet", "Allow custom UI themes");
280
281    this._cleanUpSetting();
282}
283
284WebInspector.ExperimentsSettings.prototype = {
285    /**
286     * @return {!Array.<!WebInspector.Experiment>}
287     */
288    get experiments()
289    {
290        return this._experiments.slice();
291    },
292
293    /**
294     * @return {boolean}
295     */
296    get experimentsEnabled()
297    {
298        return Preferences.experimentsEnabled || ("experiments" in WebInspector.queryParamsObject);
299    },
300
301    /**
302     * @param {string} experimentName
303     * @param {string} experimentTitle
304     * @return {!WebInspector.Experiment}
305     */
306    _createExperiment: function(experimentName, experimentTitle)
307    {
308        var experiment = new WebInspector.Experiment(this, experimentName, experimentTitle);
309        this._experiments.push(experiment);
310        return experiment;
311    },
312
313    /**
314     * @param {string} experimentName
315     * @return {boolean}
316     */
317    isEnabled: function(experimentName)
318    {
319        if (this._enabledForTest[experimentName])
320            return true;
321
322        if (!this.experimentsEnabled)
323            return false;
324
325        var experimentsSetting = this._setting.get();
326        return experimentsSetting[experimentName];
327    },
328
329    /**
330     * @param {string} experimentName
331     * @param {boolean} enabled
332     */
333    setEnabled: function(experimentName, enabled)
334    {
335        var experimentsSetting = this._setting.get();
336        experimentsSetting[experimentName] = enabled;
337        this._setting.set(experimentsSetting);
338    },
339
340    /**
341     * @param {string} experimentName
342     */
343    _enableForTest: function(experimentName)
344    {
345        this._enabledForTest[experimentName] = true;
346    },
347
348    _cleanUpSetting: function()
349    {
350        var experimentsSetting = this._setting.get();
351        var cleanedUpExperimentSetting = {};
352        for (var i = 0; i < this._experiments.length; ++i) {
353            var experimentName = this._experiments[i].name;
354            if (experimentsSetting[experimentName])
355                cleanedUpExperimentSetting[experimentName] = true;
356        }
357        this._setting.set(cleanedUpExperimentSetting);
358    }
359}
360
361/**
362 * @constructor
363 * @param {!WebInspector.ExperimentsSettings} experimentsSettings
364 * @param {string} name
365 * @param {string} title
366 */
367WebInspector.Experiment = function(experimentsSettings, name, title)
368{
369    this._name = name;
370    this._title = title;
371    this._experimentsSettings = experimentsSettings;
372}
373
374WebInspector.Experiment.prototype = {
375    /**
376     * @return {string}
377     */
378    get name()
379    {
380        return this._name;
381    },
382
383    /**
384     * @return {string}
385     */
386    get title()
387    {
388        return this._title;
389    },
390
391    /**
392     * @return {boolean}
393     */
394    isEnabled: function()
395    {
396        return this._experimentsSettings.isEnabled(this._name);
397    },
398
399    /**
400     * @param {boolean} enabled
401     */
402    setEnabled: function(enabled)
403    {
404        return this._experimentsSettings.setEnabled(this._name, enabled);
405    },
406
407    enableForTest: function()
408    {
409        this._experimentsSettings._enableForTest(this._name);
410    }
411}
412
413/**
414 * @constructor
415 */
416WebInspector.VersionController = function()
417{
418}
419
420WebInspector.VersionController.currentVersion = 4;
421
422WebInspector.VersionController.prototype = {
423    updateVersion: function()
424    {
425        var versionSetting = WebInspector.settings.createSetting("inspectorVersion", 0);
426        var currentVersion = WebInspector.VersionController.currentVersion;
427        var oldVersion = versionSetting.get();
428        var methodsToRun = this._methodsToRunToUpdateVersion(oldVersion, currentVersion);
429        for (var i = 0; i < methodsToRun.length; ++i)
430            this[methodsToRun[i]].call(this);
431        versionSetting.set(currentVersion);
432    },
433
434    /**
435     * @param {number} oldVersion
436     * @param {number} currentVersion
437     */
438    _methodsToRunToUpdateVersion: function(oldVersion, currentVersion)
439    {
440        var result = [];
441        for (var i = oldVersion; i < currentVersion; ++i)
442            result.push("_updateVersionFrom" + i + "To" + (i + 1));
443        return result;
444    },
445
446    _updateVersionFrom0To1: function()
447    {
448        this._clearBreakpointsWhenTooMany(WebInspector.settings.breakpoints, 500000);
449    },
450
451    _updateVersionFrom1To2: function()
452    {
453        var versionSetting = WebInspector.settings.createSetting("previouslyViewedFiles", []);
454        versionSetting.set([]);
455    },
456
457    _updateVersionFrom2To3: function()
458    {
459        var fileSystemMappingSetting = WebInspector.settings.createSetting("fileSystemMapping", {});
460        fileSystemMappingSetting.set({});
461        if (window.localStorage)
462            delete window.localStorage["fileMappingEntries"];
463    },
464
465    _updateVersionFrom3To4: function()
466    {
467        var advancedMode = WebInspector.settings.createSetting("showHeaSnapshotObjectsHiddenProperties", false).get();
468        WebInspector.settings.showAdvancedHeapSnapshotProperties.set(advancedMode);
469    },
470
471    /**
472     * @param {!WebInspector.Setting} breakpointsSetting
473     * @param {number} maxBreakpointsCount
474     */
475    _clearBreakpointsWhenTooMany: function(breakpointsSetting, maxBreakpointsCount)
476    {
477        // If there are too many breakpoints in a storage, it is likely due to a recent bug that caused
478        // periodical breakpoints duplication leading to inspector slowness.
479        if (breakpointsSetting.get().length > maxBreakpointsCount)
480            breakpointsSetting.set([]);
481    }
482}
483
484WebInspector.settings = new WebInspector.Settings();
485WebInspector.experimentsSettings = new WebInspector.ExperimentsSettings();
486