Web Inspector: Preferences for Text Editor behavior
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 29 Oct 2016 01:17:43 +0000 (01:17 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 29 Oct 2016 01:17:43 +0000 (01:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149120

Patch by Devin Rousso <dcrousso+webkit@gmail.com> on 2016-10-28
Reviewed by Timothy Hatcher.

* Localizations/en.lproj/localizedStrings.js:

* UserInterface/Base/Main.js:
(WebInspector.loaded):
(WebInspector.contentLoaded):
(WebInspector.contentLoaded.setTabSize):
(WebInspector.contentLoaded.setInvalidCharacterClassName):
(WebInspector.contentLoaded.setWhitespaceCharacterClassName):
(WebInspector._tryToRestorePendingTabs):
(WebInspector.indentString):
(WebInspector._updateNewTabButtonState): Deleted.
(WebInspector._newTabItemClicked): Deleted.
Removed calls to the New Tab tab bar item on the Tab Bar instance.
Added listener to the indentUnit setting to change the tab-size value on <body>.
Created helper function to generate the indentString value from settings.

* UserInterface/Base/Test.js:
(WebInspector.indentString):
Assume indent string is "    " for tests.

* UserInterface/Base/Setting.js:
Added global WebInspector.settings dictionary for holding settings with UI editors.

* UserInterface/Main.html:
Added GeneralTabBarItem, PinnedTabBarItem, and SettingsTabContentView.

* UserInterface/Models/CSSStyleDeclaration.js:
(WebInspector.CSSStyleDeclaration.prototype.generateCSSRuleString):
* UserInterface/Views/CSSStyleDeclarationTextEditor.js:
(WebInspector.CSSStyleDeclarationTextEditor.prototype._formattedContentFromEditor):
(WebInspector.CSSStyleDeclarationTextEditor.prototype._resetContent.update):
* UserInterface/Views/VisualStylePropertyEditor.js:
(WebInspector.VisualStylePropertyEditor.generateFormattedTextForNewProperty):
* UserInterface/Views/SourceCodeTextEditor.js:
(WebInspector.SourceCodeTextEditor.prototype._showPopoverForFunction.didGetDetails):
Now uses WebInspector.indentUnit for indentation values

* UserInterface/Views/CodeMirrorAdditions.js:
Added "showWhitespaceCharacter" option to CodeMirror.  When enabled, it adds an overlay to
the editor that will use pseudo-elements to display whitespace characters (unicode 00B7).

* UserInterface/Views/CodeMirrorOverrides.css:
(.CodeMirror .cm-tab):
(.show-whitespace-characters .CodeMirror .cm-tab::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-1::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-2::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-3::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-4::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-5::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-6::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-7::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-8::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-9::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-10::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-11::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-12::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-13::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-14::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-15::before):
(.show-whitespace-characters .CodeMirror .cm-whitespace-16::before):
(.show-invalid-characters .CodeMirror .cm-invalidchar):
(.CodeMirror .cm-invalidchar): Deleted.
Use unicode character 00B7 (middle dot) to display a space.  Also uses a grey border for
visualizing tab characters.

* UserInterface/Views/ApplicationCacheFrameContentView.js:
* UserInterface/Views/CSSStyleDeclarationTextEditor.js:
* UserInterface/Views/ClusterContentView.js:
* UserInterface/Views/DOMTreeContentView.js:
* UserInterface/Views/DatabaseContentView.js:
* UserInterface/Views/IndexedDatabaseObjectStoreContentView.js:
* UserInterface/Views/NetworkGridContentView.js:
* UserInterface/Views/ResourceContentView.js:
* UserInterface/Views/ScriptContentView.js:
* UserInterface/Views/TabContentView.js:
* UserInterface/Views/TimelineRecordingContentView.js:
Add calls to super.shown(), super.hidden(), and super.closed().

* UserInterface/Views/ConsoleTabContentView.js:
* UserInterface/Views/DebuggerTabContentView.js:
* UserInterface/Views/ElementsTabContentView.js:
* UserInterface/Views/NetworkTabContentView.js:
* UserInterface/Views/NewTabContentView.js:
* UserInterface/Views/ResourcesTabContentView.js:
* UserInterface/Views/SearchTabContentView.js:
* UserInterface/Views/StorageTabContentView.js:
* UserInterface/Views/TimelineTabContentView.js:
Now uses WebInspector.GeneralTabBarItem.

* UserInterface/Views/GeneralTabBarItem.js: Added.
(WebInspector.GeneralTabBarItem):
(WebInspector.GeneralTabBarItem.prototype.set title):
(WebInspector.GeneralTabBarItem.prototype._handleContextMenuEvent):
Split from TabBarItem.js to make pinned tab bar items more distinct.

* UserInterface/Views/Main.css:
(body):
Removed tab-size.

* UserInterface/Views/PinnedTabBarItem.js: Added.
(WebInspector.PinnedTabBarItem):
Split from TabBarItem.js to make pinned tab bar items more distinct.

* UserInterface/Views/SettingsTabContentView.css: Added.
(.content-view.settings):
(.content-view.settings > .header):
(.content-view.settings > .setting-container):
(.content-view.settings > .setting-container > .setting-name):
(.content-view.settings > .setting-container > .setting-value-controller):
(.content-view.settings > .setting-container > .setting-value-controller input[type="number"]):

* UserInterface/Views/SettingsTabContentView.js:
(WebInspector.SettingsTabContentView):
(WebInspector.SettingsTabContentView.tabInfo):
(WebInspector.SettingsTabContentView.isEphemeral):
(WebInspector.SettingsTabContentView.shouldSaveTab):
(WebInspector.SettingsTabContentView.prototype.initialLayout):
(WebInspector.SettingsTabContentView.isTabAllowed): Deleted.
(WebInspector.SettingsTabContentView.prototype.get type): Deleted.
Added logic to display an appropriate editor for each item in WebInspector.settings.

* UserInterface/Views/SourceCodeTextEditor.js:
(WebInspector.SourceCodeTextEditor.prototype.close):
Add call to super.close().

* UserInterface/Views/TabBar.css:
(.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover):
(.tab-bar > .item:not(.pinned) > .flex-space:last-child):
(.tab-bar > .item.pinned > .icon):
(.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover > .icon):
(.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover,): Deleted.
(.tab-bar > .item > .flex-space:last-child): Deleted.
(.tab-bar > .item.new-tab-button > .icon): Deleted.
(.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover > .icon,): Deleted.
Removed rules specifically targeting `.new-tab-button`.

* UserInterface/Views/TabBar.js:
(WebInspector.TabBar):
(WebInspector.TabBar.prototype.get newTabTabBarItem):
(WebInspector.TabBar.prototype.updateNewTabTabBarItemState):
(WebInspector.TabBar.prototype.insertTabBarItem):
(WebInspector.TabBar.prototype.removeTabBarItem.animateTabs):
(WebInspector.TabBar.prototype.removeTabBarItem):
(WebInspector.TabBar.prototype.selectPreviousTab):
(WebInspector.TabBar.prototype.selectNextTab):
(WebInspector.TabBar.prototype.set selectedTabBarItem):
(WebInspector.TabBar.prototype.hasNormalTab):
(WebInspector.TabBar.prototype.layout):
(WebInspector.TabBar.prototype._hasMoreThanOneNormalTab):
(WebInspector.TabBar.prototype._handleMouseDown):
(WebInspector.TabBar.prototype._handleMouseMoved):
(WebInspector.TabBar.prototype._handleMouseLeave):
(WebInspector.TabBar.prototype._handleNewTabClick):
(WebInspector.TabBar.prototype._handleNewTabMouseEnter):
(WebInspector.TabBar.prototype.get newTabItem): Deleted.
(WebInspector.TabBar.prototype.set newTabItem): Deleted.
Replaced the newTabItem setter by adding a saved pinned tab bar item (instead of relying
upon a different object to give it the pinned tab bar item) that changes modes depending on
whether a new tab is able to be created.

* UserInterface/Views/TabBarItem.js:
(WebInspector.TabBarItem):
(WebInspector.TabBarItem.prototype.get element):
(WebInspector.TabBarItem.prototype.get representedObject):
(WebInspector.TabBarItem.prototype.set representedObject):
(WebInspector.TabBarItem.prototype.get parentTabBar):
(WebInspector.TabBarItem.prototype.set parentTabBar):
(WebInspector.TabBarItem.prototype.get image):
(WebInspector.TabBarItem.prototype.set image):
(WebInspector.TabBarItem.prototype.get title):
(WebInspector.TabBarItem.prototype.set title):
(WebInspector.TabBarItem.prototype.get pinned): Deleted.
(WebInspector.TabBarItem.prototype._handleContextMenuEvent): Deleted.
Split into GeneralTabBarItem and PinnedTabBarItem to simplify the logic of the DOM and allow
for easier checking of whether a tab bar item is pinned or not.

* UserInterface/Views/TabBrowser.js:
(WebInspector.TabBrowser):
(WebInspector.TabBrowser.prototype.addTabForContentView):
(WebInspector.TabBrowser.prototype.closeTabForContentView):
(WebInspector.TabBrowser.prototype._tabBarItemSelected):
(WebInspector.TabBrowser.prototype._tabBarItemRemoved):
Replaced references to newTabItem with a set number (since each TabBar has a specific number
of pinned tabs).

* UserInterface/Views/TextEditor.js:
(WebInspector.TextEditor):
(WebInspector.TextEditor.prototype.close):.
Remove settings update event listeners to allow garbage collection.

(WebInspector.TextEditor.prototype._startWorkerPrettyPrint):
(WebInspector.TextEditor.prototype._startCodeMirrorPrettyPrint):
Now uses the settings values in WebInspector.setting for settings on the CodeMirror
instance.  Also updates the CodeMirror instance if any setting changes.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208091 268f45cc-cd09-0410-ab3c-d52691b4dbfc

41 files changed:
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Base/Main.js
Source/WebInspectorUI/UserInterface/Base/Setting.js
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js
Source/WebInspectorUI/UserInterface/Test/Test.js
Source/WebInspectorUI/UserInterface/Views/ApplicationCacheFrameContentView.js
Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.js
Source/WebInspectorUI/UserInterface/Views/ClusterContentView.js
Source/WebInspectorUI/UserInterface/Views/CodeMirrorAdditions.js
Source/WebInspectorUI/UserInterface/Views/CodeMirrorOverrides.css
Source/WebInspectorUI/UserInterface/Views/ConsoleTabContentView.js
Source/WebInspectorUI/UserInterface/Views/DOMTreeContentView.js
Source/WebInspectorUI/UserInterface/Views/DatabaseContentView.js
Source/WebInspectorUI/UserInterface/Views/DebuggerTabContentView.js
Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js
Source/WebInspectorUI/UserInterface/Views/GeneralTabBarItem.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/IndexedDatabaseObjectStoreContentView.js
Source/WebInspectorUI/UserInterface/Views/Main.css
Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js
Source/WebInspectorUI/UserInterface/Views/NetworkTabContentView.js
Source/WebInspectorUI/UserInterface/Views/NewTabContentView.js
Source/WebInspectorUI/UserInterface/Views/PinnedTabBarItem.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/ResourceContentView.js
Source/WebInspectorUI/UserInterface/Views/ResourcesTabContentView.js
Source/WebInspectorUI/UserInterface/Views/ScriptContentView.js
Source/WebInspectorUI/UserInterface/Views/SearchTabContentView.js
Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.css [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js
Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js
Source/WebInspectorUI/UserInterface/Views/StorageTabContentView.js
Source/WebInspectorUI/UserInterface/Views/TabBar.css
Source/WebInspectorUI/UserInterface/Views/TabBar.js
Source/WebInspectorUI/UserInterface/Views/TabBarItem.js
Source/WebInspectorUI/UserInterface/Views/TabBrowser.js
Source/WebInspectorUI/UserInterface/Views/TabContentView.js
Source/WebInspectorUI/UserInterface/Views/TextEditor.js
Source/WebInspectorUI/UserInterface/Views/TimelineRecordingContentView.js
Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js
Source/WebInspectorUI/UserInterface/Views/VisualStylePropertyEditor.js

index 70a8e8d..2e41b27 100644 (file)
@@ -1,3 +1,206 @@
+2016-10-28  Devin Rousso  <dcrousso+webkit@gmail.com>
+
+        Web Inspector: Preferences for Text Editor behavior
+        https://bugs.webkit.org/show_bug.cgi?id=149120
+
+        Reviewed by Timothy Hatcher.
+
+        * Localizations/en.lproj/localizedStrings.js:
+
+        * UserInterface/Base/Main.js:
+        (WebInspector.loaded):
+        (WebInspector.contentLoaded):
+        (WebInspector.contentLoaded.setTabSize):
+        (WebInspector.contentLoaded.setInvalidCharacterClassName):
+        (WebInspector.contentLoaded.setWhitespaceCharacterClassName):
+        (WebInspector._tryToRestorePendingTabs):
+        (WebInspector.indentString):
+        (WebInspector._updateNewTabButtonState): Deleted.
+        (WebInspector._newTabItemClicked): Deleted.
+        Removed calls to the New Tab tab bar item on the Tab Bar instance.
+        Added listener to the indentUnit setting to change the tab-size value on <body>.
+        Created helper function to generate the indentString value from settings.
+
+        * UserInterface/Base/Test.js:
+        (WebInspector.indentString):
+        Assume indent string is "    " for tests.
+
+        * UserInterface/Base/Setting.js:
+        Added global WebInspector.settings dictionary for holding settings with UI editors.
+
+        * UserInterface/Main.html:
+        Added GeneralTabBarItem, PinnedTabBarItem, and SettingsTabContentView.
+
+        * UserInterface/Models/CSSStyleDeclaration.js:
+        (WebInspector.CSSStyleDeclaration.prototype.generateCSSRuleString):
+        * UserInterface/Views/CSSStyleDeclarationTextEditor.js:
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._formattedContentFromEditor):
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._resetContent.update):
+        * UserInterface/Views/VisualStylePropertyEditor.js:
+        (WebInspector.VisualStylePropertyEditor.generateFormattedTextForNewProperty):
+        * UserInterface/Views/SourceCodeTextEditor.js:
+        (WebInspector.SourceCodeTextEditor.prototype._showPopoverForFunction.didGetDetails):
+        Now uses WebInspector.indentUnit for indentation values
+
+        * UserInterface/Views/CodeMirrorAdditions.js:
+        Added "showWhitespaceCharacter" option to CodeMirror.  When enabled, it adds an overlay to
+        the editor that will use pseudo-elements to display whitespace characters (unicode 00B7).
+
+        * UserInterface/Views/CodeMirrorOverrides.css:
+        (.CodeMirror .cm-tab):
+        (.show-whitespace-characters .CodeMirror .cm-tab::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-1::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-2::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-3::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-4::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-5::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-6::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-7::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-8::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-9::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-10::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-11::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-12::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-13::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-14::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-15::before):
+        (.show-whitespace-characters .CodeMirror .cm-whitespace-16::before):
+        (.show-invalid-characters .CodeMirror .cm-invalidchar):
+        (.CodeMirror .cm-invalidchar): Deleted.
+        Use unicode character 00B7 (middle dot) to display a space.  Also uses a grey border for
+        visualizing tab characters.
+
+        * UserInterface/Views/ApplicationCacheFrameContentView.js:
+        * UserInterface/Views/CSSStyleDeclarationTextEditor.js:
+        * UserInterface/Views/ClusterContentView.js:
+        * UserInterface/Views/DOMTreeContentView.js:
+        * UserInterface/Views/DatabaseContentView.js:
+        * UserInterface/Views/IndexedDatabaseObjectStoreContentView.js:
+        * UserInterface/Views/NetworkGridContentView.js:
+        * UserInterface/Views/ResourceContentView.js:
+        * UserInterface/Views/ScriptContentView.js:
+        * UserInterface/Views/TabContentView.js:
+        * UserInterface/Views/TimelineRecordingContentView.js:
+        Add calls to super.shown(), super.hidden(), and super.closed().
+
+        * UserInterface/Views/ConsoleTabContentView.js:
+        * UserInterface/Views/DebuggerTabContentView.js:
+        * UserInterface/Views/ElementsTabContentView.js:
+        * UserInterface/Views/NetworkTabContentView.js:
+        * UserInterface/Views/NewTabContentView.js:
+        * UserInterface/Views/ResourcesTabContentView.js:
+        * UserInterface/Views/SearchTabContentView.js:
+        * UserInterface/Views/StorageTabContentView.js:
+        * UserInterface/Views/TimelineTabContentView.js:
+        Now uses WebInspector.GeneralTabBarItem.
+
+        * UserInterface/Views/GeneralTabBarItem.js: Added.
+        (WebInspector.GeneralTabBarItem):
+        (WebInspector.GeneralTabBarItem.prototype.set title):
+        (WebInspector.GeneralTabBarItem.prototype._handleContextMenuEvent):
+        Split from TabBarItem.js to make pinned tab bar items more distinct.
+
+        * UserInterface/Views/Main.css:
+        (body):
+        Removed tab-size.
+
+        * UserInterface/Views/PinnedTabBarItem.js: Added.
+        (WebInspector.PinnedTabBarItem):
+        Split from TabBarItem.js to make pinned tab bar items more distinct.
+
+        * UserInterface/Views/SettingsTabContentView.css: Added.
+        (.content-view.settings):
+        (.content-view.settings > .header):
+        (.content-view.settings > .setting-container):
+        (.content-view.settings > .setting-container > .setting-name):
+        (.content-view.settings > .setting-container > .setting-value-controller):
+        (.content-view.settings > .setting-container > .setting-value-controller input[type="number"]):
+
+        * UserInterface/Views/SettingsTabContentView.js:
+        (WebInspector.SettingsTabContentView):
+        (WebInspector.SettingsTabContentView.tabInfo):
+        (WebInspector.SettingsTabContentView.isEphemeral):
+        (WebInspector.SettingsTabContentView.shouldSaveTab):
+        (WebInspector.SettingsTabContentView.prototype.initialLayout):
+        (WebInspector.SettingsTabContentView.isTabAllowed): Deleted.
+        (WebInspector.SettingsTabContentView.prototype.get type): Deleted.
+        Added logic to display an appropriate editor for each item in WebInspector.settings.
+
+        * UserInterface/Views/SourceCodeTextEditor.js:
+        (WebInspector.SourceCodeTextEditor.prototype.close):
+        Add call to super.close().
+
+        * UserInterface/Views/TabBar.css:
+        (.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover):
+        (.tab-bar > .item:not(.pinned) > .flex-space:last-child):
+        (.tab-bar > .item.pinned > .icon):
+        (.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover > .icon):
+        (.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover,): Deleted.
+        (.tab-bar > .item > .flex-space:last-child): Deleted.
+        (.tab-bar > .item.new-tab-button > .icon): Deleted.
+        (.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover > .icon,): Deleted.
+        Removed rules specifically targeting `.new-tab-button`.
+
+        * UserInterface/Views/TabBar.js:
+        (WebInspector.TabBar):
+        (WebInspector.TabBar.prototype.get newTabTabBarItem):
+        (WebInspector.TabBar.prototype.updateNewTabTabBarItemState):
+        (WebInspector.TabBar.prototype.insertTabBarItem):
+        (WebInspector.TabBar.prototype.removeTabBarItem.animateTabs):
+        (WebInspector.TabBar.prototype.removeTabBarItem):
+        (WebInspector.TabBar.prototype.selectPreviousTab):
+        (WebInspector.TabBar.prototype.selectNextTab):
+        (WebInspector.TabBar.prototype.set selectedTabBarItem):
+        (WebInspector.TabBar.prototype.hasNormalTab):
+        (WebInspector.TabBar.prototype.layout):
+        (WebInspector.TabBar.prototype._hasMoreThanOneNormalTab):
+        (WebInspector.TabBar.prototype._handleMouseDown):
+        (WebInspector.TabBar.prototype._handleMouseMoved):
+        (WebInspector.TabBar.prototype._handleMouseLeave):
+        (WebInspector.TabBar.prototype._handleNewTabClick):
+        (WebInspector.TabBar.prototype._handleNewTabMouseEnter):
+        (WebInspector.TabBar.prototype.get newTabItem): Deleted.
+        (WebInspector.TabBar.prototype.set newTabItem): Deleted.
+        Replaced the newTabItem setter by adding a saved pinned tab bar item (instead of relying
+        upon a different object to give it the pinned tab bar item) that changes modes depending on
+        whether a new tab is able to be created.
+
+        * UserInterface/Views/TabBarItem.js:
+        (WebInspector.TabBarItem):
+        (WebInspector.TabBarItem.prototype.get element):
+        (WebInspector.TabBarItem.prototype.get representedObject):
+        (WebInspector.TabBarItem.prototype.set representedObject):
+        (WebInspector.TabBarItem.prototype.get parentTabBar):
+        (WebInspector.TabBarItem.prototype.set parentTabBar):
+        (WebInspector.TabBarItem.prototype.get image):
+        (WebInspector.TabBarItem.prototype.set image):
+        (WebInspector.TabBarItem.prototype.get title):
+        (WebInspector.TabBarItem.prototype.set title):
+        (WebInspector.TabBarItem.prototype.get pinned): Deleted.
+        (WebInspector.TabBarItem.prototype._handleContextMenuEvent): Deleted.
+        Split into GeneralTabBarItem and PinnedTabBarItem to simplify the logic of the DOM and allow
+        for easier checking of whether a tab bar item is pinned or not.
+
+        * UserInterface/Views/TabBrowser.js:
+        (WebInspector.TabBrowser):
+        (WebInspector.TabBrowser.prototype.addTabForContentView):
+        (WebInspector.TabBrowser.prototype.closeTabForContentView):
+        (WebInspector.TabBrowser.prototype._tabBarItemSelected):
+        (WebInspector.TabBrowser.prototype._tabBarItemRemoved):
+        Replaced references to newTabItem with a set number (since each TabBar has a specific number
+        of pinned tabs).
+
+        * UserInterface/Views/TextEditor.js:
+        (WebInspector.TextEditor):
+        (WebInspector.TextEditor.prototype.close):.
+        Remove settings update event listeners to allow garbage collection.
+
+        (WebInspector.TextEditor.prototype._startWorkerPrettyPrint):
+        (WebInspector.TextEditor.prototype._startCodeMirrorPrettyPrint):
+        Now uses the settings values in WebInspector.setting for settings on the CodeMirror
+        instance.  Also updates the CodeMirror instance if any setting changes.
+
 2016-10-28  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Include parameter strings for native CustomElementRegistry methods in the console
index f9ad764..7ea6a1c 100644 (file)
@@ -391,15 +391,15 @@ localizedStrings["Group"] = "Group";
 localizedStrings["Grow"] = "Grow";
 localizedStrings["HTML Attributes"] = "HTML Attributes";
 localizedStrings["HTTP"] = "HTTP";
+localizedStrings["Heading Level"] = "Heading Level";
 localizedStrings["Heap Snapshot Object (@%d)"] = "Heap Snapshot Object (@%d)";
 localizedStrings["Height"] = "Height";
-localizedStrings["Heading Level"] = "Heading Level";
-localizedStrings["Hierarchy Level"] = "Hierarchy Level";
 localizedStrings["Hide compositing borders"] = "Hide compositing borders";
 localizedStrings["Hide shadow DOM nodes"] = "Hide shadow DOM nodes";
 localizedStrings["Hide the details sidebar (%s)"] = "Hide the details sidebar (%s)";
 localizedStrings["Hide the navigation sidebar (%s)"] = "Hide the navigation sidebar (%s)";
 localizedStrings["Hide type information"] = "Hide type information";
+localizedStrings["Hierarchy Level"] = "Hierarchy Level";
 localizedStrings["Highest: %s"] = "Highest: %s";
 localizedStrings["Horizontal"] = "Horizontal";
 localizedStrings["Host"] = "Host";
@@ -414,6 +414,7 @@ localizedStrings["Image Size"] = "Image Size";
 localizedStrings["Images"] = "Images";
 localizedStrings["Immediate Pause Requested"] = "Immediate Pause Requested";
 localizedStrings["Indent"] = "Indent";
+localizedStrings["Indent width:"] = "Indent width:";
 localizedStrings["Index"] = "Index";
 localizedStrings["Index Key \u2014 %s"] = "Index Key \u2014 %s";
 localizedStrings["Indexed Databases"] = "Indexed Databases";
@@ -427,6 +428,7 @@ localizedStrings["Input: "] = "Input: ";
 localizedStrings["Inset"] = "Inset";
 localizedStrings["Instances"] = "Instances";
 localizedStrings["Invalid"] = "Invalid";
+localizedStrings["Invalid Characters:"] = "Invalid Characters:";
 localizedStrings["Inverted"] = "Inverted";
 localizedStrings["Invoke getter"] = "Invoke getter";
 localizedStrings["Iterations"] = "Iterations";
@@ -453,6 +455,7 @@ localizedStrings["Ligatures"] = "Ligatures";
 localizedStrings["Line %d"] = "Line %d";
 localizedStrings["Line %d:%d"] = "Line %d:%d";
 localizedStrings["Line Number"] = "Line Number";
+localizedStrings["Line wrapping:"] = "Line wrapping:";
 localizedStrings["Linear Gradient"] = "Linear Gradient";
 localizedStrings["List Styles"] = "List Styles";
 localizedStrings["Live"] = "Live";
@@ -536,6 +539,7 @@ localizedStrings["Online"] = "Online";
 localizedStrings["Only show resources with issues"] = "Only show resources with issues";
 localizedStrings["Opacity"] = "Opacity";
 localizedStrings["Open"] = "Open";
+localizedStrings["Open Settings"] = "Open Settings";
 localizedStrings["Open in New Tab"] = "Open in New Tab";
 localizedStrings["Option-click to show all units"] = "Option-click to show all units";
 localizedStrings["Option-click to show all values"] = "Option-click to show all values";
@@ -575,6 +579,7 @@ localizedStrings["Port"] = "Port";
 localizedStrings["Position"] = "Position";
 localizedStrings["Position X"] = "Position X";
 localizedStrings["Position Y"] = "Position Y";
+localizedStrings["Prefer indent using:"] = "Prefer indent using:";
 localizedStrings["Pressed"] = "Pressed";
 localizedStrings["Pretty print"] = "Pretty print";
 localizedStrings["Primary Key"] = "Primary Key";
@@ -702,6 +707,7 @@ localizedStrings["Sockets"] = "Sockets";
 localizedStrings["Sort Ascending"] = "Sort Ascending";
 localizedStrings["Sort Descending"] = "Sort Descending";
 localizedStrings["Sources"] = "Sources";
+localizedStrings["Spaces"] = "Spaces";
 localizedStrings["Spacing"] = "Spacing";
 localizedStrings["Specificity: (%d, %d, %d)"] = "Specificity: (%d, %d, %d)";
 localizedStrings["Specificity: No value for selected element"] = "Specificity: No value for selected element";
@@ -738,6 +744,8 @@ localizedStrings["Styles \u2014 Rules"] = "Styles \u2014 Rules";
 localizedStrings["Styles \u2014 Visual"] = "Styles \u2014 Visual";
 localizedStrings["Stylesheet"] = "Stylesheet";
 localizedStrings["Stylesheets"] = "Stylesheets";
+localizedStrings["Tab width:"] = "Tab width:";
+localizedStrings["Tabs"] = "Tabs";
 localizedStrings["Take snapshot"] = "Take snapshot";
 localizedStrings["Template Content"] = "Template Content";
 localizedStrings["Text"] = "Text";
@@ -804,18 +812,21 @@ localizedStrings["Variants"] = "Variants";
 localizedStrings["Version"] = "Version";
 localizedStrings["Vertical"] = "Vertical";
 localizedStrings["Visibility"] = "Visibility";
+localizedStrings["Visible"] = "Visible";
 localizedStrings["Warning: "] = "Warning: ";
 localizedStrings["Warnings"] = "Warnings";
 localizedStrings["Watch Expressions"] = "Watch Expressions";
 localizedStrings["Web Inspector"] = "Web Inspector";
 localizedStrings["Weight"] = "Weight";
 localizedStrings["Whitespace"] = "Whitespace";
+localizedStrings["Whitespace Characters:"] = "Whitespace Characters:";
 localizedStrings["Width"] = "Width";
 localizedStrings["With Object Properties"] = "With Object Properties";
 localizedStrings["Word"] = "Word";
 localizedStrings["Worker \u2014 %s"] = "Worker \u2014 %s";
 localizedStrings["Working Copy"] = "Working Copy";
 localizedStrings["Wrap"] = "Wrap";
+localizedStrings["Wrap lines to editor width"] = "Wrap lines to editor width";
 localizedStrings["X"] = "X";
 localizedStrings["X1"] = "X1";
 localizedStrings["X2"] = "X2";
@@ -829,6 +840,7 @@ localizedStrings["Z-Index"] = "Z-Index";
 localizedStrings["key"] = "key";
 localizedStrings["line "] = "line ";
 localizedStrings["originally %s"] = "originally %s";
+localizedStrings["spaces"] = "spaces";
 localizedStrings["time before stopping"] = "time before stopping";
 localizedStrings["times before stopping"] = "times before stopping";
 localizedStrings["value"] = "value";
index 7762438..4f66a79 100644 (file)
@@ -232,13 +232,32 @@ WebInspector.contentLoaded = function()
 
     document.body.classList.add(this.debuggableType);
 
+    function setTabSize() {
+        document.body.style.tabSize = WebInspector.settings.tabSize.value;
+    }
+    WebInspector.settings.tabSize.addEventListener(WebInspector.Setting.Event.Changed, setTabSize);
+    setTabSize();
+
+    function setInvalidCharacterClassName() {
+        document.body.classList.toggle("show-invalid-characters", WebInspector.settings.showInvalidCharacters.value);
+    }
+    WebInspector.settings.showInvalidCharacters.addEventListener(WebInspector.Setting.Event.Changed, setInvalidCharacterClassName);
+    setInvalidCharacterClassName();
+
+    function setWhitespaceCharacterClassName() {
+        document.body.classList.toggle("show-whitespace-characters", WebInspector.settings.showWhitespaceCharacters.value);
+    }
+    WebInspector.settings.showWhitespaceCharacters.addEventListener(WebInspector.Setting.Event.Changed, setWhitespaceCharacterClassName);
+    setWhitespaceCharacterClassName();
+
+    this.settingsTabContentView = new WebInspector.SettingsTabContentView;
+
     // Create the user interface elements.
     this.toolbar = new WebInspector.Toolbar(document.getElementById("toolbar"), null, true);
     this.toolbar.displayMode = WebInspector.Toolbar.DisplayMode.IconOnly;
     this.toolbar.sizeMode = WebInspector.Toolbar.SizeMode.Small;
 
     this.tabBar = new WebInspector.TabBar(document.getElementById("tab-bar"));
-    this.tabBar.addEventListener(WebInspector.TabBar.Event.NewTabItemClicked, this._newTabItemClicked, this);
     this.tabBar.addEventListener(WebInspector.TabBar.Event.OpenDefaultTab, this._openDefaultTab, this);
 
     this._contentElement = document.getElementById("content");
@@ -289,9 +308,6 @@ WebInspector.contentLoaded = function()
     this.tabBrowser = new WebInspector.TabBrowser(document.getElementById("tab-browser"), this.tabBar, this.navigationSidebar, this.detailsSidebar);
     this.tabBrowser.addEventListener(WebInspector.TabBrowser.Event.SelectedTabContentViewDidChange, this._tabBrowserSelectedTabContentViewDidChange, this);
 
-    this.tabBar.addEventListener(WebInspector.TabBar.Event.TabBarItemAdded, this._updateNewTabButtonState, this);
-    this.tabBar.addEventListener(WebInspector.TabBar.Event.TabBarItemRemoved, this._updateNewTabButtonState, this);
-
     this._reloadPageKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl, "R", this._reloadPage.bind(this));
     this._reloadPageIgnoringCacheKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl | WebInspector.KeyboardShortcut.Modifier.Shift, "R", this._reloadPageIgnoringCache.bind(this));
     this._reloadPageKeyboardShortcut.implicitlyPreventsDefault = this._reloadPageIgnoringCacheKeyboardShortcut.implicitlyPreventsDefault = false;
@@ -406,6 +422,7 @@ WebInspector.contentLoaded = function()
         WebInspector.NewTabContentView,
         WebInspector.ResourcesTabContentView,
         WebInspector.SearchTabContentView,
+        WebInspector.SettingsTabContentView,
         WebInspector.StorageTabContentView,
         WebInspector.TimelineTabContentView,
     ];
@@ -447,7 +464,7 @@ WebInspector.contentLoaded = function()
     if (!this.tabBar.selectedTabBarItem)
         this.tabBar.selectedTabBarItem = 0;
 
-    if (!this.tabBar.hasNormalTab())
+    if (!this.tabBar.normalTabCount)
         this.showNewTabTab();
 
     // Listen to the events after restoring the saved tabs to avoid recursion.
@@ -538,17 +555,6 @@ WebInspector._rememberOpenTabs = function()
     this._openTabsSetting.value = openTabs;
 };
 
-WebInspector._updateNewTabButtonState = function(event)
-{
-    this.tabBar.newTabItem.disabled = !this.isNewTabWithTypeAllowed(WebInspector.NewTabContentView.Type);
-};
-
-WebInspector._newTabItemClicked = function(event)
-{
-    const shouldAnimate = true;
-    this.showNewTabTab(shouldAnimate);
-};
-
 WebInspector._openDefaultTab = function(event)
 {
     this.showNewTabTab();
@@ -574,7 +580,7 @@ WebInspector._tryToRestorePendingTabs = function()
 
     this._pendingOpenTabs = stillPendingOpenTabs;
 
-    this._updateNewTabButtonState();
+    this.tabBrowser.tabBar.updateNewTabTabBarItemState();
 };
 
 WebInspector.showNewTabTab = function(shouldAnimate)
@@ -1033,6 +1039,13 @@ WebInspector.UIString = function(string, vararg)
     return "LOCALIZED STRING NOT FOUND";
 };
 
+WebInspector.indentString = function()
+{
+    if (WebInspector.settings.indentWithTabs.value)
+        return "\t";
+    return " ".repeat(WebInspector.settings.indentUnit.value);
+};
+
 WebInspector.restoreFocusFromElement = function(element)
 {
     if (element && element.isSelfOrAncestor(this.currentFocusElement))
index acaa7a1..9c993d6 100644 (file)
@@ -101,3 +101,12 @@ WebInspector.Setting = class Setting extends WebInspector.Object
 WebInspector.Setting.Event = {
     Changed: "setting-changed"
 };
+
+WebInspector.settings = {
+    enableLineWrapping: new WebInspector.Setting("enable-line-wrapping", false),
+    indentUnit: new WebInspector.Setting("indent-unit", 4),
+    tabSize: new WebInspector.Setting("tab-size", 4),
+    indentWithTabs: new WebInspector.Setting("indent-with-tabs", false),
+    showWhitespaceCharacters: new WebInspector.Setting("show-whitespace-characters", false),
+    showInvalidCharacters: new WebInspector.Setting("show-invalid-characters", false),
+};
index 373a9e4..7b98bb3 100644 (file)
     <link rel="stylesheet" href="Views/SearchBar.css">
     <link rel="stylesheet" href="Views/SearchIcons.css">
     <link rel="stylesheet" href="Views/SearchSidebarPanel.css">
+    <link rel="stylesheet" href="Views/SettingsTabContentView.css">
     <link rel="stylesheet" href="Views/Sidebar.css">
     <link rel="stylesheet" href="Views/SidebarPanel.css">
     <link rel="stylesheet" href="Views/Slider.css">
     <script src="Views/DatabaseUserQuerySuccessView.js"></script>
     <script src="Views/DOMTreeContentView.js"></script>
     <script src="Views/DetailsSidebarPanel.js"></script>
+    <script src="Views/GeneralTabBarItem.js"></script>
     <script src="Views/GeneralTreeElement.js"></script>
     <script src="Views/NavigationSidebarPanel.js"></script>
+    <script src="Views/PinnedTabBarItem.js"></script>
     <script src="Views/ResourceContentView.js"></script>
     <script src="Views/TabContentView.js"></script>
     <script src="Views/TimelineDataGrid.js"></script>
index 1d170ff..8a7ba5f 100644 (file)
@@ -302,21 +302,20 @@ WebInspector.CSSStyleDeclaration = class CSSStyleDeclaration extends WebInspecto
 
     generateCSSRuleString()
     {
-        // FIXME: <rdar://problem/10593948> Provide a way to change the tab width in the Web Inspector
-        const indentation = "    ";
+        let indentString = WebInspector.indentString();
         let styleText = "";
         let mediaList = this.mediaList;
         let mediaQueriesCount = mediaList.length;
         for (let i = mediaQueriesCount - 1; i >= 0; --i)
-            styleText += indentation.repeat(mediaQueriesCount - i - 1) + "@media " + mediaList[i].text + " {\n";
+            styleText += indentString.repeat(mediaQueriesCount - i - 1) + "@media " + mediaList[i].text + " {\n";
 
-        styleText += indentation.repeat(mediaQueriesCount) + this.selectorText + " {\n";
+        styleText += indentString.repeat(mediaQueriesCount) + this.selectorText + " {\n";
 
         for (let property of this._properties) {
             if (property.anonymous)
                 continue;
 
-            styleText += indentation.repeat(mediaQueriesCount + 1) + property.text.trim();
+            styleText += indentString.repeat(mediaQueriesCount + 1) + property.text.trim();
 
             if (!styleText.endsWith(";"))
                 styleText += ";";
@@ -325,7 +324,7 @@ WebInspector.CSSStyleDeclaration = class CSSStyleDeclaration extends WebInspecto
         }
 
         for (let i = mediaQueriesCount; i > 0; --i)
-            styleText += indentation.repeat(i) + "}\n";
+            styleText += indentString.repeat(i) + "}\n";
 
         styleText += "}";
 
index c1015c4..78cab87 100644 (file)
@@ -101,6 +101,8 @@ WebInspector.isDebugUIEnabled = () => false;
 
 WebInspector.UIString = (string) => string;
 
+WebInspector.indentString = () => "    ";
+
 // Add stubs that are called by the frontend API.
 WebInspector.updateDockedState = () => {};
 WebInspector.updateDockingAvailability = () => {};
index 7760d95..c73fc14 100644 (file)
@@ -49,12 +49,16 @@ WebInspector.ApplicationCacheFrameContentView = class ApplicationCacheFrameConte
 
     shown()
     {
+        super.shown();
+
         this._maybeUpdate();
     }
 
     closed()
     {
         WebInspector.applicationCacheManager.removeEventListener(null, null, this);
+
+        super.closed();
     }
 
     saveToCookie(cookie)
index 9b16566..ad74b0a 100644 (file)
@@ -1466,12 +1466,11 @@ WebInspector.CSSStyleDeclarationTextEditor = class CSSStyleDeclarationTextEditor
 
     _formattedContentFromEditor()
     {
-        // FIXME: <rdar://problem/10593948> Provide a way to change the tab width in the Web Inspector
-        var indentString = "    ";
-        var builder = new FormatterContentBuilder(indentString);
-        var formatter = new WebInspector.Formatter(this._codeMirror, builder);
-        var start = {line: 0, ch: 0};
-        var end = {line: this._codeMirror.lineCount() - 1};
+        let indentString = WebInspector.indentString();
+        let builder = new FormatterContentBuilder(indentString);
+        let formatter = new WebInspector.Formatter(this._codeMirror, builder);
+        let start = {line: 0, ch: 0};
+        let end = {line: this._codeMirror.lineCount() - 1};
         formatter.format(start, end);
 
         return builder.formattedContent.trim();
@@ -1543,8 +1542,8 @@ WebInspector.CSSStyleDeclarationTextEditor = class CSSStyleDeclarationTextEditor
             let selectionHead = this._codeMirror.getCursor("head");
             let whitespaceRegex = /\s+/g;
 
-            // FIXME: <rdar://problem/10593948> Provide a way to change the tab width in the Web Inspector
-            this._linePrefixWhitespace = "    ";
+            this._linePrefixWhitespace = WebInspector.indentString();
+
             let styleTextPrefixWhitespace = styleText.match(/^\s*/);
 
             // If there is a match and the style text contains a newline, attempt to pull out the prefix whitespace
index de640b4..200190f 100644 (file)
@@ -62,16 +62,22 @@ WebInspector.ClusterContentView = class ClusterContentView extends WebInspector.
 
     shown()
     {
+        super.shown();
+
         this._contentViewContainer.shown();
     }
 
     hidden()
     {
+        super.hidden();
+
         this._contentViewContainer.hidden();
     }
 
     closed()
     {
+        super.closed();
+
         this._contentViewContainer.closeAllContentViews();
 
         WebInspector.ContentView.removeEventListener(null, null, this);
index 652e92f..5542b95 100644 (file)
         codeMirror.on("scrollCursorIntoView", scrollCursorIntoView);
     });
 
+    const maximumNeighboringWhitespaceCharacters = 16;
+    CodeMirror.defineOption("showWhitespaceCharacters", false, function(cm, value, old) {
+        if (!value || (old && old !== CodeMirror.Init)) {
+            cm.removeOverlay("whitespace");
+            return;
+        }
+
+        cm.addOverlay({
+            name: "whitespace",
+            token(stream) {
+                if (stream.peek() === " ") {
+                    let count = 0;
+                    while (count < maximumNeighboringWhitespaceCharacters && stream.peek() === " ") {
+                        ++count;
+                        stream.next();
+                    }
+                    return `whitespace whitespace-${count}`;
+                }
+
+                while (!stream.eol() && stream.peek() !== " ")
+                    stream.next();
+
+                return null;
+            }
+        });
+    });
+
     CodeMirror.defineExtension("hasLineClass", function(line, where, className) {
         // This matches the arguments to addLineClass and removeLineClass.
         var classProperty = (where === "text" ? "textClass" : (where === "background" ? "bgClass" : "wrapClass"));
index fd44940..852e82f 100644 (file)
     text-indent: 0;
 }
 
-/* FIXME: Add setting to show/hide invalid characters. */
-.CodeMirror .cm-invalidchar {
+.CodeMirror .cm-tab {
+    position: relative;
+}
+
+.show-whitespace-characters .CodeMirror .cm-tab::before {
+    position: absolute;
+    width: 90%;
+    bottom: 50%;
+    left: 5%;
+    content: "";
+    border-bottom: 1px solid hsl(0, 0%, 70%);
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace::before {
+    position: absolute;
+    pointer-events: none;
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-1::before {
+    content: "\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-2::before {
+    content: "\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-3::before {
+    content: "\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-4::before {
+    content: "\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-5::before {
+    content: "\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-6::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-7::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-8::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-9::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-10::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-11::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-12::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-13::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-14::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-15::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-whitespace-characters .CodeMirror .cm-whitespace-16::before {
+    content: "\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7\00B7";
+}
+
+.show-invalid-characters .CodeMirror .cm-invalidchar {
     display: none;
 }
index d9cd029..e0ea30e 100644 (file)
@@ -28,7 +28,7 @@ WebInspector.ConsoleTabContentView = class ConsoleTabContentView extends WebInsp
     constructor(identifier)
     {
         let {image, title} = WebInspector.ConsoleTabContentView.tabInfo();
-        let tabBarItem = new WebInspector.TabBarItem(image, title);
+        let tabBarItem = new WebInspector.GeneralTabBarItem(image, title);
 
         super(identifier || "console", "console", tabBarItem, null, null, true);
     }
index 138bfb4..76cda12 100644 (file)
@@ -83,18 +83,24 @@ WebInspector.DOMTreeContentView = class DOMTreeContentView extends WebInspector.
 
     shown()
     {
+        super.shown();
+
         this._domTreeOutline.setVisible(true, WebInspector.isConsoleFocused());
         this._updateCompositingBordersButtonToMatchPageSettings();
     }
 
     hidden()
     {
+        super.hidden();
+
         WebInspector.domTreeManager.hideDOMNodeHighlight();
         this._domTreeOutline.setVisible(false);
     }
 
     closed()
     {
+        super.closed();
+
         WebInspector.showPaintRectsSetting.removeEventListener(null, null, this);
         WebInspector.showShadowDOMSetting.removeEventListener(null, null, this);
         WebInspector.domTreeManager.removeEventListener(null, null, this);
index c545115..acc9bf7 100644 (file)
@@ -43,6 +43,8 @@ WebInspector.DatabaseContentView = class DatabaseContentView extends WebInspecto
 
     shown()
     {
+        super.shown();
+
         // FIXME: remove once <https://webkit.org/b/150741> is fixed.
         this._prompt.shown();
     }
index 3ca7b24..4f48857 100644 (file)
@@ -28,7 +28,7 @@ WebInspector.DebuggerTabContentView = class DebuggerTabContentView extends WebIn
     constructor(identifier)
     {
         let {image, title} = WebInspector.DebuggerTabContentView.tabInfo();
-        let tabBarItem = new WebInspector.TabBarItem(image, title);
+        let tabBarItem = new WebInspector.GeneralTabBarItem(image, title);
         let detailsSidebarPanels = [WebInspector.resourceDetailsSidebarPanel, WebInspector.scopeChainDetailsSidebarPanel, WebInspector.probeDetailsSidebarPanel];
 
         super(identifier || "debugger", "debugger", tabBarItem, WebInspector.DebuggerSidebarPanel, detailsSidebarPanels);
index a3a17ba..adabbe1 100644 (file)
@@ -28,7 +28,7 @@ WebInspector.ElementsTabContentView = class ElementsTabContentView extends WebIn
     constructor(identifier)
     {
         let {image, title} = WebInspector.ElementsTabContentView.tabInfo();
-        let tabBarItem = new WebInspector.TabBarItem(image, title);
+        let tabBarItem = new WebInspector.GeneralTabBarItem(image, title);
         let detailsSidebarPanels = [WebInspector.domNodeDetailsSidebarPanel, WebInspector.cssStyleDetailsSidebarPanel];
 
         if (WebInspector.layerTreeDetailsSidebarPanel)
diff --git a/Source/WebInspectorUI/UserInterface/Views/GeneralTabBarItem.js b/Source/WebInspectorUI/UserInterface/Views/GeneralTabBarItem.js
new file mode 100644 (file)
index 0000000..66d3302
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Devin Rousso <dcrousso+webkit@gmail.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.GeneralTabBarItem = class GeneralTabBarItem extends WebInspector.TabBarItem
+{
+    constructor(image, title, representedObject)
+    {
+        super(image, title, representedObject);
+
+        let closeButtonElement = document.createElement("div");
+        closeButtonElement.classList.add(WebInspector.TabBarItem.CloseButtonStyleClassName);
+        closeButtonElement.title = WebInspector.UIString("Click to close this tab");
+        this.element.insertBefore(closeButtonElement, this.element.firstChild);
+
+        this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this));
+    }
+
+    // Public
+
+    set title(title)
+    {
+        if (title) {
+            this._titleElement = document.createElement("span");
+            this._titleElement.classList.add("title");
+
+            let titleContentElement = document.createElement("span");
+            titleContentElement.classList.add("content");
+            titleContentElement.textContent = title;
+            this._titleElement.appendChild(titleContentElement);
+
+            this.element.insertBefore(this._titleElement, this.element.lastChild);
+        } else {
+            if (this._titleElement)
+                this._titleElement.remove();
+
+            this._titleElement = null;
+        }
+
+        super.title = title;
+    }
+
+    // Private
+
+    _handleContextMenuEvent(event)
+    {
+        if (!this._parentTabBar)
+            return;
+
+        let closeTab = () => {
+            this._parentTabBar.removeTabBarItem(this);
+        };
+
+        let closeOtherTabs = () => {
+            let tabBarItems = this._parentTabBar.tabBarItems;
+            for (let i = tabBarItems.length - 1; i >= 0; --i) {
+                let item = tabBarItems[i];
+                if (item === this || item instanceof WebInspector.PinnedTabBarItem)
+                    continue;
+                this._parentTabBar.removeTabBarItem(item);
+            }
+        };
+
+        let hasOtherNonPinnedTabs = this._parentTabBar.tabBarItems.some((item) => item !== this && !(item instanceof WebInspector.PinnedTabBarItem));
+        let contextMenu = WebInspector.ContextMenu.createFromEvent(event);
+        contextMenu.appendItem(WebInspector.UIString("Close Tab"), closeTab, this.isDefaultTab);
+        contextMenu.appendItem(WebInspector.UIString("Close Other Tabs"), closeOtherTabs, !hasOtherNonPinnedTabs);
+    }
+};
index aa2f288..8cc45f6 100644 (file)
@@ -93,6 +93,8 @@ WebInspector.IndexedDatabaseObjectStoreContentView = class IndexedDatabaseObject
 
     closed()
     {
+        super.closed();
+
         this._reset();
     }
 
index cbd3eb7..76667e2 100644 (file)
@@ -48,8 +48,6 @@ body {
     cursor: default;
 
     -webkit-font-smoothing: subpixel-antialiased;
-
-    tab-size: 4; /* FIXME: This should be controlled by a setting. <rdar://problem/10593948> */
 }
 
 body:not(.mavericks) {
index 1fbbea9..e278e5a 100644 (file)
@@ -157,6 +157,8 @@ WebInspector.NetworkGridContentView = class NetworkGridContentView extends WebIn
 
     closed()
     {
+        super.closed();
+
         this._dataGrid.closed();
     }
 
index fc4fcd7..3867a6a 100644 (file)
@@ -28,7 +28,7 @@ WebInspector.NetworkTabContentView = class NetworkTabContentView extends WebInsp
     constructor(identifier)
     {
         let {image, title} = WebInspector.NetworkTabContentView.tabInfo();
-        let tabBarItem = new WebInspector.TabBarItem(image, title);
+        let tabBarItem = new WebInspector.GeneralTabBarItem(image, title);
         let detailsSidebarPanels = [WebInspector.resourceDetailsSidebarPanel, WebInspector.probeDetailsSidebarPanel];
 
         super(identifier || "network", "network", tabBarItem, WebInspector.NetworkSidebarPanel, detailsSidebarPanels);
index e56ab5f..21c0142 100644 (file)
@@ -28,7 +28,7 @@ WebInspector.NewTabContentView = class NewTabContentView extends WebInspector.Ta
     constructor(identifier)
     {
         let {image, title} = WebInspector.NewTabContentView.tabInfo();
-        let tabBarItem = new WebInspector.TabBarItem(image, title);
+        let tabBarItem = new WebInspector.GeneralTabBarItem(image, title);
         tabBarItem.isDefaultTab = true;
 
         super(identifier || "new-tab", "new-tab", tabBarItem);
diff --git a/Source/WebInspectorUI/UserInterface/Views/PinnedTabBarItem.js b/Source/WebInspectorUI/UserInterface/Views/PinnedTabBarItem.js
new file mode 100644 (file)
index 0000000..8ac308e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 Devin Rousso <dcrousso+webkit@gmail.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.PinnedTabBarItem = class PinnedTabBarItem extends WebInspector.TabBarItem
+{
+    constructor(image, title, representedObject)
+    {
+        super(image, title, representedObject);
+
+        this.element.classList.add("pinned");
+    }
+};
index bbc8606..a9f21e8 100644 (file)
@@ -76,6 +76,8 @@ WebInspector.ResourceContentView = class ResourceContentView extends WebInspecto
 
     closed()
     {
+        super.closed();
+
         if (!this.managesOwnIssues)
             WebInspector.issueManager.removeEventListener(null, null, this);
     }
index c86235f..4bed286 100644 (file)
@@ -28,7 +28,7 @@ WebInspector.ResourcesTabContentView = class ResourcesTabContentView extends Web
     constructor(identifier)
     {
         let {image, title} = WebInspector.ResourcesTabContentView.tabInfo();
-        let tabBarItem = new WebInspector.TabBarItem(image, title);
+        let tabBarItem = new WebInspector.GeneralTabBarItem(image, title);
         let detailsSidebarPanels = [WebInspector.resourceDetailsSidebarPanel, WebInspector.probeDetailsSidebarPanel];
 
         // FIXME: Until ContentFlows are moved to the Elements tab, these details sidebar panels need to be included.
index 121a874..47a29a7 100644 (file)
@@ -107,16 +107,22 @@ WebInspector.ScriptContentView = class ScriptContentView extends WebInspector.Co
 
     shown()
     {
+        super.shown();
+
         this._textEditor.shown();
     }
 
     hidden()
     {
+        super.hidden();
+
         this._textEditor.hidden();
     }
 
     closed()
     {
+        super.closed();
+
         WebInspector.showJavaScriptTypeInformationSetting.removeEventListener(null, null, this);
 
         this._textEditor.close();
index e4b43fc..c4dc81d 100644 (file)
@@ -28,7 +28,7 @@ WebInspector.SearchTabContentView = class SearchTabContentView extends WebInspec
     constructor(identifier)
     {
         let {image, title} = WebInspector.SearchTabContentView.tabInfo();
-        let tabBarItem = new WebInspector.TabBarItem(image, title);
+        let tabBarItem = new WebInspector.GeneralTabBarItem(image, title);
         let detailsSidebarPanels = [WebInspector.resourceDetailsSidebarPanel, WebInspector.probeDetailsSidebarPanel,
             WebInspector.domNodeDetailsSidebarPanel, WebInspector.cssStyleDetailsSidebarPanel];
 
diff --git a/Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.css b/Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.css
new file mode 100644 (file)
index 0000000..276238f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 Devin Rousso <dcrousso+webkit@gmail.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.content-view.settings {
+    display: flex;
+    flex-direction: column;
+    font-weight: lighter;
+}
+
+.content-view.settings > .header {
+    margin: 70px auto 40px;
+    text-align: center;
+    font-size: 48px;
+}
+
+.content-view.settings > .setting-container {
+    display: flex;
+    align-items: center;
+    padding: 10px;
+    font-size: 14px;
+}
+
+.content-view.settings > .setting-container > .setting-name {
+    width: 50%;
+    margin-right: 2px;
+    text-align: right;
+}
+
+.content-view.settings > .setting-container > .setting-value-controller {
+    display: flex;
+    align-items: center;
+    width: 50%;
+    margin-left: 2px;
+}
+
+.content-view.settings > .setting-container > .setting-value-controller input[type="number"] {
+    max-width: 50px;
+    margin: 0 5px;
+    text-align: right;
+}
index 0af4ada..f16a4da 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Devin Rousso <dcrousso+webkit@gmail.com>. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,15 +28,25 @@ WebInspector.SettingsTabContentView = class SettingsTabContentView extends WebIn
 {
     constructor(identifier)
     {
-        var tabBarItem = new WebInspector.TabBarItem("Images/Gear.svg", WebInspector.UIString("Settings"), true);
+        let tabBarItem = new WebInspector.PinnedTabBarItem("Images/Gear.svg", WebInspector.UIString("Open Settings"));
 
         super(identifier || "settings", "settings", tabBarItem);
+
+        // Ensures that the Settings tab is displayable from a pinned tab bar item.
+        tabBarItem.representedObject = this;
     }
 
-    static isTabAllowed()
+    static tabInfo()
     {
-        // FIXME (149284): This tab isn't ready to be shown yet.
-        return false;
+        return {
+            image: "Images/Gear.svg",
+            title: WebInspector.UIString("Settings"),
+        };
+    }
+
+    static isEphemeral()
+    {
+        return true;
     }
 
     static shouldSaveTab()
@@ -49,6 +60,95 @@ WebInspector.SettingsTabContentView = class SettingsTabContentView extends WebIn
     {
         return WebInspector.SettingsTabContentView.Type;
     }
+
+    initialLayout()
+    {
+        let header = this.element.createChild("div", "header");
+        header.textContent = WebInspector.UIString("Settings");
+
+        let createContainer = (title, createValueController) => {
+            let container = this.element.createChild("div", "setting-container");
+
+            let titleContainer = container.createChild("div", "setting-name");
+            titleContainer.textContent = title;
+
+            let valueControllerContainer = container.createChild("div", "setting-value-controller");
+            if (typeof createValueController === "function")
+                createValueController(valueControllerContainer);
+        };
+
+        let createCheckbox = (setting) => {
+            let checkbox = document.createElement("input");
+            checkbox.type = "checkbox";
+            checkbox.checked = setting.value;
+            checkbox.addEventListener("change", (event) => {
+                setting.value = checkbox.checked;
+            });
+            return checkbox;
+        };
+
+        createContainer(WebInspector.UIString("Prefer indent using:"), (valueControllerContainer) => {
+            let select = valueControllerContainer.createChild("select");
+            select.addEventListener("change", (event) => {
+                WebInspector.settings.indentWithTabs.value = select.value === "tabs";
+            });
+
+            let tabsOption = select.createChild("option");
+            tabsOption.value = "tabs";
+            tabsOption.textContent = WebInspector.UIString("Tabs");
+            tabsOption.selected = WebInspector.settings.indentWithTabs.value;
+
+            let spacesOption = select.createChild("option");
+            spacesOption.value = "spaces";
+            spacesOption.textContent = WebInspector.UIString("Spaces");
+            spacesOption.selected = !WebInspector.settings.indentWithTabs.value;
+        });
+
+        createContainer(WebInspector.UIString("Tab width:"), (valueControllerContainer) => {
+            let input = valueControllerContainer.createChild("input");
+            input.type = "number";
+            input.min = 1;
+            input.value = WebInspector.settings.tabSize.value;
+            input.addEventListener("change", (event) => {
+                WebInspector.settings.tabSize.value = parseInt(input.value) || 4;
+            });
+
+            valueControllerContainer.append(WebInspector.UIString("spaces"));
+        });
+
+        createContainer(WebInspector.UIString("Indent width:"), (valueControllerContainer) => {
+            let input = valueControllerContainer.createChild("input");
+            input.type = "number";
+            input.min = 1;
+            input.value = WebInspector.settings.indentUnit.value;
+            input.addEventListener("change", (event) => {
+                WebInspector.settings.indentUnit.value = parseInt(input.value) || 4;
+            });
+
+            valueControllerContainer.append(WebInspector.UIString("spaces"));
+        });
+
+        createContainer(WebInspector.UIString("Line wrapping:"), (valueControllerContainer) => {
+            let checkbox = createCheckbox(WebInspector.settings.enableLineWrapping);
+            valueControllerContainer.appendChild(checkbox);
+
+            valueControllerContainer.append(WebInspector.UIString("Wrap lines to editor width"));
+        });
+
+        createContainer(WebInspector.UIString("Whitespace Characters:"), (valueControllerContainer) => {
+            let checkbox = createCheckbox(WebInspector.settings.showWhitespaceCharacters);
+            valueControllerContainer.appendChild(checkbox);
+
+            valueControllerContainer.append(WebInspector.UIString("Visible"));
+        });
+
+        createContainer(WebInspector.UIString("Invalid Characters:"), (valueControllerContainer) => {
+            let checkbox = createCheckbox(WebInspector.settings.showInvalidCharacters);
+            valueControllerContainer.appendChild(checkbox);
+
+            valueControllerContainer.append(WebInspector.UIString("Visible"));
+        });
+    }
 };
 
 WebInspector.SettingsTabContentView.Type = "settings";
index 836ce15..6504794 100644 (file)
@@ -144,6 +144,8 @@ WebInspector.SourceCodeTextEditor = class SourceCodeTextEditor extends WebInspec
 
     close()
     {
+        super.close();
+
         if (this._supportsDebugging) {
             WebInspector.Breakpoint.removeEventListener(null, null, this);
             WebInspector.debuggerManager.removeEventListener(null, null, this);
@@ -1646,10 +1648,11 @@ WebInspector.SourceCodeTextEditor = class SourceCodeTextEditor extends WebInspec
                 this._popover.update();
             });
 
-            // FIXME: <rdar://problem/10593948> Provide a way to change the tab width in the Web Inspector
             const isModule = false;
+            const indentString = WebInspector.indentString();
+            const includeSourceMapData = false;
             let workerProxy = WebInspector.FormatterWorkerProxy.singleton();
-            workerProxy.formatJavaScript(data.description, isModule, "    ", false, ({formattedText}) => {
+            workerProxy.formatJavaScript(data.description, isModule, indentString, includeSourceMapData, ({formattedText}) => {
                 codeMirror.setValue(formattedText || data.description);
             });
 
index 096048a..d443e34 100644 (file)
@@ -28,7 +28,7 @@ WebInspector.StorageTabContentView = class StorageTabContentView extends WebInsp
     constructor(identifier)
     {
         let {image, title} = WebInspector.StorageTabContentView.tabInfo();
-        let tabBarItem = new WebInspector.TabBarItem(image, title);
+        let tabBarItem = new WebInspector.GeneralTabBarItem(image, title);
         let detailsSidebarPanels = [WebInspector.applicationCacheDetailsSidebarPanel, WebInspector.indexedDatabaseDetailsSidebarPanel];
 
         super(identifier || "storage", "storage", tabBarItem, WebInspector.StorageSidebarPanel, detailsSidebarPanels);
index 1c4a27d..0ad7456 100644 (file)
@@ -119,8 +119,7 @@ body.mavericks .tab-bar > .item:not(.disabled).selected {
     border-top-color: hsl(0, 0%, 68%);
 }
 
-.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover,
-.tab-bar > .item.new-tab-button:not(.disabled):hover {
+.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover {
     background-position: 0 100%;
     border-top-color: hsl(0, 0%, 59%);
     border-left-color: hsl(0, 0%, 59%);
@@ -191,7 +190,7 @@ body:not(.window-inactive) .tab-bar.single-tab > .item.default-tab:hover > .clos
     flex: 1;
 }
 
-.tab-bar > .item > .flex-space:last-child {
+.tab-bar > .item:not(.pinned) > .flex-space:last-child {
     margin-right: 16px;
 }
 
@@ -207,6 +206,13 @@ body:not(.window-inactive) .tab-bar.single-tab > .item.default-tab:hover > .clos
     -webkit-user-drag: none;
 }
 
+.tab-bar > .item.pinned > .icon {
+    width: 15px;
+    height: 15px;
+    min-width: 15px;
+    min-height: 15px;
+}
+
 .tab-bar > .item.selected > .icon {
     opacity: 0.7;
 }
@@ -215,15 +221,7 @@ body:not(.window-inactive) .tab-bar.single-tab > .item.default-tab:hover > .clos
     opacity: 0.35;
 }
 
-.tab-bar > .item.new-tab-button > .icon {
-    width: 15px;
-    height: 15px;
-    min-width: 15px;
-    min-height: 15px;
-}
-
-.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover > .icon,
-.tab-bar > .item.new-tab-button:not(.disabled):hover > .icon {
+.tab-bar:not(.animating) > .item:not(.selected, .disabled):hover > .icon {
     opacity: 0.6;
 }
 
index 2939c40..a49af96 100644 (file)
@@ -31,53 +31,35 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
 
         this.element.classList.add("tab-bar");
         this.element.setAttribute("role", "tablist");
-
-        var topBorderElement = document.createElement("div");
-        topBorderElement.classList.add("top-border");
-        this.element.appendChild(topBorderElement);
-
         this.element.addEventListener("mousedown", this._handleMouseDown.bind(this));
         this.element.addEventListener("click", this._handleClick.bind(this));
         this.element.addEventListener("mouseleave", this._handleMouseLeave.bind(this));
 
+        this.element.createChild("div", "top-border");
+
         this._tabBarItems = [];
 
         if (tabBarItems) {
-            for (var tabBarItem in tabBarItems)
+            for (let tabBarItem in tabBarItems)
                 this.addTabBarItem(tabBarItem);
         }
-    }
 
-    // Public
+        this.addTabBarItem(WebInspector.settingsTabContentView.tabBarItem, true);
 
-    get newTabItem()
-    {
-        return this._newTabItem || null;
+        this._newTabTabBarItem = new WebInspector.PinnedTabBarItem("Images/NewTabPlus.svg", WebInspector.UIString("Create a new tab"));
+        this._newTabTabBarItem.element.addEventListener("mouseenter", this._handleNewTabMouseEnter.bind(this));
+        this._newTabTabBarItem.element.addEventListener("click", this._handleNewTabClick.bind(this));
+        this.addTabBarItem(this._newTabTabBarItem, true);
     }
 
-    set newTabItem(newTabItem)
-    {
-        if (!this._handleNewTabClickListener)
-            this._handleNewTabClickListener = this._handleNewTabClick.bind(this);
-
-        if (!this._handleNewTabMouseEnterListener)
-            this._handleNewTabMouseEnterListener = this._handleNewTabMouseEnter.bind(this);
-
-        if (this._newTabItem) {
-            this._newTabItem.element.classList.remove("new-tab-button");
-            this._newTabItem.element.removeEventListener("click", this._handleNewTabClickListener);
-            this._newTabItem.element.removeEventListener("mouseenter", this._handleNewTabMouseEnterListener);
-            this.removeTabBarItem(this._newTabItem, true);
-        }
+    // Public
 
-        if (newTabItem) {
-            newTabItem.element.classList.add("new-tab-button");
-            newTabItem.element.addEventListener("click", this._handleNewTabClickListener);
-            newTabItem.element.addEventListener("mouseenter", this._handleNewTabMouseEnterListener);
-            this.addTabBarItem(newTabItem, true);
-        }
+    get newTabTabBarItem() { return this._newTabTabBarItem; }
 
-        this._newTabItem = newTabItem || null;
+    updateNewTabTabBarItemState()
+    {
+        let newTabExists = !WebInspector.isNewTabWithTypeAllowed(WebInspector.NewTabContentView.Type);
+        this._newTabTabBarItem.disabled = newTabExists;
     }
 
     addTabBarItem(tabBarItem, doNotAnimate)
@@ -107,8 +89,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
 
         tabBarItem.parentTabBar = this;
 
-        var lastIndex = this._newTabItem ? this._tabBarItems.length - 1 : this._tabBarItems.length;
-        index = Math.max(0, Math.min(index, lastIndex));
+        index = Number.constrain(index, 0, this.normalTabCount);
 
         if (this.element.classList.contains("animating")) {
             requestAnimationFrame(removeStyles.bind(this));
@@ -122,9 +103,12 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
         this._tabBarItems.splice(index, 0, tabBarItem);
 
         var nextSibling = this._tabBarItems[index + 1];
-        var nextSiblingElement = nextSibling ? nextSibling.element : (this._newTabItem ? this._newTabItem.element : null);
+        let nextSiblingElement = nextSibling ? nextSibling.element : this._tabBarItems.lastValue.element;
 
-        this.element.insertBefore(tabBarItem.element, nextSiblingElement);
+        if (this.element.isAncestor(nextSiblingElement))
+            this.element.insertBefore(tabBarItem.element, nextSiblingElement);
+        else
+            this.element.appendChild(tabBarItem.element);
 
         this.element.classList.toggle("single-tab", !this._hasMoreThanOneNormalTab());
 
@@ -178,6 +162,9 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
         } else
             this.needsLayout();
 
+        if (!(tabBarItem instanceof WebInspector.PinnedTabBarItem))
+            this.updateNewTabTabBarItemState();
+
         this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemAdded, {tabBarItem});
 
         return tabBarItem;
@@ -185,19 +172,16 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
 
     removeTabBarItem(tabBarItemOrIndex, doNotAnimate, doNotExpand)
     {
-        var tabBarItem = this._findTabBarItem(tabBarItemOrIndex);
-        if (!tabBarItem)
+        let tabBarItem = this._findTabBarItem(tabBarItemOrIndex);
+        if (!tabBarItem || tabBarItem instanceof WebInspector.PinnedTabBarItem)
             return null;
 
         tabBarItem.parentTabBar = null;
 
-        if (tabBarItem === this._newTabItem)
-            this.newTabItem = null;
-
         if (this._selectedTabBarItem === tabBarItem) {
             var index = this._tabBarItems.indexOf(tabBarItem);
             var nextTabBarItem = this._tabBarItems[index + 1];
-            if (!nextTabBarItem || nextTabBarItem.pinned)
+            if (!nextTabBarItem || nextTabBarItem instanceof WebInspector.PinnedTabBarItem)
                 nextTabBarItem = this._tabBarItems[index - 1];
 
             this.selectedTabBarItem = nextTabBarItem;
@@ -212,7 +196,8 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
         if (!doNotAnimate)
             beforeTabSizesAndPositions = this._recordTabBarItemSizesAndPositions();
 
-        var wasLastNormalTab = this._tabBarItems.indexOf(tabBarItem) === (this._newTabItem ? this._tabBarItems.length - 2 : this._tabBarItems.length - 1);
+        // Subtract 1 from normalTabCount since arrays begin indexing at 0.
+        let wasLastNormalTab = this._tabBarItems.indexOf(tabBarItem) === this.normalTabCount - 1;
 
         this._tabBarItems.remove(tabBarItem);
         tabBarItem.element.remove();
@@ -220,7 +205,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
         var hasMoreThanOneNormalTab = this._hasMoreThanOneNormalTab();
         this.element.classList.toggle("single-tab", !hasMoreThanOneNormalTab);
 
-        const shouldOpenDefaultTab = !tabBarItem.isDefaultTab && !this.hasNormalTab();
+        const shouldOpenDefaultTab = !tabBarItem.isDefaultTab && !this.normalTabCount;
         if (shouldOpenDefaultTab)
             doNotAnimate = true;
 
@@ -231,6 +216,8 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
             } else
                 this.needsLayout();
 
+            this.updateNewTabTabBarItemState();
+
             this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemRemoved, {tabBarItem});
 
             if (shouldOpenDefaultTab)
@@ -250,7 +237,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
             for (var currentTabBarItem of this._tabBarItems) {
                 var sizeAndPosition = beforeTabSizesAndPositions.get(currentTabBarItem);
 
-                if (!currentTabBarItem.pinned) {
+                if (!(currentTabBarItem instanceof WebInspector.PinnedTabBarItem)) {
                     currentTabBarItem.element.style.left = left + "px";
                     left += sizeAndPosition.width;
                     lastNormalTabBarItem = currentTabBarItem;
@@ -295,6 +282,8 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
         } else
             this.needsLayout();
 
+        this.updateNewTabTabBarItemState();
+
         this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemRemoved, {tabBarItem});
 
         if (shouldOpenDefaultTab)
@@ -316,7 +305,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
             else
                 newIndex--;
 
-            if (!this._tabBarItems[newIndex].pinned)
+            if (!(this._tabBarItems[newIndex] instanceof WebInspector.PinnedTabBarItem))
                 break;
         } while (newIndex !== startIndex);
 
@@ -339,7 +328,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
             else
                 newIndex++;
 
-            if (!this._tabBarItems[newIndex].pinned)
+            if (!(this._tabBarItems[newIndex] instanceof WebInspector.PinnedTabBarItem))
                 break;
         } while (newIndex !== startIndex);
 
@@ -356,9 +345,11 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
 
     set selectedTabBarItem(tabBarItemOrIndex)
     {
-        var tabBarItem = this._findTabBarItem(tabBarItemOrIndex);
-        if (tabBarItem === this._newTabItem)
-            tabBarItem = this._tabBarItems[this._tabBarItems.length - 2];
+        let tabBarItem = this._findTabBarItem(tabBarItemOrIndex);
+        if (tabBarItem === this._newTabTabBarItem) {
+            // Get the item before the New-Tab item since it is not selectable.
+            tabBarItem = this._tabBarItems[this.normalTabCount - 1];
+        }
 
         if (this._selectedTabBarItem === tabBarItem)
             return;
@@ -379,9 +370,9 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
         return this._tabBarItems;
     }
 
-    hasNormalTab()
+    get normalTabCount()
     {
-        return this._tabBarItems.some((tab) => !tab.pinned);
+        return this._tabBarItems.filter((item) => !(item instanceof WebInspector.PinnedTabBarItem)).length;
     }
 
     // Protected
@@ -396,8 +387,9 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
 
         let firstNormalTabItem = null;
         for (let tabItem of this._tabBarItems) {
-            if (tabItem.pinned)
+            if (tabItem instanceof WebInspector.PinnedTabBarItem)
                 continue;
+
             firstNormalTabItem = tabItem;
             break;
         }
@@ -433,10 +425,11 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
 
     _hasMoreThanOneNormalTab()
     {
-        var normalTabCount = 0;
-        for (var tabBarItem of this._tabBarItems) {
-            if (tabBarItem.pinned)
+        let normalTabCount = 0;
+        for (let tabBarItem of this._tabBarItems) {
+            if (tabBarItem instanceof WebInspector.PinnedTabBarItem)
                 continue;
+
             ++normalTabCount;
             if (normalTabCount >= 2)
                 return true;
@@ -539,33 +532,34 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
         if (event.button !== 0 || event.ctrlKey)
             return;
 
-        var itemElement = event.target.enclosingNodeOrSelfWithClass(WebInspector.TabBarItem.StyleClassName);
+        let itemElement = event.target.enclosingNodeOrSelfWithClass(WebInspector.TabBarItem.StyleClassName);
         if (!itemElement)
             return;
 
-        var tabBarItem = itemElement[WebInspector.TabBarItem.ElementReferenceSymbol];
+        let tabBarItem = itemElement[WebInspector.TabBarItem.ElementReferenceSymbol];
         if (!tabBarItem)
             return;
 
         if (tabBarItem.disabled)
             return;
 
-        if (tabBarItem === this._newTabItem)
+        if (tabBarItem === this._newTabTabBarItem)
             return;
 
-        var closeButtonElement = event.target.enclosingNodeOrSelfWithClass(WebInspector.TabBarItem.CloseButtonStyleClassName);
+        let closeButtonElement = event.target.enclosingNodeOrSelfWithClass(WebInspector.TabBarItem.CloseButtonStyleClassName);
         if (closeButtonElement)
             return;
 
         this.selectedTabBarItem = tabBarItem;
 
-        if (tabBarItem.pinned || !this._hasMoreThanOneNormalTab())
+        if (tabBarItem instanceof WebInspector.PinnedTabBarItem || !this._hasMoreThanOneNormalTab())
             return;
 
         this._firstNormalTabItemIndex = 0;
-        for (var i = 0; i < this._tabBarItems.length; ++i) {
-            if (this._tabBarItems[i].pinned)
+        for (let i = 0; i < this._tabBarItems.length; ++i) {
+            if (this._tabBarItems[i] instanceof WebInspector.PinnedTabBarItem)
                 continue;
+
             this._firstNormalTabItemIndex = i;
             break;
         }
@@ -641,7 +635,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
         var currentIndex = this._tabBarItems.indexOf(this._selectedTabBarItem);
         var newIndex = currentIndex;
 
-        for (var tabBarItem of this._tabBarItems) {
+        for (let tabBarItem of this._tabBarItems) {
             if (tabBarItem === this._selectedTabBarItem)
                 continue;
 
@@ -654,8 +648,8 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
             break;
         }
 
-        newIndex = Math.max(this._firstNormalTabItemIndex, newIndex);
-        newIndex = Math.min(this._newTabItem ? this._tabBarItems.length - 2 : this._tabBarItems.length - 1, newIndex);
+        // Subtract 1 from normalTabCount since arrays begin indexing at 0.
+        newIndex = Number.constrain(newIndex, this._firstNormalTabItemIndex, this.normalTabCount - 1);
 
         if (currentIndex === newIndex)
             return;
@@ -663,16 +657,16 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
         this._tabBarItems.splice(currentIndex, 1);
         this._tabBarItems.splice(newIndex, 0, this._selectedTabBarItem);
 
-        var nextSibling = this._tabBarItems[newIndex + 1];
-        var nextSiblingElement = nextSibling ? nextSibling.element : (this._newTabItem ? this._newTabItem.element : null);
+        let nextSibling = this._tabBarItems[newIndex + 1];
+        let nextSiblingElement = nextSibling ? nextSibling.element : this._newTabTabBarItem.element;
 
         this.element.insertBefore(this._selectedTabBarItem.element, nextSiblingElement);
 
         // FIXME: Animate the tabs that move to make room for the selected tab. This was causing me trouble when I tried.
 
-        var left = 0;
-        for (var tabBarItem of this._tabBarItems) {
-            if (tabBarItem !== this._selectedTabBarItem && tabBarItem !== this._newTabItem && parseFloat(tabBarItem.element.style.left) !== left)
+        let left = 0;
+        for (let tabBarItem of this._tabBarItems) {
+            if (tabBarItem !== this._selectedTabBarItem && tabBarItem !== this._newTabTabBarItem && parseFloat(tabBarItem.element.style.left) !== left)
                 tabBarItem.element.style.left = left + "px";
             left += parseFloat(tabBarItem.element.style.width);
         }
@@ -723,7 +717,7 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
         // Check if the mouse really did leave the element by checking the bounds.
         // FIXME: Is this a WebKit bug or correct behavior?
         const barRect = this.element.getBoundingClientRect();
-        const newTabItemRect = this._newTabItem ? this._newTabItem.element.getBoundingClientRect() : null;
+        const newTabItemRect = this._newTabTabBarItem.element.getBoundingClientRect();
         if (event.pageY > barRect.top && event.pageY < barRect.bottom && event.pageX > barRect.left && event.pageX < (newTabItemRect ? newTabItemRect.right : barRect.right))
             return;
 
@@ -732,9 +726,8 @@ WebInspector.TabBar = class TabBar extends WebInspector.View
 
     _handleNewTabClick(event)
     {
-        if (this._newTabItem.disabled)
-            return;
-        this.dispatchEventToListeners(WebInspector.TabBar.Event.NewTabItemClicked);
+        const shouldAnimate = true;
+        WebInspector.showNewTabTab(shouldAnimate);
     }
 
     _handleNewTabMouseEnter(event)
@@ -751,6 +744,5 @@ WebInspector.TabBar.Event = {
     TabBarItemAdded: "tab-bar-tab-bar-item-added",
     TabBarItemRemoved: "tab-bar-tab-bar-item-removed",
     TabBarItemsReordered: "tab-bar-tab-bar-items-reordered",
-    NewTabItemClicked: "tab-bar-new-tab-item-clicked",
     OpenDefaultTab: "tab-bar-open-default-tab"
 };
index 92e62d7..3182b95 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Devin Rousso <dcrousso+webkit@gmail.com>. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -25,7 +26,7 @@
 
 WebInspector.TabBarItem = class TabBarItem extends WebInspector.Object
 {
-    constructor(image, title, pinned, representedObject)
+    constructor(image, title, representedObject)
     {
         super();
 
@@ -35,32 +36,15 @@ WebInspector.TabBarItem = class TabBarItem extends WebInspector.Object
         this._element.classList.add(WebInspector.TabBarItem.StyleClassName);
         this._element.setAttribute("role", "tab");
         this._element.tabIndex = 0;
-        if (pinned)
-            this._element.classList.add("pinned");
         this._element[WebInspector.TabBarItem.ElementReferenceSymbol] = this;
 
-        if (!pinned) {
-            this._closeButtonElement = document.createElement("div");
-            this._closeButtonElement.classList.add(WebInspector.TabBarItem.CloseButtonStyleClassName);
-            this._closeButtonElement.title = WebInspector.UIString("Click to close this tab");
-            this._element.appendChild(this._closeButtonElement);
-
-            var flexSpaceElement = document.createElement("div");
-            flexSpaceElement.classList.add("flex-space");
-            this._element.appendChild(flexSpaceElement);
-
-            this._element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this));
-        }
+        this._element.createChild("div", "flex-space");
 
         this._iconElement = document.createElement("img");
         this._iconElement.classList.add("icon");
         this._element.appendChild(this._iconElement);
 
-        if (!pinned) {
-            var flexSpaceElement = document.createElement("div");
-            flexSpaceElement.classList.add("flex-space");
-            this._element.appendChild(flexSpaceElement);
-        }
+        this._element.createChild("div", "flex-space");
 
         this.title = title;
         this.image = image;
@@ -69,30 +53,13 @@ WebInspector.TabBarItem = class TabBarItem extends WebInspector.Object
 
     // Public
 
-    get element()
-    {
-        return this._element;
-    }
-
-    get representedObject()
-    {
-        return this._representedObject;
-    }
-
-    set representedObject(representedObject)
-    {
-        this._representedObject = representedObject || null;
-    }
+    get element() { return this._element; }
 
-    get parentTabBar()
-    {
-        return this._parentTabBar;
-    }
+    get representedObject() { return this._representedObject; }
+    set representedObject(representedObject) { this._representedObject = representedObject || null; }
 
-    set parentTabBar(tabBar)
-    {
-        this._parentTabBar = tabBar || null;
-    }
+    get parentTabBar() { return this._parentTabBar; }
+    set parentTabBar(tabBar){ this._parentTabBar = tabBar || null; }
 
     get selected()
     {
@@ -129,76 +96,11 @@ WebInspector.TabBarItem = class TabBarItem extends WebInspector.Object
         this._element.classList.toggle("default-tab", isDefaultTab);
     }
 
-    get pinned()
-    {
-        return this._element.classList.contains("pinned");
-    }
-
-    get image()
-    {
-        return this._iconElement.src;
-    }
-
-    set image(url)
-    {
-        this._iconElement.src = url || "";
-    }
-
-    get title()
-    {
-        return this._element.title || "";
-    }
-
-    set title(title)
-    {
-        if (title && !this.pinned) {
-            this._titleElement = document.createElement("span");
-            this._titleElement.classList.add("title");
-
-            this._titleContentElement = document.createElement("span");
-            this._titleContentElement.classList.add("content");
-            this._titleElement.appendChild(this._titleContentElement);
-
-            this._titleContentElement.textContent = title;
-
-            this._element.insertBefore(this._titleElement, this._element.lastChild);
-        } else {
-            if (this._titleElement)
-                this._titleElement.remove();
-
-            this._titleContentElement = null;
-            this._titleElement = null;
-        }
-
-        this._element.title = title || "";
-    }
-
-    // Private
+    get image() { return this._iconElement.src; }
+    set image(url) { this._iconElement.src = url || ""; }
 
-    _handleContextMenuEvent(event)
-    {
-        if (!this._parentTabBar)
-            return;
-
-        let closeTab = () => {
-            this._parentTabBar.removeTabBarItem(this);
-        };
-
-        let closeOtherTabs = () => {
-            let tabBarItems = this._parentTabBar.tabBarItems;
-            for (let i = tabBarItems.length - 1; i >= 0; --i) {
-                let item = tabBarItems[i];
-                if (item === this || item.pinned)
-                    continue;
-                this._parentTabBar.removeTabBarItem(item);
-            }
-        };
-
-        let hasOtherNonPinnedTabs = this._parentTabBar.tabBarItems.some((item) => item !== this && !item.pinned);
-        let contextMenu = WebInspector.ContextMenu.createFromEvent(event);
-        contextMenu.appendItem(WebInspector.UIString("Close Tab"), closeTab, this.isDefaultTab);
-        contextMenu.appendItem(WebInspector.UIString("Close Other Tabs"), closeOtherTabs, !hasOtherNonPinnedTabs);
-    }
+    get title() { return this._element.title || ""; }
+    set title(title) { this._element.title = title || ""; }
 };
 
 WebInspector.TabBarItem.StyleClassName = "item";
index 4ee6cf7..8ce1852 100644 (file)
@@ -53,7 +53,7 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.View
         let showPreviousTab = () => { this._showPreviousTab(); };
         let closeCurrentTab = () => {
             let selectedTabBarItem = this._tabBar.selectedTabBarItem;
-            if (this._tabBar.tabBarItems.length > 2 || !selectedTabBarItem.isDefaultTab)
+            if (this._tabBar.tabBarItems.length > 3 || !selectedTabBarItem.isDefaultTab)
                 this._tabBar.removeTabBarItem(selectedTabBarItem);
         };
 
@@ -69,8 +69,6 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.View
         this._showPreviousTabKeyboardShortcut3 = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl | WebInspector.KeyboardShortcut.Modifier.Shift, WebInspector.KeyboardShortcut.Key.Left, this._showPreviousTabCheckingForEditableField.bind(this));
         this._showPreviousTabKeyboardShortcut3.implicitlyPreventsDefault = false;
 
-        this._tabBar.newTabItem = new WebInspector.TabBarItem("Images/NewTabPlus.svg", WebInspector.UIString("Create a new tab"), true);
-
         this._tabBar.addEventListener(WebInspector.TabBar.Event.TabBarItemSelected, this._tabBarItemSelected, this);
         this._tabBar.addEventListener(WebInspector.TabBar.Event.TabBarItemRemoved, this._tabBarItemRemoved, this);
 
@@ -129,7 +127,7 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.View
         if (!(tabContentView instanceof WebInspector.TabContentView))
             return false;
 
-        var tabBarItem = tabContentView.tabBarItem;
+        let tabBarItem = tabContentView.tabBarItem;
 
         console.assert(tabBarItem instanceof WebInspector.TabBarItem);
         if (!(tabBarItem instanceof WebInspector.TabBarItem))
@@ -155,7 +153,7 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.View
         else
             this._tabBar.addTabBarItem(tabBarItem, doNotAnimate);
 
-        console.assert(this._recentTabContentViews.length === this._tabBar.tabBarItems.length - (this._tabBar.newTabItem ? 1 : 0));
+        console.assert(this._recentTabContentViews.length === this._tabBar.normalTabCount);
         console.assert(!this.selectedTabContentView || this.selectedTabContentView === this._recentTabContentViews[0]);
 
         return true;
@@ -193,7 +191,7 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.View
 
         this._tabBar.removeTabBarItem(tabContentView.tabBarItem, doNotAnimate);
 
-        console.assert(this._recentTabContentViews.length === this._tabBar.tabBarItems.length - (this._tabBar.newTabItem ? 1 : 0));
+        console.assert(this._recentTabContentViews.length === this._tabBar.normalTabCount);
         console.assert(!this.selectedTabContentView || this.selectedTabContentView === this._recentTabContentViews[0]);
 
         return true;
@@ -214,17 +212,20 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.View
 
     _tabBarItemSelected(event)
     {
-        var tabContentView = this._tabBar.selectedTabBarItem ? this._tabBar.selectedTabBarItem.representedObject : null;
+        let tabContentView = this._tabBar.selectedTabBarItem ? this._tabBar.selectedTabBarItem.representedObject : null;
 
         if (tabContentView) {
-            this._recentTabContentViews.remove(tabContentView);
-            this._recentTabContentViews.unshift(tabContentView);
+            let isSettingsTab = tabContentView instanceof WebInspector.SettingsTabContentView;
+            if (!isSettingsTab) {
+                this._recentTabContentViews.remove(tabContentView);
+                this._recentTabContentViews.unshift(tabContentView);
+            }
 
             this._contentViewContainer.showContentView(tabContentView);
 
             console.assert(this.selectedTabContentView);
-            console.assert(this._recentTabContentViews.length === this._tabBar.tabBarItems.length - (this._tabBar.newTabItem ? 1 : 0));
-            console.assert(this.selectedTabContentView === this._recentTabContentViews[0]);
+            console.assert(this._recentTabContentViews.length === this._tabBar.normalTabCount);
+            console.assert(this.selectedTabContentView === this._recentTabContentViews[0] || isSettingsTab);
         } else {
             this._contentViewContainer.closeAllContentViews();
 
@@ -245,7 +246,7 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.View
 
     _tabBarItemRemoved(event)
     {
-        var tabContentView = event.data.tabBarItem.representedObject;
+        let tabContentView = event.data.tabBarItem.representedObject;
 
         console.assert(tabContentView);
         if (!tabContentView)
@@ -256,7 +257,7 @@ WebInspector.TabBrowser = class TabBrowser extends WebInspector.View
 
         tabContentView.parentTabBrowser = null;
 
-        console.assert(this._recentTabContentViews.length === this._tabBar.tabBarItems.length - (this._tabBar.newTabItem ? 1 : 0));
+        console.assert(this._recentTabContentViews.length === this._tabBar.normalTabCount);
         console.assert(!this.selectedTabContentView || this.selectedTabContentView === this._recentTabContentViews[0]);
     }
 
index ea1b27e..3587048 100644 (file)
@@ -126,6 +126,8 @@ WebInspector.TabContentView = class TabContentView extends WebInspector.ContentV
 
     shown()
     {
+        super.shown();
+
         if (this._shouldRestoreStateWhenShown)
             this.restoreStateFromCookie(WebInspector.StateRestorationType.Delayed);
     }
index 51d1cf3..01fd086 100644 (file)
@@ -31,18 +31,39 @@ WebInspector.TextEditor = class TextEditor extends WebInspector.View
 
         this.element.classList.add("text-editor", WebInspector.SyntaxHighlightedStyleClassName);
 
-        // FIXME: <https://webkit.org/b/149120> Web Inspector: Preferences for Text Editor behavior
         this._codeMirror = WebInspector.CodeMirrorEditor.create(this.element, {
             readOnly: true,
-            indentWithTabs: true,
-            indentUnit: 4,
+            indentWithTabs: WebInspector.settings.indentWithTabs.value,
+            indentUnit: WebInspector.settings.indentUnit.value,
+            tabSize: WebInspector.settings.tabSize.value,
             lineNumbers: true,
-            lineWrapping: false,
+            lineWrapping: WebInspector.settings.enableLineWrapping.value,
             matchBrackets: true,
             autoCloseBrackets: true,
+            showWhitespaceCharacters: WebInspector.settings.showWhitespaceCharacters.value,
             styleSelectedText: true,
         });
 
+        WebInspector.settings.indentWithTabs.addEventListener(WebInspector.Setting.Event.Changed, (event) => {
+            this._codeMirror.setOption("indentWithTabs", WebInspector.settings.indentWithTabs.value);
+        });
+
+        WebInspector.settings.indentUnit.addEventListener(WebInspector.Setting.Event.Changed, (event) => {
+            this._codeMirror.setOption("indentUnit", WebInspector.settings.indentUnit.value);
+        });
+
+        WebInspector.settings.tabSize.addEventListener(WebInspector.Setting.Event.Changed, (event) => {
+            this._codeMirror.setOption("tabSize", WebInspector.settings.tabSize.value);
+        });
+
+        WebInspector.settings.enableLineWrapping.addEventListener(WebInspector.Setting.Event.Changed, (event) => {
+            this._codeMirror.setOption("lineWrapping", WebInspector.settings.enableLineWrapping.value);
+        });
+
+        WebInspector.settings.showWhitespaceCharacters.addEventListener(WebInspector.Setting.Event.Changed, (event) => {
+            this._codeMirror.setOption("showWhitespaceCharacters", WebInspector.settings.showWhitespaceCharacters.value);
+        });
+
         this._codeMirror.on("change", this._contentChanged.bind(this));
         this._codeMirror.on("gutterClick", this._gutterMouseDown.bind(this));
         this._codeMirror.on("gutterContextMenu", this._gutterContextMenu.bind(this));
@@ -532,6 +553,15 @@ WebInspector.TextEditor = class TextEditor extends WebInspector.View
         this._visible = false;
     }
 
+    close()
+    {
+        WebInspector.settings.indentWithTabs.removeEventListener(null, null, this);
+        WebInspector.settings.indentUnit.removeEventListener(null, null, this);
+        WebInspector.settings.tabSize.removeEventListener(null, null, this);
+        WebInspector.settings.enableLineWrapping.removeEventListener(null, null, this);
+        WebInspector.settings.showWhitespaceCharacters.removeEventListener(null, null, this);
+    }
+
     setBreakpointInfoForLineAndColumn(lineNumber, columnNumber, breakpointInfo)
     {
         if (this._ignoreSetBreakpointInfoCalls)
@@ -807,10 +837,9 @@ WebInspector.TextEditor = class TextEditor extends WebInspector.View
 
     _startWorkerPrettyPrint(beforePrettyPrintState, callback)
     {
-        // <rdar://problem/10593948> Provide a way to change the tab width in the Web Inspector
-        let indentString = "    ";
         let sourceText = this._codeMirror.getValue();
-        let includeSourceMapData = true;
+        let indentString = WebInspector.indentString();
+        const includeSourceMapData = true;
 
         // FIXME: Properly pass if this is a module or script.
         const isModule = false;
@@ -828,8 +857,7 @@ WebInspector.TextEditor = class TextEditor extends WebInspector.View
 
     _startCodeMirrorPrettyPrint(beforePrettyPrintState, callback)
     {
-        // <rdar://problem/10593948> Provide a way to change the tab width in the Web Inspector
-        let indentString = "    ";
+        let indentString = WebInspector.indentString();
         let start = {line: 0, ch: 0};
         let end = {line: this._codeMirror.lineCount() - 1};
         let builder = new FormatterContentBuilder(indentString);
index 12ccb41..83500fd 100644 (file)
@@ -174,6 +174,8 @@ WebInspector.TimelineRecordingContentView = class TimelineRecordingContentView e
 
     shown()
     {
+        super.shown();
+
         this._timelineOverview.shown();
         this._timelineContentBrowser.shown();
         this._clearTimelineNavigationItem.enabled = !this._recording.readonly && !isNaN(this._recording.startTime);
@@ -186,6 +188,8 @@ WebInspector.TimelineRecordingContentView = class TimelineRecordingContentView e
 
     hidden()
     {
+        super.hidden();
+
         this._timelineOverview.hidden();
         this._timelineContentBrowser.hidden();
 
@@ -195,6 +199,8 @@ WebInspector.TimelineRecordingContentView = class TimelineRecordingContentView e
 
     closed()
     {
+        super.closed();
+
         this._timelineContentBrowser.contentViewContainer.closeAllContentViews();
 
         this._recording.removeEventListener(null, null, this);
index ca61676..95dfffb 100644 (file)
@@ -28,7 +28,7 @@ WebInspector.TimelineTabContentView = class TimelineTabContentView extends WebIn
     constructor(identifier)
     {
         let {image, title} = WebInspector.TimelineTabContentView.tabInfo();
-        let tabBarItem = new WebInspector.TabBarItem(image, title);
+        let tabBarItem = new WebInspector.GeneralTabBarItem(image, title);
         let detailsSidebarPanels = [WebInspector.resourceDetailsSidebarPanel, WebInspector.probeDetailsSidebarPanel];
 
         super(identifier || "timeline", "timeline", tabBarItem, null, detailsSidebarPanels);
index 30047c8..85276dd 100644 (file)
@@ -122,8 +122,7 @@ WebInspector.VisualStylePropertyEditor = class VisualStylePropertyEditor extends
 
         styleText = styleText || "";
 
-        // FIXME: <rdar://problem/10593948> Provide a way to change the tab width in the Web Inspector
-        let linePrefixText = "    ";
+        let linePrefixText = WebInspector.indentString();
         let lineSuffixWhitespace = "\n";
         let trimmedText = styleText.trimRight();
         let textHasNewlines = trimmedText.includes("\n");