Merge pull request #881 from atom/ks-globalization

Clean up globals
This commit is contained in:
Kevin Sawicki 2013-10-02 13:45:36 -07:00
commit 46762327c6
16 changed files with 621 additions and 505 deletions

View File

@ -1,4 +1,5 @@
require '../src/atom' Atom = require '../src/atom'
window.atom = new Atom()
{runSpecSuite} = require '../spec/jasmine-helper' {runSpecSuite} = require '../spec/jasmine-helper'
atom.openDevTools() atom.openDevTools()

View File

@ -6,29 +6,6 @@ describe "the `atom` global", ->
beforeEach -> beforeEach ->
window.rootView = new RootView window.rootView = new RootView
describe "base stylesheet loading", ->
beforeEach ->
rootView.append $$ -> @div class: 'editor'
rootView.attachToDom()
atom.themes.load()
atom.watchThemes()
afterEach ->
atom.themes.unload()
config.set('core.themes', [])
atom.reloadBaseStylesheets()
it "loads the correct values from the theme's ui-variables file", ->
config.set('core.themes', ['theme-with-ui-variables'])
# an override loaded in the base css
expect(rootView.css("background-color")).toBe "rgb(0, 0, 255)"
# from within the theme itself
expect($(".editor").css("padding-top")).toBe "150px"
expect($(".editor").css("padding-right")).toBe "150px"
expect($(".editor").css("padding-bottom")).toBe "150px"
describe "package lifecycle methods", -> describe "package lifecycle methods", ->
describe ".loadPackage(name)", -> describe ".loadPackage(name)", ->
describe "when the package has deferred deserializers", -> describe "when the package has deferred deserializers", ->
@ -205,15 +182,15 @@ describe "the `atom` global", ->
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css") one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less") two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css") three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
expect(stylesheetElementForId(one)).not.toExist() expect(atom.themes.stylesheetElementForId(one)).not.toExist()
expect(stylesheetElementForId(two)).not.toExist() expect(atom.themes.stylesheetElementForId(two)).not.toExist()
expect(stylesheetElementForId(three)).not.toExist() expect(atom.themes.stylesheetElementForId(three)).not.toExist()
atom.activatePackage("package-with-stylesheets-manifest") atom.activatePackage("package-with-stylesheets-manifest")
expect(stylesheetElementForId(one)).toExist() expect(atom.themes.stylesheetElementForId(one)).toExist()
expect(stylesheetElementForId(two)).toExist() expect(atom.themes.stylesheetElementForId(two)).toExist()
expect(stylesheetElementForId(three)).not.toExist() expect(atom.themes.stylesheetElementForId(three)).not.toExist()
expect($('#jasmine-content').css('font-size')).toBe '1px' expect($('#jasmine-content').css('font-size')).toBe '1px'
describe "when the metadata does not contain a 'stylesheets' manifest", -> describe "when the metadata does not contain a 'stylesheets' manifest", ->
@ -221,14 +198,14 @@ describe "the `atom` global", ->
one = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/1.css") one = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/1.css")
two = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/2.less") two = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/2.less")
three = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/3.css") three = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/3.css")
expect(stylesheetElementForId(one)).not.toExist() expect(atom.themes.stylesheetElementForId(one)).not.toExist()
expect(stylesheetElementForId(two)).not.toExist() expect(atom.themes.stylesheetElementForId(two)).not.toExist()
expect(stylesheetElementForId(three)).not.toExist() expect(atom.themes.stylesheetElementForId(three)).not.toExist()
atom.activatePackage("package-with-stylesheets") atom.activatePackage("package-with-stylesheets")
expect(stylesheetElementForId(one)).toExist() expect(atom.themes.stylesheetElementForId(one)).toExist()
expect(stylesheetElementForId(two)).toExist() expect(atom.themes.stylesheetElementForId(two)).toExist()
expect(stylesheetElementForId(three)).toExist() expect(atom.themes.stylesheetElementForId(three)).toExist()
expect($('#jasmine-content').css('font-size')).toBe '3px' expect($('#jasmine-content').css('font-size')).toBe '3px'
describe "grammar loading", -> describe "grammar loading", ->
@ -298,8 +275,8 @@ describe "the `atom` global", ->
atom.activatePackage('package-with-serialize-error', immediate: true) atom.activatePackage('package-with-serialize-error', immediate: true)
atom.activatePackage('package-with-serialization', immediate: true) atom.activatePackage('package-with-serialization', immediate: true)
atom.deactivatePackages() atom.deactivatePackages()
expect(atom.packageStates['package-with-serialize-error']).toBeUndefined() expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined()
expect(atom.packageStates['package-with-serialization']).toEqual someNumber: 1 expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1
expect(console.error).toHaveBeenCalled() expect(console.error).toHaveBeenCalled()
it "removes the package's grammars", -> it "removes the package's grammars", ->
@ -320,9 +297,9 @@ describe "the `atom` global", ->
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css") one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less") two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css") three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
expect(stylesheetElementForId(one)).not.toExist() expect(atom.themes.stylesheetElementForId(one)).not.toExist()
expect(stylesheetElementForId(two)).not.toExist() expect(atom.themes.stylesheetElementForId(two)).not.toExist()
expect(stylesheetElementForId(three)).not.toExist() expect(atom.themes.stylesheetElementForId(three)).not.toExist()
it "removes the package's scoped-properties", -> it "removes the package's scoped-properties", ->
atom.activatePackage("package-with-scoped-properties") atom.activatePackage("package-with-scoped-properties")

View File

@ -0,0 +1,33 @@
DeserializerManager = require '../src/deserializer-manager'
describe ".deserialize(state)", ->
deserializer = null
class Foo
@deserialize: ({name}) -> new Foo(name)
constructor: (@name) ->
beforeEach ->
deserializer = new DeserializerManager()
deserializer.registerDeserializer(Foo)
it "calls deserialize on the deserializer for the given state object, or returns undefined if one can't be found", ->
spyOn(console, 'warn')
object = deserializer.deserialize({ deserializer: 'Foo', name: 'Bar' })
expect(object.name).toBe 'Bar'
expect(deserializer.deserialize({ deserializer: 'Bogus' })).toBeUndefined()
describe "when the deserializer has a version", ->
beforeEach ->
Foo.version = 2
describe "when the deserialized state has a matching version", ->
it "attempts to deserialize the state", ->
object = deserializer.deserialize({ deserializer: 'Foo', version: 2, name: 'Bar' })
expect(object.name).toBe 'Bar'
describe "when the deserialized state has a non-matching version", ->
it "returns undefined", ->
expect(deserializer.deserialize({ deserializer: 'Foo', version: 3, name: 'Bar' })).toBeUndefined()
expect(deserializer.deserialize({ deserializer: 'Foo', version: 1, name: 'Bar' })).toBeUndefined()
expect(deserializer.deserialize({ deserializer: 'Foo', name: 'Bar' })).toBeUndefined()

View File

@ -1,7 +1,8 @@
try try
require '../src/atom'
require '../src/window' require '../src/window'
atom.show() Atom = require '../src/atom'
window.atom = new Atom()
window.atom.show()
{runSpecSuite} = require './jasmine-helper' {runSpecSuite} = require './jasmine-helper'
document.title = "Spec Suite" document.title = "Spec Suite"

View File

@ -14,12 +14,11 @@ TokenizedBuffer = require '../src/tokenized-buffer'
pathwatcher = require 'pathwatcher' pathwatcher = require 'pathwatcher'
clipboard = require 'clipboard' clipboard = require 'clipboard'
atom.loadBaseStylesheets() atom.themes.loadBaseStylesheets()
requireStylesheet '../static/jasmine' atom.themes.requireStylesheet '../static/jasmine'
fixturePackagesPath = path.resolve(__dirname, './fixtures/packages') fixturePackagesPath = path.resolve(__dirname, './fixtures/packages')
config.packageDirPaths.unshift(fixturePackagesPath) atom.keymap.loadBundledKeymaps()
keymap.loadBundledKeymaps()
[bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = [] [bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = []
$(window).on 'core:close', -> window.close() $(window).on 'core:close', -> window.close()
@ -36,20 +35,22 @@ specProjectPath = path.join(specDirectory, 'fixtures')
beforeEach -> beforeEach ->
$.fx.off = true $.fx.off = true
window.project = new Project(specProjectPath) atom.project = new Project(specProjectPath)
window.project = atom.project
window.resetTimeouts() window.resetTimeouts()
atom.packageStates = {} atom.packages.packageStates = {}
spyOn(atom, 'saveWindowState') spyOn(atom, 'saveWindowState')
syntax.clearGrammarOverrides() atom.syntax.clearGrammarOverrides()
syntax.clearProperties() atom.syntax.clearProperties()
# used to reset keymap after each spec # used to reset keymap after each spec
bindingSetsToRestore = _.clone(keymap.bindingSets) bindingSetsToRestore = _.clone(keymap.bindingSets)
bindingSetsByFirstKeystrokeToRestore = _.clone(keymap.bindingSetsByFirstKeystroke) bindingSetsByFirstKeystrokeToRestore = _.clone(keymap.bindingSetsByFirstKeystroke)
# reset config before each spec; don't load or save from/to `config.json` # reset config before each spec; don't load or save from/to `config.json`
window.config = new Config() config = new Config()
config.packageDirPaths.unshift(fixturePackagesPath)
spyOn(config, 'load') spyOn(config, 'load')
spyOn(config, 'save') spyOn(config, 'save')
config.set "editor.fontFamily", "Courier" config.set "editor.fontFamily", "Courier"
@ -57,6 +58,8 @@ beforeEach ->
config.set "editor.autoIndent", false config.set "editor.autoIndent", false
config.set "core.disabledPackages", ["package-that-throws-an-exception"] config.set "core.disabledPackages", ["package-that-throws-an-exception"]
config.save.reset() config.save.reset()
atom.config = config
window.config = config
# make editor display updates synchronous # make editor display updates synchronous
spyOn(Editor.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay() spyOn(Editor.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()

View File

@ -1,4 +1,5 @@
{$} = require 'atom' path = require 'path'
{$, $$, fs, RootView} = require 'atom'
ThemeManager = require '../src/theme-manager' ThemeManager = require '../src/theme-manager'
AtomPackage = require '../src/atom-package' AtomPackage = require '../src/atom-package'
@ -73,3 +74,81 @@ describe "ThemeManager", ->
expect(loadHandler).toHaveBeenCalled() expect(loadHandler).toHaveBeenCalled()
expect(loadHandler.mostRecentCall.args[0]).toBeInstanceOf AtomPackage expect(loadHandler.mostRecentCall.args[0]).toBeInstanceOf AtomPackage
describe "requireStylesheet(path)", ->
it "synchronously loads css at the given path and installs a style tag for it in the head", ->
cssPath = project.resolve('css.css')
lengthBefore = $('head style').length
themeManager.requireStylesheet(cssPath)
expect($('head style').length).toBe lengthBefore + 1
element = $('head style[id*="css.css"]')
expect(element.attr('id')).toBe cssPath
expect(element.text()).toBe fs.read(cssPath)
# doesn't append twice
themeManager.requireStylesheet(cssPath)
expect($('head style').length).toBe lengthBefore + 1
$('head style[id*="css.css"]').remove()
it "synchronously loads and parses less files at the given path and installs a style tag for it in the head", ->
lessPath = project.resolve('sample.less')
lengthBefore = $('head style').length
themeManager.requireStylesheet(lessPath)
expect($('head style').length).toBe lengthBefore + 1
element = $('head style[id*="sample.less"]')
expect(element.attr('id')).toBe lessPath
expect(element.text()).toBe """
#header {
color: #4d926f;
}
h2 {
color: #4d926f;
}
"""
# doesn't append twice
themeManager.requireStylesheet(lessPath)
expect($('head style').length).toBe lengthBefore + 1
$('head style[id*="sample.less"]').remove()
it "supports requiring css and less stylesheets without an explicit extension", ->
themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'css')
expect($('head style[id*="css.css"]').attr('id')).toBe project.resolve('css.css')
themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'sample')
expect($('head style[id*="sample.less"]').attr('id')).toBe project.resolve('sample.less')
$('head style[id*="css.css"]').remove()
$('head style[id*="sample.less"]').remove()
describe ".removeStylesheet(path)", ->
it "removes styling applied by given stylesheet path", ->
cssPath = require.resolve('./fixtures/css.css')
expect($(document.body).css('font-weight')).not.toBe("bold")
themeManager.requireStylesheet(cssPath)
expect($(document.body).css('font-weight')).toBe("bold")
themeManager.removeStylesheet(cssPath)
expect($(document.body).css('font-weight')).not.toBe("bold")
describe "base stylesheet loading", ->
beforeEach ->
window.rootView = new RootView
rootView.append $$ -> @div class: 'editor'
rootView.attachToDom()
themeManager.load()
it "loads the correct values from the theme's ui-variables file", ->
config.set('core.themes', ['theme-with-ui-variables'])
# an override loaded in the base css
expect(rootView.css("background-color")).toBe "rgb(0, 0, 255)"
# from within the theme itself
expect($(".editor").css("padding-top")).toBe "150px"
expect($(".editor").css("padding-right")).toBe "150px"
expect($(".editor").css("padding-bottom")).toBe "150px"

View File

@ -75,66 +75,6 @@ describe "Window", ->
expect(window.onbeforeunload(new Event('beforeunload'))).toBeFalsy() expect(window.onbeforeunload(new Event('beforeunload'))).toBeFalsy()
expect(atom.confirmSync).toHaveBeenCalled() expect(atom.confirmSync).toHaveBeenCalled()
describe "requireStylesheet(path)", ->
it "synchronously loads css at the given path and installs a style tag for it in the head", ->
cssPath = project.resolve('css.css')
lengthBefore = $('head style').length
requireStylesheet(cssPath)
expect($('head style').length).toBe lengthBefore + 1
element = $('head style[id*="css.css"]')
expect(element.attr('id')).toBe cssPath
expect(element.text()).toBe fs.read(cssPath)
# doesn't append twice
requireStylesheet(cssPath)
expect($('head style').length).toBe lengthBefore + 1
$('head style[id*="css.css"]').remove()
it "synchronously loads and parses less files at the given path and installs a style tag for it in the head", ->
lessPath = project.resolve('sample.less')
lengthBefore = $('head style').length
requireStylesheet(lessPath)
expect($('head style').length).toBe lengthBefore + 1
element = $('head style[id*="sample.less"]')
expect(element.attr('id')).toBe lessPath
expect(element.text()).toBe """
#header {
color: #4d926f;
}
h2 {
color: #4d926f;
}
"""
# doesn't append twice
requireStylesheet(lessPath)
expect($('head style').length).toBe lengthBefore + 1
$('head style[id*="sample.less"]').remove()
it "supports requiring css and less stylesheets without an explicit extension", ->
requireStylesheet path.join(__dirname, 'fixtures', 'css')
expect($('head style[id*="css.css"]').attr('id')).toBe project.resolve('css.css')
requireStylesheet path.join(__dirname, 'fixtures', 'sample')
expect($('head style[id*="sample.less"]').attr('id')).toBe project.resolve('sample.less')
$('head style[id*="css.css"]').remove()
$('head style[id*="sample.less"]').remove()
describe ".removeStylesheet(path)", ->
it "removes styling applied by given stylesheet path", ->
cssPath = require.resolve('./fixtures/css.css')
expect($(document.body).css('font-weight')).not.toBe("bold")
requireStylesheet(cssPath)
expect($(document.body).css('font-weight')).toBe("bold")
removeStylesheet(cssPath)
expect($(document.body).css('font-weight')).not.toBe("bold")
describe ".unloadEditorWindow()", -> describe ".unloadEditorWindow()", ->
it "saves the serialized state of the window so it can be deserialized after reload", -> it "saves the serialized state of the window so it can be deserialized after reload", ->
rootViewState = rootView.serialize() rootViewState = rootView.serialize()
@ -156,38 +96,6 @@ describe "Window", ->
expect(buffer.subscriptionCount()).toBe 0 expect(buffer.subscriptionCount()).toBe 0
describe ".deserialize(state)", ->
class Foo
@deserialize: ({name}) -> new Foo(name)
constructor: (@name) ->
beforeEach ->
registerDeserializer(Foo)
afterEach ->
unregisterDeserializer(Foo)
it "calls deserialize on the deserializer for the given state object, or returns undefined if one can't be found", ->
spyOn(console, 'warn')
object = deserialize({ deserializer: 'Foo', name: 'Bar' })
expect(object.name).toBe 'Bar'
expect(deserialize({ deserializer: 'Bogus' })).toBeUndefined()
describe "when the deserializer has a version", ->
beforeEach ->
Foo.version = 2
describe "when the deserialized state has a matching version", ->
it "attempts to deserialize the state", ->
object = deserialize({ deserializer: 'Foo', version: 2, name: 'Bar' })
expect(object.name).toBe 'Bar'
describe "when the deserialized state has a non-matching version", ->
it "returns undefined", ->
expect(deserialize({ deserializer: 'Foo', version: 3, name: 'Bar' })).toBeUndefined()
expect(deserialize({ deserializer: 'Foo', version: 1, name: 'Bar' })).toBeUndefined()
expect(deserialize({ deserializer: 'Foo', name: 'Bar' })).toBeUndefined()
describe "drag and drop", -> describe "drag and drop", ->
buildDragEvent = (type, files) -> buildDragEvent = (type, files) ->
dataTransfer = dataTransfer =
@ -206,7 +114,7 @@ describe "Window", ->
it "opens it", -> it "opens it", ->
spyOn(atom, "open") spyOn(atom, "open")
event = buildDragEvent("drop", [ {path: "/fake1"}, {path: "/fake2"} ]) event = buildDragEvent("drop", [ {path: "/fake1"}, {path: "/fake2"} ])
window.onDrop(event) $(document).trigger(event)
expect(atom.open.callCount).toBe 1 expect(atom.open.callCount).toBe 1
expect(atom.open.argsForCall[0][0]).toEqual pathsToOpen: ['/fake1', '/fake2'] expect(atom.open.argsForCall[0][0]).toEqual pathsToOpen: ['/fake1', '/fake2']
@ -214,7 +122,7 @@ describe "Window", ->
it "does nothing", -> it "does nothing", ->
spyOn(atom, "open") spyOn(atom, "open")
event = buildDragEvent("drop", []) event = buildDragEvent("drop", [])
window.onDrop(event) $(document).trigger(event)
expect(atom.open).not.toHaveBeenCalled() expect(atom.open).not.toHaveBeenCalled()
describe "when a link is clicked", -> describe "when a link is clicked", ->

View File

@ -83,7 +83,8 @@ class AtomPackage extends Package
activateStylesheets: -> activateStylesheets: ->
type = if @metadata.theme then 'theme' else 'bundled' type = if @metadata.theme then 'theme' else 'bundled'
applyStylesheet(stylesheetPath, content, type) for [stylesheetPath, content] in @stylesheets for [stylesheetPath, content] in @stylesheets
atom.themes.applyStylesheet(stylesheetPath, content, type)
activateResources: -> activateResources: ->
keymap.add(keymapPath, map) for [keymapPath, map] in @keymaps keymap.add(keymapPath, map) for [keymapPath, map] in @keymaps
@ -113,7 +114,8 @@ class AtomPackage extends Package
fsUtils.listSync(menusDirPath, ['cson', 'json']) fsUtils.listSync(menusDirPath, ['cson', 'json'])
loadStylesheets: -> loadStylesheets: ->
@stylesheets = @getStylesheetPaths().map (stylesheetPath) -> [stylesheetPath, loadStylesheet(stylesheetPath)] @stylesheets = @getStylesheetPaths().map (stylesheetPath) ->
[stylesheetPath, atom.themes.loadStylesheet(stylesheetPath)]
getStylesheetsPath: -> getStylesheetsPath: ->
path.join(@path, @constructor.stylesheetsDir) path.join(@path, @constructor.stylesheetsDir)
@ -165,17 +167,17 @@ class AtomPackage extends Package
syntax.removeGrammar(grammar) for grammar in @grammars syntax.removeGrammar(grammar) for grammar in @grammars
syntax.removeProperties(scopedPropertiesPath) for [scopedPropertiesPath] in @scopedProperties syntax.removeProperties(scopedPropertiesPath) for [scopedPropertiesPath] in @scopedProperties
keymap.remove(keymapPath) for [keymapPath] in @keymaps keymap.remove(keymapPath) for [keymapPath] in @keymaps
removeStylesheet(stylesheetPath) for [stylesheetPath] in @stylesheets atom.themes.removeStylesheet(stylesheetPath) for [stylesheetPath] in @stylesheets
reloadStylesheets: -> reloadStylesheets: ->
oldSheets = _.clone(@stylesheets) oldSheets = _.clone(@stylesheets)
@loadStylesheets() @loadStylesheets()
removeStylesheet(stylesheetPath) for [stylesheetPath] in oldSheets atom.themes.removeStylesheet(stylesheetPath) for [stylesheetPath] in oldSheets
@reloadStylesheet(stylesheetPath, content) for [stylesheetPath, content] in @stylesheets @reloadStylesheet(stylesheetPath, content) for [stylesheetPath, content] in @stylesheets
reloadStylesheet: (stylesheetPath, content) -> reloadStylesheet: (stylesheetPath, content) ->
type = if @metadata.theme then 'theme' else 'bundled' type = if @metadata.theme then 'theme' else 'bundled'
window.applyStylesheet(stylesheetPath, content, type) atom.themes.applyStylesheet(stylesheetPath, content, type)
requireMainModule: -> requireMainModule: ->
return @mainModule if @mainModule? return @mainModule if @mainModule?

View File

@ -10,155 +10,140 @@ path = require 'path'
dialog = remote.require 'dialog' dialog = remote.require 'dialog'
app = remote.require 'app' app = remote.require 'app'
{Document} = require 'telepath' {Document} = require 'telepath'
ThemeManager = require './theme-manager' DeserializerManager = require './deserializer-manager'
ContextMenuManager = require './context-menu-manager' Subscriber = require './subscriber'
window.atom = # Public: Atom global for dealing with packages, themes, menus, and the window.
loadedPackages: {} #
activePackages: {} # An instance of this class is always available as the `atom` global.
packageStates: {} module.exports =
themes: new ThemeManager() class Atom
contextMenu: new ContextMenuManager(remote.getCurrentWindow().loadSettings.devMode) _.extend @prototype, Subscriber
getLoadSettings: -> constructor: ->
@getCurrentWindow().loadSettings @rootViewParentSelector = 'body'
@deserializers = new DeserializerManager()
initialize: ->
@unsubscribe()
Config = require './config'
Keymap = require './keymap'
PackageManager = require './package-manager'
Pasteboard = require './pasteboard'
Syntax = require './syntax'
ThemeManager = require './theme-manager'
ContextMenuManager = require './context-menu-manager'
@packages = new PackageManager()
#TODO Remove once packages have been updated to not touch atom.packageStates directly
@__defineGetter__ 'packageStates', => @packages.packageStates
@__defineSetter__ 'packageStates', (packageStates) => @packages.packageStates = packageStates
@subscribe @packages, 'loaded', => @watchThemes()
@themes = new ThemeManager()
@contextMenu = new ContextMenuManager(@getLoadSettings().devMode)
@config = new Config()
@pasteboard = new Pasteboard()
@keymap = new Keymap()
@syntax = deserialize(@getWindowState('syntax')) ? new Syntax()
getCurrentWindow: -> getCurrentWindow: ->
remote.getCurrentWindow() remote.getCurrentWindow()
getPackageState: (name) -> # Public: Get the dimensions of this window.
@packageStates[name] #
# Returns an object with x, y, width, and height keys.
getDimensions: ->
browserWindow = @getCurrentWindow()
[x, y] = browserWindow.getPosition()
[width, height] = browserWindow.getSize()
{x, y, width, height}
setPackageState: (name, state) -> # Public: Set the dimensions of the window.
@packageStates[name] = state #
# The window will be centered if either the x or y coordinate is not set
activatePackages: -> # in the dimensions parameter.
@activatePackage(pack.name) for pack in @getLoadedPackages() #
# * dimensions:
activatePackage: (name, options) -> # + x:
if pack = @loadPackage(name, options) # The new x coordinate.
@activePackages[pack.name] = pack # + y:
pack.activate(options) # The new y coordinate.
pack # + width:
# The new width.
deactivatePackages: -> # + height:
@deactivatePackage(pack.name) for pack in @getActivePackages() # The new height.
setDimensions: ({x, y, width, height}) ->
deactivatePackage: (name) -> browserWindow = @getCurrentWindow()
if pack = @getActivePackage(name) browserWindow.setSize(width, height)
@setPackageState(pack.name, state) if state = pack.serialize?() if x? and y?
pack.deactivate() browserWindow.setPosition(x, y)
delete @activePackages[pack.name]
else else
throw new Error("No active package for name '#{name}'") browserWindow.center()
getActivePackage: (name) -> restoreDimensions: (defaultDimensions={width: 800, height: 600})->
@activePackages[name] dimensions = @getWindowState().getObject('dimensions')
dimensions = defaultDimensions unless dimensions?.width and dimensions?.height
@setDimensions(dimensions)
isPackageActive: (name) -> getLoadSettings: ->
@getActivePackage(name)? @getCurrentWindow().loadSettings
getActivePackages: -> deserializeProject: ->
_.values(@activePackages) Project = require './project'
state = @getWindowState()
@project = deserialize(state.get('project'))
unless @project?
@project = new Project(@getLoadSettings().initialPath)
state.set('project', @project.getState())
loadPackages: -> deserializeRootView: ->
# Ensure atom exports is already in the require cache so the load time RootView = require './root-view'
# of the first package isn't skewed by being the first to require atom state = @getWindowState()
require '../exports/atom' @rootView = deserialize(state.get('rootView'))
unless @rootView?
@rootView = new RootView()
state.set('rootView', @rootView.getState())
$(@rootViewParentSelector).append(@rootView)
@loadPackage(name) for name in @getAvailablePackageNames() when not @isPackageDisabled(name) deserializePackageStates: ->
@watchThemes() state = @getWindowState()
@packages.packageStates = state.getObject('packageStates') ? {}
state.remove('packageStates')
loadPackage: (name, options) -> #TODO Remove theses once packages have been migrated
if @isPackageDisabled(name) getPackageState: (args...) -> @packages.getPackageState(args...)
return console.warn("Tried to load disabled package '#{name}'") setPackageState: (args...) -> @packages.setPackageState(args...)
activatePackages: (args...) -> @packages.activatePackages(args...)
if packagePath = @resolvePackagePath(name) activatePackage: (args...) -> @packages.activatePackage(args...)
return pack if pack = @getLoadedPackage(name) deactivatePackages: (args...) -> @packages.deactivatePackages(args...)
pack = Package.load(packagePath, options) deactivatePackage: (args...) -> @packages.deactivatePackage(args...)
if pack.metadata.theme getActivePackage: (args...) -> @packages.getActivePackage(args...)
@themes.register(pack) isPackageActive: (args...) -> @packages.isPackageActive(args...)
else getActivePackages: (args...) -> @packages.getActivePackages(args...)
@loadedPackages[pack.name] = pack loadPackages: (args...) -> @packages.loadPackages(args...)
pack loadPackage: (args...) -> @packages.loadPackage(args...)
else unloadPackage: (args...) -> @packages.unloadPackage(args...)
throw new Error("Could not resolve '#{name}' to a package path") resolvePackagePath: (args...) -> @packages.resolvePackagePath(args...)
isInternalPackage: (args...) -> @packages.isInternalPackage(args...)
unloadPackage: (name) -> getLoadedPackage: (args...) -> @packages.getLoadedPackage(args...)
if @isPackageActive(name) isPackageLoaded: (args...) -> @packages.isPackageLoaded(args...)
throw new Error("Tried to unload active package '#{name}'") getLoadedPackages: (args...) -> @packages.getLoadedPackages(args...)
isPackageDisabled: (args...) -> @packages.isPackageDisabled(args...)
if pack = @getLoadedPackage(name) getAvailablePackagePaths: (args...) -> @packages.getAvailablePackagePaths(args...)
delete @loadedPackages[pack.name] getAvailablePackageNames: (args...) -> @packages.getAvailablePackageNames(args...)
else getAvailablePackageMetadata: (args...)-> @packages.getAvailablePackageMetadata(args...)
throw new Error("No loaded package for name '#{name}'")
resolvePackagePath: (name) ->
return name if fsUtils.isDirectorySync(name)
packagePath = fsUtils.resolve(config.packageDirPaths..., name)
return packagePath if fsUtils.isDirectorySync(packagePath)
packagePath = path.join(window.resourcePath, 'node_modules', name)
return packagePath if @isInternalPackage(packagePath)
isInternalPackage: (packagePath) ->
{engines} = Package.loadMetadata(packagePath, true)
engines?.atom?
getLoadedPackage: (name) ->
@loadedPackages[name]
isPackageLoaded: (name) ->
@getLoadedPackage(name)?
getLoadedPackages: ->
_.values(@loadedPackages)
isPackageDisabled: (name) ->
_.include(config.get('core.disabledPackages') ? [], name)
getAvailablePackagePaths: ->
packagePaths = []
for packageDirPath in config.packageDirPaths
for packagePath in fsUtils.listSync(packageDirPath)
packagePaths.push(packagePath) if fsUtils.isDirectorySync(packagePath)
for packagePath in fsUtils.listSync(path.join(window.resourcePath, 'node_modules'))
packagePaths.push(packagePath) if @isInternalPackage(packagePath)
_.uniq(packagePaths)
getAvailablePackageNames: ->
_.uniq _.map @getAvailablePackagePaths(), (packagePath) -> path.basename(packagePath)
getAvailablePackageMetadata: ->
packages = []
for packagePath in atom.getAvailablePackagePaths()
name = path.basename(packagePath)
metadata = atom.getLoadedPackage(name)?.metadata ? Package.loadMetadata(packagePath, true)
packages.push(metadata)
packages
loadThemes: -> loadThemes: ->
@themes.load() @themes.load()
watchThemes: -> watchThemes: ->
@themes.on 'reloaded', => @themes.on 'reloaded', =>
@reloadBaseStylesheets() pack.reloadStylesheets?() for name, pack of @getLoadedPackages()
pack.reloadStylesheets?() for name, pack of @loadedPackages
null null
loadBaseStylesheets: ->
requireStylesheet('bootstrap/less/bootstrap')
@reloadBaseStylesheets()
reloadBaseStylesheets: ->
requireStylesheet('../static/atom')
if nativeStylesheetPath = fsUtils.resolveOnLoadPath(process.platform, ['css', 'less'])
requireStylesheet(nativeStylesheetPath)
open: (options) -> open: (options) ->
ipc.sendChannel('open', options) ipc.sendChannel('open', options)
@ -210,8 +195,7 @@ window.atom =
close: -> close: ->
@getCurrentWindow().close() @getCurrentWindow().close()
exit: (status) -> exit: (status) -> app.exit(status)
app.exit(status)
toggleFullScreen: -> toggleFullScreen: ->
@setFullScreen(!@isFullScreen()) @setFullScreen(!@isFullScreen())
@ -236,7 +220,7 @@ window.atom =
filename = "editor-#{sha1}" filename = "editor-#{sha1}"
if filename if filename
path.join(config.userStoragePath, filename) path.join(@config.userStoragePath, filename)
else else
null null
@ -289,8 +273,22 @@ window.atom =
shell.beep() shell.beep()
requireUserInitScript: -> requireUserInitScript: ->
userInitScriptPath = path.join(config.configDirPath, "user.coffee") userInitScriptPath = path.join(@config.configDirPath, "user.coffee")
try try
require userInitScriptPath if fsUtils.isFileSync(userInitScriptPath) require userInitScriptPath if fsUtils.isFileSync(userInitScriptPath)
catch error catch error
console.error "Failed to load `#{userInitScriptPath}`", error.stack, error console.error "Failed to load `#{userInitScriptPath}`", error.stack, error
requireWithGlobals: (id, globals={}) ->
existingGlobals = {}
for key, value of globals
existingGlobals[key] = window[key]
window[key] = value
require(id)
for key, value of existingGlobals
if value is undefined
delete window[key]
else
window[key] = value

View File

@ -8,12 +8,6 @@ async = require 'async'
pathWatcher = require 'pathwatcher' pathWatcher = require 'pathwatcher'
configDirPath = fsUtils.absolute("~/.atom") configDirPath = fsUtils.absolute("~/.atom")
nodeModulesDirPath = path.join(resourcePath, "node_modules")
bundledKeymapsDirPath = path.join(resourcePath, "keymaps")
userPackagesDirPath = path.join(configDirPath, "packages")
userPackageDirPaths = [userPackagesDirPath]
userPackageDirPaths.unshift(path.join(configDirPath, "dev", "packages")) if atom.getLoadSettings().devMode
userStoragePath = path.join(configDirPath, "storage")
# Public: Used to access all of Atom's configuration details. # Public: Used to access all of Atom's configuration details.
# #
@ -36,23 +30,26 @@ module.exports =
class Config class Config
_.extend @prototype, EventEmitter _.extend @prototype, EventEmitter
configDirPath: configDirPath
bundledPackageDirPaths: [nodeModulesDirPath]
bundledKeymapsDirPath: bundledKeymapsDirPath
nodeModulesDirPath: nodeModulesDirPath
packageDirPaths: _.clone(userPackageDirPaths)
userPackageDirPaths: userPackageDirPaths
userStoragePath: userStoragePath
lessSearchPaths: [
path.join(resourcePath, 'static', 'variables')
path.join(resourcePath, 'static')
]
defaultSettings: null defaultSettings: null
settings: null settings: null
configFileHasErrors: null configFileHasErrors: null
# Private: Created during initialization, available as `global.config` # Private: Created during initialization, available as `global.config`
constructor: -> constructor: ->
@configDirPath = configDirPath
@bundledKeymapsDirPath = path.join(resourcePath, "keymaps")
@nodeModulesDirPath = path.join(resourcePath, "node_modules")
@bundledPackageDirPaths = [@nodeModulesDirPath]
@lessSearchPaths = [
path.join(resourcePath, 'static', 'variables')
path.join(resourcePath, 'static')
]
@packageDirPaths = [path.join(configDirPath, "packages")]
if atom.getLoadSettings().devMode
@packageDirPaths.unshift(path.join(configDirPath, "dev", "packages"))
@userPackageDirPaths = _.clone(@packageDirPaths)
@userStoragePath = path.join(configDirPath, "storage")
@defaultSettings = @defaultSettings =
core: _.clone(require('./root-view').configDefaults) core: _.clone(require('./root-view').configDefaults)
editor: _.clone(require('./editor').configDefaults) editor: _.clone(require('./editor').configDefaults)

View File

@ -0,0 +1,38 @@
{Document} = require 'telepath'
module.exports =
class DeserializerManager
constructor: ->
@deserializers = {}
@deferredDeserializers = {}
registerDeserializer: (klasses...) ->
@deserializers[klass.name] = klass for klass in klasses
registerDeferredDeserializer: (name, fn) ->
@deferredDeserializers[name] = fn
unregisterDeserializer: (klasses...) ->
delete @deserializers[klass.name] for klass in klasses
deserialize: (state, params) ->
return unless state?
if deserializer = @getDeserializer(state)
stateVersion = state.get?('version') ? state.version
return if deserializer.version? and deserializer.version isnt stateVersion
if (state instanceof Document) and not deserializer.acceptsDocuments
state = state.toObject()
deserializer.deserialize(state, params)
else
console.warn "No deserializer found for", state
getDeserializer: (state) ->
return unless state?
name = state.get?('deserializer') ? state.deserializer
if @deferredDeserializers[name]
@deferredDeserializers[name]()
delete @deferredDeserializers[name]
@deserializers[name]

129
src/package-manager.coffee Normal file
View File

@ -0,0 +1,129 @@
EventEmitter = require './event-emitter'
fsUtils = require './fs-utils'
_ = require './underscore-extensions'
Package = require './package'
path = require 'path'
module.exports =
class PackageManager
_.extend @prototype, EventEmitter
constructor: ->
@loadedPackages = {}
@activePackages = {}
@packageStates = {}
getPackageState: (name) ->
@packageStates[name]
setPackageState: (name, state) ->
@packageStates[name] = state
activatePackages: ->
@activatePackage(pack.name) for pack in @getLoadedPackages()
activatePackage: (name, options) ->
if pack = @loadPackage(name, options)
@activePackages[pack.name] = pack
pack.activate(options)
pack
deactivatePackages: ->
@deactivatePackage(pack.name) for pack in @getActivePackages()
deactivatePackage: (name) ->
if pack = @getActivePackage(name)
@setPackageState(pack.name, state) if state = pack.serialize?()
pack.deactivate()
delete @activePackages[pack.name]
else
throw new Error("No active package for name '#{name}'")
getActivePackage: (name) ->
@activePackages[name]
isPackageActive: (name) ->
@getActivePackage(name)?
getActivePackages: ->
_.values(@activePackages)
loadPackages: ->
# Ensure atom exports is already in the require cache so the load time
# of the first package isn't skewed by being the first to require atom
require '../exports/atom'
@loadPackage(name) for name in @getAvailablePackageNames() when not @isPackageDisabled(name)
@trigger 'loaded'
loadPackage: (name, options) ->
if @isPackageDisabled(name)
return console.warn("Tried to load disabled package '#{name}'")
if packagePath = @resolvePackagePath(name)
return pack if pack = @getLoadedPackage(name)
pack = Package.load(packagePath, options)
if pack.metadata.theme
atom.themes.register(pack)
else
@loadedPackages[pack.name] = pack
pack
else
throw new Error("Could not resolve '#{name}' to a package path")
unloadPackage: (name) ->
if @isPackageActive(name)
throw new Error("Tried to unload active package '#{name}'")
if pack = @getLoadedPackage(name)
delete @loadedPackages[pack.name]
else
throw new Error("No loaded package for name '#{name}'")
resolvePackagePath: (name) ->
return name if fsUtils.isDirectorySync(name)
packagePath = fsUtils.resolve(config.packageDirPaths..., name)
return packagePath if fsUtils.isDirectorySync(packagePath)
packagePath = path.join(window.resourcePath, 'node_modules', name)
return packagePath if @isInternalPackage(packagePath)
isInternalPackage: (packagePath) ->
{engines} = Package.loadMetadata(packagePath, true)
engines?.atom?
getLoadedPackage: (name) ->
@loadedPackages[name]
isPackageLoaded: (name) ->
@getLoadedPackage(name)?
getLoadedPackages: ->
_.values(@loadedPackages)
isPackageDisabled: (name) ->
_.include(config.get('core.disabledPackages') ? [], name)
getAvailablePackagePaths: ->
packagePaths = []
for packageDirPath in config.packageDirPaths
for packagePath in fsUtils.listSync(packageDirPath)
packagePaths.push(packagePath) if fsUtils.isDirectorySync(packagePath)
for packagePath in fsUtils.listSync(path.join(window.resourcePath, 'node_modules'))
packagePaths.push(packagePath) if @isInternalPackage(packagePath)
_.uniq(packagePaths)
getAvailablePackageNames: ->
_.uniq _.map @getAvailablePackagePaths(), (packagePath) -> path.basename(packagePath)
getAvailablePackageMetadata: ->
packages = []
for packagePath in atom.getAvailablePackagePaths()
name = path.basename(packagePath)
metadata = atom.getLoadedPackage(name)?.metadata ? Package.loadMetadata(packagePath, true)
packages.push(metadata)
packages

View File

@ -4,7 +4,7 @@ Package = require './package'
AtomPackage = require './atom-package' AtomPackage = require './atom-package'
_ = require './underscore-extensions' _ = require './underscore-extensions'
$ = require './jquery-extensions'
fsUtils = require './fs-utils' fsUtils = require './fs-utils'
# Private: Handles discovering and loading available themes. # Private: Handles discovering and loading available themes.
@ -15,6 +15,7 @@ class ThemeManager
constructor: -> constructor: ->
@loadedThemes = [] @loadedThemes = []
@activeThemes = [] @activeThemes = []
@lessCache = null
# Internal-only: # Internal-only:
register: (theme) -> register: (theme) ->
@ -33,9 +34,85 @@ class ThemeManager
getLoadedThemes: -> getLoadedThemes: ->
_.clone(@loadedThemes) _.clone(@loadedThemes)
# Internal-only:
loadBaseStylesheets: ->
@requireStylesheet('bootstrap/less/bootstrap')
@reloadBaseStylesheets()
# Internal-only:
reloadBaseStylesheets: ->
@requireStylesheet('../static/atom')
if nativeStylesheetPath = fsUtils.resolveOnLoadPath(process.platform, ['css', 'less'])
@requireStylesheet(nativeStylesheetPath)
# Internal-only:
stylesheetElementForId: (id) ->
$("""head style[id="#{id}"]""")
# Internal-only:
resolveStylesheet: (stylesheetPath) ->
if path.extname(stylesheetPath).length > 0
fsUtils.resolveOnLoadPath(stylesheetPath)
else
fsUtils.resolveOnLoadPath(stylesheetPath, ['css', 'less'])
# Public: resolves and applies the stylesheet specified by the path.
#
# * stylesheetPath: String. Can be an absolute path or the name of a CSS or
# LESS file in the stylesheets path.
#
# Returns the absolute path to the stylesheet
requireStylesheet: (stylesheetPath) ->
if fullPath = @resolveStylesheet(stylesheetPath)
content = @loadStylesheet(fullPath)
@applyStylesheet(fullPath, content)
else
throw new Error("Could not find a file at path '#{stylesheetPath}'")
fullPath
# Internal-only:
loadStylesheet: (stylesheetPath) ->
if path.extname(stylesheetPath) is '.less'
@loadLessStylesheet(stylesheetPath)
else
fsUtils.read(stylesheetPath)
# Internal-only:
loadLessStylesheet: (lessStylesheetPath) ->
unless lessCache?
LessCompileCache = require './less-compile-cache'
@lessCache = new LessCompileCache()
try
@lessCache.read(lessStylesheetPath)
catch e
console.error """
Error compiling less stylesheet: #{lessStylesheetPath}
Line number: #{e.line}
#{e.message}
"""
# Internal-only:
removeStylesheet: (stylesheetPath) ->
unless fullPath = @resolveStylesheet(stylesheetPath)
throw new Error("Could not find a file at path '#{stylesheetPath}'")
@stylesheetElementForId(fullPath).remove()
# Internal-only:
applyStylesheet: (id, text, ttype = 'bundled') ->
styleElement = @stylesheetElementForId(id)
if styleElement.length
styleElement.text(text)
else
if $("head style.#{ttype}").length
$("head style.#{ttype}:last").after "<style class='#{ttype}' id='#{id}'>#{text}</style>"
else
$("head").append "<style class='#{ttype}' id='#{id}'>#{text}</style>"
# Internal-only: # Internal-only:
unload: -> unload: ->
removeStylesheet(@userStylesheetPath) if @userStylesheetPath? @removeStylesheet(@userStylesheetPath) if @userStylesheetPath?
theme.deactivate() while theme = @activeThemes.pop() theme.deactivate() while theme = @activeThemes.pop()
# Internal-only: # Internal-only:
@ -50,7 +127,7 @@ class ThemeManager
@activateTheme(themeName) for themeName in themeNames @activateTheme(themeName) for themeName in themeNames
@loadUserStylesheet() @loadUserStylesheet()
@reloadBaseStylesheets()
@trigger('reloaded') @trigger('reloaded')
# Private: # Private:
@ -118,5 +195,5 @@ class ThemeManager
loadUserStylesheet: -> loadUserStylesheet: ->
if userStylesheetPath = @getUserStylesheetPath() if userStylesheetPath = @getUserStylesheetPath()
@userStylesheetPath = userStylesheetPath @userStylesheetPath = userStylesheetPath
userStylesheetContents = loadStylesheet(userStylesheetPath) userStylesheetContents = @loadStylesheet(userStylesheetPath)
applyStylesheet(userStylesheetPath, userStylesheetContents, 'userTheme') @applyStylesheet(userStylesheetPath, userStylesheetContents, 'userTheme')

View File

@ -1,9 +1,10 @@
# Like sands through the hourglass, so are the days of our lives. # Like sands through the hourglass, so are the days of our lives.
startTime = new Date().getTime() startTime = new Date().getTime()
require './atom'
require './window' require './window'
Atom = require './atom'
window.atom = new Atom()
window.setUpEnvironment('editor') window.setUpEnvironment('editor')
window.startEditorWindow() window.startEditorWindow()
console.log "Window load time: #{new Date().getTime() - startTime}ms" console.log "Window load time: #{new Date().getTime() - startTime}ms"

View File

@ -1,7 +1,7 @@
$ = require './jquery-extensions' $ = require './jquery-extensions'
_ = require './underscore-extensions' _ = require './underscore-extensions'
ipc = require 'ipc' ipc = require 'ipc'
remote = require 'remote' shell = require 'shell'
Subscriber = require './subscriber' Subscriber = require './subscriber'
fsUtils = require './fs-utils' fsUtils = require './fs-utils'
@ -20,27 +20,43 @@ class WindowEventHandler
$(atom.contextMenu.activeElement).trigger(command, args...) $(atom.contextMenu.activeElement).trigger(command, args...)
@subscribe $(window), 'focus', -> $("body").removeClass('is-blurred') @subscribe $(window), 'focus', -> $("body").removeClass('is-blurred')
@subscribe $(window), 'blur', -> $("body").addClass('is-blurred') @subscribe $(window), 'blur', -> $("body").addClass('is-blurred')
@subscribe $(window), 'window:open-path', (event, {pathToOpen, initialLine}) -> @subscribe $(window), 'window:open-path', (event, {pathToOpen, initialLine}) ->
rootView?.open(pathToOpen, {initialLine}) unless fsUtils.isDirectorySync(pathToOpen) atom.rootView?.open(pathToOpen, {initialLine}) unless fsUtils.isDirectorySync(pathToOpen)
@subscribe $(window), 'beforeunload', => @subscribe $(window), 'beforeunload', =>
confirmed = rootView?.confirmClose() confirmed = atom.rootView?.confirmClose()
atom.hide() if confirmed and not @reloadRequested and remote.getCurrentWindow().isWebViewFocused() atom.hide() if confirmed and not @reloadRequested and atom.getCurrentWindow().isWebViewFocused()
@reloadRequested = false @reloadRequested = false
confirmed confirmed
@subscribe $(window), 'unload', ->
atom.getWindowState().set('dimensions', atom.getDimensions())
@subscribeToCommand $(window), 'window:toggle-full-screen', => atom.toggleFullScreen() @subscribeToCommand $(window), 'window:toggle-full-screen', => atom.toggleFullScreen()
@subscribeToCommand $(window), 'window:close', => atom.close() @subscribeToCommand $(window), 'window:close', => atom.close()
@subscribeToCommand $(window), 'window:reload', => @subscribeToCommand $(window), 'window:reload', =>
@reloadRequested = true @reloadRequested = true
atom.reload() atom.reload()
@subscribeToCommand $(window), 'window:toggle-dev-tools', => atom.toggleDevTools() @subscribeToCommand $(window), 'window:toggle-dev-tools', => atom.toggleDevTools()
@subscribeToCommand $(document), 'core:focus-next', @focusNext @subscribeToCommand $(document), 'core:focus-next', @focusNext
@subscribeToCommand $(document), 'core:focus-previous', @focusPrevious @subscribeToCommand $(document), 'core:focus-previous', @focusPrevious
@subscribe $(document), 'keydown', keymap.handleKeyEvent @subscribe $(document), 'keydown', atom.keymap.handleKeyEvent
@subscribe $(document), 'drop', (e) ->
e.preventDefault()
e.stopPropagation()
pathsToOpen = _.pluck(e.originalEvent.dataTransfer.files, 'path')
atom.open({pathsToOpen}) if pathsToOpen.length > 0
@subscribe $(document), 'drop', onDrop
@subscribe $(document), 'dragover', (e) -> @subscribe $(document), 'dragover', (e) ->
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
@ -54,7 +70,7 @@ class WindowEventHandler
openLink: (event) => openLink: (event) =>
location = $(event.target).attr('href') location = $(event.target).attr('href')
if location and location[0] isnt '#' and /^https?:\/\//.test(location) if location and location[0] isnt '#' and /^https?:\/\//.test(location)
require('shell').openExternal(location) shell.openExternal(location)
false false
eachTabIndexedElement: (callback) -> eachTabIndexedElement: (callback) ->

View File

@ -1,17 +1,9 @@
fsUtils = require './fs-utils'
path = require 'path' path = require 'path'
telepath = require 'telepath'
$ = require './jquery-extensions' $ = require './jquery-extensions'
_ = require './underscore-extensions' _ = require './underscore-extensions'
remote = require 'remote'
ipc = require 'ipc' ipc = require 'ipc'
WindowEventHandler = require './window-event-handler' WindowEventHandler = require './window-event-handler'
deserializers = {}
deferredDeserializers = {}
defaultWindowDimensions = {width: 800, height: 600}
lessCache = null
### Internal ### ### Internal ###
windowEventHandler = null windowEventHandler = null
@ -28,19 +20,13 @@ displayWindow = ->
# This method is called in any window needing a general environment, including specs # This method is called in any window needing a general environment, including specs
window.setUpEnvironment = (windowMode) -> window.setUpEnvironment = (windowMode) ->
atom.windowMode = windowMode atom.windowMode = windowMode
window.resourcePath = remote.getCurrentWindow().loadSettings.resourcePath window.resourcePath = atom.getLoadSettings().resourcePath
atom.initialize()
Config = require './config' #TODO remove once all packages use the atom global
Syntax = require './syntax' window.config = atom.config
Pasteboard = require './pasteboard' window.syntax = atom.syntax
Keymap = require './keymap' window.pasteboard = atom.pasteboard
window.keymap = atom.keymap
window.rootViewParentSelector = 'body'
window.config = new Config
window.syntax = deserialize(atom.getWindowState('syntax')) ? new Syntax
window.pasteboard = new Pasteboard
window.keymap = new Keymap()
# Set up the default event handlers and menus for a non-editor windows. # Set up the default event handlers and menus for a non-editor windows.
# #
@ -50,8 +36,8 @@ window.setUpEnvironment = (windowMode) ->
# This should only be called after setUpEnvironment() has been called. # This should only be called after setUpEnvironment() has been called.
window.setUpDefaultEvents = -> window.setUpDefaultEvents = ->
windowEventHandler = new WindowEventHandler windowEventHandler = new WindowEventHandler
keymap.loadBundledKeymaps() atom.keymap.loadBundledKeymaps()
ipc.sendChannel 'update-application-menu', keymap.keystrokesByCommandForSelector('body') ipc.sendChannel 'update-application-menu', atom.keymap.keystrokesByCommandForSelector('body')
# This method is only called when opening a real application window # This method is only called when opening a real application window
window.startEditorWindow = -> window.startEditorWindow = ->
@ -60,16 +46,16 @@ window.startEditorWindow = ->
windowEventHandler = new WindowEventHandler windowEventHandler = new WindowEventHandler
restoreDimensions() restoreDimensions()
config.load() atom.config.load()
keymap.loadBundledKeymaps() atom.keymap.loadBundledKeymaps()
atom.loadBaseStylesheets() atom.themes.loadBaseStylesheets()
atom.loadPackages() atom.packages.loadPackages()
atom.loadThemes() atom.themes.load()
deserializeEditorWindow() deserializeEditorWindow()
atom.activatePackages() atom.packages.activatePackages()
keymap.loadUserKeymaps() atom.keymap.loadUserKeymaps()
atom.requireUserInitScript() atom.requireUserInitScript()
ipc.sendChannel 'update-application-menu', keymap.keystrokesByCommandForSelector('body') ipc.sendChannel 'update-application-menu', atom.keymap.keystrokesByCommandForSelector('body')
$(window).on 'unload', -> $(window).on 'unload', ->
$(document.body).hide() $(document.body).hide()
unloadEditorWindow() unloadEditorWindow()
@ -78,188 +64,58 @@ window.startEditorWindow = ->
displayWindow() displayWindow()
window.unloadEditorWindow = -> window.unloadEditorWindow = ->
return if not project and not rootView return if not atom.project and not atom.rootView
windowState = atom.getWindowState() windowState = atom.getWindowState()
windowState.set('project', project.serialize()) windowState.set('project', atom.project.serialize())
windowState.set('syntax', syntax.serialize()) windowState.set('syntax', atom.syntax.serialize())
windowState.set('rootView', rootView.serialize()) windowState.set('rootView', atom.rootView.serialize())
atom.deactivatePackages() atom.packages.deactivatePackages()
windowState.set('packageStates', atom.packageStates) windowState.set('packageStates', atom.packages.packageStates)
atom.saveWindowState() atom.saveWindowState()
rootView.remove() atom.rootView.remove()
project.destroy() atom.project.destroy()
windowEventHandler?.unsubscribe() windowEventHandler?.unsubscribe()
lessCache?.destroy()
window.rootView = null window.rootView = null
window.project = null window.project = null
window.installAtomCommand = (callback) -> installAtomCommand = (callback) ->
commandPath = path.join(window.resourcePath, 'atom.sh') commandPath = path.join(window.resourcePath, 'atom.sh')
require('./command-installer').install(commandPath, callback) require('./command-installer').install(commandPath, callback)
window.installApmCommand = (callback) -> installApmCommand = (callback) ->
commandPath = path.join(window.resourcePath, 'node_modules', '.bin', 'apm') commandPath = path.join(window.resourcePath, 'node_modules', '.bin', 'apm')
require('./command-installer').install(commandPath, callback) require('./command-installer').install(commandPath, callback)
window.onDrop = (e) ->
e.preventDefault()
e.stopPropagation()
pathsToOpen = _.pluck(e.originalEvent.dataTransfer.files, 'path')
atom.open({pathsToOpen}) if pathsToOpen.length > 0
window.deserializeEditorWindow = -> window.deserializeEditorWindow = ->
RootView = require './root-view' atom.deserializePackageStates()
Project = require './project' atom.deserializeProject()
window.project = atom.project
atom.deserializeRootView()
window.rootView = atom.rootView
windowState = atom.getWindowState() window.getDimensions = -> atom.getDimensions()
atom.packageStates = windowState.getObject('packageStates') ? {} window.setDimensions = (args...) -> atom.setDimensions(args...)
windowState.remove('packageStates')
window.project = deserialize(windowState.get('project')) window.restoreDimensions = (args...) -> atom.restoreDimensions(args...)
unless window.project?
window.project = new Project(atom.getLoadSettings().initialPath)
windowState.set('project', window.project.getState())
window.rootView = deserialize(windowState.get('rootView'))
unless window.rootView?
window.rootView = new RootView()
windowState.set('rootView', window.rootView.getState())
$(rootViewParentSelector).append(rootView)
project.on 'path-changed', ->
projectPath = project.getPath()
atom.getLoadSettings().initialPath = projectPath
window.stylesheetElementForId = (id) ->
$("""head style[id="#{id}"]""")
window.resolveStylesheet = (stylesheetPath) ->
if path.extname(stylesheetPath).length > 0
fsUtils.resolveOnLoadPath(stylesheetPath)
else
fsUtils.resolveOnLoadPath(stylesheetPath, ['css', 'less'])
# Public: resolves and applies the stylesheet specified by the path.
#
# * stylesheetPath: String. Can be an absolute path or the name of a CSS or
# LESS file in the stylesheets path.
#
# Returns the absolute path to the stylesheet
window.requireStylesheet = (stylesheetPath) ->
if fullPath = window.resolveStylesheet(stylesheetPath)
content = window.loadStylesheet(fullPath)
window.applyStylesheet(fullPath, content)
else
throw new Error("Could not find a file at path '#{stylesheetPath}'")
fullPath
window.loadStylesheet = (stylesheetPath) ->
if path.extname(stylesheetPath) is '.less'
loadLessStylesheet(stylesheetPath)
else
fsUtils.read(stylesheetPath)
window.loadLessStylesheet = (lessStylesheetPath) ->
unless lessCache?
LessCompileCache = require './less-compile-cache'
lessCache = new LessCompileCache()
try
lessCache.read(lessStylesheetPath)
catch e
console.error """
Error compiling less stylesheet: #{lessStylesheetPath}
Line number: #{e.line}
#{e.message}
"""
window.removeStylesheet = (stylesheetPath) ->
unless fullPath = window.resolveStylesheet(stylesheetPath)
throw new Error("Could not find a file at path '#{stylesheetPath}'")
window.stylesheetElementForId(fullPath).remove()
window.applyStylesheet = (id, text, ttype = 'bundled') ->
styleElement = window.stylesheetElementForId(id)
if styleElement.length
styleElement.text(text)
else
if $("head style.#{ttype}").length
$("head style.#{ttype}:last").after "<style class='#{ttype}' id='#{id}'>#{text}</style>"
else
$("head").append "<style class='#{ttype}' id='#{id}'>#{text}</style>"
window.getDimensions = ->
browserWindow = remote.getCurrentWindow()
[x, y] = browserWindow.getPosition()
[width, height] = browserWindow.getSize()
{x, y, width, height}
window.setDimensions = ({x, y, width, height}) ->
browserWindow = remote.getCurrentWindow()
browserWindow.setSize(width, height)
if x? and y?
browserWindow.setPosition(x, y)
else
browserWindow.center()
window.restoreDimensions = ->
dimensions = atom.getWindowState().getObject('dimensions')
dimensions = defaultWindowDimensions unless dimensions?.width and dimensions?.height
window.setDimensions(dimensions)
$(window).on 'unload', -> atom.getWindowState().set('dimensions', window.getDimensions())
window.onerror = -> window.onerror = ->
atom.openDevTools() atom.openDevTools()
window.registerDeserializers = (args...) -> window.registerDeserializers = (args...) ->
registerDeserializer(arg) for arg in args atom.deserializers.registerDeserializer(args...)
window.registerDeserializer = (args...) ->
window.registerDeserializer = (klass) -> atom.deserializers.registerDeserializer(args...)
deserializers[klass.name] = klass window.registerDeferredDeserializer = (args...) ->
atom.deserializers.registerDeferredDeserializer(args...)
window.registerDeferredDeserializer = (name, fn) -> window.unregisterDeserializer = (args...) ->
deferredDeserializers[name] = fn atom.deserializers.unregisterDeserializer(args...)
window.deserialize = (args...) ->
window.unregisterDeserializer = (klass) -> atom.deserializers.deserialize(args...)
delete deserializers[klass.name] window.getDeserializer = (args...) ->
atom.deserializer.getDeserializer(args...)
window.deserialize = (state, params) -> window.requireWithGlobals = (args...) ->
return unless state? atom.requireWithGlobals(args...)
if deserializer = getDeserializer(state)
stateVersion = state.get?('version') ? state.version
return if deserializer.version? and deserializer.version isnt stateVersion
if (state instanceof telepath.Document) and not deserializer.acceptsDocuments
state = state.toObject()
deserializer.deserialize(state, params)
else
console.warn "No deserializer found for", state
window.getDeserializer = (state) ->
return unless state?
name = state.get?('deserializer') ? state.deserializer
if deferredDeserializers[name]
deferredDeserializers[name]()
delete deferredDeserializers[name]
deserializers[name]
window.requireWithGlobals = (id, globals={}) ->
existingGlobals = {}
for key, value of globals
existingGlobals[key] = window[key]
window[key] = value
require(id)
for key, value of existingGlobals
if value is undefined
delete window[key]
else
window[key] = value
window.measure = (description, fn) -> window.measure = (description, fn) ->
start = new Date().getTime() start = new Date().getTime()