mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2025-01-08 16:19:17 +03:00
Merge pull request #3633 from atom/ns-workspace-custom-elements
Use custom elements for workspace views
This commit is contained in:
commit
4c124b8174
@ -55,7 +55,7 @@
|
||||
"season": "^1.0.2",
|
||||
"semver": "1.1.4",
|
||||
"serializable": "^1",
|
||||
"space-pen": "3.4.7",
|
||||
"space-pen": "3.6.1",
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^3.2.6",
|
||||
"theorist": "^1.0.2",
|
||||
@ -74,11 +74,11 @@
|
||||
"archive-view": "0.37.0",
|
||||
"autocomplete": "0.32.0",
|
||||
"autoflow": "0.18.0",
|
||||
"autosave": "0.17.0",
|
||||
"autosave": "0.18.0",
|
||||
"background-tips": "0.17.0",
|
||||
"bookmarks": "0.28.0",
|
||||
"bracket-matcher": "0.61.0",
|
||||
"command-palette": "0.26.0",
|
||||
"command-palette": "0.27.0",
|
||||
"deprecation-cop": "0.10.0",
|
||||
"dev-live-reload": "0.34.0",
|
||||
"exception-reporting": "0.20.0",
|
||||
@ -100,7 +100,7 @@
|
||||
"settings-view": "0.149.0",
|
||||
"snippets": "0.53.0",
|
||||
"spell-check": "0.42.0",
|
||||
"status-bar": "0.45.0",
|
||||
"status-bar": "0.46.0",
|
||||
"styleguide": "0.30.0",
|
||||
"symbols-view": "0.66.0",
|
||||
"tabs": "0.54.0",
|
||||
|
@ -20,7 +20,7 @@ describe "install(commandPath, callback)", ->
|
||||
|
||||
installDone = false
|
||||
installError = null
|
||||
installer.install commandFilePath, false, (error) ->
|
||||
installer.createSymlink commandFilePath, false, (error) ->
|
||||
installDone = true
|
||||
installError = error
|
||||
|
||||
|
@ -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", ->
|
||||
|
@ -115,3 +115,29 @@ describe "PaneContainer", ->
|
||||
pane3.addItems([new Object, new Object])
|
||||
|
||||
expect(observed).toEqual container.getPaneItems()
|
||||
|
||||
describe "::confirmClose()", ->
|
||||
[container, pane1, pane2] = []
|
||||
|
||||
beforeEach ->
|
||||
class TestItem
|
||||
shouldPromptToSave: -> true
|
||||
getUri: -> 'test'
|
||||
|
||||
container = new PaneContainer
|
||||
container.getRoot().splitRight()
|
||||
[pane1, pane2] = container.getPanes()
|
||||
pane1.addItem(new TestItem)
|
||||
pane2.addItem(new TestItem)
|
||||
|
||||
it "returns true if the user saves all modified files when prompted", ->
|
||||
spyOn(atom, "confirm").andReturn(0)
|
||||
saved = container.confirmClose()
|
||||
expect(saved).toBeTruthy()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "returns false if the user cancels saving any modified file", ->
|
||||
spyOn(atom, "confirm").andReturn(1)
|
||||
saved = container.confirmClose()
|
||||
expect(saved).toBeFalsy()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
@ -1,5 +1,6 @@
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
PaneContainerView = require '../src/pane-container-view'
|
||||
PaneView = require '../src/pane-view'
|
||||
{$, View, $$} = require 'atom'
|
||||
@ -18,7 +19,7 @@ describe "PaneContainerView", ->
|
||||
save: -> @saved = true
|
||||
isEqual: (other) -> @name is other?.name
|
||||
|
||||
container = new PaneContainerView
|
||||
container = atom.workspace.getView(atom.workspace.paneContainer).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(new TestView('1'))
|
||||
pane2 = pane1.splitRight(new TestView('2'))
|
||||
@ -70,32 +71,9 @@ describe "PaneContainerView", ->
|
||||
for item in pane.getItems()
|
||||
expect(item.saved).toBeTruthy()
|
||||
|
||||
describe ".confirmClose()", ->
|
||||
it "returns true after modified files are saved", ->
|
||||
pane1.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
pane2.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
spyOn(atom, "confirm").andReturn(0)
|
||||
|
||||
saved = container.confirmClose()
|
||||
|
||||
runs ->
|
||||
expect(saved).toBeTruthy()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "returns false if the user cancels saving", ->
|
||||
pane1.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
pane2.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
spyOn(atom, "confirm").andReturn(1)
|
||||
|
||||
saved = container.confirmClose()
|
||||
|
||||
runs ->
|
||||
expect(saved).toBeFalsy()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
describe "serialization", ->
|
||||
it "can be serialized and deserialized, and correctly adjusts dimensions of deserialized panes after attach", ->
|
||||
newContainer = new PaneContainerView(container.model.testSerialization())
|
||||
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
|
||||
expect(newContainer.find('.pane-row > :contains(1)')).toExist()
|
||||
expect(newContainer.find('.pane-row > .pane-column > :contains(2)')).toExist()
|
||||
expect(newContainer.find('.pane-row > .pane-column > :contains(3)')).toExist()
|
||||
@ -111,14 +89,14 @@ describe "PaneContainerView", ->
|
||||
|
||||
describe "if the 'core.destroyEmptyPanes' config option is false (the default)", ->
|
||||
it "leaves the empty panes intact", ->
|
||||
newContainer = new PaneContainerView(container.model.testSerialization())
|
||||
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
|
||||
expect(newContainer.find('.pane-row > :contains(1)')).toExist()
|
||||
expect(newContainer.find('.pane-row > .pane-column > .pane').length).toBe 2
|
||||
|
||||
describe "if the 'core.destroyEmptyPanes' config option is true", ->
|
||||
it "removes empty panes on deserialization", ->
|
||||
atom.config.set('core.destroyEmptyPanes', true)
|
||||
newContainer = new PaneContainerView(container.model.testSerialization())
|
||||
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
|
||||
expect(newContainer.find('.pane-row, .pane-column')).not.toExist()
|
||||
expect(newContainer.find('> :contains(1)')).toExist()
|
||||
|
||||
@ -131,7 +109,7 @@ describe "PaneContainerView", ->
|
||||
item2b = new TestView('2b')
|
||||
item3a = new TestView('3a')
|
||||
|
||||
container = new PaneContainerView
|
||||
container = atom.workspace.getView(new PaneContainer).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(item1a)
|
||||
container.attachToDom()
|
||||
@ -281,7 +259,7 @@ describe "PaneContainerView", ->
|
||||
# |7|8|9|
|
||||
# -------
|
||||
|
||||
container = new PaneContainerView
|
||||
container = atom.workspace.getView(new PaneContainer).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(new TestView('1'))
|
||||
pane4 = pane1.splitDown(new TestView('4'))
|
||||
|
@ -1,4 +1,4 @@
|
||||
PaneContainerView = require '../src/pane-container-view'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
PaneView = require '../src/pane-view'
|
||||
fs = require 'fs-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
@ -24,7 +24,7 @@ describe "PaneView", ->
|
||||
|
||||
beforeEach ->
|
||||
deserializerDisposable = atom.deserializers.add(TestView)
|
||||
container = new PaneContainerView
|
||||
container = atom.workspace.getView(new PaneContainer).__spacePenView
|
||||
containerModel = container.model
|
||||
view1 = new TestView(id: 'view-1', text: 'View 1')
|
||||
view2 = new TestView(id: 'view-2', text: 'View 2')
|
||||
@ -311,13 +311,13 @@ describe "PaneView", ->
|
||||
container.attachToDom()
|
||||
pane.focus()
|
||||
|
||||
container2 = new PaneContainerView(container.model.testSerialization())
|
||||
container2 = atom.workspace.getView(container.model.testSerialization()).__spacePenView
|
||||
pane2 = container2.getRoot()
|
||||
container2.attachToDom()
|
||||
expect(pane2).toMatchSelector(':has(:focus)')
|
||||
|
||||
$(document.activeElement).blur()
|
||||
container3 = new PaneContainerView(container.model.testSerialization())
|
||||
container3 = atom.workspace.getView(container.model.testSerialization()).__spacePenView
|
||||
pane3 = container3.getRoot()
|
||||
container3.attachToDom()
|
||||
expect(pane3).not.toMatchSelector(':has(:focus)')
|
||||
|
@ -29,12 +29,18 @@ atom.keymaps.loadBundledKeymaps()
|
||||
keyBindingsToRestore = atom.keymaps.getKeyBindings()
|
||||
commandsToRestore = atom.commands.getSnapshot()
|
||||
|
||||
$(window).on 'core:close', -> window.close()
|
||||
$(window).on 'beforeunload', ->
|
||||
window.addEventListener 'core:close', -> window.close()
|
||||
window.addEventListener 'beforeunload', ->
|
||||
atom.storeWindowDimensions()
|
||||
atom.saveSync()
|
||||
$('html,body').css('overflow', 'auto')
|
||||
|
||||
# Allow document.title to be assigned in specs without screwing up spec window title
|
||||
documentTitle = null
|
||||
Object.defineProperty document, 'title',
|
||||
get: -> documentTitle
|
||||
set: (title) -> documentTitle = title
|
||||
|
||||
jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions
|
||||
|
||||
if process.platform is 'win32' and process.env.JANKY_SHA1
|
||||
@ -61,6 +67,7 @@ isCoreSpec = specDirectory == fs.realpathSync(__dirname)
|
||||
beforeEach ->
|
||||
Grim.clearDeprecations() if isCoreSpec
|
||||
$.fx.off = true
|
||||
documentTitle = null
|
||||
projectPath = specProjectPath ? path.join(@specDirectory, 'fixtures')
|
||||
atom.project = new Project(paths: [projectPath])
|
||||
atom.workspace = new Workspace()
|
||||
@ -106,7 +113,7 @@ beforeEach ->
|
||||
spyOn(TextEditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
|
||||
TextEditorComponent.performSyncUpdates = true
|
||||
|
||||
spyOn(WorkspaceView.prototype, 'setTitle').andCallFake (@title) ->
|
||||
spyOn(atom, "setRepresentedFilename")
|
||||
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
|
||||
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
|
||||
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
|
||||
@ -351,7 +358,7 @@ $.fn.enableKeymap = ->
|
||||
not e.originalEvent.defaultPrevented
|
||||
|
||||
$.fn.attachToDom = ->
|
||||
@appendTo($('#jasmine-content'))
|
||||
@appendTo($('#jasmine-content')) unless @isOnDom()
|
||||
|
||||
$.fn.simulateDomAttachment = ->
|
||||
$('<html>').append(this)
|
||||
|
@ -63,9 +63,9 @@ describe "Window", ->
|
||||
beforeUnloadEvent = $.Event(new Event('beforeunload'))
|
||||
|
||||
describe "when pane items are are modified", ->
|
||||
it "prompts user to save and and calls workspaceView.confirmClose", ->
|
||||
it "prompts user to save and calls atom.workspace.confirmClose", ->
|
||||
editor = null
|
||||
spyOn(atom.workspaceView, 'confirmClose').andCallThrough()
|
||||
spyOn(atom.workspace, 'confirmClose').andCallThrough()
|
||||
spyOn(atom, "confirm").andReturn(2)
|
||||
|
||||
waitsForPromise ->
|
||||
@ -74,7 +74,7 @@ describe "Window", ->
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
expect(atom.workspaceView.confirmClose).toHaveBeenCalled()
|
||||
expect(atom.workspace.confirmClose).toHaveBeenCalled()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "prompts user to save and handler returns true if don't save", ->
|
||||
|
@ -1,3 +1,5 @@
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
Workspace = require '../src/workspace'
|
||||
{View} = require '../src/space-pen-extensions'
|
||||
|
||||
@ -369,3 +371,90 @@ describe "Workspace", ->
|
||||
workspace2 = Workspace.deserialize(state)
|
||||
expect(jsPackage.loadGrammarsSync.callCount).toBe 1
|
||||
expect(coffeePackage.loadGrammarsSync.callCount).toBe 1
|
||||
|
||||
describe "document.title", ->
|
||||
describe "when the project has no path", ->
|
||||
it "sets the title to 'untitled'", ->
|
||||
atom.project.setPath(undefined)
|
||||
expect(document.title).toBe 'untitled'
|
||||
|
||||
describe "when the project has a path", ->
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b')
|
||||
|
||||
describe "when there is an active pane item", ->
|
||||
it "sets the title to the pane item's title plus the project path", ->
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
console.log item.getTitle()
|
||||
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the title of the active pane item changes", ->
|
||||
it "updates the window title based on the item's new title", ->
|
||||
editor = atom.workspace.getActivePaneItem()
|
||||
editor.buffer.setPath(path.join(temp.dir, 'hi'))
|
||||
expect(document.title).toBe "#{editor.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the active pane's item changes", ->
|
||||
it "updates the title to the new item's title plus the project path", ->
|
||||
atom.workspace.getActivePane().activateNextItem()
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the last pane item is removed", ->
|
||||
it "updates the title to contain the project's path", ->
|
||||
atom.workspace.getActivePane().destroy()
|
||||
expect(atom.workspace.getActivePaneItem()).toBeUndefined()
|
||||
expect(document.title).toBe atom.project.getPaths()[0]
|
||||
|
||||
describe "when an inactive pane's item changes", ->
|
||||
it "does not update the title", ->
|
||||
pane = atom.workspace.getActivePane()
|
||||
pane.splitRight()
|
||||
initialTitle = document.title
|
||||
pane.activateNextItem()
|
||||
expect(document.title).toBe initialTitle
|
||||
|
||||
describe "when the workspace is deserialized", ->
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.workspace.open('a')
|
||||
|
||||
it "updates the title to contain the project's path", ->
|
||||
document.title = null
|
||||
console.log atom.workspace.getActivePaneItem()
|
||||
workspace2 = atom.workspace.testSerialization()
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
workspace2.destroy()
|
||||
|
||||
describe "document edited status", ->
|
||||
[item1, item2] = []
|
||||
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.workspace.open('a')
|
||||
waitsForPromise -> atom.workspace.open('b')
|
||||
runs ->
|
||||
[item1, item2] = atom.workspace.getPaneItems()
|
||||
spyOn(atom, 'setDocumentEdited')
|
||||
|
||||
it "calls atom.setDocumentEdited when the active item changes", ->
|
||||
expect(atom.workspace.getActivePaneItem()).toBe item2
|
||||
item1.insertText('a')
|
||||
expect(item1.isModified()).toBe true
|
||||
atom.workspace.getActivePane().activateNextItem()
|
||||
|
||||
expect(atom.setDocumentEdited).toHaveBeenCalledWith(true)
|
||||
|
||||
it "calls atom.setDocumentEdited when the active item's modified status changes", ->
|
||||
expect(atom.workspace.getActivePaneItem()).toBe item2
|
||||
item2.insertText('a')
|
||||
advanceClock(item2.getBuffer().getStoppedChangingDelay())
|
||||
|
||||
expect(item2.isModified()).toBe true
|
||||
expect(atom.setDocumentEdited).toHaveBeenCalledWith(true)
|
||||
|
||||
item2.undo()
|
||||
advanceClock(item2.getBuffer().getStoppedChangingDelay())
|
||||
|
||||
expect(item2.isModified()).toBe false
|
||||
expect(atom.setDocumentEdited).toHaveBeenCalledWith(false)
|
||||
|
@ -49,7 +49,7 @@ describe "WorkspaceView", ->
|
||||
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 2
|
||||
expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]
|
||||
expect(atom.workspaceView.title).toBe "untitled - #{atom.project.getPaths()[0]}"
|
||||
expect(document.title).toBe "untitled - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when there are open editors", ->
|
||||
it "constructs the view with the same panes", ->
|
||||
@ -106,7 +106,7 @@ describe "WorkspaceView", ->
|
||||
expect(editorView3).not.toHaveFocus()
|
||||
expect(editorView4).not.toHaveFocus()
|
||||
|
||||
expect(atom.workspaceView.title).toBe "#{path.basename(editorView2.getEditor().getPath())} - #{atom.project.getPaths()[0]}"
|
||||
expect(document.title).toBe "#{path.basename(editorView2.getEditor().getPath())} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "where there are no open editors", ->
|
||||
it "constructs the view with no open editors", ->
|
||||
@ -141,56 +141,6 @@ describe "WorkspaceView", ->
|
||||
atom.workspaceView.trigger(event)
|
||||
expect(commandHandler).toHaveBeenCalled()
|
||||
|
||||
describe "window title", ->
|
||||
describe "when the project has no path", ->
|
||||
it "sets the title to 'untitled'", ->
|
||||
atom.project.setPaths([])
|
||||
expect(atom.workspaceView.title).toBe 'untitled'
|
||||
|
||||
describe "when the project has a path", ->
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b')
|
||||
|
||||
describe "when there is an active pane item", ->
|
||||
it "sets the title to the pane item's title plus the project path", ->
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(atom.workspaceView.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the title of the active pane item changes", ->
|
||||
it "updates the window title based on the item's new title", ->
|
||||
editor = atom.workspace.getActivePaneItem()
|
||||
editor.buffer.setPath(path.join(temp.dir, 'hi'))
|
||||
expect(atom.workspaceView.title).toBe "#{editor.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the active pane's item changes", ->
|
||||
it "updates the title to the new item's title plus the project path", ->
|
||||
atom.workspaceView.getActivePaneView().activateNextItem()
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(atom.workspaceView.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
|
||||
describe "when the last pane item is removed", ->
|
||||
it "updates the title to contain the project's path", ->
|
||||
atom.workspaceView.getActivePaneView().remove()
|
||||
expect(atom.workspace.getActivePaneItem()).toBeUndefined()
|
||||
expect(atom.workspaceView.title).toBe atom.project.getPaths()[0]
|
||||
|
||||
describe "when an inactive pane's item changes", ->
|
||||
it "does not update the title", ->
|
||||
pane = atom.workspaceView.getActivePaneView()
|
||||
pane.splitRight()
|
||||
initialTitle = atom.workspaceView.title
|
||||
pane.activateNextItem()
|
||||
expect(atom.workspaceView.title).toBe initialTitle
|
||||
|
||||
describe "when the root view is deserialized", ->
|
||||
it "updates the title to contain the project's path", ->
|
||||
workspace2 = atom.workspace.testSerialization()
|
||||
workspaceView2 = workspace2.getView(workspace2).__spacePenView
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(workspaceView2.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]}"
|
||||
workspaceView2.remove()
|
||||
|
||||
describe "window:toggle-invisibles event", ->
|
||||
it "shows/hides invisibles in all open and future editors", ->
|
||||
atom.workspaceView.height(200)
|
||||
|
@ -30,14 +30,41 @@ module.exports =
|
||||
getInstallDirectory: ->
|
||||
"/usr/local/bin"
|
||||
|
||||
install: (commandPath, askForPrivilege, callback) ->
|
||||
installShellCommandsInteractively: ->
|
||||
showErrorDialog = (error) ->
|
||||
atom.confirm
|
||||
message: "Failed to install shell commands"
|
||||
detailedMessage: error.message
|
||||
|
||||
resourcePath = atom.getLoadSettings().resourcePath
|
||||
@installAtomCommand resourcePath, true, (error) =>
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
@installApmCommand resourcePath, true, (error) =>
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
atom.confirm
|
||||
message: "Commands installed."
|
||||
detailedMessage: "The shell commands `atom` and `apm` are installed."
|
||||
|
||||
installAtomCommand: (resourcePath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(resourcePath, 'atom.sh')
|
||||
@createSymlink commandPath, askForPrivilege, callback
|
||||
|
||||
installApmCommand: (resourcePath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm')
|
||||
@createSymlink commandPath, askForPrivilege, callback
|
||||
|
||||
createSymlink: (commandPath, askForPrivilege, callback) ->
|
||||
return unless process.platform is 'darwin'
|
||||
|
||||
commandName = path.basename(commandPath, path.extname(commandPath))
|
||||
destinationPath = path.join(@getInstallDirectory(), commandName)
|
||||
|
||||
fs.readlink destinationPath, (error, realpath) ->
|
||||
if realpath == commandPath
|
||||
if realpath is commandPath
|
||||
callback()
|
||||
return
|
||||
|
||||
@ -49,11 +76,3 @@ module.exports =
|
||||
catch error
|
||||
|
||||
callback?(error)
|
||||
|
||||
installAtomCommand: (resourcePath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(resourcePath, 'atom.sh')
|
||||
@install commandPath, askForPrivilege, callback
|
||||
|
||||
installApmCommand: (resourcePath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm')
|
||||
@install commandPath, askForPrivilege, callback
|
||||
|
44
src/pane-axis-element.coffee
Normal file
44
src/pane-axis-element.coffee
Normal file
@ -0,0 +1,44 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{callAttachHooks} = require './space-pen-extensions'
|
||||
|
||||
class PaneAxisElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
detachedCallback: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
setModel: (@model) ->
|
||||
@subscriptions.add @model.onDidAddChild(@childAdded.bind(this))
|
||||
@subscriptions.add @model.onDidRemoveChild(@childRemoved.bind(this))
|
||||
@subscriptions.add @model.onDidReplaceChild(@childReplaced.bind(this))
|
||||
|
||||
@childAdded({child, index}) for child, index in @model.getChildren()
|
||||
|
||||
switch @model.getOrientation()
|
||||
when 'horizontal'
|
||||
@classList.add('pane-row')
|
||||
when 'vertical'
|
||||
@classList.add('pane-column')
|
||||
|
||||
childAdded: ({child, index}) ->
|
||||
view = @model.getView(child)
|
||||
@insertBefore(view, @children[index])
|
||||
callAttachHooks(view) # for backward compatibility with SpacePen views
|
||||
|
||||
childRemoved: ({child}) ->
|
||||
view = @model.getView(child)
|
||||
view.remove()
|
||||
|
||||
childReplaced: ({index, oldChild, newChild}) ->
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@childRemoved({child: oldChild, index})
|
||||
@childAdded({child: newChild, index})
|
||||
focusedElement?.focus() if document.activeElement is document.body
|
||||
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
module.exports = PaneAxisElement = document.registerElement 'atom-pane-axis',
|
||||
prototype: PaneAxisElement.prototype
|
||||
extends: 'div'
|
@ -1,37 +0,0 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{View} = require './space-pen-extensions'
|
||||
PaneView = null
|
||||
|
||||
module.exports =
|
||||
class PaneAxisView extends View
|
||||
initialize: (@model) ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@onChildAdded({child, index}) for child, index in @model.getChildren()
|
||||
|
||||
@subscriptions.add @model.onDidAddChild(@onChildAdded)
|
||||
@subscriptions.add @model.onDidRemoveChild(@onChildRemoved)
|
||||
@subscriptions.add @model.onDidReplaceChild(@onChildReplaced)
|
||||
|
||||
afterAttach: ->
|
||||
@container = @closest('.panes').view()
|
||||
|
||||
onChildReplaced: ({index, oldChild, newChild}) =>
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@onChildRemoved({child: oldChild, index})
|
||||
@onChildAdded({child: newChild, index})
|
||||
focusedElement?.focus() if document.activeElement is document.body
|
||||
|
||||
onChildAdded: ({child, index}) =>
|
||||
view = @model.getView(child).__spacePenView
|
||||
@insertAt(index, view)
|
||||
|
||||
onChildRemoved: ({child}) =>
|
||||
view = @model.getView(child).__spacePenView
|
||||
view.detach()
|
||||
PaneView ?= require './pane-view'
|
||||
if view instanceof PaneView and view.model.isDestroyed()
|
||||
@container?.trigger 'pane:removed', [view]
|
||||
|
||||
beforeRemove: ->
|
||||
@subscriptions.dispose()
|
@ -3,9 +3,6 @@
|
||||
{flatten} = require 'underscore-plus'
|
||||
Serializable = require 'serializable'
|
||||
|
||||
PaneRowView = null
|
||||
PaneColumnView = null
|
||||
|
||||
module.exports =
|
||||
class PaneAxis extends Model
|
||||
atom.deserializers.add(this)
|
||||
@ -40,11 +37,7 @@ class PaneAxis extends Model
|
||||
|
||||
setContainer: (@container) -> @container
|
||||
|
||||
getViewClass: ->
|
||||
if @orientation is 'vertical'
|
||||
PaneColumnView ?= require './pane-column-view'
|
||||
else
|
||||
PaneRowView ?= require './pane-row-view'
|
||||
getOrientation: -> @orientation
|
||||
|
||||
getView: (object) ->
|
||||
@container.getView(object)
|
||||
|
@ -1,12 +0,0 @@
|
||||
{$} = require './space-pen-extensions'
|
||||
_ = require 'underscore-plus'
|
||||
PaneAxisView = require './pane-axis-view'
|
||||
|
||||
module.exports =
|
||||
class PaneColumnView extends PaneAxisView
|
||||
|
||||
@content: ->
|
||||
@div class: 'pane-column'
|
||||
|
||||
className: ->
|
||||
"PaneColumn"
|
80
src/pane-container-element.coffee
Normal file
80
src/pane-container-element.coffee
Normal file
@ -0,0 +1,80 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{callAttachHooks} = require './space-pen-extensions'
|
||||
PaneContainerView = null
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports =
|
||||
class PaneContainerElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
@classList.add 'panes'
|
||||
PaneContainerView ?= require './pane-container-view'
|
||||
@__spacePenView = new PaneContainerView(this)
|
||||
|
||||
setModel: (@model) ->
|
||||
@subscriptions.add @model.observeRoot(@rootChanged.bind(this))
|
||||
@__spacePenView.setModel(@model)
|
||||
|
||||
rootChanged: (root) ->
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@firstChild?.remove()
|
||||
if root?
|
||||
view = @model.getView(root)
|
||||
@appendChild(view)
|
||||
callAttachHooks(view)
|
||||
focusedElement?.focus()
|
||||
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
focusPaneViewAbove: ->
|
||||
@nearestPaneInDirection('above')?.focus()
|
||||
|
||||
focusPaneViewBelow: ->
|
||||
@nearestPaneInDirection('below')?.focus()
|
||||
|
||||
focusPaneViewOnLeft: ->
|
||||
@nearestPaneInDirection('left')?.focus()
|
||||
|
||||
focusPaneViewOnRight: ->
|
||||
@nearestPaneInDirection('right')?.focus()
|
||||
|
||||
nearestPaneInDirection: (direction) ->
|
||||
distance = (pointA, pointB) ->
|
||||
x = pointB.x - pointA.x
|
||||
y = pointB.y - pointA.y
|
||||
Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
|
||||
|
||||
paneView = @model.getView(@model.getActivePane())
|
||||
box = @boundingBoxForPaneView(paneView)
|
||||
|
||||
paneViews = _.toArray(@querySelectorAll('.pane'))
|
||||
.filter (otherPaneView) =>
|
||||
otherBox = @boundingBoxForPaneView(otherPaneView)
|
||||
switch direction
|
||||
when 'left' then otherBox.right.x <= box.left.x
|
||||
when 'right' then otherBox.left.x >= box.right.x
|
||||
when 'above' then otherBox.bottom.y <= box.top.y
|
||||
when 'below' then otherBox.top.y >= box.bottom.y
|
||||
.sort (paneViewA, paneViewB) =>
|
||||
boxA = @boundingBoxForPaneView(paneViewA)
|
||||
boxB = @boundingBoxForPaneView(paneViewB)
|
||||
switch direction
|
||||
when 'left' then distance(box.left, boxA.right) - distance(box.left, boxB.right)
|
||||
when 'right' then distance(box.right, boxA.left) - distance(box.right, boxB.left)
|
||||
when 'above' then distance(box.top, boxA.bottom) - distance(box.top, boxB.bottom)
|
||||
when 'below' then distance(box.bottom, boxA.top) - distance(box.bottom, boxB.top)
|
||||
|
||||
paneViews[0]
|
||||
|
||||
boundingBoxForPaneView: (paneView) ->
|
||||
boundingBox = paneView.getBoundingClientRect()
|
||||
|
||||
left: {x: boundingBox.left, y: boundingBox.top}
|
||||
right: {x: boundingBox.right, y: boundingBox.top}
|
||||
top: {x: boundingBox.left, y: boundingBox.top}
|
||||
bottom: {x: boundingBox.left, y: boundingBox.bottom}
|
||||
|
||||
module.exports = PaneContainerElement = document.registerElement 'atom-pane-container',
|
||||
prototype: PaneContainerElement.prototype
|
||||
extends: 'div'
|
@ -1,7 +1,7 @@
|
||||
{deprecate} = require 'grim'
|
||||
Delegator = require 'delegato'
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{$, View} = require './space-pen-extensions'
|
||||
{$, View, callAttachHooks} = require './space-pen-extensions'
|
||||
PaneView = require './pane-view'
|
||||
PaneContainer = require './pane-container'
|
||||
|
||||
@ -15,50 +15,22 @@ class PaneContainerView extends View
|
||||
@content: ->
|
||||
@div class: 'panes'
|
||||
|
||||
initialize: (params) ->
|
||||
constructor: (@element) ->
|
||||
super
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
if params instanceof PaneContainer
|
||||
@model = params
|
||||
else
|
||||
@model = new PaneContainer({root: params?.root?.model})
|
||||
|
||||
@subscriptions.add @model.observeRoot(@onRootChanged)
|
||||
setModel: (@model) ->
|
||||
@subscriptions.add @model.onDidChangeActivePaneItem(@onActivePaneItemChanged)
|
||||
|
||||
getRoot: ->
|
||||
@children().first().view()
|
||||
|
||||
onRootChanged: (root) =>
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
|
||||
oldRoot = @getRoot()
|
||||
if oldRoot instanceof PaneView and oldRoot.model.isDestroyed()
|
||||
@trigger 'pane:removed', [oldRoot]
|
||||
oldRoot?.detach()
|
||||
if root?
|
||||
view = @model.getView(root).__spacePenView
|
||||
@append(view)
|
||||
focusedElement?.focus()
|
||||
else
|
||||
atom.workspaceView?.focus() if focusedElement?
|
||||
view = @model.getView(@model.getRoot())
|
||||
view.__spacePenView ? view
|
||||
|
||||
onActivePaneItemChanged: (activeItem) =>
|
||||
@trigger 'pane-container:active-pane-item-changed', [activeItem]
|
||||
|
||||
removeChild: (child) ->
|
||||
throw new Error("Removing non-existant child") unless @getRoot() is child
|
||||
@setRoot(null)
|
||||
@trigger 'pane:removed', [child] if child instanceof PaneView
|
||||
|
||||
confirmClose: ->
|
||||
saved = true
|
||||
for paneView in @getPaneViews()
|
||||
for item in paneView.getItems()
|
||||
if not paneView.promptToSaveItem(item)
|
||||
saved = false
|
||||
break
|
||||
saved
|
||||
@model.confirmClose()
|
||||
|
||||
getPaneViews: ->
|
||||
@find('.pane').views()
|
||||
@ -101,56 +73,17 @@ class PaneContainerView extends View
|
||||
@model.activatePreviousPane()
|
||||
|
||||
focusPaneViewAbove: ->
|
||||
@nearestPaneInDirection('above')?.focus()
|
||||
@element.focusPaneViewAbove()
|
||||
|
||||
focusPaneViewBelow: ->
|
||||
@nearestPaneInDirection('below')?.focus()
|
||||
@element.focusPaneViewBelow()
|
||||
|
||||
focusPaneViewOnLeft: ->
|
||||
@nearestPaneInDirection('left')?.focus()
|
||||
@element.focusPaneViewOnLeft()
|
||||
|
||||
focusPaneViewOnRight: ->
|
||||
@nearestPaneInDirection('right')?.focus()
|
||||
@element.focusPaneViewOnRight()
|
||||
|
||||
nearestPaneInDirection: (direction) ->
|
||||
distance = (pointA, pointB) ->
|
||||
x = pointB.x - pointA.x
|
||||
y = pointB.y - pointA.y
|
||||
Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
|
||||
|
||||
paneView = @getActivePaneView()
|
||||
box = @boundingBoxForPaneView(paneView)
|
||||
paneViews = @getPaneViews()
|
||||
.filter (otherPaneView) =>
|
||||
otherBox = @boundingBoxForPaneView(otherPaneView)
|
||||
switch direction
|
||||
when 'left' then otherBox.right.x <= box.left.x
|
||||
when 'right' then otherBox.left.x >= box.right.x
|
||||
when 'above' then otherBox.bottom.y <= box.top.y
|
||||
when 'below' then otherBox.top.y >= box.bottom.y
|
||||
.sort (paneViewA, paneViewB) =>
|
||||
boxA = @boundingBoxForPaneView(paneViewA)
|
||||
boxB = @boundingBoxForPaneView(paneViewB)
|
||||
switch direction
|
||||
when 'left' then distance(box.left, boxA.right) - distance(box.left, boxB.right)
|
||||
when 'right' then distance(box.right, boxA.left) - distance(box.right, boxB.left)
|
||||
when 'above' then distance(box.top, boxA.bottom) - distance(box.top, boxB.bottom)
|
||||
when 'below' then distance(box.bottom, boxA.top) - distance(box.bottom, boxB.top)
|
||||
|
||||
paneViews[0]
|
||||
|
||||
boundingBoxForPaneView: (paneView) ->
|
||||
boundingBox = paneView[0].getBoundingClientRect()
|
||||
|
||||
left: {x: boundingBox.left, y: boundingBox.top}
|
||||
right: {x: boundingBox.right, y: boundingBox.top}
|
||||
top: {x: boundingBox.left, y: boundingBox.top}
|
||||
bottom: {x: boundingBox.left, y: boundingBox.bottom}
|
||||
|
||||
# Deprecated
|
||||
getPanes: ->
|
||||
deprecate("Use PaneContainerView::getPaneViews() instead")
|
||||
@getPaneViews()
|
||||
|
||||
beforeRemove: ->
|
||||
@subscriptions.dispose()
|
||||
|
@ -3,9 +3,12 @@
|
||||
{Emitter, CompositeDisposable} = require 'event-kit'
|
||||
Serializable = require 'serializable'
|
||||
Pane = require './pane'
|
||||
PaneElement = require './pane-element'
|
||||
PaneContainerElement = require './pane-container-element'
|
||||
PaneAxisElement = require './pane-axis-element'
|
||||
PaneAxis = require './pane-axis'
|
||||
ViewRegistry = require './view-registry'
|
||||
ItemRegistry = require './item-registry'
|
||||
PaneContainerView = null
|
||||
|
||||
module.exports =
|
||||
class PaneContainer extends Model
|
||||
@ -30,8 +33,10 @@ class PaneContainer extends Model
|
||||
@emitter = new Emitter
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@viewRegistry = params?.viewRegistry ? new ViewRegistry
|
||||
@itemRegistry = new ItemRegistry
|
||||
@viewRegistry = params?.viewRegistry ? new ViewRegistry
|
||||
@registerViewProviders()
|
||||
|
||||
@setRoot(params?.root ? new Pane)
|
||||
@destroyEmptyPanes() if params?.destroyEmptyPanes
|
||||
|
||||
@ -48,8 +53,18 @@ class PaneContainer extends Model
|
||||
root: @root?.serialize()
|
||||
activePaneId: @activePane.id
|
||||
|
||||
getViewClass: ->
|
||||
PaneContainerView ?= require './pane-container-view'
|
||||
registerViewProviders: ->
|
||||
@viewRegistry.addViewProvider
|
||||
modelConstructor: PaneContainer
|
||||
viewConstructor: PaneContainerElement
|
||||
|
||||
@viewRegistry.addViewProvider
|
||||
modelConstructor: PaneAxis
|
||||
viewConstructor: PaneAxisElement
|
||||
|
||||
@viewRegistry.addViewProvider
|
||||
modelConstructor: Pane
|
||||
viewConstructor: PaneElement
|
||||
|
||||
getView: (object) ->
|
||||
@viewRegistry.getView(object)
|
||||
@ -129,6 +144,17 @@ class PaneContainer extends Model
|
||||
saveAll: ->
|
||||
pane.saveItems() for pane in @getPanes()
|
||||
|
||||
confirmClose: ->
|
||||
allSaved = true
|
||||
|
||||
for pane in @getPanes()
|
||||
for item in pane.getItems()
|
||||
unless pane.promptToSaveItem(item)
|
||||
allSaved = false
|
||||
break
|
||||
|
||||
allSaved
|
||||
|
||||
activateNextPane: ->
|
||||
panes = @getPanes()
|
||||
if panes.length > 1
|
||||
|
100
src/pane-element.coffee
Normal file
100
src/pane-element.coffee
Normal file
@ -0,0 +1,100 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{$} = require './space-pen-extensions'
|
||||
PaneView = require './pane-view'
|
||||
|
||||
class PaneElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
@initializeContent()
|
||||
@subscribeToDOMEvents()
|
||||
@createSpacePenShim()
|
||||
|
||||
attachedCallback: ->
|
||||
@focus() if @model.isFocused()
|
||||
|
||||
initializeContent: ->
|
||||
@setAttribute 'class', 'pane'
|
||||
@setAttribute 'tabindex', -1
|
||||
@appendChild @itemViews = document.createElement('div')
|
||||
@itemViews.setAttribute 'class', 'item-views'
|
||||
|
||||
subscribeToDOMEvents: ->
|
||||
@addEventListener 'focusin', => @model.focus()
|
||||
@addEventListener 'focusout', => @model.blur()
|
||||
@addEventListener 'focus', => @getActiveView()?.focus()
|
||||
|
||||
createSpacePenShim: ->
|
||||
@__spacePenView = new PaneView(this)
|
||||
|
||||
getModel: -> @model
|
||||
|
||||
setModel: (@model) ->
|
||||
@subscriptions.add @model.onDidActivate(@activated.bind(this))
|
||||
@subscriptions.add @model.observeActive(@activeStatusChanged.bind(this))
|
||||
@subscriptions.add @model.observeActiveItem(@activeItemChanged.bind(this))
|
||||
@subscriptions.add @model.onDidRemoveItem(@itemRemoved.bind(this))
|
||||
@subscriptions.add @model.onDidDestroy(@paneDestroyed.bind(this))
|
||||
@__spacePenView.setModel(@model)
|
||||
|
||||
activated: ->
|
||||
@focus() unless @hasFocus()
|
||||
|
||||
activeStatusChanged: (active) ->
|
||||
if active
|
||||
@classList.add('active')
|
||||
else
|
||||
@classList.remove('active')
|
||||
|
||||
activeItemChanged: (item) ->
|
||||
return unless item?
|
||||
|
||||
$itemViews = $(@itemViews)
|
||||
view = @model.getView(item).__spacePenView
|
||||
otherView.hide() for otherView in $itemViews.children().not(view).views()
|
||||
$itemViews.append(view) unless view.parent().is($itemViews)
|
||||
view.show()
|
||||
view.focus() if @hasFocus()
|
||||
|
||||
itemRemoved: ({item, index, destroyed}) ->
|
||||
if item instanceof $
|
||||
viewToRemove = item
|
||||
else
|
||||
viewToRemove = @model.getView(item).__spacePenView
|
||||
|
||||
if viewToRemove?
|
||||
if destroyed
|
||||
viewToRemove.remove()
|
||||
else
|
||||
viewToRemove.detach()
|
||||
|
||||
paneDestroyed: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
getActiveView: -> @model.getView(@model.getActiveItem())
|
||||
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
atom.commands.add '.pane',
|
||||
'pane:save-items': -> @getModel().saveItems()
|
||||
'pane:show-next-item': -> @getModel().activateNextItem()
|
||||
'pane:show-previous-item': -> @getModel().activatePreviousItem()
|
||||
'pane:show-item-1': -> @getModel().activateItemAtIndex(0)
|
||||
'pane:show-item-2': -> @getModel().activateItemAtIndex(1)
|
||||
'pane:show-item-3': -> @getModel().activateItemAtIndex(2)
|
||||
'pane:show-item-4': -> @getModel().activateItemAtIndex(3)
|
||||
'pane:show-item-5': -> @getModel().activateItemAtIndex(4)
|
||||
'pane:show-item-6': -> @getModel().activateItemAtIndex(5)
|
||||
'pane:show-item-7': -> @getModel().activateItemAtIndex(6)
|
||||
'pane:show-item-8': -> @getModel().activateItemAtIndex(7)
|
||||
'pane:show-item-9': -> @getModel().activateItemAtIndex(8)
|
||||
'pane:split-left': -> @getModel().splitLeft(copyActiveItem: true)
|
||||
'pane:split-right': -> @getModel().splitRight(copyActiveItem: true)
|
||||
'pane:split-up': -> @getModel().splitUp(copyActiveItem: true)
|
||||
'pane:split-down': -> @getModel().splitDown(copyActiveItem: true)
|
||||
'pane:close': -> @getModel().destroy()
|
||||
'pane:close-other-items': -> @getModel().destroyInactiveItems()
|
||||
|
||||
module.exports = PaneElement = document.registerElement 'atom-pane',
|
||||
prototype: PaneElement.prototype
|
||||
extends: 'div'
|
@ -1,11 +0,0 @@
|
||||
{$} = require './space-pen-extensions'
|
||||
_ = require 'underscore-plus'
|
||||
PaneAxisView = require './pane-axis-view'
|
||||
|
||||
module.exports =
|
||||
class PaneRowView extends PaneAxisView
|
||||
@content: ->
|
||||
@div class: 'pane-row'
|
||||
|
||||
className: ->
|
||||
"PaneRow"
|
@ -17,12 +17,6 @@ class PaneView extends View
|
||||
Delegator.includeInto(this)
|
||||
PropertyAccessors.includeInto(this)
|
||||
|
||||
@version: 1
|
||||
|
||||
@content: (wrappedView) ->
|
||||
@div class: 'pane', tabindex: -1, =>
|
||||
@div class: 'item-views', outlet: 'itemViews'
|
||||
|
||||
@delegatesProperties 'items', 'activeItem', toProperty: 'model'
|
||||
@delegatesMethods 'getItems', 'activateNextItem', 'activatePreviousItem', 'getActiveItemIndex',
|
||||
'activateItemAtIndex', 'activateItem', 'addItem', 'itemAtIndex', 'moveItem', 'moveItemToPane',
|
||||
@ -32,49 +26,33 @@ class PaneView extends View
|
||||
'activate', 'getActiveItem', toProperty: 'model'
|
||||
|
||||
previousActiveItem: null
|
||||
attached: false
|
||||
|
||||
initialize: (@model) ->
|
||||
constructor: (@element) ->
|
||||
@itemViews = $(element.itemViews)
|
||||
super
|
||||
|
||||
setModel: (@model) ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
@onItemAdded(item) for item in @items
|
||||
@handleEvents()
|
||||
|
||||
handleEvents: ->
|
||||
@subscriptions.add @model.observeActiveItem(@onActiveItemChanged)
|
||||
@subscriptions.add @model.onDidAddItem(@onItemAdded)
|
||||
@subscriptions.add @model.onDidRemoveItem(@onItemRemoved)
|
||||
@subscriptions.add @model.onDidMoveItem(@onItemMoved)
|
||||
@subscriptions.add @model.onWillDestroyItem(@onBeforeItemDestroyed)
|
||||
@subscriptions.add @model.onDidActivate(@onActivated)
|
||||
@subscriptions.add @model.observeActive(@onActiveStatusChanged)
|
||||
@subscriptions.add @model.onDidDestroy(@onPaneDestroyed)
|
||||
|
||||
@subscribe this, 'focusin', => @model.focus()
|
||||
@subscribe this, 'focusout', => @model.blur()
|
||||
@subscribe this, 'focus', =>
|
||||
@activeView?.focus()
|
||||
false
|
||||
afterAttach: ->
|
||||
@container ?= @closest('.panes').view()
|
||||
@trigger('pane:attached', [this]) unless @attached
|
||||
@attached = true
|
||||
|
||||
@command 'pane:save-items', => @saveItems()
|
||||
@command 'pane:show-next-item', => @activateNextItem()
|
||||
@command 'pane:show-previous-item', => @activatePreviousItem()
|
||||
onPaneDestroyed: =>
|
||||
@container?.trigger 'pane:removed', [this]
|
||||
@subscriptions.dispose()
|
||||
|
||||
@command 'pane:show-item-1', => @activateItemAtIndex(0)
|
||||
@command 'pane:show-item-2', => @activateItemAtIndex(1)
|
||||
@command 'pane:show-item-3', => @activateItemAtIndex(2)
|
||||
@command 'pane:show-item-4', => @activateItemAtIndex(3)
|
||||
@command 'pane:show-item-5', => @activateItemAtIndex(4)
|
||||
@command 'pane:show-item-6', => @activateItemAtIndex(5)
|
||||
@command 'pane:show-item-7', => @activateItemAtIndex(6)
|
||||
@command 'pane:show-item-8', => @activateItemAtIndex(7)
|
||||
@command 'pane:show-item-9', => @activateItemAtIndex(8)
|
||||
|
||||
@command 'pane:split-left', => @model.splitLeft(copyActiveItem: true)
|
||||
@command 'pane:split-right', => @model.splitRight(copyActiveItem: true)
|
||||
@command 'pane:split-up', => @model.splitUp(copyActiveItem: true)
|
||||
@command 'pane:split-down', => @model.splitDown(copyActiveItem: true)
|
||||
@command 'pane:close', =>
|
||||
@model.destroyItems()
|
||||
@model.destroy()
|
||||
@command 'pane:close-other-items', => @destroyInactiveItems()
|
||||
remove: ->
|
||||
@model.destroy() unless @model.isDestroyed()
|
||||
|
||||
# Essential: Returns the {Pane} model underlying this pane view
|
||||
getModel: -> @model
|
||||
@ -109,23 +87,10 @@ class PaneView extends View
|
||||
deprecate("Use PaneView::activatePreviousItem instead")
|
||||
@activatePreviousItem()
|
||||
|
||||
afterAttach: (onDom) ->
|
||||
@focus() if @model.focused and onDom
|
||||
|
||||
return if @attached
|
||||
@container = @closest('.panes').view()
|
||||
@attached = true
|
||||
@trigger 'pane:attached', [this]
|
||||
|
||||
onActivated: =>
|
||||
@focus() unless @hasFocus()
|
||||
|
||||
onActiveStatusChanged: (active) =>
|
||||
if active
|
||||
@addClass('active')
|
||||
@trigger 'pane:became-active'
|
||||
else
|
||||
@removeClass('active')
|
||||
@trigger 'pane:became-inactive'
|
||||
|
||||
# Public: Returns the next pane, ordered by creation.
|
||||
@ -179,23 +144,12 @@ class PaneView extends View
|
||||
@trigger 'pane:item-added', [item, index]
|
||||
|
||||
onItemRemoved: ({item, index, destroyed}) =>
|
||||
if item instanceof $
|
||||
viewToRemove = item
|
||||
else
|
||||
viewToRemove = @model.getView(item).__spacePenView
|
||||
|
||||
if viewToRemove?
|
||||
if destroyed
|
||||
viewToRemove.remove()
|
||||
else
|
||||
viewToRemove.detach()
|
||||
|
||||
@trigger 'pane:item-removed', [item, index]
|
||||
|
||||
onItemMoved: ({item, newIndex}) =>
|
||||
@trigger 'pane:item-moved', [item, newIndex]
|
||||
|
||||
onBeforeItemDestroyed: (item) =>
|
||||
onBeforeItemDestroyed: ({item}) =>
|
||||
@unsubscribe(item) if typeof item.off is 'function'
|
||||
@trigger 'pane:before-item-destroyed', [item]
|
||||
|
||||
@ -215,17 +169,7 @@ class PaneView extends View
|
||||
|
||||
splitDown: (items...) -> @model.getView(@model.splitDown({items})).__spacePenView
|
||||
|
||||
# Public: Get the container view housing this pane.
|
||||
#
|
||||
# Returns a {View}.
|
||||
getContainer: ->
|
||||
@closest('.panes').view()
|
||||
getContainer: -> @closest('.panes').view()
|
||||
|
||||
beforeRemove: ->
|
||||
@subscriptions.dispose()
|
||||
@model.destroy() unless @model.isDestroyed()
|
||||
|
||||
remove: (selector, keepData) ->
|
||||
return super if keepData
|
||||
@unsubscribe()
|
||||
super
|
||||
focus: ->
|
||||
@element.focus()
|
||||
|
@ -53,9 +53,6 @@ class Pane extends Model
|
||||
params.activeItem = find params.items, (item) -> item.getUri?() is activeItemUri
|
||||
params
|
||||
|
||||
# Called by the view layer to construct a view for this model.
|
||||
getViewClass: -> PaneView ?= require './pane-view'
|
||||
|
||||
getView: (object) ->
|
||||
@container.getView(object)
|
||||
|
||||
@ -238,6 +235,8 @@ class Pane extends Model
|
||||
@focused = false
|
||||
true # if this is called from an event handler, don't cancel it
|
||||
|
||||
isFocused: -> @focused
|
||||
|
||||
getPanes: -> [this]
|
||||
|
||||
###
|
||||
@ -414,9 +413,8 @@ class Pane extends Model
|
||||
@destroyItem(item) for item in @getItems() when item isnt @activeItem
|
||||
|
||||
promptToSaveItem: (item) ->
|
||||
return true unless item.shouldPromptToSave?()
|
||||
return true unless typeof item.getUri is 'function' and item.shouldPromptToSave?()
|
||||
|
||||
uri = item.getUri()
|
||||
chosen = atom.confirm
|
||||
message: "'#{item.getTitle?() ? item.getUri()}' has changes, do you want to save them?"
|
||||
detailedMessage: "Your changes will be lost if you close this item without saving."
|
||||
|
@ -9,3 +9,9 @@ atom.initialize()
|
||||
atom.startEditorWindow()
|
||||
window.atom.loadTime = Date.now() - startTime
|
||||
console.log "Window load time: #{atom.getWindowLoadTime()}ms"
|
||||
|
||||
# Workaround for focus getting cleared upon window creation
|
||||
windowFocused = ->
|
||||
window.removeEventListener('focus', windowFocused)
|
||||
setTimeout (-> document.querySelector('.workspace').focus()), 0
|
||||
window.addEventListener('focus', windowFocused)
|
||||
|
@ -37,7 +37,7 @@ class WindowEventHandler
|
||||
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
|
||||
@subscribe $(window), 'beforeunload', =>
|
||||
confirmed = atom.workspaceView?.confirmClose()
|
||||
confirmed = atom.workspace?.confirmClose()
|
||||
atom.hide() if confirmed and not @reloadRequested and atom.getCurrentWindow().isWebViewFocused()
|
||||
@reloadRequested = false
|
||||
|
||||
|
137
src/workspace-element.coffee
Normal file
137
src/workspace-element.coffee
Normal file
@ -0,0 +1,137 @@
|
||||
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)
|
||||
|
||||
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'
|
@ -6,19 +6,12 @@ Delegator = require 'delegato'
|
||||
{deprecate, logDeprecationWarnings} = require 'grim'
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
{$, $$, View} = require './space-pen-extensions'
|
||||
fs = require 'fs-plus'
|
||||
Workspace = require './workspace'
|
||||
CommandInstaller = require './command-installer'
|
||||
PaneView = require './pane-view'
|
||||
PaneColumnView = require './pane-column-view'
|
||||
PaneRowView = require './pane-row-view'
|
||||
PaneContainerView = require './pane-container-view'
|
||||
TextEditor = require './text-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.
|
||||
#
|
||||
@ -64,100 +57,20 @@ class WorkspaceView extends View
|
||||
'saveActivePaneItem', 'saveActivePaneItemAs', 'saveAll', 'destroyActivePaneItem',
|
||||
'destroyActivePane', 'increaseFontSize', 'decreaseFontSize', toProperty: 'model'
|
||||
|
||||
@version: 4
|
||||
|
||||
@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) ->
|
||||
unless @element?
|
||||
return atom.workspace.getView(atom.workspace).__spacePenView
|
||||
super
|
||||
@deprecateViewEvents()
|
||||
|
||||
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
|
||||
|
||||
@updateTitle()
|
||||
|
||||
@on 'focus', (e) => @handleFocus(e)
|
||||
@subscribe $(window), 'focus', (e) =>
|
||||
@handleFocus(e) if document.activeElement is document.body
|
||||
|
||||
atom.project.onDidChangePaths => @updateTitle()
|
||||
@on 'pane-container:active-pane-item-changed', => @updateTitle()
|
||||
@on 'pane:active-item-title-changed', '.active.pane', => @updateTitle()
|
||||
@on 'pane:active-item-modified-status-changed', '.active.pane', => @updateDocumentEdited()
|
||||
|
||||
@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', => @installShellCommands()
|
||||
|
||||
@command 'window:run-package-specs', -> ipc.send('run-package-specs', path.join(atom.project.getPaths()[0], '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.set("editor.showInvisibles", not atom.config.get("editor.showInvisibles"))
|
||||
@command 'window:log-deprecation-warnings', -> logDeprecationWarnings()
|
||||
|
||||
@command 'window:toggle-auto-indent', ->
|
||||
atom.config.set("editor.autoIndent", not atom.config.get("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,83 +222,9 @@ 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)
|
||||
|
||||
# Install the Atom shell commands on the user's system.
|
||||
installShellCommands: ->
|
||||
showErrorDialog = (error) ->
|
||||
installDirectory = CommandInstaller.getInstallDirectory()
|
||||
atom.confirm
|
||||
message: "Failed to install shell commands"
|
||||
detailedMessage: error.message
|
||||
|
||||
resourcePath = atom.getLoadSettings().resourcePath
|
||||
CommandInstaller.installAtomCommand resourcePath, true, (error) ->
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
CommandInstaller.installApmCommand resourcePath, true, (error) ->
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
atom.confirm
|
||||
message: "Commands installed."
|
||||
detailedMessage: "The shell commands `atom` and `apm` are installed."
|
||||
|
||||
handleFocus: ->
|
||||
if @getActivePaneView()
|
||||
@getActivePaneView().focus()
|
||||
false
|
||||
else
|
||||
@updateTitle()
|
||||
focusableChild = @find("[tabindex=-1]:visible:first")
|
||||
if focusableChild.length
|
||||
focusableChild.focus()
|
||||
false
|
||||
else
|
||||
$(document.body).focus()
|
||||
true
|
||||
|
||||
# Prompts to save all unsaved items
|
||||
confirmClose: ->
|
||||
@panes.confirmClose()
|
||||
|
||||
# Updates the application's title and proxy icon based on whichever file is
|
||||
# open.
|
||||
updateTitle: ->
|
||||
if projectPath = atom.project.getPaths()[0]
|
||||
if item = @getModel().getActivePaneItem()
|
||||
title = "#{item.getTitle?() ? 'untitled'} - #{projectPath}"
|
||||
@setTitle(title, item.getPath?())
|
||||
else
|
||||
@setTitle(projectPath, projectPath)
|
||||
else
|
||||
@setTitle('untitled')
|
||||
|
||||
# Sets the application's title (and the proxy icon on OS X)
|
||||
setTitle: (title, proxyIconPath='') ->
|
||||
document.title = title
|
||||
atom.setRepresentedFilename(proxyIconPath)
|
||||
|
||||
# On OS X, fades the application window's proxy icon when the current file
|
||||
# has been modified.
|
||||
updateDocumentEdited: ->
|
||||
modified = @model.getActivePaneItem()?.isModified?() ? false
|
||||
atom.setDocumentEdited(modified)
|
||||
@model.confirmClose()
|
||||
|
||||
# Get all editor views.
|
||||
#
|
||||
@ -403,7 +242,7 @@ class WorkspaceView extends View
|
||||
Section: Deprecated
|
||||
###
|
||||
|
||||
deprecatedViewEvents: ->
|
||||
deprecateViewEvents: ->
|
||||
originalWorkspaceViewOn = @on
|
||||
|
||||
@on = (eventName) =>
|
||||
|
@ -5,13 +5,13 @@ _ = require 'underscore-plus'
|
||||
Q = require 'q'
|
||||
Serializable = require 'serializable'
|
||||
Delegator = require 'delegato'
|
||||
{Emitter, Disposable} = require 'event-kit'
|
||||
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
TextEditor = require './text-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.
|
||||
@ -30,11 +30,12 @@ class Workspace extends Model
|
||||
@delegatesProperty 'activePane', 'activePaneItem', toProperty: 'paneContainer'
|
||||
|
||||
@properties
|
||||
viewRegistry: null
|
||||
paneContainer: null
|
||||
fullScreen: false
|
||||
destroyedItemUris: -> []
|
||||
|
||||
constructor: ->
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
@emitter = new Emitter
|
||||
@ -44,6 +45,8 @@ class Workspace extends Model
|
||||
@paneContainer ?= new PaneContainer({@viewRegistry})
|
||||
@paneContainer.onDidDestroyPaneItem(@onPaneItemDestroyed)
|
||||
|
||||
@subscribeToActiveItem()
|
||||
|
||||
@addOpener (filePath) =>
|
||||
switch filePath
|
||||
when 'atom://.atom/stylesheet'
|
||||
@ -55,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 ? []
|
||||
@ -71,9 +78,6 @@ class Workspace extends Model
|
||||
fullScreen: atom.isFullScreen()
|
||||
packagesWithActiveGrammars: @getPackageNamesWithActiveGrammars()
|
||||
|
||||
getViewClass: ->
|
||||
WorkspaceView ?= require './workspace-view'
|
||||
|
||||
getPackageNamesWithActiveGrammars: ->
|
||||
packageNames = []
|
||||
addGrammar = ({includedGrammarScopes, packageName}={}) ->
|
||||
@ -97,6 +101,58 @@ class Workspace extends Model
|
||||
editorAdded: (editor) ->
|
||||
@emit 'editor-created', editor
|
||||
|
||||
installShellCommands: ->
|
||||
CommandInstaller.installShellCommandsInteractively()
|
||||
|
||||
subscribeToActiveItem: ->
|
||||
@updateWindowTitle()
|
||||
@updateDocumentEdited()
|
||||
atom.project.onDidChangePaths @updateWindowTitle
|
||||
|
||||
@observeActivePaneItem (item) =>
|
||||
@updateWindowTitle()
|
||||
@updateDocumentEdited()
|
||||
|
||||
@activeItemSubscriptions?.dispose()
|
||||
@activeItemSubscriptions = new CompositeDisposable
|
||||
|
||||
if typeof item?.onDidChangeTitle is 'function'
|
||||
titleSubscription = item.onDidChangeTitle(@updateWindowTitle)
|
||||
else if typeof item?.on is 'function'
|
||||
titleSubscription = item.on('title-changed', @updateWindowTitle)
|
||||
unless typeof titleSubscription?.dispose is 'function'
|
||||
titleSubscription = new Disposable => item.off('title-changed', @updateWindowTitle)
|
||||
|
||||
if typeof item?.onDidChangeModified is 'function'
|
||||
modifiedSubscription = item.onDidChangeModified(@updateDocumentEdited)
|
||||
else if typeof item?.on? is 'function'
|
||||
modifiedSubscription = item.on('modified-status-changed', @updateDocumentEdited)
|
||||
unless typeof modifiedSubscription?.dispose is 'function'
|
||||
modifiedSubscription = new Disposable => item.off('modified-status-changed', @updateDocumentEdited)
|
||||
|
||||
@activeItemSubscriptions.add(titleSubscription) if titleSubscription?
|
||||
@activeItemSubscriptions.add(modifiedSubscription) if modifiedSubscription?
|
||||
|
||||
# Updates the application's title and proxy icon based on whichever file is
|
||||
# open.
|
||||
updateWindowTitle: =>
|
||||
if projectPath = atom.project?.getPaths()[0]
|
||||
if item = @getActivePaneItem()
|
||||
document.title = "#{item.getTitle?() ? 'untitled'} - #{projectPath}"
|
||||
atom.setRepresentedFilename(item.getPath?() ? projectPath)
|
||||
else
|
||||
document.title = projectPath
|
||||
atom.setRepresentedFilename(projectPath)
|
||||
else
|
||||
document.title = 'untitled'
|
||||
atom.setRepresentedFilename('')
|
||||
|
||||
# On OS X, fades the application window's proxy icon when the current file
|
||||
# has been modified.
|
||||
updateDocumentEdited: =>
|
||||
modified = @getActivePaneItem()?.isModified?() ? false
|
||||
atom.setDocumentEdited(modified)
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
###
|
||||
@ -113,8 +169,8 @@ class Workspace extends Model
|
||||
callback(textEditor) for textEditor in @getTextEditors()
|
||||
@onDidAddTextEditor ({textEditor}) -> callback(textEditor)
|
||||
|
||||
# Essential: Invoke the given callback with all current and future panes items in
|
||||
# the workspace.
|
||||
# Essential: Invoke the given callback with all current and future panes items
|
||||
# in the workspace.
|
||||
#
|
||||
# * `callback` {Function} to be called with current and future pane items.
|
||||
# * `item` An item that is present in {::getPaneItems} at the time of
|
||||
@ -132,6 +188,15 @@ class Workspace extends Model
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidChangeActivePaneItem: (callback) -> @paneContainer.onDidChangeActivePaneItem(callback)
|
||||
|
||||
# Essential: Invoke the given callback with the current active pane item and
|
||||
# with all future active pane items in the workspace.
|
||||
#
|
||||
# * `callback` {Function} to be called when the active pane item changes.
|
||||
# * `item` The current active pane item.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
observeActivePaneItem: (callback) -> @paneContainer.observeActivePaneItem(callback)
|
||||
|
||||
# Essential: Invoke the given callback whenever an item is opened. Unlike
|
||||
# {::onDidAddPaneItem}, observers will be notified for items that are already
|
||||
# present in the workspace when they are reopened.
|
||||
@ -417,6 +482,9 @@ class Workspace extends Model
|
||||
saveAll: ->
|
||||
@paneContainer.saveAll()
|
||||
|
||||
confirmClose: ->
|
||||
@paneContainer.confirmClose()
|
||||
|
||||
# Save the active pane item.
|
||||
#
|
||||
# If the active pane item currently has a URI according to the item's
|
||||
@ -477,6 +545,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)
|
||||
@ -503,6 +575,7 @@ class Workspace extends Model
|
||||
# Called by Model superclass when destroyed
|
||||
destroyed: ->
|
||||
@paneContainer.destroy()
|
||||
@activeItemSubscriptions?.dispose()
|
||||
|
||||
###
|
||||
Section: View Management
|
||||
|
Loading…
Reference in New Issue
Block a user