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 = /** @type {!Set.<!WebInspector.ModuleManager.Extens
ion>} */ (extensionsBySectionId.get(explicitSectionOrder[i])); | |
260 if (!extensions) | |
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], /** @ty
pe {!Set.<!WebInspector.ModuleManager.Extension>} */ (extensionsBySectionId.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 = /** @type {!Set.<!WebInspector.ModuleManager
.Extension>|undefined} */ (childSettingExtensionsByParentName.get(settingName)); | |
309 if (childSettings) { | |
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 {function(!Element, string, ?string)} itemRenderer | |
691 */ | |
692 WebInspector.SettingsList = function(columns, itemRenderer) | |
693 { | |
694 this.element = document.createElement("div"); | |
695 this.element.classList.add("settings-list"); | |
696 this.element.tabIndex = -1; | |
697 this._itemRenderer = itemRenderer; | |
698 this._listItems = {}; | |
699 this._ids = []; | |
700 this._columns = columns; | |
701 } | |
702 | |
703 WebInspector.SettingsList.Events = { | |
704 Selected: "Selected", | |
705 Removed: "Removed", | |
706 DoubleClicked: "DoubleClicked", | |
707 } | |
708 | |
709 WebInspector.SettingsList.prototype = { | |
710 /** | |
711 * @param {?string} itemId | |
712 * @param {?string=} beforeId | |
713 * @return {!Element} | |
714 */ | |
715 addItem: function(itemId, beforeId) | |
716 { | |
717 var listItem = document.createElement("div"); | |
718 listItem._id = itemId; | |
719 listItem.classList.add("settings-list-item"); | |
720 if (typeof beforeId !== undefined) | |
721 this.element.insertBefore(listItem, this._listItems[beforeId]); | |
722 else | |
723 this.element.appendChild(listItem); | |
724 | |
725 var listItemContents = listItem.createChild("div", "settings-list-item-c
ontents"); | |
726 var listItemColumnsElement = listItemContents.createChild("div", "settin
gs-list-item-columns"); | |
727 | |
728 listItem.columnElements = {}; | |
729 for (var i = 0; i < this._columns.length; ++i) { | |
730 var columnElement = listItemColumnsElement.createChild("div", "list-
column"); | |
731 var columnId = this._columns[i]; | |
732 listItem.columnElements[columnId] = columnElement; | |
733 this._itemRenderer(columnElement, columnId, itemId); | |
734 } | |
735 var removeItemButton = this._createRemoveButton(removeItemClicked.bind(t
his)); | |
736 listItemContents.addEventListener("click", this.selectItem.bind(this, it
emId), false); | |
737 listItemContents.addEventListener("dblclick", this._onDoubleClick.bind(t
his, itemId), false); | |
738 listItemContents.appendChild(removeItemButton); | |
739 | |
740 this._listItems[itemId] = listItem; | |
741 if (typeof beforeId !== undefined) | |
742 this._ids.splice(this._ids.indexOf(beforeId), 0, itemId); | |
743 else | |
744 this._ids.push(itemId); | |
745 | |
746 /** | |
747 * @param {?Event} event | |
748 * @this {WebInspector.SettingsList} | |
749 */ | |
750 function removeItemClicked(event) | |
751 { | |
752 removeItemButton.disabled = true; | |
753 this.removeItem(itemId); | |
754 this.dispatchEventToListeners(WebInspector.SettingsList.Events.Remov
ed, itemId); | |
755 event.consume(); | |
756 } | |
757 | |
758 return listItem; | |
759 }, | |
760 | |
761 /** | |
762 * @param {?string} id | |
763 */ | |
764 removeItem: function(id) | |
765 { | |
766 this._listItems[id].remove(); | |
767 delete this._listItems[id]; | |
768 this._ids.remove(id); | |
769 if (id === this._selectedId) { | |
770 delete this._selectedId; | |
771 if (this._ids.length) | |
772 this.selectItem(this._ids[0]); | |
773 } | |
774 }, | |
775 | |
776 /** | |
777 * @return {!Array.<?string>} | |
778 */ | |
779 itemIds: function() | |
780 { | |
781 return this._ids.slice(); | |
782 }, | |
783 | |
784 /** | |
785 * @return {!Array.<string>} | |
786 */ | |
787 columns: function() | |
788 { | |
789 return this._columns.slice(); | |
790 }, | |
791 | |
792 /** | |
793 * @return {?string} | |
794 */ | |
795 selectedId: function() | |
796 { | |
797 return this._selectedId; | |
798 }, | |
799 | |
800 /** | |
801 * @return {!Element} | |
802 */ | |
803 selectedItem: function() | |
804 { | |
805 return this._selectedId ? this._listItems[this._selectedId] : null; | |
806 }, | |
807 | |
808 /** | |
809 * @param {string} itemId | |
810 * @return {!Element} | |
811 */ | |
812 itemForId: function(itemId) | |
813 { | |
814 return this._listItems[itemId]; | |
815 }, | |
816 | |
817 /** | |
818 * @param {?string} id | |
819 * @param {!Event=} event | |
820 */ | |
821 _onDoubleClick: function(id, event) | |
822 { | |
823 this.dispatchEventToListeners(WebInspector.SettingsList.Events.DoubleCli
cked, id); | |
824 }, | |
825 | |
826 /** | |
827 * @param {?string} id | |
828 * @param {!Event=} event | |
829 */ | |
830 selectItem: function(id, event) | |
831 { | |
832 if (typeof this._selectedId !== "undefined") { | |
833 this._listItems[this._selectedId].classList.remove("selected"); | |
834 } | |
835 | |
836 this._selectedId = id; | |
837 if (typeof this._selectedId !== "undefined") { | |
838 this._listItems[this._selectedId].classList.add("selected"); | |
839 } | |
840 this.dispatchEventToListeners(WebInspector.SettingsList.Events.Selected,
id); | |
841 if (event) | |
842 event.consume(); | |
843 }, | |
844 | |
845 /** | |
846 * @param {function(?Event)} handler | |
847 * @return {!Element} | |
848 */ | |
849 _createRemoveButton: function(handler) | |
850 { | |
851 var removeButton = document.createElement("button"); | |
852 removeButton.classList.add("remove-item-button"); | |
853 removeButton.value = WebInspector.UIString("Remove"); | |
854 removeButton.addEventListener("click", handler, false); | |
855 return removeButton; | |
856 }, | |
857 | |
858 __proto__: WebInspector.Object.prototype | |
859 } | |
860 | |
861 /** | |
862 * @constructor | |
863 * @extends {WebInspector.SettingsList} | |
864 * @param {function(?string, !Object)} validateHandler | |
865 * @param {function(?string, !Object)} editHandler | |
866 */ | |
867 WebInspector.EditableSettingsList = function(columns, valuesProvider, validateHa
ndler, editHandler) | |
868 { | |
869 WebInspector.SettingsList.call(this, columns, this._renderColumn.bind(this))
; | |
870 this._validateHandler = validateHandler; | |
871 this._editHandler = editHandler; | |
872 this._valuesProvider = valuesProvider; | |
873 /** @type {!Object.<string, !HTMLInputElement>} */ | |
874 this._addInputElements = {}; | |
875 /** @type {!Object.<string, !Object.<string, !HTMLInputElement>>} */ | |
876 this._editInputElements = {}; | |
877 /** @type {!Object.<string, !Object.<string, !HTMLSpanElement>>} */ | |
878 this._textElements = {}; | |
879 | |
880 this._addMappingItem = this.addItem(null); | |
881 this._addMappingItem.classList.add("item-editing"); | |
882 this._addMappingItem.classList.add("add-list-item"); | |
883 } | |
884 | |
885 WebInspector.EditableSettingsList.prototype = { | |
886 /** | |
887 * @param {?string} itemId | |
888 * @param {?string=} beforeId | |
889 * @return {!Element} | |
890 */ | |
891 addItem: function(itemId, beforeId) | |
892 { | |
893 var listItem = WebInspector.SettingsList.prototype.addItem.call(this, it
emId, beforeId); | |
894 listItem.classList.add("editable"); | |
895 return listItem; | |
896 }, | |
897 | |
898 /** | |
899 * @param {!Element} columnElement | |
900 * @param {string} columnId | |
901 * @param {?string} itemId | |
902 */ | |
903 _renderColumn: function(columnElement, columnId, itemId) | |
904 { | |
905 columnElement.classList.add("settings-list-column-" + columnId); | |
906 var placeholder = (columnId === "url") ? WebInspector.UIString("URL pref
ix") : WebInspector.UIString("Folder path"); | |
907 if (itemId === null) { | |
908 var inputElement = columnElement.createChild("input", "list-column-e
ditor"); | |
909 inputElement.placeholder = placeholder; | |
910 inputElement.addEventListener("blur", this._onAddMappingInputBlur.bi
nd(this)); | |
911 inputElement.addEventListener("input", this._validateEdit.bind(this,
itemId)); | |
912 this._addInputElements[columnId] = inputElement; | |
913 return; | |
914 } | |
915 var validItemId = itemId; | |
916 | |
917 if (!this._editInputElements[itemId]) | |
918 this._editInputElements[itemId] = {}; | |
919 if (!this._textElements[itemId]) | |
920 this._textElements[itemId] = {}; | |
921 | |
922 var value = this._valuesProvider(itemId, columnId); | |
923 | |
924 var textElement = columnElement.createChild("span", "list-column-text"); | |
925 textElement.textContent = value; | |
926 textElement.title = value; | |
927 columnElement.addEventListener("click", rowClicked.bind(this), false); | |
928 this._textElements[itemId][columnId] = textElement; | |
929 | |
930 var inputElement = columnElement.createChild("input", "list-column-edito
r"); | |
931 inputElement.value = value; | |
932 inputElement.addEventListener("blur", this._editMappingBlur.bind(this, i
temId)); | |
933 inputElement.addEventListener("input", this._validateEdit.bind(this, ite
mId)); | |
934 columnElement.inputElement = inputElement; | |
935 this._editInputElements[itemId][columnId] = inputElement; | |
936 | |
937 /** | |
938 * @param {?Event} event | |
939 * @this {WebInspector.EditableSettingsList} | |
940 */ | |
941 function rowClicked(event) | |
942 { | |
943 if (itemId === this._editingId) | |
944 return; | |
945 event.consume(); | |
946 console.assert(!this._editingId); | |
947 this._editingId = validItemId; | |
948 var listItem = this.itemForId(validItemId); | |
949 listItem.classList.add("item-editing"); | |
950 var inputElement = event.target.inputElement || this._editInputEleme
nts[validItemId][this.columns()[0]]; | |
951 inputElement.focus(); | |
952 inputElement.select(); | |
953 } | |
954 }, | |
955 | |
956 /** | |
957 * @param {?string} itemId | |
958 * @return {!Object} | |
959 */ | |
960 _data: function(itemId) | |
961 { | |
962 var inputElements = this._inputElements(itemId); | |
963 var data = {}; | |
964 var columns = this.columns(); | |
965 for (var i = 0; i < columns.length; ++i) | |
966 data[columns[i]] = inputElements[columns[i]].value; | |
967 return data; | |
968 }, | |
969 | |
970 /** | |
971 * @param {?string} itemId | |
972 * @return {?Object.<string, !HTMLInputElement>} | |
973 */ | |
974 _inputElements: function(itemId) | |
975 { | |
976 if (!itemId) | |
977 return this._addInputElements; | |
978 return this._editInputElements[itemId] || null; | |
979 }, | |
980 | |
981 /** | |
982 * @param {?string} itemId | |
983 * @return {boolean} | |
984 */ | |
985 _validateEdit: function(itemId) | |
986 { | |
987 var errorColumns = this._validateHandler(itemId, this._data(itemId)); | |
988 var hasChanges = this._hasChanges(itemId); | |
989 var columns = this.columns(); | |
990 for (var i = 0; i < columns.length; ++i) { | |
991 var columnId = columns[i]; | |
992 var inputElement = this._inputElements(itemId)[columnId]; | |
993 if (hasChanges && errorColumns.indexOf(columnId) !== -1) | |
994 inputElement.classList.add("editable-item-error"); | |
995 else | |
996 inputElement.classList.remove("editable-item-error"); | |
997 } | |
998 return !errorColumns.length; | |
999 }, | |
1000 | |
1001 /** | |
1002 * @param {?string} itemId | |
1003 * @return {boolean} | |
1004 */ | |
1005 _hasChanges: function(itemId) | |
1006 { | |
1007 var hasChanges = false; | |
1008 var columns = this.columns(); | |
1009 for (var i = 0; i < columns.length; ++i) { | |
1010 var columnId = columns[i]; | |
1011 var oldValue = itemId ? this._textElements[itemId][columnId].textCon
tent : ""; | |
1012 var newValue = this._inputElements(itemId)[columnId].value; | |
1013 if (oldValue !== newValue) { | |
1014 hasChanges = true; | |
1015 break; | |
1016 } | |
1017 } | |
1018 return hasChanges; | |
1019 }, | |
1020 | |
1021 /** | |
1022 * @param {string} itemId | |
1023 */ | |
1024 _editMappingBlur: function(itemId, event) | |
1025 { | |
1026 var inputElements = Object.values(this._editInputElements[itemId]); | |
1027 if (inputElements.indexOf(event.relatedTarget) !== -1) | |
1028 return; | |
1029 | |
1030 var listItem = this.itemForId(itemId); | |
1031 listItem.classList.remove("item-editing"); | |
1032 delete this._editingId; | |
1033 | |
1034 if (!this._hasChanges(itemId)) | |
1035 return; | |
1036 | |
1037 if (!this._validateEdit(itemId)) { | |
1038 var columns = this.columns(); | |
1039 for (var i = 0; i < columns.length; ++i) { | |
1040 var columnId = columns[i]; | |
1041 var inputElement = this._editInputElements[itemId][columnId]; | |
1042 inputElement.value = this._textElements[itemId][columnId].textCo
ntent; | |
1043 inputElement.classList.remove("editable-item-error"); | |
1044 } | |
1045 return; | |
1046 } | |
1047 this._editHandler(itemId, this._data(itemId)); | |
1048 }, | |
1049 | |
1050 _onAddMappingInputBlur: function(event) | |
1051 { | |
1052 var inputElements = Object.values(this._addInputElements); | |
1053 if (inputElements.indexOf(event.relatedTarget) !== -1) | |
1054 return; | |
1055 | |
1056 if (!this._hasChanges(null)) | |
1057 return; | |
1058 | |
1059 if (!this._validateEdit(null)) | |
1060 return; | |
1061 | |
1062 this._editHandler(null, this._data(null)); | |
1063 var columns = this.columns(); | |
1064 for (var i = 0; i < columns.length; ++i) { | |
1065 var columnId = columns[i]; | |
1066 var inputElement = this._addInputElements[columnId]; | |
1067 inputElement.value = ""; | |
1068 } | |
1069 }, | |
1070 | |
1071 __proto__: WebInspector.SettingsList.prototype | |
1072 } | |
1073 | |
1074 /** @type {!WebInspector.SettingsController} */ | |
1075 WebInspector.settingsController; | |
OLD | NEW |