OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2013 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 * @constructor | |
33 * @param {!function()} onHide | |
34 * @extends {WebInspector.HelpScreen} | |
35 */ | |
36 WebInspector.SettingsScreen = function(onHide) | |
37 { | |
38 WebInspector.HelpScreen.call(this); | |
39 this.element.id = "settings-screen"; | |
40 | |
41 /** @type {function()} */ | |
42 this._onHide = onHide; | |
43 | |
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, WebInsp
ector.UIString("General"), new WebInspector.GenericSettingsTab()); | |
52 this._tabbedPane.appendTab(WebInspector.SettingsScreen.Tabs.Workspace, WebIn
spector.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, WebIn
spector.UIString("Shortcuts"), WebInspector.shortcutsScreen.createShortcutsTabVi
ew()); | |
56 this._tabbedPane.shrinkableTabs = false; | |
57 this._tabbedPane.verticalTabLayout = true; | |
58 | |
59 this._lastSelectedTabSetting = WebInspector.settings.createSetting("lastSele
ctedSettingsTab", WebInspector.SettingsScreen.Tabs.General); | |
60 this.selectTab(this._lastSelectedTabSetting.get()); | |
61 this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSele
cted, this._tabSelected, this); | |
62 this.element.addEventListener("keydown", this._keyDown.bind(this), false); | |
63 this._developerModeCounter = 0; | |
64 } | |
65 | |
66 /** | |
67 * @param {number} min | |
68 * @param {number} max | |
69 * @param {string} text | |
70 * @return {?string} | |
71 */ | |
72 WebInspector.SettingsScreen.integerValidator = function(min, max, text) | |
73 { | |
74 var value = Number(text); | |
75 if (isNaN(value)) | |
76 return WebInspector.UIString("Invalid number format"); | |
77 if (value < min || value > max) | |
78 return WebInspector.UIString("Value is out of range [%d, %d]", min, max)
; | |
79 return null; | |
80 } | |
81 | |
82 WebInspector.SettingsScreen.Tabs = { | |
83 General: "general", | |
84 Overrides: "overrides", | |
85 Workspace: "workspace", | |
86 Experiments: "experiments", | |
87 Shortcuts: "shortcuts" | |
88 } | |
89 | |
90 WebInspector.SettingsScreen.prototype = { | |
91 /** | |
92 * @param {string} tabId | |
93 */ | |
94 selectTab: function(tabId) | |
95 { | |
96 this._tabbedPane.selectTab(tabId); | |
97 }, | |
98 | |
99 /** | |
100 * @param {!WebInspector.Event} event | |
101 */ | |
102 _tabSelected: function(event) | |
103 { | |
104 this._lastSelectedTabSetting.set(this._tabbedPane.selectedTabId); | |
105 }, | |
106 | |
107 /** | |
108 * @override | |
109 */ | |
110 wasShown: function() | |
111 { | |
112 this._tabbedPane.show(this.element); | |
113 WebInspector.HelpScreen.prototype.wasShown.call(this); | |
114 }, | |
115 | |
116 /** | |
117 * @override | |
118 * @return {boolean} | |
119 */ | |
120 isClosingKey: function(keyCode) | |
121 { | |
122 return [ | |
123 WebInspector.KeyboardShortcut.Keys.Enter.code, | |
124 WebInspector.KeyboardShortcut.Keys.Esc.code, | |
125 ].indexOf(keyCode) >= 0; | |
126 }, | |
127 | |
128 /** | |
129 * @override | |
130 */ | |
131 willHide: function() | |
132 { | |
133 this._onHide(); | |
134 WebInspector.HelpScreen.prototype.willHide.call(this); | |
135 }, | |
136 | |
137 /** | |
138 * @param {?Event} event | |
139 */ | |
140 _keyDown: function(event) | |
141 { | |
142 var shiftKeyCode = 16; | |
143 if (event.keyCode === shiftKeyCode && ++this._developerModeCounter > 5) | |
144 this.element.classList.add("settings-developer-mode"); | |
145 }, | |
146 | |
147 __proto__: WebInspector.HelpScreen.prototype | |
148 } | |
149 | |
150 /** | |
151 * @constructor | |
152 * @extends {WebInspector.VBox} | |
153 * @param {string} name | |
154 * @param {string=} id | |
155 */ | |
156 WebInspector.SettingsTab = function(name, id) | |
157 { | |
158 WebInspector.VBox.call(this); | |
159 this.element.classList.add("settings-tab-container"); | |
160 if (id) | |
161 this.element.id = id; | |
162 var header = this.element.createChild("header"); | |
163 header.createChild("h3").appendChild(document.createTextNode(name)); | |
164 this.containerElement = this.element.createChild("div", "help-container-wrap
per").createChild("div", "settings-tab help-content help-container"); | |
165 } | |
166 | |
167 WebInspector.SettingsTab.prototype = { | |
168 /** | |
169 * @param {string=} name | |
170 * @return {!Element} | |
171 */ | |
172 _appendSection: function(name) | |
173 { | |
174 var block = this.containerElement.createChild("div", "help-block"); | |
175 if (name) | |
176 block.createChild("div", "help-section-title").textContent = name; | |
177 return block; | |
178 }, | |
179 | |
180 _createSelectSetting: function(name, options, setting) | |
181 { | |
182 var p = document.createElement("p"); | |
183 var labelElement = p.createChild("label"); | |
184 labelElement.textContent = name; | |
185 | |
186 var select = p.createChild("select"); | |
187 var settingValue = setting.get(); | |
188 | |
189 for (var i = 0; i < options.length; ++i) { | |
190 var option = options[i]; | |
191 select.add(new Option(option[0], option[1])); | |
192 if (settingValue === option[1]) | |
193 select.selectedIndex = i; | |
194 } | |
195 | |
196 function changeListener(e) | |
197 { | |
198 // Don't use e.target.value to avoid conversion of the value to stri
ng. | |
199 setting.set(options[select.selectedIndex][1]); | |
200 } | |
201 | |
202 select.addEventListener("change", changeListener, false); | |
203 return p; | |
204 }, | |
205 | |
206 __proto__: WebInspector.VBox.prototype | |
207 } | |
208 | |
209 /** | |
210 * @constructor | |
211 * @extends {WebInspector.SettingsTab} | |
212 */ | |
213 WebInspector.GenericSettingsTab = function() | |
214 { | |
215 WebInspector.SettingsTab.call(this, WebInspector.UIString("General"), "gener
al-tab-content"); | |
216 | |
217 this._populateSectionsFromExtensions(); | |
218 | |
219 var restoreDefaults = this._appendSection().createChild("input", "settings-t
ab-text-button"); | |
220 restoreDefaults.type = "button"; | |
221 restoreDefaults.value = WebInspector.UIString("Restore defaults and reload")
; | |
222 restoreDefaults.addEventListener("click", restoreAndReload); | |
223 | |
224 function restoreAndReload() | |
225 { | |
226 if (window.localStorage) | |
227 window.localStorage.clear(); | |
228 WebInspector.reload(); | |
229 } | |
230 } | |
231 | |
232 WebInspector.GenericSettingsTab.prototype = { | |
233 _populateSectionsFromExtensions: function() | |
234 { | |
235 /** @const */ | |
236 var explicitSectionOrder = ["", "Appearance", "Elements", "Sources", "Pr
ofiler", "Console", "Extensions"]; | |
237 | |
238 var allExtensions = WebInspector.moduleManager.extensions("ui-setting"); | |
239 | |
240 /** @type {!StringMultimap.<!WebInspector.ModuleManager.Extension>} */ | |
241 var extensionsBySectionId = new StringMultimap(); | |
242 /** @type {!StringMultimap.<!WebInspector.ModuleManager.Extension>} */ | |
243 var childSettingExtensionsByParentName = new StringMultimap(); | |
244 | |
245 allExtensions.forEach(function(extension) { | |
246 var descriptor = extension.descriptor(); | |
247 var sectionName = descriptor["section"] || ""; | |
248 if (!sectionName && descriptor["parentSettingName"]) { | |
249 childSettingExtensionsByParentName.put(descriptor["parentSetting
Name"], extension); | |
250 return; | |
251 } | |
252 extensionsBySectionId.put(sectionName, extension); | |
253 }); | |
254 | |
255 var sectionIds = extensionsBySectionId.keys(); | |
256 var explicitlyOrderedSections = {}; | |
257 for (var i = 0; i < explicitSectionOrder.length; ++i) { | |
258 explicitlyOrderedSections[explicitSectionOrder[i]] = true; | |
259 var extensions = extensionsBySectionId.get(explicitSectionOrder[i]); | |
260 if (!extensions.size()) | |
261 continue; | |
262 this._addSectionWithExtensionProvidedSettings(explicitSectionOrder[i
], extensions.values(), childSettingExtensionsByParentName); | |
263 } | |
264 for (var i = 0; i < sectionIds.length; ++i) { | |
265 if (explicitlyOrderedSections[sectionIds[i]]) | |
266 continue; | |
267 this._addSectionWithExtensionProvidedSettings(sectionIds[i], extensi
onsBySectionId.get(sectionIds[i]).values(), childSettingExtensionsByParentName); | |
268 } | |
269 }, | |
270 | |
271 /** | |
272 * @param {string} sectionName | |
273 * @param {!Array.<!WebInspector.ModuleManager.Extension>} extensions | |
274 * @param {!StringMultimap.<!WebInspector.ModuleManager.Extension>} childSet
tingExtensionsByParentName | |
275 */ | |
276 _addSectionWithExtensionProvidedSettings: function(sectionName, extensions,
childSettingExtensionsByParentName) | |
277 { | |
278 var uiSectionName = sectionName && WebInspector.UIString(sectionName); | |
279 var sectionElement = this._appendSection(uiSectionName); | |
280 extensions.forEach(processSetting.bind(this, null)); | |
281 | |
282 /** | |
283 * @param {?Element} parentFieldset | |
284 * @param {!WebInspector.ModuleManager.Extension} extension | |
285 * @this {WebInspector.GenericSettingsTab} | |
286 */ | |
287 function processSetting(parentFieldset, extension) | |
288 { | |
289 var descriptor = extension.descriptor(); | |
290 var experimentName = descriptor["experiment"]; | |
291 if (experimentName && (!WebInspector.experimentsSettings[experimentN
ame] || !WebInspector.experimentsSettings[experimentName].isEnabled())) | |
292 return; | |
293 | |
294 var settingName = descriptor["settingName"]; | |
295 var setting = WebInspector.settings[settingName]; | |
296 var instance = extension.instance(); | |
297 var settingControl; | |
298 if (instance && descriptor["settingType"] === "custom") { | |
299 settingControl = instance.settingElement(); | |
300 if (!settingControl) | |
301 return; | |
302 } | |
303 if (!settingControl) { | |
304 var uiTitle = WebInspector.UIString(descriptor["title"]); | |
305 settingControl = createSettingControl.call(this, uiTitle, settin
g, descriptor, instance); | |
306 } | |
307 if (settingName) { | |
308 var childSettings = childSettingExtensionsByParentName.get(setti
ngName); | |
309 if (childSettings.size()) { | |
310 var fieldSet = WebInspector.SettingsUI.createSettingFieldset
(setting); | |
311 settingControl.appendChild(fieldSet); | |
312 childSettings.values().forEach(function(item) { processSetti
ng.call(this, fieldSet, item); }, this); | |
313 } | |
314 } | |
315 var containerElement = parentFieldset || sectionElement; | |
316 containerElement.appendChild(settingControl); | |
317 } | |
318 | |
319 /** | |
320 * @param {string} uiTitle | |
321 * @param {!WebInspector.Setting} setting | |
322 * @param {!Object} descriptor | |
323 * @param {?Object} instance | |
324 * @return {!Element} | |
325 * @this {WebInspector.GenericSettingsTab} | |
326 */ | |
327 function createSettingControl(uiTitle, setting, descriptor, instance) | |
328 { | |
329 switch (descriptor["settingType"]) { | |
330 case "checkbox": | |
331 return WebInspector.SettingsUI.createSettingCheckbox(uiTitle, se
tting); | |
332 case "select": | |
333 var descriptorOptions = descriptor["options"] | |
334 var options = new Array(descriptorOptions.length); | |
335 for (var i = 0; i < options.length; ++i) { | |
336 // The third array item flags that the option name is "raw"
(non-i18n-izable). | |
337 var optionName = descriptorOptions[i][2] ? descriptorOptions
[i][0] : WebInspector.UIString(descriptorOptions[i][0]); | |
338 options[i] = [WebInspector.UIString(descriptorOptions[i][0])
, descriptorOptions[i][1]]; | |
339 } | |
340 return this._createSelectSetting(uiTitle, options, setting); | |
341 default: | |
342 throw "Invalid setting type: " + descriptor["settingType"]; | |
343 } | |
344 } | |
345 }, | |
346 | |
347 /** | |
348 * @param {?Element} p | |
349 */ | |
350 _appendDrawerNote: function(p) | |
351 { | |
352 var noteElement = p.createChild("div", "help-field-note"); | |
353 noteElement.createTextChild("Hit "); | |
354 noteElement.createChild("span", "help-key").textContent = "Esc"; | |
355 noteElement.createTextChild(WebInspector.UIString(" or click the")); | |
356 noteElement.appendChild(new WebInspector.StatusBarButton(WebInspector.UI
String("Drawer"), "console-status-bar-item").element); | |
357 noteElement.createTextChild(WebInspector.UIString("toolbar item")); | |
358 }, | |
359 | |
360 __proto__: WebInspector.SettingsTab.prototype | |
361 } | |
362 | |
363 /** | |
364 * @constructor | |
365 * @extends {WebInspector.SettingsTab} | |
366 */ | |
367 WebInspector.WorkspaceSettingsTab = function() | |
368 { | |
369 WebInspector.SettingsTab.call(this, WebInspector.UIString("Workspace"), "wor
kspace-tab-content"); | |
370 WebInspector.isolatedFileSystemManager.addEventListener(WebInspector.Isolate
dFileSystemManager.Events.FileSystemAdded, this._fileSystemAdded, this); | |
371 WebInspector.isolatedFileSystemManager.addEventListener(WebInspector.Isolate
dFileSystemManager.Events.FileSystemRemoved, this._fileSystemRemoved, this); | |
372 | |
373 this._commonSection = this._appendSection(WebInspector.UIString("Common")); | |
374 var folderExcludePatternInput = WebInspector.SettingsUI.createSettingInputFi
eld(WebInspector.UIString("Folder exclude pattern"), WebInspector.settings.works
paceFolderExcludePattern, false, 0, "270px", WebInspector.SettingsUI.regexValida
tor); | |
375 this._commonSection.appendChild(folderExcludePatternInput); | |
376 | |
377 this._fileSystemsSection = this._appendSection(WebInspector.UIString("Folder
s")); | |
378 this._fileSystemsListContainer = this._fileSystemsSection.createChild("p", "
settings-list-container"); | |
379 | |
380 this._addFileSystemRowElement = this._fileSystemsSection.createChild("div"); | |
381 var addFileSystemButton = this._addFileSystemRowElement.createChild("input",
"settings-tab-text-button"); | |
382 addFileSystemButton.type = "button"; | |
383 addFileSystemButton.value = WebInspector.UIString("Add folder\u2026"); | |
384 addFileSystemButton.addEventListener("click", this._addFileSystemClicked.bin
d(this)); | |
385 | |
386 this._editFileSystemButton = this._addFileSystemRowElement.createChild("inpu
t", "settings-tab-text-button"); | |
387 this._editFileSystemButton.type = "button"; | |
388 this._editFileSystemButton.value = WebInspector.UIString("Edit\u2026"); | |
389 this._editFileSystemButton.addEventListener("click", this._editFileSystemCli
cked.bind(this)); | |
390 this._updateEditFileSystemButtonState(); | |
391 | |
392 this._reset(); | |
393 } | |
394 | |
395 WebInspector.WorkspaceSettingsTab.prototype = { | |
396 wasShown: function() | |
397 { | |
398 WebInspector.SettingsTab.prototype.wasShown.call(this); | |
399 this._reset(); | |
400 }, | |
401 | |
402 _reset: function() | |
403 { | |
404 this._resetFileSystems(); | |
405 }, | |
406 | |
407 _resetFileSystems: function() | |
408 { | |
409 this._fileSystemsListContainer.removeChildren(); | |
410 var fileSystemPaths = WebInspector.isolatedFileSystemManager.mapping().f
ileSystemPaths(); | |
411 delete this._fileSystemsList; | |
412 | |
413 if (!fileSystemPaths.length) { | |
414 var noFileSystemsMessageElement = this._fileSystemsListContainer.cre
ateChild("div", "no-file-systems-message"); | |
415 noFileSystemsMessageElement.textContent = WebInspector.UIString("You
have no file systems added."); | |
416 return; | |
417 } | |
418 | |
419 this._fileSystemsList = new WebInspector.SettingsList(["path"], this._re
nderFileSystem.bind(this)); | |
420 this._fileSystemsList.element.classList.add("file-systems-list"); | |
421 this._fileSystemsList.addEventListener(WebInspector.SettingsList.Events.
Selected, this._fileSystemSelected.bind(this)); | |
422 this._fileSystemsList.addEventListener(WebInspector.SettingsList.Events.
Removed, this._fileSystemRemovedfromList.bind(this)); | |
423 this._fileSystemsList.addEventListener(WebInspector.SettingsList.Events.
DoubleClicked, this._fileSystemDoubleClicked.bind(this)); | |
424 this._fileSystemsListContainer.appendChild(this._fileSystemsList.element
); | |
425 for (var i = 0; i < fileSystemPaths.length; ++i) | |
426 this._fileSystemsList.addItem(fileSystemPaths[i]); | |
427 this._updateEditFileSystemButtonState(); | |
428 }, | |
429 | |
430 _updateEditFileSystemButtonState: function() | |
431 { | |
432 this._editFileSystemButton.disabled = !this._selectedFileSystemPath(); | |
433 }, | |
434 | |
435 /** | |
436 * @param {!WebInspector.Event} event | |
437 */ | |
438 _fileSystemSelected: function(event) | |
439 { | |
440 this._updateEditFileSystemButtonState(); | |
441 }, | |
442 | |
443 /** | |
444 * @param {!WebInspector.Event} event | |
445 */ | |
446 _fileSystemDoubleClicked: function(event) | |
447 { | |
448 var id = /** @type{?string} */ (event.data); | |
449 this._editFileSystem(id); | |
450 }, | |
451 | |
452 /** | |
453 * @param {!WebInspector.Event=} event | |
454 */ | |
455 _editFileSystemClicked: function(event) | |
456 { | |
457 this._editFileSystem(this._selectedFileSystemPath()); | |
458 }, | |
459 | |
460 /** | |
461 * @param {?string} id | |
462 */ | |
463 _editFileSystem: function(id) | |
464 { | |
465 WebInspector.EditFileSystemDialog.show(WebInspector.inspectorView.elemen
t, id); | |
466 }, | |
467 | |
468 /** | |
469 * @param {function(?Event)} handler | |
470 * @return {!Element} | |
471 */ | |
472 _createRemoveButton: function(handler) | |
473 { | |
474 var removeButton = document.createElement("button"); | |
475 removeButton.classList.add("button"); | |
476 removeButton.classList.add("remove-item-button"); | |
477 removeButton.value = WebInspector.UIString("Remove"); | |
478 if (handler) | |
479 removeButton.addEventListener("click", handler, false); | |
480 else | |
481 removeButton.disabled = true; | |
482 return removeButton; | |
483 }, | |
484 | |
485 /** | |
486 * @param {!Element} columnElement | |
487 * @param {string} column | |
488 * @param {?string} id | |
489 */ | |
490 _renderFileSystem: function(columnElement, column, id) | |
491 { | |
492 if (!id) | |
493 return ""; | |
494 var fileSystemPath = id; | |
495 var textElement = columnElement.createChild("span", "list-column-text"); | |
496 var pathElement = textElement.createChild("span", "file-system-path"); | |
497 pathElement.title = fileSystemPath; | |
498 | |
499 const maxTotalPathLength = 55; | |
500 const maxFolderNameLength = 30; | |
501 | |
502 var lastIndexOfSlash = fileSystemPath.lastIndexOf(WebInspector.isWin() ?
"\\" : "/"); | |
503 var folderName = fileSystemPath.substr(lastIndexOfSlash + 1); | |
504 var folderPath = fileSystemPath.substr(0, lastIndexOfSlash + 1); | |
505 folderPath = folderPath.trimMiddle(maxTotalPathLength - Math.min(maxFold
erNameLength, folderName.length)); | |
506 folderName = folderName.trimMiddle(maxFolderNameLength); | |
507 | |
508 var folderPathElement = pathElement.createChild("span"); | |
509 folderPathElement.textContent = folderPath; | |
510 | |
511 var nameElement = pathElement.createChild("span", "file-system-path-name
"); | |
512 nameElement.textContent = folderName; | |
513 }, | |
514 | |
515 /** | |
516 * @param {!WebInspector.Event} event | |
517 */ | |
518 _fileSystemRemovedfromList: function(event) | |
519 { | |
520 var id = /** @type{?string} */ (event.data); | |
521 if (!id) | |
522 return; | |
523 WebInspector.isolatedFileSystemManager.removeFileSystem(id); | |
524 }, | |
525 | |
526 _addFileSystemClicked: function() | |
527 { | |
528 WebInspector.isolatedFileSystemManager.addFileSystem(); | |
529 }, | |
530 | |
531 _fileSystemAdded: function(event) | |
532 { | |
533 var fileSystem = /** @type {!WebInspector.IsolatedFileSystem} */ (event.
data); | |
534 if (!this._fileSystemsList) | |
535 this._reset(); | |
536 else | |
537 this._fileSystemsList.addItem(fileSystem.path()); | |
538 }, | |
539 | |
540 _fileSystemRemoved: function(event) | |
541 { | |
542 var fileSystem = /** @type {!WebInspector.IsolatedFileSystem} */ (event.
data); | |
543 var selectedFileSystemPath = this._selectedFileSystemPath(); | |
544 if (this._fileSystemsList.itemForId(fileSystem.path())) | |
545 this._fileSystemsList.removeItem(fileSystem.path()); | |
546 if (!this._fileSystemsList.itemIds().length) | |
547 this._reset(); | |
548 this._updateEditFileSystemButtonState(); | |
549 }, | |
550 | |
551 _selectedFileSystemPath: function() | |
552 { | |
553 return this._fileSystemsList ? this._fileSystemsList.selectedId() : null
; | |
554 }, | |
555 | |
556 __proto__: WebInspector.SettingsTab.prototype | |
557 } | |
558 | |
559 | |
560 /** | |
561 * @constructor | |
562 * @extends {WebInspector.SettingsTab} | |
563 */ | |
564 WebInspector.ExperimentsSettingsTab = function() | |
565 { | |
566 WebInspector.SettingsTab.call(this, WebInspector.UIString("Experiments"), "e
xperiments-tab-content"); | |
567 | |
568 var experiments = WebInspector.experimentsSettings.experiments; | |
569 if (experiments.length) { | |
570 var experimentsSection = this._appendSection(); | |
571 experimentsSection.appendChild(this._createExperimentsWarningSubsection(
)); | |
572 for (var i = 0; i < experiments.length; ++i) | |
573 experimentsSection.appendChild(this._createExperimentCheckbox(experi
ments[i])); | |
574 } | |
575 } | |
576 | |
577 WebInspector.ExperimentsSettingsTab.prototype = { | |
578 /** | |
579 * @return {!Element} element | |
580 */ | |
581 _createExperimentsWarningSubsection: function() | |
582 { | |
583 var subsection = document.createElement("div"); | |
584 var warning = subsection.createChild("span", "settings-experiments-warni
ng-subsection-warning"); | |
585 warning.textContent = WebInspector.UIString("WARNING:"); | |
586 subsection.appendChild(document.createTextNode(" ")); | |
587 var message = subsection.createChild("span", "settings-experiments-warni
ng-subsection-message"); | |
588 message.textContent = WebInspector.UIString("These experiments could be
dangerous and may require restart."); | |
589 return subsection; | |
590 }, | |
591 | |
592 _createExperimentCheckbox: function(experiment) | |
593 { | |
594 var input = document.createElement("input"); | |
595 input.type = "checkbox"; | |
596 input.name = experiment.name; | |
597 input.checked = experiment.isEnabled(); | |
598 function listener() | |
599 { | |
600 experiment.setEnabled(input.checked); | |
601 } | |
602 input.addEventListener("click", listener, false); | |
603 | |
604 var p = document.createElement("p"); | |
605 p.className = experiment.hidden && !experiment.isEnabled() ? "settings-e
xperiment-hidden" : ""; | |
606 var label = p.createChild("label"); | |
607 label.appendChild(input); | |
608 label.appendChild(document.createTextNode(WebInspector.UIString(experime
nt.title))); | |
609 p.appendChild(label); | |
610 return p; | |
611 }, | |
612 | |
613 __proto__: WebInspector.SettingsTab.prototype | |
614 } | |
615 | |
616 /** | |
617 * @constructor | |
618 */ | |
619 WebInspector.SettingsController = function() | |
620 { | |
621 this._statusBarButton = new WebInspector.StatusBarButton(WebInspector.UIStri
ng("Settings"), "settings-status-bar-item"); | |
622 this._statusBarButton.element.addEventListener("mouseup", this._mouseUp.bind
(this), false); | |
623 | |
624 /** @type {?WebInspector.SettingsScreen} */ | |
625 this._settingsScreen; | |
626 } | |
627 | |
628 WebInspector.SettingsController.prototype = | |
629 { | |
630 /** | |
631 * @return {!Element} | |
632 */ | |
633 get statusBarItem() | |
634 { | |
635 return this._statusBarButton.element; | |
636 }, | |
637 | |
638 _mouseUp: function() | |
639 { | |
640 this.showSettingsScreen(); | |
641 }, | |
642 | |
643 _onHideSettingsScreen: function() | |
644 { | |
645 delete this._settingsScreenVisible; | |
646 }, | |
647 | |
648 /** | |
649 * @param {string=} tabId | |
650 */ | |
651 showSettingsScreen: function(tabId) | |
652 { | |
653 if (!this._settingsScreen) | |
654 this._settingsScreen = new WebInspector.SettingsScreen(this._onHideS
ettingsScreen.bind(this)); | |
655 | |
656 if (tabId) | |
657 this._settingsScreen.selectTab(tabId); | |
658 | |
659 this._settingsScreen.showModal(); | |
660 this._settingsScreenVisible = true; | |
661 }, | |
662 | |
663 resize: function() | |
664 { | |
665 if (this._settingsScreen && this._settingsScreen.isShowing()) | |
666 this._settingsScreen.doResize(); | |
667 } | |
668 } | |
669 | |
670 /** | |
671 * @constructor | |
672 * @implements {WebInspector.ActionDelegate} | |
673 */ | |
674 WebInspector.SettingsController.SettingsScreenActionDelegate = function() { } | |
675 | |
676 WebInspector.SettingsController.SettingsScreenActionDelegate.prototype = { | |
677 /** | |
678 * @return {boolean} | |
679 */ | |
680 handleAction: function() | |
681 { | |
682 WebInspector.settingsController.showSettingsScreen(WebInspector.Settings
Screen.Tabs.General); | |
683 return true; | |
684 } | |
685 } | |
686 | |
687 /** | |
688 * @constructor | |
689 * @extends {WebInspector.Object} | |
690 * @param {!Array.<string>} columns | |
691 * @param {function(!Element, string, ?string)} itemRenderer | |
692 */ | |
693 WebInspector.SettingsList = function(columns, itemRenderer) | |
694 { | |
695 this.element = document.createElement("div"); | |
696 this.element.classList.add("settings-list"); | |
697 this.element.tabIndex = -1; | |
698 this._itemRenderer = itemRenderer; | |
699 this._listItems = {}; | |
700 this._ids = []; | |
701 this._columns = columns; | |
702 } | |
703 | |
704 WebInspector.SettingsList.Events = { | |
705 Selected: "Selected", | |
706 Removed: "Removed", | |
707 DoubleClicked: "DoubleClicked", | |
708 } | |
709 | |
710 WebInspector.SettingsList.prototype = { | |
711 /** | |
712 * @param {?string} itemId | |
713 * @param {?string=} beforeId | |
714 * @return {!Element} | |
715 */ | |
716 addItem: function(itemId, beforeId) | |
717 { | |
718 var listItem = document.createElement("div"); | |
719 listItem._id = itemId; | |
720 listItem.classList.add("settings-list-item"); | |
721 if (typeof beforeId !== undefined) | |
722 this.element.insertBefore(listItem, this._listItems[beforeId]); | |
723 else | |
724 this.element.appendChild(listItem); | |
725 | |
726 var listItemContents = listItem.createChild("div", "settings-list-item-c
ontents"); | |
727 var listItemColumnsElement = listItemContents.createChild("div", "settin
gs-list-item-columns"); | |
728 | |
729 listItem.columnElements = {}; | |
730 for (var i = 0; i < this._columns.length; ++i) { | |
731 var columnElement = listItemColumnsElement.createChild("div", "list-
column"); | |
732 var columnId = this._columns[i]; | |
733 listItem.columnElements[columnId] = columnElement; | |
734 this._itemRenderer(columnElement, columnId, itemId); | |
735 } | |
736 var removeItemButton = this._createRemoveButton(removeItemClicked.bind(t
his)); | |
737 listItemContents.addEventListener("click", this.selectItem.bind(this, it
emId), false); | |
738 listItemContents.addEventListener("dblclick", this._onDoubleClick.bind(t
his, itemId), false); | |
739 listItemContents.appendChild(removeItemButton); | |
740 | |
741 this._listItems[itemId] = listItem; | |
742 if (typeof beforeId !== undefined) | |
743 this._ids.splice(this._ids.indexOf(beforeId), 0, itemId); | |
744 else | |
745 this._ids.push(itemId); | |
746 | |
747 /** | |
748 * @param {?Event} event | |
749 * @this {WebInspector.SettingsList} | |
750 */ | |
751 function removeItemClicked(event) | |
752 { | |
753 removeItemButton.disabled = true; | |
754 this.removeItem(itemId); | |
755 this.dispatchEventToListeners(WebInspector.SettingsList.Events.Remov
ed, itemId); | |
756 event.consume(); | |
757 } | |
758 | |
759 return listItem; | |
760 }, | |
761 | |
762 /** | |
763 * @param {?string} id | |
764 */ | |
765 removeItem: function(id) | |
766 { | |
767 this._listItems[id].remove(); | |
768 delete this._listItems[id]; | |
769 this._ids.remove(id); | |
770 if (id === this._selectedId) { | |
771 delete this._selectedId; | |
772 if (this._ids.length) | |
773 this.selectItem(this._ids[0]); | |
774 } | |
775 }, | |
776 | |
777 /** | |
778 * @return {!Array.<?string>} | |
779 */ | |
780 itemIds: function() | |
781 { | |
782 return this._ids.slice(); | |
783 }, | |
784 | |
785 /** | |
786 * @return {!Array.<string>} | |
787 */ | |
788 columns: function() | |
789 { | |
790 return this._columns.slice(); | |
791 }, | |
792 | |
793 /** | |
794 * @return {?string} | |
795 */ | |
796 selectedId: function() | |
797 { | |
798 return this._selectedId; | |
799 }, | |
800 | |
801 /** | |
802 * @return {!Element} | |
803 */ | |
804 selectedItem: function() | |
805 { | |
806 return this._selectedId ? this._listItems[this._selectedId] : null; | |
807 }, | |
808 | |
809 /** | |
810 * @param {string} itemId | |
811 * @return {!Element} | |
812 */ | |
813 itemForId: function(itemId) | |
814 { | |
815 return this._listItems[itemId]; | |
816 }, | |
817 | |
818 /** | |
819 * @param {?string} id | |
820 * @param {!Event=} event | |
821 */ | |
822 _onDoubleClick: function(id, event) | |
823 { | |
824 this.dispatchEventToListeners(WebInspector.SettingsList.Events.DoubleCli
cked, id); | |
825 }, | |
826 | |
827 /** | |
828 * @param {?string} id | |
829 * @param {!Event=} event | |
830 */ | |
831 selectItem: function(id, event) | |
832 { | |
833 if (typeof this._selectedId !== "undefined") { | |
834 this._listItems[this._selectedId].classList.remove("selected"); | |
835 } | |
836 | |
837 this._selectedId = id; | |
838 if (typeof this._selectedId !== "undefined") { | |
839 this._listItems[this._selectedId].classList.add("selected"); | |
840 } | |
841 this.dispatchEventToListeners(WebInspector.SettingsList.Events.Selected,
id); | |
842 if (event) | |
843 event.consume(); | |
844 }, | |
845 | |
846 /** | |
847 * @param {function(?Event)} handler | |
848 * @return {!Element} | |
849 */ | |
850 _createRemoveButton: function(handler) | |
851 { | |
852 var removeButton = document.createElement("button"); | |
853 removeButton.classList.add("remove-item-button"); | |
854 removeButton.value = WebInspector.UIString("Remove"); | |
855 removeButton.addEventListener("click", handler, false); | |
856 return removeButton; | |
857 }, | |
858 | |
859 __proto__: WebInspector.Object.prototype | |
860 } | |
861 | |
862 /** | |
863 * @constructor | |
864 * @extends {WebInspector.SettingsList} | |
865 * @param {!Array.<string>} columns | |
866 * @param {function(string, string):string} valuesProvider | |
867 * @param {function(?string, !Object)} validateHandler | |
868 * @param {function(?string, !Object)} editHandler | |
869 */ | |
870 WebInspector.EditableSettingsList = function(columns, valuesProvider, validateHa
ndler, editHandler) | |
871 { | |
872 WebInspector.SettingsList.call(this, columns, this._renderColumn.bind(this))
; | |
873 this._validateHandler = validateHandler; | |
874 this._editHandler = editHandler; | |
875 this._valuesProvider = valuesProvider; | |
876 /** @type {!Object.<string, !HTMLInputElement>} */ | |
877 this._addInputElements = {}; | |
878 /** @type {!Object.<string, !Object.<string, !HTMLInputElement>>} */ | |
879 this._editInputElements = {}; | |
880 /** @type {!Object.<string, !Object.<string, !HTMLSpanElement>>} */ | |
881 this._textElements = {}; | |
882 | |
883 this._addMappingItem = this.addItem(null); | |
884 this._addMappingItem.classList.add("item-editing"); | |
885 this._addMappingItem.classList.add("add-list-item"); | |
886 } | |
887 | |
888 WebInspector.EditableSettingsList.prototype = { | |
889 /** | |
890 * @param {?string} itemId | |
891 * @param {?string=} beforeId | |
892 * @return {!Element} | |
893 */ | |
894 addItem: function(itemId, beforeId) | |
895 { | |
896 var listItem = WebInspector.SettingsList.prototype.addItem.call(this, it
emId, beforeId); | |
897 listItem.classList.add("editable"); | |
898 return listItem; | |
899 }, | |
900 | |
901 /** | |
902 * @param {!Element} columnElement | |
903 * @param {string} columnId | |
904 * @param {?string} itemId | |
905 */ | |
906 _renderColumn: function(columnElement, columnId, itemId) | |
907 { | |
908 columnElement.classList.add("settings-list-column-" + columnId); | |
909 var placeholder = (columnId === "url") ? WebInspector.UIString("URL pref
ix") : WebInspector.UIString("Folder path"); | |
910 if (itemId === null) { | |
911 var inputElement = columnElement.createChild("input", "list-column-e
ditor"); | |
912 inputElement.placeholder = placeholder; | |
913 inputElement.addEventListener("blur", this._onAddMappingInputBlur.bi
nd(this)); | |
914 inputElement.addEventListener("input", this._validateEdit.bind(this,
itemId)); | |
915 this._addInputElements[columnId] = inputElement; | |
916 return; | |
917 } | |
918 var validItemId = itemId; | |
919 | |
920 if (!this._editInputElements[itemId]) | |
921 this._editInputElements[itemId] = {}; | |
922 if (!this._textElements[itemId]) | |
923 this._textElements[itemId] = {}; | |
924 | |
925 var value = this._valuesProvider(itemId, columnId); | |
926 | |
927 var textElement = columnElement.createChild("span", "list-column-text"); | |
928 textElement.textContent = value; | |
929 textElement.title = value; | |
930 columnElement.addEventListener("click", rowClicked.bind(this), false); | |
931 this._textElements[itemId][columnId] = textElement; | |
932 | |
933 var inputElement = columnElement.createChild("input", "list-column-edito
r"); | |
934 inputElement.value = value; | |
935 inputElement.addEventListener("blur", this._editMappingBlur.bind(this, i
temId)); | |
936 inputElement.addEventListener("input", this._validateEdit.bind(this, ite
mId)); | |
937 columnElement.inputElement = inputElement; | |
938 this._editInputElements[itemId][columnId] = inputElement; | |
939 | |
940 /** | |
941 * @param {?Event} event | |
942 * @this {WebInspector.EditableSettingsList} | |
943 */ | |
944 function rowClicked(event) | |
945 { | |
946 if (itemId === this._editingId) | |
947 return; | |
948 event.consume(); | |
949 console.assert(!this._editingId); | |
950 this._editingId = validItemId; | |
951 var listItem = this.itemForId(validItemId); | |
952 listItem.classList.add("item-editing"); | |
953 var inputElement = event.target.inputElement || this._editInputEleme
nts[validItemId][this.columns()[0]]; | |
954 inputElement.focus(); | |
955 inputElement.select(); | |
956 } | |
957 }, | |
958 | |
959 /** | |
960 * @param {?string} itemId | |
961 * @return {!Object} | |
962 */ | |
963 _data: function(itemId) | |
964 { | |
965 var inputElements = this._inputElements(itemId); | |
966 var data = {}; | |
967 var columns = this.columns(); | |
968 for (var i = 0; i < columns.length; ++i) | |
969 data[columns[i]] = inputElements[columns[i]].value; | |
970 return data; | |
971 }, | |
972 | |
973 /** | |
974 * @param {?string} itemId | |
975 * @return {?Object.<string, !HTMLInputElement>} | |
976 */ | |
977 _inputElements: function(itemId) | |
978 { | |
979 if (!itemId) | |
980 return this._addInputElements; | |
981 return this._editInputElements[itemId] || null; | |
982 }, | |
983 | |
984 /** | |
985 * @param {?string} itemId | |
986 * @return {boolean} | |
987 */ | |
988 _validateEdit: function(itemId) | |
989 { | |
990 var errorColumns = this._validateHandler(itemId, this._data(itemId)); | |
991 var hasChanges = this._hasChanges(itemId); | |
992 var columns = this.columns(); | |
993 for (var i = 0; i < columns.length; ++i) { | |
994 var columnId = columns[i]; | |
995 var inputElement = this._inputElements(itemId)[columnId]; | |
996 if (hasChanges && errorColumns.indexOf(columnId) !== -1) | |
997 inputElement.classList.add("editable-item-error"); | |
998 else | |
999 inputElement.classList.remove("editable-item-error"); | |
1000 } | |
1001 return !errorColumns.length; | |
1002 }, | |
1003 | |
1004 /** | |
1005 * @param {?string} itemId | |
1006 * @return {boolean} | |
1007 */ | |
1008 _hasChanges: function(itemId) | |
1009 { | |
1010 var hasChanges = false; | |
1011 var columns = this.columns(); | |
1012 for (var i = 0; i < columns.length; ++i) { | |
1013 var columnId = columns[i]; | |
1014 var oldValue = itemId ? this._textElements[itemId][columnId].textCon
tent : ""; | |
1015 var newValue = this._inputElements(itemId)[columnId].value; | |
1016 if (oldValue !== newValue) { | |
1017 hasChanges = true; | |
1018 break; | |
1019 } | |
1020 } | |
1021 return hasChanges; | |
1022 }, | |
1023 | |
1024 /** | |
1025 * @param {string} itemId | |
1026 * @param {!Event} event | |
1027 */ | |
1028 _editMappingBlur: function(itemId, event) | |
1029 { | |
1030 var inputElements = Object.values(this._editInputElements[itemId]); | |
1031 if (inputElements.indexOf(event.relatedTarget) !== -1) | |
1032 return; | |
1033 | |
1034 var listItem = this.itemForId(itemId); | |
1035 listItem.classList.remove("item-editing"); | |
1036 delete this._editingId; | |
1037 | |
1038 if (!this._hasChanges(itemId)) | |
1039 return; | |
1040 | |
1041 if (!this._validateEdit(itemId)) { | |
1042 var columns = this.columns(); | |
1043 for (var i = 0; i < columns.length; ++i) { | |
1044 var columnId = columns[i]; | |
1045 var inputElement = this._editInputElements[itemId][columnId]; | |
1046 inputElement.value = this._textElements[itemId][columnId].textCo
ntent; | |
1047 inputElement.classList.remove("editable-item-error"); | |
1048 } | |
1049 return; | |
1050 } | |
1051 this._editHandler(itemId, this._data(itemId)); | |
1052 }, | |
1053 | |
1054 _onAddMappingInputBlur: function(event) | |
1055 { | |
1056 var inputElements = Object.values(this._addInputElements); | |
1057 if (inputElements.indexOf(event.relatedTarget) !== -1) | |
1058 return; | |
1059 | |
1060 if (!this._hasChanges(null)) | |
1061 return; | |
1062 | |
1063 if (!this._validateEdit(null)) | |
1064 return; | |
1065 | |
1066 this._editHandler(null, this._data(null)); | |
1067 var columns = this.columns(); | |
1068 for (var i = 0; i < columns.length; ++i) { | |
1069 var columnId = columns[i]; | |
1070 var inputElement = this._addInputElements[columnId]; | |
1071 inputElement.value = ""; | |
1072 } | |
1073 }, | |
1074 | |
1075 __proto__: WebInspector.SettingsList.prototype | |
1076 } | |
1077 | |
1078 /** @type {!WebInspector.SettingsController} */ | |
1079 WebInspector.settingsController; | |
OLD | NEW |