From 670f3e4946e17a5fde9fcbdb5d73f025c6360ff7 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 24 Sep 2014 19:42:36 -0600 Subject: [PATCH] Add WorkspaceElement --- spec/package-manager-spec.coffee | 2 +- spec/workspace-view-spec.coffee | 2 + src/editor-view.coffee | 1 + src/pane-container-element.coffee | 3 +- src/workspace-element.coffee | 153 ++++++++++++++++++++++++++++++ src/workspace-view.coffee | 128 ++----------------------- src/workspace.coffee | 15 ++- 7 files changed, 178 insertions(+), 126 deletions(-) create mode 100644 src/workspace-element.coffee diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index bb1f1f048..f7c3084f4 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -3,7 +3,7 @@ Package = require '../src/package' describe "PackageManager", -> beforeEach -> - atom.workspaceView = new WorkspaceView + atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView describe "::loadPackage(name)", -> it "continues if the package has an invalid package.json", -> diff --git a/spec/workspace-view-spec.coffee b/spec/workspace-view-spec.coffee index b738349c5..4c76532f5 100644 --- a/spec/workspace-view-spec.coffee +++ b/spec/workspace-view-spec.coffee @@ -26,10 +26,12 @@ describe "WorkspaceView", -> simulateReload = -> workspaceState = atom.workspace.serialize() projectState = atom.project.serialize() + atom.workspaceView.debugId = 'initial' atom.workspaceView.remove() atom.project = atom.deserializers.deserialize(projectState) atom.workspace = Workspace.deserialize(workspaceState) atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView + atom.workspaceView.debugId = 'second' atom.workspaceView.attachToDom() describe "when the serialized WorkspaceView has an unsaved buffer", -> diff --git a/src/editor-view.coffee b/src/editor-view.coffee index b96d523b3..3c9d8623b 100644 --- a/src/editor-view.coffee +++ b/src/editor-view.coffee @@ -208,6 +208,7 @@ class EditorView extends View beforeRemove: -> return unless @attached @attached = false + debugger unless @component?.isMounted() @unmountComponent() @editor.destroy() @trigger 'editor:detached', this diff --git a/src/pane-container-element.coffee b/src/pane-container-element.coffee index c76a81508..cdde59f90 100644 --- a/src/pane-container-element.coffee +++ b/src/pane-container-element.coffee @@ -1,6 +1,6 @@ {CompositeDisposable} = require 'event-kit' {callAttachHooks} = require './space-pen-extensions' -PaneContainerView = require './pane-container-view' +PaneContainerView = null _ = require 'underscore-plus' module.exports = @@ -8,6 +8,7 @@ class PaneContainerElement extends HTMLElement createdCallback: -> @subscriptions = new CompositeDisposable @classList.add 'panes' + PaneContainerView ?= require './pane-container-view' @__spacePenView = new PaneContainerView(this) setModel: (@model) -> diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee new file mode 100644 index 000000000..cb1f02567 --- /dev/null +++ b/src/workspace-element.coffee @@ -0,0 +1,153 @@ +ipc = require 'ipc' +path = require 'path' +{Disposable, CompositeDisposable} = require 'event-kit' +Grim = require 'grim' +scrollbarStyle = require 'scrollbar-style' +{callAttachHooks} = require 'space-pen' +WorkspaceView = null + +module.exports = +class WorkspaceElement extends HTMLElement + createdCallback: -> + @subscriptions = new CompositeDisposable + atom.commands.setRootNode(this) + @initializeContent() + @observeScrollbarStyle() + @observeTextEditorFontConfig() + @createSpacePenShim() + + attachedCallback: -> + callAttachHooks(this) + @focus() + + detachedCallback: -> + @model.destroy() + + initializeContent: -> + @classList.add 'workspace' + @setAttribute 'tabindex', -1 + + + @verticalAxis = document.createElement('div') + @verticalAxis.classList.add('vertical') + + @horizontalAxis = document.createElement('div') + @horizontalAxis.classList.add('horizontal') + @horizontalAxis.appendChild(@verticalAxis) + + @appendChild(@horizontalAxis) + + observeScrollbarStyle: -> + @subscriptions.add scrollbarStyle.onValue (style) => + switch style + when 'legacy' + @classList.remove('scrollbars-visible-when-scrolling') + @classList.add("scrollbars-visible-always") + when 'overlay' + @classList.remove('scrollbars-visible-always') + @classList.add("scrollbars-visible-when-scrolling") + + observeTextEditorFontConfig: -> + @subscriptions.add atom.config.observe 'editor.fontSize', @setTextEditorFontSize + @subscriptions.add atom.config.observe 'editor.fontFamily', @setTextEditorFontFamily + @subscriptions.add atom.config.observe 'editor.lineHeight', @setTextEditorLineHeight + + createSpacePenShim: -> + WorkspaceView ?= require './workspace-view' + @__spacePenView = new WorkspaceView(this) + + getModel: -> @model + + setModel: (@model) -> + @paneContainer = @model.getView(@model.paneContainer) + @verticalAxis.appendChild(@paneContainer) + + @addEventListener 'focus', @handleFocus.bind(this) + handleWindowFocus = @handleWindowFocus.bind(this) + window.addEventListener 'focus', handleWindowFocus + @subscriptions.add(new Disposable => window.removeEventListener 'focus', handleWindowFocus) + + @__spacePenView.setModel(@model) + + # Essential: Focus the pane directly above the active pane. + focusPaneViewAbove: -> @panes.focusPaneViewAbove() + + # Essential: Focus the pane directly below the active pane. + focusPaneViewBelow: -> @panes.focusPaneViewBelow() + + # Essential: Focus the pane directly to the left of the active pane. + focusPaneViewOnLeft: -> @panes.focusPaneViewOnLeft() + + # Essential: Focus the pane directly to the right of the active pane. + focusPaneViewOnRight: -> @panes.focusPaneViewOnRight() + + ### + Section: Private + ### + + setTextEditorFontSize: (fontSize) -> + atom.themes.updateGlobalEditorStyle('font-size', fontSize + 'px') + + setTextEditorFontFamily: (fontFamily) -> + atom.themes.updateGlobalEditorStyle('font-family', fontFamily) + + setTextEditorLineHeight: (lineHeight) -> + atom.themes.updateGlobalEditorStyle('line-height', lineHeight) + + handleFocus: (event) -> + @model.getActivePane().activate() + + handleWindowFocus: (event) -> + @handleFocus(event) if document.activeElement is document.body + +if process.platform is 'darwin' + atom.commands.add '.workspace', 'window:install-shell-commands', -> @getModel().installShellCommands() + +atom.commands.add '.workspace', + 'window:increase-font-size': -> @getModel().increaseFontSize() + 'window:decrease-font-size': -> @getModel().decreaseFontSize() + 'window:reset-font-size': -> @getModel().resetFontSize() + 'application:about': -> ipc.send('command', 'application:about') + 'application:run-all-specs': -> ipc.send('command', 'application:run-all-specs') + 'application:run-benchmarks': -> ipc.send('command', 'application:run-benchmarks') + 'application:show-settings': -> ipc.send('command', 'application:show-settings') + 'application:quit': -> ipc.send('command', 'application:quit') + 'application:hide': -> ipc.send('command', 'application:hide') + 'application:hide-other-applications': -> ipc.send('command', 'application:hide-other-applications') + 'application:install-update': -> ipc.send('command', 'application:install-update') + 'application:unhide-all-applications': -> ipc.send('command', 'application:unhide-all-applications') + 'application:new-window': -> ipc.send('command', 'application:new-window') + 'application:new-file': -> ipc.send('command', 'application:new-file') + 'application:open': -> ipc.send('command', 'application:open') + 'application:open-file': -> ipc.send('command', 'application:open-file') + 'application:open-folder': -> ipc.send('command', 'application:open-folder') + 'application:open-dev': -> ipc.send('command', 'application:open-dev') + 'application:open-safe': -> ipc.send('command', 'application:open-safe') + 'application:minimize': -> ipc.send('command', 'application:minimize') + 'application:zoom': -> ipc.send('command', 'application:zoom') + 'application:bring-all-windows-to-front': -> ipc.send('command', 'application:bring-all-windows-to-front') + 'application:open-your-config': -> ipc.send('command', 'application:open-your-config') + 'application:open-your-init-script': -> ipc.send('command', 'application:open-your-init-script') + 'application:open-your-keymap': -> ipc.send('command', 'application:open-your-keymap') + 'application:open-your-snippets': -> ipc.send('command', 'application:open-your-snippets') + 'application:open-your-stylesheet': -> ipc.send('command', 'application:open-your-stylesheet') + 'application:open-license': -> @getModel().openLicense() + 'window:run-package-specs': -> ipc.send('run-package-specs', path.join(atom.project.getPath(), 'spec')) + 'window:focus-next-pane': -> @getModel().activateNextPane() + 'window:focus-previous-pane': -> @getModel().activatePreviousPane() + 'window:focus-pane-above': -> @focusPaneViewAbove() + 'window:focus-pane-below': -> @focusPaneViewBelow() + 'window:focus-pane-on-left': -> @focusPaneViewOnLeft() + 'window:focus-pane-on-right': -> @focusPaneViewOnRight() + 'window:save-all': -> @getModel().saveAll() + 'window:toggle-invisibles': -> atom.config.toggle("editor.showInvisibles") + 'window:log-deprecation-warnings': -> Grim.logDeprecationWarnings() + 'window:toggle-auto-indent': -> atom.config.toggle("editor.autoIndent") + 'pane:reopen-closed-item': -> @getModel().reopenItem() + 'core:close': -> @getModel().destroyActivePaneItemOrEmptyPane() + 'core:save': -> @getModel().saveActivePaneItem() + 'core:save-as': -> @getModel().saveActivePaneItemAs() + +module.exports = WorkspaceElement = document.registerElement 'atom-workspace', + prototype: WorkspaceElement.prototype + extends: 'div' diff --git a/src/workspace-view.coffee b/src/workspace-view.coffee index 7c0a9be79..3e7b82421 100644 --- a/src/workspace-view.coffee +++ b/src/workspace-view.coffee @@ -7,16 +7,10 @@ Delegator = require 'delegato' scrollbarStyle = require 'scrollbar-style' {$, $$, View} = require './space-pen-extensions' fs = require 'fs-plus' -Workspace = require './workspace' PaneView = require './pane-view' PaneContainerView = require './pane-container-view' Editor = require './editor' -atom.commands.add '.workspace', - 'window:increase-font-size': -> @getModel().increaseFontSize() - 'window:decrease-font-size': -> @getModel().decreaseFontSize() - 'window:reset-font-size': -> @getModel().resetFontSize() - # Extended: The top-level view for the entire window. An instance of this class is # available via the `atom.workspaceView` global. # @@ -62,8 +56,6 @@ class WorkspaceView extends View 'saveActivePaneItem', 'saveActivePaneItemAs', 'saveAll', 'destroyActivePaneItem', 'destroyActivePane', 'increaseFontSize', 'decreaseFontSize', toProperty: 'model' - @version: 4 - @configDefaults: ignoredNames: [".git", ".hg", ".svn", ".DS_Store", "Thumbs.db"] excludeVcsIgnoredPaths: true @@ -73,91 +65,18 @@ class WorkspaceView extends View audioBeep: true destroyEmptyPanes: true - @content: -> - @div class: 'workspace', tabindex: -1, => - @div class: 'horizontal', outlet: 'horizontal', => - @div class: 'vertical', outlet: 'vertical', => - @div class: 'panes', outlet: 'panes' - - initialize: (model) -> - @model = model ? atom.workspace ? new Workspace unless @model? - @element.getModel = -> model - atom.commands.setRootNode(@[0]) - - panes = @model.getView(@model.paneContainer).__spacePenView - @panes.replaceWith(panes) - @panes = panes + constructor: (@element) -> + super + @deprecatedViewEvents() + setModel: (@model) -> + @horizontal = @find('.horizontal') + @vertical = @find('.vertical') + @panes = @find('.panes').view() @subscribe @model.onDidOpen => @trigger 'uri-opened' - @subscribe scrollbarStyle, (style) => - @removeClass('scrollbars-visible-always scrollbars-visible-when-scrolling') - switch style - when 'legacy' - @addClass("scrollbars-visible-always") - when 'overlay' - @addClass("scrollbars-visible-when-scrolling") - - - @subscribe atom.config.observe 'editor.fontSize', @setEditorFontSize - @subscribe atom.config.observe 'editor.fontFamily', @setEditorFontFamily - @subscribe atom.config.observe 'editor.lineHeight', @setEditorLineHeight - - @on 'focus', (e) => @handleFocus(e) - @subscribe $(window), 'focus', (e) => - @handleFocus(e) if document.activeElement is document.body - - @command 'application:about', -> ipc.send('command', 'application:about') - @command 'application:run-all-specs', -> ipc.send('command', 'application:run-all-specs') - @command 'application:run-benchmarks', -> ipc.send('command', 'application:run-benchmarks') - @command 'application:show-settings', -> ipc.send('command', 'application:show-settings') - @command 'application:quit', -> ipc.send('command', 'application:quit') - @command 'application:hide', -> ipc.send('command', 'application:hide') - @command 'application:hide-other-applications', -> ipc.send('command', 'application:hide-other-applications') - @command 'application:install-update', -> ipc.send('command', 'application:install-update') - @command 'application:unhide-all-applications', -> ipc.send('command', 'application:unhide-all-applications') - @command 'application:new-window', -> ipc.send('command', 'application:new-window') - @command 'application:new-file', -> ipc.send('command', 'application:new-file') - @command 'application:open', -> ipc.send('command', 'application:open') - @command 'application:open-file', -> ipc.send('command', 'application:open-file') - @command 'application:open-folder', -> ipc.send('command', 'application:open-folder') - @command 'application:open-dev', -> ipc.send('command', 'application:open-dev') - @command 'application:open-safe', -> ipc.send('command', 'application:open-safe') - @command 'application:minimize', -> ipc.send('command', 'application:minimize') - @command 'application:zoom', -> ipc.send('command', 'application:zoom') - @command 'application:bring-all-windows-to-front', -> ipc.send('command', 'application:bring-all-windows-to-front') - @command 'application:open-your-config', -> ipc.send('command', 'application:open-your-config') - @command 'application:open-your-init-script', -> ipc.send('command', 'application:open-your-init-script') - @command 'application:open-your-keymap', -> ipc.send('command', 'application:open-your-keymap') - @command 'application:open-your-snippets', -> ipc.send('command', 'application:open-your-snippets') - @command 'application:open-your-stylesheet', -> ipc.send('command', 'application:open-your-stylesheet') - @command 'application:open-license', => @model.openLicense() - - if process.platform is 'darwin' - @command 'window:install-shell-commands', => @getModel().installShellCommands() - - @command 'window:run-package-specs', -> ipc.send('run-package-specs', path.join(atom.project.getPath(), 'spec')) - - @command 'window:focus-next-pane', => @focusNextPaneView() - @command 'window:focus-previous-pane', => @focusPreviousPaneView() - @command 'window:focus-pane-above', => @focusPaneViewAbove() - @command 'window:focus-pane-below', => @focusPaneViewBelow() - @command 'window:focus-pane-on-left', => @focusPaneViewOnLeft() - @command 'window:focus-pane-on-right', => @focusPaneViewOnRight() - @command 'window:save-all', => @saveAll() - @command 'window:toggle-invisibles', -> atom.config.toggle("editor.showInvisibles") - @command 'window:log-deprecation-warnings', -> logDeprecationWarnings() - - @command 'window:toggle-auto-indent', -> - atom.config.toggle("editor.autoIndent") - - @command 'pane:reopen-closed-item', => @getModel().reopenItem() - - @command 'core:close', => if @getModel().getActivePaneItem()? then @destroyActivePaneItem() else @destroyActivePane() - @command 'core:save', => @saveActivePaneItem() - @command 'core:save-as', => @saveActivePaneItemAs() - - @deprecatedViewEvents() + beforeRemove: -> + @model?.destroy() ### Section: Accessing the Workspace Model @@ -309,35 +228,6 @@ class WorkspaceView extends View Section: Private ### - afterAttach: (onDom) -> - @focus() if onDom - - # Called by SpacePen - beforeRemove: -> - @model.destroy() - - setEditorFontSize: (fontSize) -> - atom.themes.updateGlobalEditorStyle('font-size', fontSize + 'px') - - setEditorFontFamily: (fontFamily) -> - atom.themes.updateGlobalEditorStyle('font-family', fontFamily) - - setEditorLineHeight: (lineHeight) -> - atom.themes.updateGlobalEditorStyle('line-height', lineHeight) - - handleFocus: -> - if @getActivePaneView() - @getActivePaneView().focus() - false - else - focusableChild = @find("[tabindex=-1]:visible:first") - if focusableChild.length - focusableChild.focus() - false - else - $(document.body).focus() - true - # Prompts to save all unsaved items confirmClose: -> @model.confirmClose() diff --git a/src/workspace.coffee b/src/workspace.coffee index d0356315d..ad30eea74 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -11,7 +11,7 @@ Editor = require './editor' PaneContainer = require './pane-container' Pane = require './pane' ViewRegistry = require './view-registry' -WorkspaceView = null +WorkspaceElement = require './workspace-element' # Essential: Represents the state of the user interface for the entire window. # An instance of this class is available via the `atom.workspace` global. @@ -58,6 +58,10 @@ class Workspace extends Model when 'atom://.atom/init-script' @open(atom.getUserInitScriptPath()) + @addViewProvider + modelConstructor: Workspace + viewConstructor: WorkspaceElement + # Called by the Serializable mixin during deserialization deserializeParams: (params) -> for packageName in params.packagesWithActiveGrammars ? [] @@ -74,9 +78,6 @@ class Workspace extends Model fullScreen: atom.isFullScreen() packagesWithActiveGrammars: @getPackageNamesWithActiveGrammars() - getViewClass: -> - WorkspaceView ?= require './workspace-view' - getPackageNamesWithActiveGrammars: -> packageNames = [] addGrammar = ({includedGrammarScopes, packageName}={}) -> @@ -152,7 +153,7 @@ class Workspace extends Model # Updates the application's title and proxy icon based on whichever file is # open. updateWindowTitle: => - if projectPath = atom.project.getPath() + if projectPath = atom.project?.getPath() if item = @getActivePaneItem() document.title = "#{item.getTitle?() ? 'untitled'} - #{projectPath}" atom.setRepresentedFilename(item.getPath?()) @@ -556,6 +557,10 @@ class Workspace extends Model destroyActivePane: -> @activePane?.destroy() + # Destroy the active pane item or the active pane if it is empty. + destroyActivePaneItemOrEmptyPane: -> + if @getActivePaneItem()? then @destroyActivePaneItem() else @destroyActivePane() + # Increase the editor font size by 1px. increaseFontSize: -> atom.config.set("editor.fontSize", atom.config.get("editor.fontSize") + 1)