2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 * @param {!function()} onHide
34 * @extends {WebInspector.HelpScreen}
36 WebInspector.SettingsScreen = function(onHide)
38 WebInspector.HelpScreen.call(this);
39 this.element.id = "settings-screen";
41 /** @type {function()} */
42 this._onHide = onHide;
44 this._tabbedPane = new WebInspector.TabbedPane();
45 this._tabbedPane.element.classList.add("help-window-main");
46 var settingsLabelElement = document.createElement("div");
47 settingsLabelElement.className = "help-window-label";
48 settingsLabelElement.createTextChild(WebInspector.UIString("Settings"));
49 this._tabbedPane.element.insertBefore(settingsLabelElement, this._tabbedPane.element.firstChild);
50 this._tabbedPane.element.appendChild(this._createCloseButton());
51 this._tabbedPane.appendTab(WebInspector.SettingsScreen.Tabs.General, WebInspector.UIString("General"), new WebInspector.GenericSettingsTab());
52 this._tabbedPane.appendTab(WebInspector.SettingsScreen.Tabs.Workspace, WebInspector.UIString("Workspace"), new WebInspector.WorkspaceSettingsTab());
53 if (WebInspector.experimentsSettings.experimentsEnabled)
54 this._tabbedPane.appendTab(WebInspector.SettingsScreen.Tabs.Experiments, WebInspector.UIString("Experiments"), new WebInspector.ExperimentsSettingsTab());
55 this._tabbedPane.appendTab(WebInspector.SettingsScreen.Tabs.Shortcuts, WebInspector.UIString("Shortcuts"), WebInspector.shortcutsScreen.createShortcutsTabView());
56 this._tabbedPane.shrinkableTabs = false;
57 this._tabbedPane.verticalTabLayout = true;
59 this._lastSelectedTabSetting = WebInspector.settings.createSetting("lastSelectedSettingsTab", WebInspector.SettingsScreen.Tabs.General);
60 this.selectTab(this._lastSelectedTabSetting.get());
61 this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
65 * @param {string} text
68 WebInspector.SettingsScreen.regexValidator = function(text)
72 regex = new RegExp(text);
75 return regex ? null : WebInspector.UIString("Invalid pattern");
81 * @param {string} text
84 WebInspector.SettingsScreen.integerValidator = function(min, max, text)
86 var value = Number(text);
88 return WebInspector.UIString("Invalid number format");
89 if (value < min || value > max)
90 return WebInspector.UIString("Value is out of range [%d, %d]", min, max);
94 WebInspector.SettingsScreen.Tabs = {
96 Overrides: "overrides",
97 Workspace: "workspace",
98 Experiments: "experiments",
99 Shortcuts: "shortcuts"
102 WebInspector.SettingsScreen.prototype = {
104 * @param {string} tabId
106 selectTab: function(tabId)
108 this._tabbedPane.selectTab(tabId);
112 * @param {!WebInspector.Event} event
114 _tabSelected: function(event)
116 this._lastSelectedTabSetting.set(this._tabbedPane.selectedTabId);
124 this._tabbedPane.show(this.element);
125 WebInspector.HelpScreen.prototype.wasShown.call(this);
132 isClosingKey: function(keyCode)
135 WebInspector.KeyboardShortcut.Keys.Enter.code,
136 WebInspector.KeyboardShortcut.Keys.Esc.code,
137 ].indexOf(keyCode) >= 0;
146 WebInspector.HelpScreen.prototype.willHide.call(this);
149 __proto__: WebInspector.HelpScreen.prototype
154 * @extends {WebInspector.View}
155 * @param {string} name
156 * @param {string=} id
158 WebInspector.SettingsTab = function(name, id)
160 WebInspector.View.call(this);
161 this.element.classList.add("settings-tab-container");
163 this.element.id = id;
164 var header = this.element.createChild("header");
165 header.createChild("h3").appendChild(document.createTextNode(name));
166 this.containerElement = this.element.createChild("div", "help-container-wrapper").createChild("div", "settings-tab help-content help-container");
169 WebInspector.SettingsTab.prototype = {
171 * @param {string=} name
174 _appendSection: function(name)
176 var block = this.containerElement.createChild("div", "help-block");
178 block.createChild("div", "help-section-title").textContent = name;
182 _createSelectSetting: function(name, options, setting)
184 var p = document.createElement("p");
185 var labelElement = p.createChild("label");
186 labelElement.textContent = name;
188 var select = p.createChild("select");
189 var settingValue = setting.get();
191 for (var i = 0; i < options.length; ++i) {
192 var option = options[i];
193 select.add(new Option(option[0], option[1]));
194 if (settingValue === option[1])
195 select.selectedIndex = i;
198 function changeListener(e)
200 // Don't use e.target.value to avoid conversion of the value to string.
201 setting.set(options[select.selectedIndex][1]);
204 select.addEventListener("change", changeListener, false);
209 * @param {string} label
210 * @param {!WebInspector.Setting} setting
211 * @param {boolean} numeric
212 * @param {number=} maxLength
213 * @param {string=} width
214 * @param {function(string):?string=} validatorCallback
216 _createInputSetting: function(label, setting, numeric, maxLength, width, validatorCallback)
218 var p = document.createElement("p");
219 var labelElement = p.createChild("label");
220 labelElement.textContent = label;
221 var inputElement = p.createChild("input");
222 inputElement.value = setting.get();
223 inputElement.type = "text";
225 inputElement.className = "numeric";
227 inputElement.maxLength = maxLength;
229 inputElement.style.width = width;
230 if (validatorCallback) {
231 var errorMessageLabel = p.createChild("div");
232 errorMessageLabel.classList.add("field-error-message");
233 errorMessageLabel.style.color = "DarkRed";
234 inputElement.oninput = function()
236 var error = validatorCallback(inputElement.value);
239 errorMessageLabel.textContent = error;
245 setting.set(numeric ? Number(inputElement.value) : inputElement.value);
247 inputElement.addEventListener("blur", onBlur, false);
252 _createCustomSetting: function(name, element)
254 var p = document.createElement("p");
255 var fieldsetElement = document.createElement("fieldset");
256 fieldsetElement.createChild("label").textContent = name;
257 fieldsetElement.appendChild(element);
258 p.appendChild(fieldsetElement);
262 __proto__: WebInspector.View.prototype
267 * @extends {WebInspector.SettingsTab}
269 WebInspector.GenericSettingsTab = function()
271 WebInspector.SettingsTab.call(this, WebInspector.UIString("General"), "general-tab-content");
273 var p = this._appendSection();
274 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Disable cache (while DevTools is open)"), WebInspector.settings.cacheDisabled));
275 var disableJSElement = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Disable JavaScript"), WebInspector.settings.javaScriptDisabled);
276 p.appendChild(disableJSElement);
277 WebInspector.settings.javaScriptDisabled.addChangeListener(this._javaScriptDisabledChanged, this);
278 this._disableJSCheckbox = disableJSElement.getElementsByTagName("input")[0];
279 this._updateScriptDisabledCheckbox();
281 p = this._appendSection(WebInspector.UIString("Appearance"));
282 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Show 'Emulation' view in console drawer."), WebInspector.settings.showEmulationViewInDrawer));
283 this._appendDrawerNote(p.lastElementChild);
284 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Show 'Rendering' view in console drawer."), WebInspector.settings.showRenderingViewInDrawer));
285 this._appendDrawerNote(p.lastElementChild);
286 var splitVerticallyTitle = WebInspector.UIString("Split panels vertically when docked to %s", WebInspector.experimentsSettings.dockToLeft.isEnabled() ? "left or right" : "right");
287 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(splitVerticallyTitle, WebInspector.settings.splitVerticallyWhenDockedToRight));
288 var panelShortcutTitle = WebInspector.UIString("Enable %s + 1-9 shortcut to switch panels", WebInspector.isMac() ? "Cmd" : "Ctrl");
289 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(panelShortcutTitle, WebInspector.settings.shortcutPanelSwitch));
291 p = this._appendSection(WebInspector.UIString("Elements"));
292 var colorFormatElement = this._createSelectSetting(WebInspector.UIString("Color format"), [
293 [ WebInspector.UIString("As authored"), WebInspector.Color.Format.Original ],
294 [ "HEX: #DAC0DE", WebInspector.Color.Format.HEX ],
295 [ "RGB: rgb(128, 255, 255)", WebInspector.Color.Format.RGB ],
296 [ "HSL: hsl(300, 80%, 90%)", WebInspector.Color.Format.HSL ]
297 ], WebInspector.settings.colorFormat);
298 p.appendChild(colorFormatElement);
299 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Show user agent styles"), WebInspector.settings.showUserAgentStyles));
300 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Word wrap"), WebInspector.settings.domWordWrap));
301 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Show Shadow DOM"), WebInspector.settings.showShadowDOM));
302 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Show rulers"), WebInspector.settings.showMetricsRulers));
304 p = this._appendSection(WebInspector.UIString("Sources"));
305 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Search in content scripts"), WebInspector.settings.searchInContentScripts));
306 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Enable JavaScript source maps"), WebInspector.settings.jsSourceMapsEnabled));
308 var checkbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Enable CSS source maps"), WebInspector.settings.cssSourceMapsEnabled);
309 p.appendChild(checkbox);
310 var fieldset = WebInspector.SettingsUI.createSettingFieldset(WebInspector.settings.cssSourceMapsEnabled);
311 var autoReloadCSSCheckbox = fieldset.createChild("input");
312 fieldset.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Auto-reload generated CSS"), WebInspector.settings.cssReloadEnabled, false, autoReloadCSSCheckbox));
313 checkbox.appendChild(fieldset);
315 var indentationElement = this._createSelectSetting(WebInspector.UIString("Default indentation"), [
316 [ WebInspector.UIString("2 spaces"), WebInspector.TextUtils.Indent.TwoSpaces ],
317 [ WebInspector.UIString("4 spaces"), WebInspector.TextUtils.Indent.FourSpaces ],
318 [ WebInspector.UIString("8 spaces"), WebInspector.TextUtils.Indent.EightSpaces ],
319 [ WebInspector.UIString("Tab character"), WebInspector.TextUtils.Indent.TabCharacter ]
320 ], WebInspector.settings.textEditorIndent);
321 p.appendChild(indentationElement);
322 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Detect indentation"), WebInspector.settings.textEditorAutoDetectIndent));
323 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Autocompletion"), WebInspector.settings.textEditorAutocompletion));
324 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Bracket matching"), WebInspector.settings.textEditorBracketMatching));
325 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Show whitespace characters"), WebInspector.settings.showWhitespacesInEditor));
326 if (WebInspector.experimentsSettings.frameworksDebuggingSupport.isEnabled()) {
327 checkbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Skip stepping through sources with particular names"), WebInspector.settings.skipStackFramesSwitch);
328 fieldset = WebInspector.SettingsUI.createSettingFieldset(WebInspector.settings.skipStackFramesSwitch);
329 fieldset.appendChild(this._createInputSetting(WebInspector.UIString("Pattern"), WebInspector.settings.skipStackFramesPattern, false, 1000, "100px", WebInspector.SettingsScreen.regexValidator));
330 checkbox.appendChild(fieldset);
331 p.appendChild(checkbox);
333 WebInspector.settings.skipStackFramesSwitch.addChangeListener(this._skipStackFramesSwitchOrPatternChanged, this);
334 WebInspector.settings.skipStackFramesPattern.addChangeListener(this._skipStackFramesSwitchOrPatternChanged, this);
336 p = this._appendSection(WebInspector.UIString("Profiler"));
337 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Show advanced heap snapshot properties"), WebInspector.settings.showAdvancedHeapSnapshotProperties));
338 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("High resolution CPU profiling"), WebInspector.settings.highResolutionCpuProfiling));
340 p = this._appendSection(WebInspector.UIString("Console"));
341 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Log XMLHttpRequests"), WebInspector.settings.monitoringXHREnabled));
342 p.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Preserve log upon navigation"), WebInspector.settings.preserveConsoleLog));
344 if (WebInspector.openAnchorLocationRegistry.handlerNames.length > 0) {
345 var handlerSelector = new WebInspector.HandlerSelector(WebInspector.openAnchorLocationRegistry);
346 p = this._appendSection(WebInspector.UIString("Extensions"));
347 p.appendChild(this._createCustomSetting(WebInspector.UIString("Open links in"), handlerSelector.element));
350 p = this._appendSection();
352 var restoreDefaults = p.createChild("input", "settings-tab-text-button");
353 restoreDefaults.type = "button";
354 restoreDefaults.value = WebInspector.UIString("Restore defaults and reload");
355 restoreDefaults.addEventListener("click", restoreAndReload);
357 function restoreAndReload()
359 if (window.localStorage)
360 window.localStorage.clear();
361 WebInspector.reload();
365 WebInspector.GenericSettingsTab.prototype = {
366 _updateScriptDisabledCheckbox: function()
369 * @param {?Protocol.Error} error
370 * @param {string} status
371 * @this {WebInspector.GenericSettingsTab}
373 function executionStatusCallback(error, status)
375 if (error || !status)
380 this._disableJSCheckbox.checked = true;
381 this._disableJSCheckbox.disabled = true;
384 this._disableJSCheckbox.checked = true;
387 this._disableJSCheckbox.checked = false;
392 PageAgent.getScriptExecutionStatus(executionStatusCallback.bind(this));
395 _javaScriptDisabledChanged: function()
397 // We need to manually update the checkbox state, since enabling JavaScript in the page can actually uncover the "forbidden" state.
398 PageAgent.setScriptExecutionDisabled(WebInspector.settings.javaScriptDisabled.get(), this._updateScriptDisabledCheckbox.bind(this));
401 _skipStackFramesSwitchOrPatternChanged: function()
403 WebInspector.DebuggerModel.applySkipStackFrameSettings();
407 * @param {?Element} p
409 _appendDrawerNote: function(p)
411 var noteElement = p.createChild("div", "help-field-note");
412 noteElement.createTextChild("Hit ");
413 noteElement.createChild("span", "help-key").textContent = "Esc";
414 noteElement.createTextChild(WebInspector.UIString(" or click the"));
415 noteElement.appendChild(new WebInspector.StatusBarButton(WebInspector.UIString("Drawer"), "console-status-bar-item").element);
416 noteElement.createTextChild(WebInspector.UIString("toolbar item"));
419 __proto__: WebInspector.SettingsTab.prototype
424 * @extends {WebInspector.SettingsTab}
426 WebInspector.WorkspaceSettingsTab = function()
428 WebInspector.SettingsTab.call(this, WebInspector.UIString("Workspace"), "workspace-tab-content");
429 WebInspector.isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemAdded, this._fileSystemAdded, this);
430 WebInspector.isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemRemoved, this._fileSystemRemoved, this);
432 this._commonSection = this._appendSection(WebInspector.UIString("Common"));
433 var folderExcludePatternInput = this._createInputSetting(WebInspector.UIString("Folder exclude pattern"), WebInspector.settings.workspaceFolderExcludePattern, false, 0, "270px", WebInspector.SettingsScreen.regexValidator);
434 this._commonSection.appendChild(folderExcludePatternInput);
436 this._fileSystemsSection = this._appendSection(WebInspector.UIString("Folders"));
437 this._fileSystemsListContainer = this._fileSystemsSection.createChild("p", "settings-list-container");
439 this._addFileSystemRowElement = this._fileSystemsSection.createChild("div");
440 var addFileSystemButton = this._addFileSystemRowElement.createChild("input", "settings-tab-text-button");
441 addFileSystemButton.type = "button";
442 addFileSystemButton.value = WebInspector.UIString("Add folder\u2026");
443 addFileSystemButton.addEventListener("click", this._addFileSystemClicked.bind(this));
445 this._editFileSystemButton = this._addFileSystemRowElement.createChild("input", "settings-tab-text-button");
446 this._editFileSystemButton.type = "button";
447 this._editFileSystemButton.value = WebInspector.UIString("Edit\u2026");
448 this._editFileSystemButton.addEventListener("click", this._editFileSystemClicked.bind(this));
449 this._updateEditFileSystemButtonState();
454 WebInspector.WorkspaceSettingsTab.prototype = {
457 WebInspector.SettingsTab.prototype.wasShown.call(this);
463 this._resetFileSystems();
466 _resetFileSystems: function()
468 this._fileSystemsListContainer.removeChildren();
469 var fileSystemPaths = WebInspector.isolatedFileSystemManager.mapping().fileSystemPaths();
470 delete this._fileSystemsList;
472 if (!fileSystemPaths.length) {
473 var noFileSystemsMessageElement = this._fileSystemsListContainer.createChild("div", "no-file-systems-message");
474 noFileSystemsMessageElement.textContent = WebInspector.UIString("You have no file systems added.");
478 this._fileSystemsList = new WebInspector.SettingsList(["path"], this._renderFileSystem.bind(this));
479 this._fileSystemsList.element.classList.add("file-systems-list");
480 this._fileSystemsList.addEventListener(WebInspector.SettingsList.Events.Selected, this._fileSystemSelected.bind(this));
481 this._fileSystemsList.addEventListener(WebInspector.SettingsList.Events.Removed, this._fileSystemRemovedfromList.bind(this));
482 this._fileSystemsList.addEventListener(WebInspector.SettingsList.Events.DoubleClicked, this._fileSystemDoubleClicked.bind(this));
483 this._fileSystemsListContainer.appendChild(this._fileSystemsList.element);
484 for (var i = 0; i < fileSystemPaths.length; ++i)
485 this._fileSystemsList.addItem(fileSystemPaths[i]);
486 this._updateEditFileSystemButtonState();
489 _updateEditFileSystemButtonState: function()
491 this._editFileSystemButton.disabled = !this._selectedFileSystemPath();
495 * @param {!WebInspector.Event} event
497 _fileSystemSelected: function(event)
499 this._updateEditFileSystemButtonState();
503 * @param {!WebInspector.Event} event
505 _fileSystemDoubleClicked: function(event)
507 var id = /** @type{?string} */ (event.data);
508 this._editFileSystem(id);
512 * @param {!WebInspector.Event=} event
514 _editFileSystemClicked: function(event)
516 this._editFileSystem(this._selectedFileSystemPath());
520 * @param {?string} id
522 _editFileSystem: function(id)
524 WebInspector.EditFileSystemDialog.show(WebInspector.inspectorView.devtoolsElement(), id);
528 * @param {function(?Event)} handler
531 _createRemoveButton: function(handler)
533 var removeButton = document.createElement("button");
534 removeButton.classList.add("button");
535 removeButton.classList.add("remove-item-button");
536 removeButton.value = WebInspector.UIString("Remove");
538 removeButton.addEventListener("click", handler, false);
540 removeButton.disabled = true;
545 * @param {!Element} columnElement
546 * @param {string} column
547 * @param {?string} id
549 _renderFileSystem: function(columnElement, column, id)
553 var fileSystemPath = id;
554 var textElement = columnElement.createChild("span", "list-column-text");
555 var pathElement = textElement.createChild("span", "file-system-path");
556 pathElement.title = fileSystemPath;
558 const maxTotalPathLength = 55;
559 const maxFolderNameLength = 30;
561 var lastIndexOfSlash = fileSystemPath.lastIndexOf(WebInspector.isWin() ? "\\" : "/");
562 var folderName = fileSystemPath.substr(lastIndexOfSlash + 1);
563 var folderPath = fileSystemPath.substr(0, lastIndexOfSlash + 1);
564 folderPath = folderPath.trimMiddle(maxTotalPathLength - Math.min(maxFolderNameLength, folderName.length));
565 folderName = folderName.trimMiddle(maxFolderNameLength);
567 var folderPathElement = pathElement.createChild("span");
568 folderPathElement.textContent = folderPath;
570 var nameElement = pathElement.createChild("span", "file-system-path-name");
571 nameElement.textContent = folderName;
575 * @param {!WebInspector.Event} event
577 _fileSystemRemovedfromList: function(event)
579 var id = /** @type{?string} */ (event.data);
582 WebInspector.isolatedFileSystemManager.removeFileSystem(id);
585 _addFileSystemClicked: function()
587 WebInspector.isolatedFileSystemManager.addFileSystem();
590 _fileSystemAdded: function(event)
592 var fileSystem = /** @type {!WebInspector.IsolatedFileSystem} */ (event.data);
593 if (!this._fileSystemsList)
596 this._fileSystemsList.addItem(fileSystem.path());
599 _fileSystemRemoved: function(event)
601 var fileSystem = /** @type {!WebInspector.IsolatedFileSystem} */ (event.data);
602 var selectedFileSystemPath = this._selectedFileSystemPath();
603 if (this._fileSystemsList.itemForId(fileSystem.path()))
604 this._fileSystemsList.removeItem(fileSystem.path());
605 if (!this._fileSystemsList.itemIds().length)
607 this._updateEditFileSystemButtonState();
610 _selectedFileSystemPath: function()
612 return this._fileSystemsList ? this._fileSystemsList.selectedId() : null;
615 __proto__: WebInspector.SettingsTab.prototype
621 * @extends {WebInspector.SettingsTab}
623 WebInspector.ExperimentsSettingsTab = function()
625 WebInspector.SettingsTab.call(this, WebInspector.UIString("Experiments"), "experiments-tab-content");
627 var experiments = WebInspector.experimentsSettings.experiments;
628 if (experiments.length) {
629 var experimentsSection = this._appendSection();
630 experimentsSection.appendChild(this._createExperimentsWarningSubsection());
631 for (var i = 0; i < experiments.length; ++i)
632 experimentsSection.appendChild(this._createExperimentCheckbox(experiments[i]));
636 WebInspector.ExperimentsSettingsTab.prototype = {
638 * @return {!Element} element
640 _createExperimentsWarningSubsection: function()
642 var subsection = document.createElement("div");
643 var warning = subsection.createChild("span", "settings-experiments-warning-subsection-warning");
644 warning.textContent = WebInspector.UIString("WARNING:");
645 subsection.appendChild(document.createTextNode(" "));
646 var message = subsection.createChild("span", "settings-experiments-warning-subsection-message");
647 message.textContent = WebInspector.UIString("These experiments could be dangerous and may require restart.");
651 _createExperimentCheckbox: function(experiment)
653 var input = document.createElement("input");
654 input.type = "checkbox";
655 input.name = experiment.name;
656 input.checked = experiment.isEnabled();
659 experiment.setEnabled(input.checked);
661 input.addEventListener("click", listener, false);
663 var p = document.createElement("p");
664 var label = document.createElement("label");
665 label.appendChild(input);
666 label.appendChild(document.createTextNode(WebInspector.UIString(experiment.title)));
667 p.appendChild(label);
671 __proto__: WebInspector.SettingsTab.prototype
677 WebInspector.SettingsController = function()
679 this._statusBarButton = new WebInspector.StatusBarButton(WebInspector.UIString("Settings"), "settings-status-bar-item");
680 this._statusBarButton.element.addEventListener("mouseup", this._mouseUp.bind(this), false);
682 /** @type {?WebInspector.SettingsScreen} */
683 this._settingsScreen;
686 WebInspector.SettingsController.prototype =
693 return this._statusBarButton.element;
698 this.showSettingsScreen();
701 _onHideSettingsScreen: function()
703 delete this._settingsScreenVisible;
707 * @param {string=} tabId
709 showSettingsScreen: function(tabId)
711 if (!this._settingsScreen)
712 this._settingsScreen = new WebInspector.SettingsScreen(this._onHideSettingsScreen.bind(this));
715 this._settingsScreen.selectTab(tabId);
717 this._settingsScreen.showModal();
718 this._settingsScreenVisible = true;
721 _hideSettingsScreen: function()
723 if (this._settingsScreen)
724 this._settingsScreen.hide();
729 if (this._settingsScreen && this._settingsScreen.isShowing())
730 this._settingsScreen.doResize();
736 * @extends {WebInspector.Object}
737 * @param {function(!Element, string, ?string)} itemRenderer
739 WebInspector.SettingsList = function(columns, itemRenderer)
741 this.element = document.createElement("div");
742 this.element.classList.add("settings-list");
743 this.element.tabIndex = -1;
744 this._itemRenderer = itemRenderer;
745 this._listItems = {};
747 this._columns = columns;
750 WebInspector.SettingsList.Events = {
751 Selected: "Selected",
753 DoubleClicked: "DoubleClicked",
756 WebInspector.SettingsList.prototype = {
758 * @param {?string} itemId
759 * @param {?string=} beforeId
762 addItem: function(itemId, beforeId)
764 var listItem = document.createElement("div");
765 listItem._id = itemId;
766 listItem.classList.add("settings-list-item");
767 if (typeof beforeId !== undefined)
768 this.element.insertBefore(listItem, this._listItems[beforeId]);
770 this.element.appendChild(listItem);
772 var listItemContents = listItem.createChild("div", "settings-list-item-contents");
773 var listItemColumnsElement = listItemContents.createChild("div", "settings-list-item-columns");
775 listItem.columnElements = {};
776 for (var i = 0; i < this._columns.length; ++i) {
777 var columnElement = listItemColumnsElement.createChild("div", "list-column");
778 var columnId = this._columns[i];
779 listItem.columnElements[columnId] = columnElement;
780 this._itemRenderer(columnElement, columnId, itemId);
782 var removeItemButton = this._createRemoveButton(removeItemClicked.bind(this));
783 listItemContents.addEventListener("click", this.selectItem.bind(this, itemId), false);
784 listItemContents.addEventListener("dblclick", this._onDoubleClick.bind(this, itemId), false);
785 listItemContents.appendChild(removeItemButton);
787 this._listItems[itemId] = listItem;
788 if (typeof beforeId !== undefined)
789 this._ids.splice(this._ids.indexOf(beforeId), 0, itemId);
791 this._ids.push(itemId);
794 * @param {?Event} event
795 * @this {WebInspector.SettingsList}
797 function removeItemClicked(event)
799 removeItemButton.disabled = true;
800 this.removeItem(itemId);
801 this.dispatchEventToListeners(WebInspector.SettingsList.Events.Removed, itemId);
809 * @param {?string} id
811 removeItem: function(id)
813 this._listItems[id].remove();
814 delete this._listItems[id];
815 this._ids.remove(id);
816 if (id === this._selectedId) {
817 delete this._selectedId;
818 if (this._ids.length)
819 this.selectItem(this._ids[0]);
824 * @return {!Array.<?string>}
828 return this._ids.slice();
832 * @return {!Array.<string>}
836 return this._columns.slice();
842 selectedId: function()
844 return this._selectedId;
850 selectedItem: function()
852 return this._selectedId ? this._listItems[this._selectedId] : null;
856 * @param {string} itemId
859 itemForId: function(itemId)
861 return this._listItems[itemId];
865 * @param {?string} id
866 * @param {!Event=} event
868 _onDoubleClick: function(id, event)
870 this.dispatchEventToListeners(WebInspector.SettingsList.Events.DoubleClicked, id);
874 * @param {?string} id
875 * @param {!Event=} event
877 selectItem: function(id, event)
879 if (typeof this._selectedId !== "undefined") {
880 this._listItems[this._selectedId].classList.remove("selected");
883 this._selectedId = id;
884 if (typeof this._selectedId !== "undefined") {
885 this._listItems[this._selectedId].classList.add("selected");
887 this.dispatchEventToListeners(WebInspector.SettingsList.Events.Selected, id);
893 * @param {function(?Event)} handler
896 _createRemoveButton: function(handler)
898 var removeButton = document.createElement("button");
899 removeButton.classList.add("remove-item-button");
900 removeButton.value = WebInspector.UIString("Remove");
901 removeButton.addEventListener("click", handler, false);
905 __proto__: WebInspector.Object.prototype
910 * @extends {WebInspector.SettingsList}
911 * @param {function(?string, !Object)} validateHandler
912 * @param {function(?string, !Object)} editHandler
914 WebInspector.EditableSettingsList = function(columns, valuesProvider, validateHandler, editHandler)
916 WebInspector.SettingsList.call(this, columns, this._renderColumn.bind(this));
917 this._validateHandler = validateHandler;
918 this._editHandler = editHandler;
919 this._valuesProvider = valuesProvider;
920 /** @type {!Object.<string, !HTMLInputElement>} */
921 this._addInputElements = {};
922 /** @type {!Object.<string, !Object.<string, !HTMLInputElement>>} */
923 this._editInputElements = {};
924 /** @type {!Object.<string, !Object.<string, !HTMLSpanElement>>} */
925 this._textElements = {};
927 this._addMappingItem = this.addItem(null);
928 this._addMappingItem.classList.add("item-editing");
929 this._addMappingItem.classList.add("add-list-item");
932 WebInspector.EditableSettingsList.prototype = {
934 * @param {?string} itemId
935 * @param {?string=} beforeId
938 addItem: function(itemId, beforeId)
940 var listItem = WebInspector.SettingsList.prototype.addItem.call(this, itemId, beforeId);
941 listItem.classList.add("editable");
946 * @param {!Element} columnElement
947 * @param {string} columnId
948 * @param {?string} itemId
950 _renderColumn: function(columnElement, columnId, itemId)
952 columnElement.classList.add("settings-list-column-" + columnId);
953 var placeholder = (columnId === "url") ? WebInspector.UIString("URL prefix") : WebInspector.UIString("Folder path");
954 if (itemId === null) {
955 var inputElement = columnElement.createChild("input", "list-column-editor");
956 inputElement.placeholder = placeholder;
957 inputElement.addEventListener("blur", this._onAddMappingInputBlur.bind(this));
958 inputElement.addEventListener("input", this._validateEdit.bind(this, itemId));
959 this._addInputElements[columnId] = inputElement;
962 var validItemId = itemId;
964 if (!this._editInputElements[itemId])
965 this._editInputElements[itemId] = {};
966 if (!this._textElements[itemId])
967 this._textElements[itemId] = {};
969 var value = this._valuesProvider(itemId, columnId);
971 var textElement = columnElement.createChild("span", "list-column-text");
972 textElement.textContent = value;
973 textElement.title = value;
974 columnElement.addEventListener("click", rowClicked.bind(this), false);
975 this._textElements[itemId][columnId] = textElement;
977 var inputElement = columnElement.createChild("input", "list-column-editor");
978 inputElement.value = value;
979 inputElement.addEventListener("blur", this._editMappingBlur.bind(this, itemId));
980 inputElement.addEventListener("input", this._validateEdit.bind(this, itemId));
981 columnElement.inputElement = inputElement;
982 this._editInputElements[itemId][columnId] = inputElement;
985 * @param {?Event} event
986 * @this {WebInspector.EditableSettingsList}
988 function rowClicked(event)
990 if (itemId === this._editingId)
993 console.assert(!this._editingId);
994 this._editingId = validItemId;
995 var listItem = this.itemForId(validItemId);
996 listItem.classList.add("item-editing");
997 var inputElement = event.target.inputElement || this._editInputElements[validItemId][this.columns()[0]];
998 inputElement.focus();
999 inputElement.select();
1004 * @param {?string} itemId
1007 _data: function(itemId)
1009 var inputElements = this._inputElements(itemId);
1011 var columns = this.columns();
1012 for (var i = 0; i < columns.length; ++i)
1013 data[columns[i]] = inputElements[columns[i]].value;
1018 * @param {?string} itemId
1019 * @return {?Object.<string, !HTMLInputElement>}
1021 _inputElements: function(itemId)
1024 return this._addInputElements;
1025 return this._editInputElements[itemId] || null;
1029 * @param {?string} itemId
1032 _validateEdit: function(itemId)
1034 var errorColumns = this._validateHandler(itemId, this._data(itemId));
1035 var hasChanges = this._hasChanges(itemId);
1036 var columns = this.columns();
1037 for (var i = 0; i < columns.length; ++i) {
1038 var columnId = columns[i];
1039 var inputElement = this._inputElements(itemId)[columnId];
1040 if (hasChanges && errorColumns.indexOf(columnId) !== -1)
1041 inputElement.classList.add("editable-item-error");
1043 inputElement.classList.remove("editable-item-error");
1045 return !errorColumns.length;
1049 * @param {?string} itemId
1052 _hasChanges: function(itemId)
1054 var hasChanges = false;
1055 var columns = this.columns();
1056 for (var i = 0; i < columns.length; ++i) {
1057 var columnId = columns[i];
1058 var oldValue = itemId ? this._textElements[itemId][columnId].textContent : "";
1059 var newValue = this._inputElements(itemId)[columnId].value;
1060 if (oldValue !== newValue) {
1069 * @param {string} itemId
1071 _editMappingBlur: function(itemId, event)
1073 var inputElements = Object.values(this._editInputElements[itemId]);
1074 if (inputElements.indexOf(event.relatedTarget) !== -1)
1077 var listItem = this.itemForId(itemId);
1078 listItem.classList.remove("item-editing");
1079 delete this._editingId;
1081 if (!this._hasChanges(itemId))
1084 if (!this._validateEdit(itemId)) {
1085 var columns = this.columns();
1086 for (var i = 0; i < columns.length; ++i) {
1087 var columnId = columns[i];
1088 var inputElement = this._editInputElements[itemId][columnId];
1089 inputElement.value = this._textElements[itemId][columnId].textContent;
1090 inputElement.classList.remove("editable-item-error");
1094 this._editHandler(itemId, this._data(itemId));
1097 _onAddMappingInputBlur: function(event)
1099 var inputElements = Object.values(this._addInputElements);
1100 if (inputElements.indexOf(event.relatedTarget) !== -1)
1103 if (!this._hasChanges(null))
1106 if (!this._validateEdit(null))
1109 this._editHandler(null, this._data(null));
1110 var columns = this.columns();
1111 for (var i = 0; i < columns.length; ++i) {
1112 var columnId = columns[i];
1113 var inputElement = this._addInputElements[columnId];
1114 inputElement.value = "";
1118 __proto__: WebInspector.SettingsList.prototype
1121 /** @type {!WebInspector.SettingsController} */
1122 WebInspector.settingsController;