Comparar commits

..

10 Commits

Autor SHA1 Mensagem Data
Nathan Sobo fdfb88c8e5 Invoke handlers on detached DOM nodes 2014-10-30 09:46:31 -06:00
Nathan Sobo 0a73550213 Patch Node::add/removeEventListener to use the CommandRegistry
This ensures that all listeners slot into the correct location in a
single dispatch, regardless of whether they are added with
Node::addEventListener or via CommandRegistry::listen/capture. This
allows selector-based listeners to integrate into the rest of events
in a global way.
2014-10-29 17:09:23 -06:00
Nathan Sobo d88b8e854b Add CommandRegistry::capture and perform capture-phase dispatch 2014-10-29 15:40:36 -06:00
Nathan Sobo 3ea2746b4d Rename CommandManager::add to ::listen
This will complement a method for registering capture-phase listeners,
which will be called ::capture instead of ::listen. This is clearer than
passing a boolean argument like the native APIs do, and we need to
support capture if we’re going to take over all event handling.
2014-10-29 11:42:23 -06:00
Nathan Sobo 752ba0a698 Use default ::bubbles setting when dispatching native events w/ strings 2014-10-29 11:42:23 -06:00
Nathan Sobo a75eefcf55 Honor the ::bubbles property on dispatched events 2014-10-29 11:41:35 -06:00
Nathan Sobo 6e89c07891 Handle keydown events via CommandRegistry 2014-10-29 11:41:35 -06:00
Nathan Sobo 5a041721cd Use addEventListener in $.fn.enableKeymap 2014-10-29 11:41:35 -06:00
Nathan Sobo 3feb5568f2 Route all jQuery events via CommandRegistry unless they have namespaces 2014-10-29 11:41:35 -06:00
Nathan Sobo 5e320b39d9 Allow event objects to be dispatched via CommandRegistry::dispatch 2014-10-29 11:41:35 -06:00
45 arquivos alterados com 1471 adições e 459 exclusões
+13 -6
Ver Arquivo
@@ -101,23 +101,30 @@ For more information on how to work with Atom's official packages, see
## Documentation Styleguide
* Use [AtomDoc](https://github.com/atom/atomdoc).
* Use [TomDoc](http://tomdoc.org).
* Use [Markdown](https://daringfireball.net/projects/markdown).
* Reference methods and classes in markdown with the custom `{}` notation:
* Reference classes with `{ClassName}`
* Reference instance methods with `{ClassName::methodName}`
* Reference class methods with `{ClassName.methodName}`
* Delegate to comments elsewhere with `{Delegates to: ClassName.methodName}`
style notation.
### Example
```coffee
# Public: Disable the package with the given name.
#
# * `name` The {String} name of the package to disable.
# * `options` (optional) The {Object} with disable options (default: {}):
# * `trackTime` A {Boolean}, `true` to track the amount of time taken.
# * `ignoreErrors` A {Boolean}, `true` to catch and ignore errors thrown.
# * `callback` The {Function} to call after the package has been disabled.
# This method emits multiple events:
#
# * `package-will-be-disabled` - before the package is disabled.
# * `package-disabled` - after the package is disabled.
#
# name - The {String} name of the package to disable.
# options - The {Object} with disable options (default: {}):
# :trackTime - `true` to track the amount of time disabling took.
# :ignoreErrors - `true` to catch and ignore errors thrown.
# callback - The {Function} to call after the package has been disabled.
#
# Returns `undefined`.
disablePackage: (name, options, callback) ->
+1 -1
Ver Arquivo
@@ -7,7 +7,7 @@ describe "editorView.", ->
beforeEach ->
atom.workspaceViewParentSelector = '#jasmine-content'
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
atom.workspaceView.attachToDom()
atom.workspaceView.width(1024)
-15
Ver Arquivo
@@ -60,18 +60,3 @@ module.exports =
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""
'jschardet@1.1.0':
license: 'LGPL'
source: 'README.md in the repository'
sourceText: """
JsChardet
=========
Port of python's chardet (http://chardet.feedparser.org/).
License
-------
LGPL
"""
+4 -35
Ver Arquivo
@@ -1,5 +1,4 @@
{Point, Range} = require 'text-buffer'
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
{deprecate} = require 'grim'
module.exports =
@@ -14,49 +13,19 @@ module.exports =
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
{$, $$, $$$, View} = require '../src/space-pen-extensions'
module.exports.Emitter = Emitter
module.exports.Disposable = Disposable
module.exports.CompositeDisposable = CompositeDisposable
module.exports.$ = $
module.exports.$$ = $$
module.exports.$$$ = $$$
module.exports.View = View
module.exports.TextEditorElement = require '../src/text-editor-element'
module.exports.TextEditorView = require '../src/text-editor-view'
module.exports.ScrollView = require '../src/scroll-view'
module.exports.SelectListView = require '../src/select-list-view'
module.exports.Task = require '../src/task'
module.exports.View = View
module.exports.WorkspaceView = require '../src/workspace-view'
module.exports.Workspace = require '../src/workspace'
module.exports.React = require 'react-atom-fork'
module.exports.Reactionary = require 'reactionary-atom-fork'
# Export deprecated SpacePen views.
# Adjust their prototype chain to inherit from our extend version of SpacePen
#
# We avoid using/assigning a cached module for these classes in order to
# prevent polluting every required version with these changes. The only
# versions that should get their prototypes adjusted are the ones exported
# here.
uncachedRequire = (id) ->
modulePath = require.resolve(id)
delete require.cache[modulePath]
loadedModule = require(modulePath)
delete require.cache[modulePath]
loadedModule
TextEditorView = uncachedRequire 'atom-space-pen-views/lib/text-editor-view'
ScrollView = uncachedRequire 'atom-space-pen-views/lib/scroll-view'
SelectListView = uncachedRequire 'atom-space-pen-views/lib/select-list-view'
# Make Atom's modified SpacePen View prototype the prototype of the imported View
TextEditorView.prototype.__proto__.__proto__ = View.prototype
TextEditorView.prototype.__proto__.useLegacyAttachHooks = true
module.exports.TextEditorView = TextEditorView
module.exports.ScrollView = ScrollView
module.exports.SelectListView = SelectListView
Object.defineProperty module.exports, 'Git', get: ->
deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`"
module.exports.GitRepository
-6
Ver Arquivo
@@ -190,12 +190,6 @@
submenu: [
{ label: 'Terms of Use', command: 'application:open-terms-of-use' }
{ label: 'Documentation', command: 'application:open-documentation' }
{ label: 'Roadmap', command: 'application:open-roadmap' }
{ label: 'Frequently Asked Questions', command: 'application:open-faq' }
{ type: 'separator' }
{ label: 'Community Discussions', command: 'application:open-discussions' }
{ label: 'Report Issue', command: 'application:report-issue' }
{ label: 'Search Issues', command: 'application:search-issues' }
{ type: 'separator' }
]
}
-6
Ver Arquivo
@@ -147,12 +147,6 @@
{ label: "VERSION", enabled: false }
{ type: 'separator' }
{ label: '&Documentation', command: 'application:open-documentation' }
{ label: 'Roadmap', command: 'application:open-roadmap' }
{ label: 'Frequently Asked Questions', command: 'application:open-faq' }
{ type: 'separator' }
{ label: 'Community Discussions', command: 'application:open-discussions' }
{ label: 'Report Issue', command: 'application:report-issue' }
{ label: 'Search Issues', command: 'application:search-issues' }
{ type: 'separator' }
]
}
-6
Ver Arquivo
@@ -165,12 +165,6 @@
{ label: "VERSION", enabled: false }
{ type: 'separator' }
{ label: '&Documentation', command: 'application:open-documentation' }
{ label: 'Roadmap', command: 'application:open-roadmap' }
{ label: 'Frequently Asked Questions', command: 'application:open-faq' }
{ type: 'separator' }
{ label: 'Community Discussions', command: 'application:open-discussions' }
{ label: 'Report Issue', command: 'application:report-issue' }
{ label: 'Search Issues', command: 'application:search-issues' }
{ type: 'separator' }
]
}
+10 -11
Ver Arquivo
@@ -1,7 +1,7 @@
{
{
"name": "atom",
"productName": "Atom",
"version": "0.142.0",
"version": "0.141.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -21,7 +21,6 @@
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^2.2.1",
"atom-space-pen-views": "^0.11.0",
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
"clear-cut": "0.4.0",
"coffee-script": "1.7.0",
@@ -44,7 +43,7 @@
"nslog": "^1.0.1",
"oniguruma": "^3.0.4",
"optimist": "0.4.0",
"pathwatcher": "^2.3.2",
"pathwatcher": "^2.1.3",
"property-accessors": "^1",
"q": "^1.0.1",
"random-words": "0.0.1",
@@ -57,9 +56,9 @@
"season": "^1.0.2",
"semver": "2.2.1",
"serializable": "^1",
"space-pen": "^3.8.1",
"space-pen": "3.8.0",
"temp": "0.7.0",
"text-buffer": "^3.4",
"text-buffer": "^3.3.0",
"theorist": "^1.0.2",
"underscore-plus": "^1.6.1",
"vm-compatibility-layer": "0.1.0"
@@ -82,15 +81,15 @@
"bracket-matcher": "0.62.0",
"command-palette": "0.27.0",
"deprecation-cop": "0.11.0",
"dev-live-reload": "0.35.0",
"encoding-selector": "0.5.0",
"dev-live-reload": "0.34.0",
"exception-reporting": "0.20.0",
"feedback": "0.33.0",
"find-and-replace": "0.141.0",
"fuzzy-finder": "0.60.0",
"git-diff": "0.42.0",
"go-to-line": "0.26.0",
"grammar-selector": "0.37.0",
"image-view": "0.40.0",
"grammar-selector": "0.35.0",
"image-view": "0.38.0",
"incompatible-packages": "0.10.0",
"keybinding-resolver": "0.20.0",
"link": "0.26.0",
@@ -99,7 +98,7 @@
"open-on-github": "0.30.0",
"package-generator": "0.31.0",
"release-notes": "0.36.0",
"settings-view": "0.154.0",
"settings-view": "0.153.0",
"snippets": "0.56.0",
"spell-check": "0.43.0",
"status-bar": "0.46.0",
+1 -1
Ver Arquivo
@@ -6,7 +6,7 @@ ThemeManager = require '../src/theme-manager'
describe "the `atom` global", ->
beforeEach ->
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
describe 'window sizing methods', ->
describe '::getPosition and ::setPosition', ->
+126 -33
Ver Arquivo
@@ -15,14 +15,18 @@ describe "CommandRegistry", ->
document.querySelector('#jasmine-content').appendChild(parent)
registry = new CommandRegistry
atom.commands.restoreDOMEventMethods()
registry.patchDOMEventMethods()
afterEach ->
registry.restoreDOMEventMethods()
atom.commands.patchDOMEventMethods()
registry.destroy()
describe "when a command event is dispatched on an element", ->
it "invokes callbacks with selectors matching the target", ->
called = false
registry.add '.grandchild', 'command', (event) ->
registry.listen '.grandchild', 'command', (event) ->
expect(this).toBe grandchild
expect(event.type).toBe 'command'
expect(event.eventPhase).toBe Event.BUBBLING_PHASE
@@ -36,13 +40,13 @@ describe "CommandRegistry", ->
it "invokes callbacks with selectors matching ancestors of the target", ->
calls = []
registry.add '.child', 'command', (event) ->
registry.listen '.child', 'command', (event) ->
expect(this).toBe child
expect(event.target).toBe grandchild
expect(event.currentTarget).toBe child
calls.push('child')
registry.add '.parent', 'command', (event) ->
registry.listen '.parent', 'command', (event) ->
expect(this).toBe parent
expect(event.target).toBe grandchild
expect(event.currentTarget).toBe parent
@@ -53,10 +57,10 @@ describe "CommandRegistry", ->
it "invokes inline listeners prior to listeners applied via selectors", ->
calls = []
registry.add '.grandchild', 'command', -> calls.push('grandchild')
registry.add child, 'command', -> calls.push('child-inline')
registry.add '.child', 'command', -> calls.push('child')
registry.add '.parent', 'command', -> calls.push('parent')
registry.listen '.grandchild', 'command', -> calls.push('grandchild')
registry.listen child, 'command', -> calls.push('child-inline')
registry.listen '.child', 'command', -> calls.push('child')
registry.listen '.parent', 'command', -> calls.push('parent')
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['grandchild', 'child-inline', 'child', 'parent']
@@ -65,41 +69,77 @@ describe "CommandRegistry", ->
child.classList.add('foo', 'bar')
calls = []
registry.add '.foo.bar', 'command', -> calls.push('.foo.bar')
registry.add '.foo', 'command', -> calls.push('.foo')
registry.add '.bar', 'command', -> calls.push('.bar') # specificity ties favor commands added later, like CSS
registry.listen '.foo.bar', 'command', -> calls.push('.foo.bar')
registry.listen '.foo', 'command', -> calls.push('.foo')
registry.listen '.bar', 'command', -> calls.push('.bar') # specificity ties favor commands added later, like CSS
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['.foo.bar', '.bar', '.foo']
it "does not bubble the event if the ::bubbles property is false on the dispatched event", ->
calls = []
registry.listen '.grandchild', 'command', -> calls.push('grandchild')
registry.listen '.child', 'command', -> calls.push('child')
registry.listen '.parent', 'command', -> calls.push('parent')
grandchild.dispatchEvent(new CustomEvent('command', bubbles: false))
expect(calls).toEqual ['grandchild']
it "invokes capture-phase listeners before bubble-phase listeners", ->
calls = []
# Spot-check event details for both capture and bubbling phase
registry.capture '.grandchild', 'command', (event) ->
expect(this).toBe grandchild
expect(event.type).toBe 'command'
expect(event.eventPhase).toBe Event.CAPTURING_PHASE
expect(event.target).toBe grandchild
expect(event.currentTarget).toBe grandchild
calls.push('grandchild-capture')
registry.listen '.grandchild', 'command', (event) ->
expect(this).toBe grandchild
expect(event.type).toBe 'command'
expect(event.eventPhase).toBe Event.BUBBLING_PHASE
expect(event.target).toBe grandchild
expect(event.currentTarget).toBe grandchild
calls.push('grandchild-bubble')
registry.capture child, 'command', -> calls.push('child-inline-capture')
registry.listen child, 'command', -> calls.push('child-inline-bubble')
registry.capture '.child', 'command', -> calls.push('child-capture')
registry.capture '.parent', 'command', -> calls.push('parent-capture')
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['parent-capture', 'child-inline-capture', 'child-capture', 'grandchild-capture', 'grandchild-bubble', 'child-inline-bubble']
it "stops bubbling through ancestors when .stopPropagation() is called on the event", ->
calls = []
registry.add '.parent', 'command', -> calls.push('parent')
registry.add '.child', 'command', -> calls.push('child-2')
registry.add '.child', 'command', (event) -> calls.push('child-1'); event.stopPropagation()
registry.listen '.parent', 'command', -> calls.push('parent')
registry.listen '.child', 'command', -> calls.push('child-2')
registry.listen '.child', 'command', (event) -> calls.push('child-1'); event.stopPropagation()
dispatchedEvent = new CustomEvent('command', bubbles: true)
spyOn(dispatchedEvent, 'stopPropagation')
grandchild.dispatchEvent(dispatchedEvent)
expect(calls).toEqual ['child-1', 'child-2']
expect(dispatchedEvent.stopPropagation).toHaveBeenCalled()
it "stops invoking callbacks when .stopImmediatePropagation() is called on the event", ->
calls = []
registry.add '.parent', 'command', -> calls.push('parent')
registry.add '.child', 'command', -> calls.push('child-2')
registry.add '.child', 'command', (event) -> calls.push('child-1'); event.stopImmediatePropagation()
registry.listen '.parent', 'command', -> calls.push('parent')
registry.listen '.child', 'command', -> calls.push('child-2')
registry.listen '.child', 'command', (event) -> calls.push('child-1'); event.stopImmediatePropagation()
dispatchedEvent = new CustomEvent('command', bubbles: true)
spyOn(dispatchedEvent, 'stopImmediatePropagation')
grandchild.dispatchEvent(dispatchedEvent)
expect(calls).toEqual ['child-1']
expect(dispatchedEvent.stopImmediatePropagation).toHaveBeenCalled()
it "forwards .preventDefault() calls from the synthetic event to the original", ->
registry.add '.child', 'command', (event) -> event.preventDefault()
registry.listen '.child', 'command', (event) -> event.preventDefault()
dispatchedEvent = new CustomEvent('command', bubbles: true)
spyOn(dispatchedEvent, 'preventDefault')
@@ -107,7 +147,7 @@ describe "CommandRegistry", ->
expect(dispatchedEvent.preventDefault).toHaveBeenCalled()
it "forwards .abortKeyBinding() calls from the synthetic event to the original", ->
registry.add '.child', 'command', (event) -> event.abortKeyBinding()
registry.listen '.child', 'command', (event) -> event.abortKeyBinding()
dispatchedEvent = new CustomEvent('command', bubbles: true)
dispatchedEvent.abortKeyBinding = jasmine.createSpy('abortKeyBinding')
@@ -117,8 +157,8 @@ describe "CommandRegistry", ->
it "allows listeners to be removed via a disposable returned by ::add", ->
calls = []
disposable1 = registry.add '.parent', 'command', -> calls.push('parent')
disposable2 = registry.add '.child', 'command', -> calls.push('child')
disposable1 = registry.listen '.parent', 'command', -> calls.push('parent')
disposable2 = registry.listen '.child', 'command', -> calls.push('child')
disposable1.dispose()
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
@@ -132,7 +172,7 @@ describe "CommandRegistry", ->
it "allows multiple commands to be registered under one selector when called with an object", ->
calls = []
disposable = registry.add '.child',
disposable = registry.listen '.child',
'command-1': -> calls.push('command-1')
'command-2': -> calls.push('command-2')
@@ -149,10 +189,10 @@ describe "CommandRegistry", ->
describe "::findCommands({target})", ->
it "returns commands that can be invoked on the target or its ancestors", ->
registry.add '.parent', 'namespace:command-1', ->
registry.add '.child', 'namespace:command-2', ->
registry.add '.grandchild', 'namespace:command-3', ->
registry.add '.grandchild.no-match', 'namespace:command-4', ->
registry.listen '.parent', 'namespace:command-1', ->
registry.listen '.child', 'namespace:command-2', ->
registry.listen '.grandchild', 'namespace:command-3', ->
registry.listen '.grandchild.no-match', 'namespace:command-4', ->
expect(registry.findCommands(target: grandchild)[0..2]).toEqual [
{name: 'namespace:command-3', displayName: 'Namespace: Command 3'}
@@ -163,7 +203,7 @@ describe "CommandRegistry", ->
describe "::dispatch(target, commandName)", ->
it "simulates invocation of the given command ", ->
called = false
registry.add '.grandchild', 'command', (event) ->
registry.listen '.grandchild', 'command', (event) ->
expect(this).toBe grandchild
expect(event.type).toBe 'command'
expect(event.eventPhase).toBe Event.BUBBLING_PHASE
@@ -175,18 +215,42 @@ describe "CommandRegistry", ->
expect(called).toBe true
it "returns a boolean indicating whether any listeners matched the command", ->
registry.add '.grandchild', 'command', ->
registry.listen '.grandchild', 'command', ->
expect(registry.dispatch(grandchild, 'command')).toBe true
expect(registry.dispatch(grandchild, 'bogus')).toBe false
expect(registry.dispatch(parent, 'command')).toBe false
it "does not perform bubbling for native event names that should not bubble", ->
calls = []
registry.listen '.grandchild', 'focus', -> calls.push('grandchild')
registry.listen '.child', 'focus', -> calls.push('child')
registry.listen '.parent', 'focus', -> calls.push('parent')
registry.dispatch(grandchild, 'focus')
expect(calls).toEqual ['grandchild']
it "allows an event object to be passed instead of an event name", ->
called = false
registry.listen '.grandchild', 'command', (event) ->
expect(this).toBe grandchild
expect(event.type).toBe 'command'
expect(event.eventPhase).toBe Event.BUBBLING_PHASE
expect(event.target).toBe grandchild
expect(event.currentTarget).toBe grandchild
expect(event.detail).toEqual {a: 1}
called = true
registry.dispatch(grandchild, new CustomEvent('command', bubbles: true), {a: 1})
expect(called).toBe true
describe "::getSnapshot and ::restoreSnapshot", ->
it "removes all command handlers except for those in the snapshot", ->
registry.add '.parent', 'namespace:command-1', ->
registry.add '.child', 'namespace:command-2', ->
registry.listen '.parent', 'namespace:command-1', ->
registry.listen '.child', 'namespace:command-2', ->
snapshot = registry.getSnapshot()
registry.add '.grandchild', 'namespace:command-3', ->
registry.listen '.grandchild', 'namespace:command-3', ->
expect(registry.findCommands(target: grandchild)[0..2]).toEqual [
{name: 'namespace:command-3', displayName: 'Namespace: Command 3'}
@@ -201,10 +265,39 @@ describe "CommandRegistry", ->
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
]
registry.add '.grandchild', 'namespace:command-3', ->
registry.listen '.grandchild', 'namespace:command-3', ->
registry.restoreSnapshot(snapshot)
expect(registry.findCommands(target: grandchild)[0..1]).toEqual [
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
]
describe "::addEventListener and ::removeEventListener overrides", ->
it "mixes listeners registered via ::addEventListener with selector-based listeners", ->
calls = []
registry.listen '.grandchild', 'command', -> calls.push('grandchild')
registry.listen '.child', 'command', -> calls.push('child')
registry.listen '.parent', 'command', -> calls.push('parent')
bubbleListener = -> calls.push('child-inline-bubble')
captureListener = -> calls.push('child-inline-capture')
child.addEventListener('command', bubbleListener)
child.addEventListener('command', captureListener, true)
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['child-inline-capture', 'grandchild', 'child-inline-bubble', 'child', 'parent']
child.removeEventListener('command', bubbleListener)
child.removeEventListener('command', captureListener, true)
calls = []
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['grandchild', 'child', 'parent']
it "invokes handlers on detached DOM nodes", ->
detachedNode = document.createElement('div')
called = false
detachedNode.addEventListener 'command', -> called = true
detachedNode.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(called).toBe true
@@ -6,7 +6,7 @@ module.exports =
activate: ->
@activateCallCount++
atom.commands.add 'atom-workspace', 'activation-command', =>
atom.commands.listen 'atom-workspace', 'activation-command', =>
@activationCommandCallCount++
atom.workspaceView.getActiveView()?.command 'activation-command', =>
@@ -1,4 +0,0 @@
{
"theme": "syntax",
"stylesheets": ["editor.less"]
}
+3 -3
Ver Arquivo
@@ -3,7 +3,7 @@ Package = require '../src/package'
describe "PackageManager", ->
beforeEach ->
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
describe "::loadPackage(name)", ->
it "continues if the package has an invalid package.json", ->
@@ -118,7 +118,7 @@ describe "PackageManager", ->
spyOn(Package.prototype, 'requireMainModule').andCallThrough()
workspaceCommandListener = jasmine.createSpy('workspaceCommandListener')
atom.commands.add '.workspace', 'activation-command', workspaceCommandListener
atom.commands.listen '.workspace', 'activation-command', workspaceCommandListener
promise = atom.packages.activatePackage('package-with-activation-commands')
@@ -138,7 +138,7 @@ describe "PackageManager", ->
legacyCommandListener = jasmine.createSpy("legacyCommandListener")
editorView.command 'activation-command', legacyCommandListener
editorCommandListener = jasmine.createSpy("editorCommandListener")
atom.commands.add 'atom-text-editor', 'activation-command', editorCommandListener
atom.commands.listen 'atom-text-editor', 'activation-command', editorCommandListener
editorView[0].dispatchEvent(new CustomEvent('activation-command', bubbles: true))
expect(mainModule.activate.callCount).toBe 1
expect(mainModule.legacyActivationCommandCallCount).toBe 1
+6 -6
Ver Arquivo
@@ -19,7 +19,7 @@ describe "PaneContainerView", ->
save: -> @saved = true
isEqual: (other) -> @name is other?.name
container = atom.views.getView(atom.workspace.paneContainer).__spacePenView
container = atom.workspace.getView(atom.workspace.paneContainer).__spacePenView
pane1 = container.getRoot()
pane1.activateItem(new TestView('1'))
pane2 = pane1.splitRight(new TestView('2'))
@@ -73,7 +73,7 @@ describe "PaneContainerView", ->
describe "serialization", ->
it "can be serialized and deserialized, and correctly adjusts dimensions of deserialized panes after attach", ->
newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)')).toExist()
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(2)')).toExist()
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(3)')).toExist()
@@ -89,14 +89,14 @@ describe "PaneContainerView", ->
describe "if the 'core.destroyEmptyPanes' config option is false (the default)", ->
it "leaves the empty panes intact", ->
newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)')).toExist()
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-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 = atom.views.getView(container.model.testSerialization()).__spacePenView
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
expect(newContainer.find('atom-pane-axis.horizontal, atom-pane-axis.vertical')).not.toExist()
expect(newContainer.find('> :contains(1)')).toExist()
@@ -109,7 +109,7 @@ describe "PaneContainerView", ->
item2b = new TestView('2b')
item3a = new TestView('3a')
container = atom.views.getView(new PaneContainer).__spacePenView
container = atom.workspace.getView(new PaneContainer).__spacePenView
pane1 = container.getRoot()
pane1.activateItem(item1a)
container.attachToDom()
@@ -259,7 +259,7 @@ describe "PaneContainerView", ->
# |7|8|9|
# -------
container = atom.views.getView(new PaneContainer).__spacePenView
container = atom.workspace.getView(new PaneContainer).__spacePenView
pane1 = container.getRoot()
pane1.activateItem(new TestView('1'))
pane4 = pane1.splitDown(new TestView('4'))
+3 -3
Ver Arquivo
@@ -24,7 +24,7 @@ describe "PaneView", ->
beforeEach ->
deserializerDisposable = atom.deserializers.add(TestView)
container = atom.views.getView(new PaneContainer).__spacePenView
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 = atom.views.getView(container.model.testSerialization()).__spacePenView
container2 = atom.workspace.getView(container.model.testSerialization()).__spacePenView
pane2 = container2.getRoot()
container2.attachToDom()
expect(pane2).toMatchSelector(':has(:focus)')
$(document.activeElement).blur()
container3 = atom.views.getView(container.model.testSerialization()).__spacePenView
container3 = atom.workspace.getView(container.model.testSerialization()).__spacePenView
pane3 = container3.getRoot()
container3.attachToDom()
expect(pane3).not.toMatchSelector(':has(:focus)')
+212
Ver Arquivo
@@ -0,0 +1,212 @@
SelectListView = require '../src/select-list-view'
{$, $$} = require 'atom'
describe "SelectListView", ->
[selectList, items, list, filterEditorView] = []
beforeEach ->
items = [
["A", "Alpha"], ["B", "Bravo"], ["C", "Charlie"],
["D", "Delta"], ["E", "Echo"], ["F", "Foxtrot"]
]
selectList = new SelectListView
selectList.setMaxItems(4)
selectList.getFilterKey = -> 1
selectList.viewForItem = (item) ->
$$ -> @li item[1], class: item[0]
selectList.confirmed = jasmine.createSpy('confirmed hook')
selectList.cancelled = jasmine.createSpy('cancelled hook')
selectList.setItems(items)
{list, filterEditorView} = selectList
describe "when an array is assigned", ->
it "populates the list with up to maxItems items, based on the liForElement function", ->
expect(list.find('li').length).toBe selectList.maxItems
expect(list.find('li:eq(0)')).toHaveText 'Alpha'
expect(list.find('li:eq(0)')).toHaveClass 'A'
describe "viewForItem(item)", ->
it "allows raw DOM elements to be returned", ->
selectList.viewForItem = (item) ->
li = document.createElement('li')
li.classList.add(item[0])
li.innerText = item[1]
li
selectList.setItems(items)
expect(list.find('li').length).toBe selectList.maxItems
expect(list.find('li:eq(0)')).toHaveText 'Alpha'
expect(list.find('li:eq(0)')).toHaveClass 'A'
expect(selectList.getSelectedItem()).toBe items[0]
it "allows raw HTML to be returned", ->
selectList.viewForItem = (item) ->
"<li>#{item}</li>"
selectList.setItems(['Bermuda', 'Bahama'])
expect(list.find('li:eq(0)')).toHaveText 'Bermuda'
expect(selectList.getSelectedItem()).toBe 'Bermuda'
describe "when the text of the mini editor changes", ->
beforeEach ->
selectList.attachToDom()
it "filters the elements in the list based on the scoreElement function and selects the first item", ->
filterEditorView.getEditor().insertText('la')
window.advanceClock(selectList.inputThrottle)
expect(list.find('li').length).toBe 2
expect(list.find('li:contains(Alpha)')).toExist()
expect(list.find('li:contains(Delta)')).toExist()
expect(list.find('li:first')).toHaveClass 'selected'
expect(selectList.error).not.toBeVisible()
it "displays an error if there are no matches, removes error when there are matches", ->
filterEditorView.getEditor().insertText('nothing will match this')
window.advanceClock(selectList.inputThrottle)
expect(list.find('li').length).toBe 0
expect(selectList.error).not.toBeHidden()
filterEditorView.getEditor().setText('la')
window.advanceClock(selectList.inputThrottle)
expect(list.find('li').length).toBe 2
expect(selectList.error).not.toBeVisible()
it "displays no elements until the array has been set on the list", ->
selectList.items = null
selectList.list.empty()
filterEditorView.getEditor().insertText('la')
window.advanceClock(selectList.inputThrottle)
expect(list.find('li').length).toBe 0
expect(selectList.error).toBeHidden()
selectList.setItems(items)
expect(list.find('li').length).toBe 2
describe "when core:move-up / core:move-down are triggered on the filterEditorView", ->
it "selects the previous / next item in the list, or wraps around to the other side", ->
expect(list.find('li:first')).toHaveClass 'selected'
filterEditorView.trigger 'core:move-up'
expect(list.find('li:first')).not.toHaveClass 'selected'
expect(list.find('li:last')).toHaveClass 'selected'
filterEditorView.trigger 'core:move-down'
expect(list.find('li:first')).toHaveClass 'selected'
expect(list.find('li:last')).not.toHaveClass 'selected'
filterEditorView.trigger 'core:move-down'
expect(list.find('li:eq(0)')).not.toHaveClass 'selected'
expect(list.find('li:eq(1)')).toHaveClass 'selected'
filterEditorView.trigger 'core:move-down'
expect(list.find('li:eq(1)')).not.toHaveClass 'selected'
expect(list.find('li:eq(2)')).toHaveClass 'selected'
filterEditorView.trigger 'core:move-up'
expect(list.find('li:eq(2)')).not.toHaveClass 'selected'
expect(list.find('li:eq(1)')).toHaveClass 'selected'
it "scrolls to keep the selected item in view", ->
selectList.attachToDom()
itemHeight = list.find('li').outerHeight()
list.height(itemHeight * 2)
filterEditorView.trigger 'core:move-down'
filterEditorView.trigger 'core:move-down'
expect(list.scrollBottom()).toBe itemHeight * 3
filterEditorView.trigger 'core:move-down'
expect(list.scrollBottom()).toBe itemHeight * 4
filterEditorView.trigger 'core:move-up'
filterEditorView.trigger 'core:move-up'
expect(list.scrollTop()).toBe itemHeight
describe "the core:confirm event", ->
describe "when there is an item selected (because the list in not empty)", ->
it "triggers the selected hook with the selected array element", ->
filterEditorView.trigger 'core:move-down'
filterEditorView.trigger 'core:move-down'
filterEditorView.trigger 'core:confirm'
expect(selectList.confirmed).toHaveBeenCalledWith(items[2])
describe "when there is no item selected (because the list is empty)", ->
beforeEach ->
selectList.attachToDom()
it "does not trigger the confirmed hook", ->
filterEditorView.getEditor().insertText("i will never match anything")
window.advanceClock(selectList.inputThrottle)
expect(list.find('li')).not.toExist()
filterEditorView.trigger 'core:confirm'
expect(selectList.confirmed).not.toHaveBeenCalled()
it "does trigger the cancelled hook", ->
filterEditorView.getEditor().insertText("i will never match anything")
window.advanceClock(selectList.inputThrottle)
expect(list.find('li')).not.toExist()
filterEditorView.trigger 'core:confirm'
expect(selectList.cancelled).toHaveBeenCalled()
describe "when a list item is clicked", ->
it "selects the item on mousedown and confirms it on mouseup", ->
item = list.find('li:eq(1)')
item.mousedown()
expect(item).toHaveClass 'selected'
item.mouseup()
expect(selectList.confirmed).toHaveBeenCalledWith(items[1])
describe "the core:cancel event", ->
it "triggers the cancelled hook and detaches and empties the select list", ->
spyOn(selectList, 'detach')
filterEditorView.trigger 'core:cancel'
expect(selectList.cancelled).toHaveBeenCalled()
expect(selectList.detach).toHaveBeenCalled()
expect(selectList.list).toBeEmpty()
describe "when the mini editor loses focus", ->
it "triggers the cancelled hook and detaches the select list", ->
spyOn(selectList, 'detach')
filterEditorView.hiddenInput.trigger 'focusout'
expect(selectList.cancelled).toHaveBeenCalled()
expect(selectList.detach).toHaveBeenCalled()
describe "the core:move-to-top event", ->
it "scrolls to the top, selects the first element, and does not bubble the event", ->
selectList.attachToDom()
moveToTopHandler = jasmine.createSpy("moveToTopHandler")
selectList.parent().on 'core:move-to-top', moveToTopHandler
selectList.trigger 'core:move-down'
expect(list.find('li:eq(1)')).toHaveClass 'selected'
selectList.trigger 'core:move-to-top'
expect(list.find('li:first')).toHaveClass 'selected'
expect(moveToTopHandler).not.toHaveBeenCalled()
describe "the core:move-to-bottom event", ->
it "scrolls to the bottom, selects the last element, and does not bubble the event", ->
selectList.attachToDom()
moveToBottomHandler = jasmine.createSpy("moveToBottomHandler")
selectList.parent().on 'core:move-to-bottom', moveToBottomHandler
expect(list.find('li:first')).toHaveClass 'selected'
selectList.trigger 'core:move-to-bottom'
expect(list.find('li:last')).toHaveClass 'selected'
expect(moveToBottomHandler).not.toHaveBeenCalled()
+3 -5
Ver Arquivo
@@ -14,6 +14,7 @@ Config = require '../src/config'
{Point} = require 'text-buffer'
Project = require '../src/project'
TextEditor = require '../src/text-editor'
TextEditorView = require '../src/text-editor-view'
TokenizedBuffer = require '../src/tokenized-buffer'
TextEditorComponent = require '../src/text-editor-component'
pathwatcher = require 'pathwatcher'
@@ -109,6 +110,7 @@ beforeEach ->
config.save.reset()
# make editor display updates synchronous
spyOn(TextEditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
TextEditorComponent.performSyncUpdates = true
spyOn(atom, "setRepresentedFilename")
@@ -349,11 +351,7 @@ $.fn.resultOfTrigger = (type) ->
event.result
$.fn.enableKeymap = ->
@on 'keydown', (e) ->
originalEvent = e.originalEvent ? e
Object.defineProperty(originalEvent, 'target', get: -> e.target) unless originalEvent.target?
atom.keymaps.handleKeyboardEvent(originalEvent)
not e.originalEvent.defaultPrevented
@element.addEventListener 'keydown', (event) -> atom.keymaps.handleKeyboardEvent(event)
$.fn.attachToDom = ->
@appendTo($('#jasmine-content')) unless @isOnDom()
+1 -7
Ver Arquivo
@@ -1,7 +1,7 @@
_ = require 'underscore-plus'
{extend, flatten, toArray, last} = _
{TextEditorView} = require 'atom'
TextEditorView = require '../src/text-editor-view'
TextEditorComponent = require '../src/text-editor-component'
nbsp = String.fromCharCode(160)
@@ -2286,12 +2286,6 @@ describe "TextEditorComponent", ->
editor.setGrammar(atom.syntax.nullGrammar)
expect(wrapperNode.dataset.grammar).toBe 'text plain null-grammar'
describe "encoding data attributes", ->
it "adds and updates the encoding data attribute based on the current encoding", ->
expect(wrapperNode.dataset.encoding).toBe 'utf8'
editor.setEncoding('utf16le')
expect(wrapperNode.dataset.encoding).toBe 'utf16le'
describe "detaching and reattaching the editor (regression)", ->
it "does not throw an exception", ->
wrapperView.detach()
-13
Ver Arquivo
@@ -157,19 +157,6 @@ describe "TextEditor", ->
expect(observed).toEqual [__filename, undefined]
describe "encoding", ->
it "notifies ::onDidChangeEncoding observers when the editor encoding changes", ->
observed = []
editor.onDidChangeEncoding (encoding) -> observed.push(encoding)
editor.setEncoding('utf16le')
editor.setEncoding('utf16le')
editor.setEncoding('utf16be')
editor.setEncoding()
editor.setEncoding()
expect(observed).toEqual ['utf16le', 'utf16be', 'utf8']
describe "cursor", ->
describe ".getLastCursor()", ->
it "returns the most recently created cursor", ->
+21 -18
Ver Arquivo
@@ -92,8 +92,8 @@ describe "ThemeManager", ->
runs ->
reloadHandler.reset()
expect($('style[group=theme]')).toHaveLength 2
expect($('style[group=theme]:eq(1)').attr('source-path')).toMatch /atom-dark-syntax/
expect($('style[group=theme]')).toHaveLength 1
expect($('style[group=theme]:eq(0)').attr('source-path')).toMatch /atom-dark-syntax/
atom.config.set('core.themes', ['atom-light-syntax', 'atom-dark-syntax'])
waitsFor ->
@@ -111,7 +111,7 @@ describe "ThemeManager", ->
runs ->
reloadHandler.reset()
expect($('style[group=theme]')).toHaveLength 2
expect($('style[group=theme]')).toHaveLength 0
# atom-dark-ui has an directory path, the syntax one doesn't
atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui'])
@@ -208,7 +208,7 @@ describe "ThemeManager", ->
describe "base stylesheet loading", ->
beforeEach ->
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
atom.workspaceView.append $('<atom-text-editor>')
atom.workspaceView.attachToDom()
@@ -217,7 +217,7 @@ describe "ThemeManager", ->
it "loads the correct values from the theme's ui-variables file", ->
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables'])
atom.config.set('core.themes', ['theme-with-ui-variables'])
waitsFor ->
reloadHandler.callCount > 0
@@ -234,7 +234,7 @@ describe "ThemeManager", ->
describe "when there is a theme with incomplete variables", ->
it "loads the correct values from the fallback ui-variables", ->
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
atom.config.set('core.themes', ['theme-with-incomplete-ui-variables', 'theme-with-syntax-variables'])
atom.config.set('core.themes', ['theme-with-incomplete-ui-variables'])
waitsFor ->
reloadHandler.callCount > 0
@@ -251,7 +251,7 @@ describe "ThemeManager", ->
expect(atom.workspaceView).toHaveClass 'theme-atom-dark-ui'
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables'])
atom.config.set('core.themes', ['theme-with-ui-variables'])
waitsFor ->
reloadHandler.callCount > 0
@@ -259,9 +259,7 @@ describe "ThemeManager", ->
runs ->
# `theme-` twice as it prefixes the name with `theme-`
expect(atom.workspaceView).toHaveClass 'theme-theme-with-ui-variables'
expect(atom.workspaceView).toHaveClass 'theme-theme-with-syntax-variables'
expect(atom.workspaceView).not.toHaveClass 'theme-atom-dark-ui'
expect(atom.workspaceView).not.toHaveClass 'theme-atom-dark-syntax'
describe "when the user stylesheet changes", ->
it "reloads it", ->
@@ -310,19 +308,24 @@ describe "ThemeManager", ->
expect(stylesheetsChangedHandler).toHaveBeenCalled()
describe "when a non-existent theme is present in the config", ->
beforeEach ->
spyOn(console, 'warn')
atom.config.set('core.themes', ['non-existent-dark-ui', 'non-existent-dark-syntax'])
it "logs a warning but does not throw an exception (regression)", ->
reloaded = false
waitsForPromise ->
themeManager.activateThemes()
it 'uses the default dark UI and syntax themes and logs a warning', ->
activeThemeNames = themeManager.getActiveNames()
expect(console.warn.callCount).toBe 2
expect(activeThemeNames.length).toBe(2)
expect(activeThemeNames).toContain('atom-dark-ui')
expect(activeThemeNames).toContain('atom-dark-syntax')
runs ->
disposable = themeManager.onDidReloadAll ->
disposable.dispose()
reloaded = true
spyOn(console, 'warn')
expect(-> atom.config.set('core.themes', ['atom-light-ui', 'theme-really-does-not-exist'])).not.toThrow()
waitsFor -> reloaded
runs ->
expect(console.warn.callCount).toBe 1
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
describe "when in safe mode", ->
beforeEach ->
+2 -5
Ver Arquivo
@@ -14,14 +14,9 @@ describe "Window", ->
loadSettings.initialPath = initialPath
loadSettings
atom.project.destroy()
windowEventHandler = new WindowEventHandler()
atom.deserializeEditorWindow()
projectPath = atom.project.getPaths()[0]
afterEach ->
windowEventHandler.unsubscribe()
$(window).off 'beforeunload'
describe "when the window is loaded", ->
it "doesn't have .is-blurred on the body tag", ->
expect($("body")).not.toHaveClass("is-blurred")
@@ -107,6 +102,8 @@ describe "Window", ->
describe ".removeEditorWindow()", ->
it "unsubscribes from all buffers", ->
spyOn(atom.windowEventHandler, 'unsubscribe') # don't unsubscribe from window events
waitsForPromise ->
atom.workspace.open("sample.js")
+5 -4
Ver Arquivo
@@ -1,7 +1,8 @@
{$, $$, WorkspaceView, View, TextEditorView} = require 'atom'
{$, $$, WorkspaceView, View} = require 'atom'
Q = require 'q'
path = require 'path'
temp = require 'temp'
TextEditorView = require '../src/text-editor-view'
PaneView = require '../src/pane-view'
Workspace = require '../src/workspace'
@@ -12,7 +13,7 @@ describe "WorkspaceView", ->
atom.project.setPaths([atom.project.resolve('dir')])
pathToOpen = atom.project.resolve('a')
atom.workspace = new Workspace
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
atom.workspaceView.enableKeymap()
atom.workspaceView.focus()
@@ -28,7 +29,7 @@ describe "WorkspaceView", ->
atom.workspaceView.remove()
atom.project = atom.deserializers.deserialize(projectState)
atom.workspace = Workspace.deserialize(workspaceState)
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
atom.workspaceView.attachToDom()
describe "when the serialized WorkspaceView has an unsaved buffer", ->
@@ -273,7 +274,7 @@ describe "WorkspaceView", ->
describe 'panel containers', ->
workspaceElement = null
beforeEach ->
workspaceElement = atom.views.getView(atom.workspace)
workspaceElement = atom.workspace.getView(atom.workspace)
it 'inserts panel container elements in the correct places in the DOM', ->
leftContainer = workspaceElement.querySelector('atom-panel-container[location="left"]')
+2 -6
Ver Arquivo
@@ -140,9 +140,6 @@ class Atom extends Model
# Public: A {DeserializerManager} instance
deserializers: null
# Public: A {ViewRegistry} instance
views: null
# Public: A {Workspace} instance
workspace: null
@@ -185,7 +182,6 @@ class Atom extends Model
Config = require './config'
KeymapManager = require './keymap-extensions'
ViewRegistry = require './view-registry'
CommandRegistry = require './command-registry'
PackageManager = require './package-manager'
Clipboard = require './clipboard'
@@ -213,7 +209,7 @@ class Atom extends Model
@keymaps = new KeymapManager({configDirPath, resourcePath})
@keymap = @keymaps # Deprecated
@commands = new CommandRegistry
@views = new ViewRegistry
@commands.patchDOMEventMethods()
@packages = new PackageManager({devMode, configDirPath, resourcePath, safeMode})
@styles = new StyleManager
document.head.appendChild(new StylesElement)
@@ -602,7 +598,7 @@ class Atom extends Model
startTime = Date.now()
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
@workspaceView = @views.getView(@workspace).__spacePenView
@workspaceView = @workspace.getView(@workspace).__spacePenView
@deserializeTimings.workspace = Date.now() - startTime
@keymaps.defaultTarget = @workspaceView[0]
+5 -3
Ver Arquivo
@@ -22,10 +22,14 @@ class ApplicationMenu
# keystrokesByCommand - An Object where the keys are commands and the values
# are Arrays containing the keystroke.
update: (window, template, keystrokesByCommand) ->
return unless window is @lastFocusedWindow
@translateTemplate(template, keystrokesByCommand)
@substituteVersion(template)
@windowTemplates.set(window, template)
@setActiveTemplate(template) if window is @lastFocusedWindow
@setActiveTemplate(template)
@showUpdateMenuItem(global.atomApplication.autoUpdateManager.getState())
setActiveTemplate: (template) ->
unless _.isEqual(template, @activeTemplate)
@@ -33,8 +37,6 @@ class ApplicationMenu
@menu = Menu.buildFromTemplate(_.deepClone(template))
Menu.setApplicationMenu(@menu)
@showUpdateMenuItem(global.atomApplication.autoUpdateManager.getState())
# Register a BrowserWindow with this application menu.
addWindow: (window) ->
@lastFocusedWindow ?= window
-6
Ver Arquivo
@@ -155,13 +155,7 @@ class AtomApplication
atomWindow?.browserWindow.inspectElement(x, y)
@on 'application:open-documentation', -> require('shell').openExternal('https://atom.io/docs/latest/?app')
@on 'application:open-discussions', -> require('shell').openExternal('https://discuss.atom.io')
@on 'application:open-roadmap', -> require('shell').openExternal('https://atom.io/roadmap?app')
@on 'application:open-faq', -> require('shell').openExternal('https://atom.io/faq')
@on 'application:open-terms-of-use', -> require('shell').openExternal('https://atom.io/terms')
@on 'application:report-issue', -> require('shell').openExternal('https://github.com/atom/atom/issues/new')
@on 'application:search-issues', -> require('shell').openExternal('https://github.com/issues?q=+is%3Aissue+user%3Aatom')
@on 'application:install-update', -> @autoUpdateManager.install()
@on 'application:check-for-update', => @autoUpdateManager.check()
+178 -42
Ver Arquivo
@@ -1,15 +1,50 @@
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
{specificity} = require 'clear-cut'
_ = require 'underscore-plus'
Grim = require 'grim'
{$} = require './space-pen-extensions'
SequenceCount = 0
SpecificityCache = {}
# Public: Associates listener functions with commands in a
# context-sensitive way using CSS selectors. You can access a global instance of
# this class via `atom.commands`, and commands registered there will be
# presented in the command palette.
NativeEventBubbling =
abort: false
beforeinput: true
blur: false
click: true
compositionstart: true
compositionupdate: true
compositionend: true
dblclick: true
error: false
focus: false
focusin: true
focusout: true
input: true
keydown: true
keyup: true
load: false
mousedown: true
mouseenter: false
mouseleave: false
mousemove: true
mouseout: true
mouseover: true
mouseup: true
resize: false
scroll: false
select: true
textInput: true
unload: false
wheel: true
mousewheel: true
module.exports =
# Public: Associates listener functions with commands in a context-sensitive way
# using CSS selectors. You can access a global instance of this class via
# `atom.commands`, and commands registered there will be presented in the
# command palette.
#
# The global command registry facilitates a style of event handling known as
# *event delegation* that was popularized by jQuery. Atom commands are expressed
@@ -33,7 +68,7 @@ SpecificityCache = {}
# Here is a command that inserts the current date in an editor:
#
# ```coffee
# atom.commands.add 'atom-text-editor',
# atom.commands.listen 'atom-text-editor',
# 'user:insert-date': (event) ->
# editor = $(this).view().getModel()
# # soon the above above line will be:
@@ -42,8 +77,13 @@ SpecificityCache = {}
# ```
module.exports =
class CommandRegistry
patchedDOMEventMethods: false
originalAddEventListener: Node::addEventListener
originalRemoveEventListener: Node::removeEventListener
constructor: (@rootNode) ->
@registeredCommands = {}
@registeredCommandsByInlineNode = new WeakMap
@selectorBasedListenersByCommandName = {}
@inlineListenersByCommandName = {}
@emitter = new Emitter
@@ -52,6 +92,52 @@ class CommandRegistry
for commandName of @registeredCommands
window.removeEventListener(commandName, @handleCommandEvent, true)
patchDOMEventMethods: ->
if @patchedDOMEventMethods
throw new Error("Already patched DOM event methods for this registry.")
else
@patchedDOMEventMethods = true
registry = this
disposablesByEventName = {}
@originalAddEventListener = Node::addEventListener
@originalRemoveEventListener = Node::originalRemoveEventListener
Node::addEventListener = (eventName, callback, useCapture=false) ->
return unless callback?
target = this
disposable = registry.listen(target, eventName, callback, useCapture)
disposablesByEventName[eventName] ?= {}
disposablesByUseCapture = disposablesByEventName[eventName]
disposablesByUseCapture[useCapture] ?= new WeakMap
disposablesByTarget = disposablesByUseCapture[useCapture]
disposablesByTarget.set(target, new WeakMap) unless disposablesByTarget.has(target)
disposablesByCallback = disposablesByTarget.get(target)
disposablesByCallback.set(callback, new CompositeDisposable) unless disposablesByCallback.has(callback)
disposablesByCallback.get(callback).add(disposable)
return
Node::removeEventListener = (eventName, callback, useCapture=false) ->
return unless callback?
target = this
disposablesByEventName[eventName]?[useCapture]?.get(target)?.get(callback)?.dispose()
return
restoreDOMEventMethods: ->
Node::addEventListener = @originalAddEventListener
Node::removeEventListener = @originalRemoveEventListener
@patchedDOMEventMethods = false
addEventListener: (target, eventName, callback, useCapture) ->
@originalAddEventListener.call(target, eventName, callback, useCapture)
removeEventListener: (target, eventName, callback, useCapture) ->
@originalRemoveEventListener.call(target, eventName, callback, useCapture)
# Public: Add one or more command listeners associated with a selector.
#
# ## Arguments: Registering One Command
@@ -77,23 +163,30 @@ class CommandRegistry
#
# Returns a {Disposable} on which `.dispose()` can be called to remove the
# added command handler(s).
add: (target, commandName, callback) ->
listen: (target, commandName, callback, useCapture=false) ->
if typeof commandName is 'object'
commands = commandName
disposable = new CompositeDisposable
for commandName, callback of commands
disposable.add @add(target, commandName, callback)
disposable.add @listen(target, commandName, callback, useCapture)
return disposable
if typeof target is 'string'
@addSelectorBasedListener(target, commandName, callback)
@addSelectorBasedListener(target, commandName, callback, useCapture)
else
@addInlineListener(target, commandName, callback)
@addInlineListener(target, commandName, callback, useCapture)
addSelectorBasedListener: (selector, commandName, callback) ->
add: (target, commandName, callback) ->
Grim.deprecate("Use CommandRegistry::listen instead")
@listen(target, commandName, callback)
capture: (target, commandName, callback) ->
@listen(target, commandName, callback, true)
addSelectorBasedListener: (selector, commandName, callback, useCapture) ->
@selectorBasedListenersByCommandName[commandName] ?= []
listenersForCommand = @selectorBasedListenersByCommandName[commandName]
listener = new SelectorBasedListener(selector, callback)
listener = new SelectorBasedListener(selector, callback, useCapture)
listenersForCommand.push(listener)
@commandRegistered(commandName)
@@ -102,17 +195,17 @@ class CommandRegistry
listenersForCommand.splice(listenersForCommand.indexOf(listener), 1)
delete @selectorBasedListenersByCommandName[commandName] if listenersForCommand.length is 0
addInlineListener: (element, commandName, callback) ->
addInlineListener: (element, commandName, callback, useCapture) ->
@inlineListenersByCommandName[commandName] ?= new WeakMap
listenersForCommand = @inlineListenersByCommandName[commandName]
unless listenersForElement = listenersForCommand.get(element)
listenersForElement = []
listenersForCommand.set(element, listenersForElement)
listener = new InlineListener(callback)
listener = new InlineListener(callback, useCapture)
listenersForElement.push(listener)
@commandRegistered(commandName)
@commandRegistered(commandName, element)
new Disposable ->
listenersForElement.splice(listenersForElement.indexOf(listener), 1)
@@ -160,11 +253,17 @@ class CommandRegistry
# processed.
#
# * `target` The DOM node at which to start bubbling the command event.
# * `commandName` {String} indicating the name of the command to dispatch.
dispatch: (target, commandName, detail) ->
event = new CustomEvent(commandName, {bubbles: true, detail})
# * `event` {String} indicating the name of the command to dispatch or a
# DOM event object.
# * `detail` The detail to associate with the dispatched DOM event. If present
# overrides the `detail` of the `event` if it is a DOM event object.
dispatch: (target, event, detail) ->
if typeof event is 'string'
event = new CustomEvent(event, {bubbles: NativeEventBubbling[event] ? true})
eventWithTarget = Object.create event,
target: value: target
detail: value: detail ? event.detail
preventDefault: value: ->
stopPropagation: value: ->
stopImmediatePropagation: value: ->
@@ -185,56 +284,93 @@ class CommandRegistry
@selectorBasedListenersByCommandName[commandName] = listeners.slice()
handleCommandEvent: (originalEvent) =>
originalEvent.stopImmediatePropagation()
propagationStopped = false
immediatePropagationStopped = false
matched = false
currentTarget = originalEvent.target
invokedListener = false
{target, type} = originalEvent
currentTarget = null
bubbles = NativeEventBubbling[type] ? originalEvent.bubbles
syntheticEvent = Object.create originalEvent,
eventPhase: value: Event.BUBBLING_PHASE
eventPhase: get: -> eventPhase
currentTarget: get: -> currentTarget
preventDefault: value: ->
originalEvent.preventDefault()
stopPropagation: value: ->
originalEvent.stopPropagation()
propagationStopped = true
stopImmediatePropagation: value: ->
originalEvent.stopImmediatePropagation()
propagationStopped = true
immediatePropagationStopped = true
preventDefault: value: ->
originalEvent.preventDefault()
abortKeyBinding: value: ->
originalEvent.abortKeyBinding?()
@emitter.emit 'will-dispatch', syntheticEvent
loop
listeners = @inlineListenersByCommandName[originalEvent.type]?.get(currentTarget) ? []
if currentTarget.webkitMatchesSelector?
selectorBasedListeners =
(@selectorBasedListenersByCommandName[originalEvent.type] ? [])
.filter (listener) -> currentTarget.webkitMatchesSelector(listener.selector)
.sort (a, b) -> a.compare(b)
listeners = listeners.concat(selectorBasedListeners)
path = @getBubblePath(target)
matched = true if listeners.length > 0
for listener in listeners
# Capture phase: Invoke listeners registered via {::capture}, starting with
# the window and moving downward towards the event target.
eventPhase = Event.CAPTURING_PHASE
for pathIndex in [(path.length - 1)..0]
currentTarget = path[pathIndex]
listeners = @listenersForNode(currentTarget, type)
for listener in listeners when listener.useCapture
break if immediatePropagationStopped
invokedListener = true
listener.callback.call(currentTarget, syntheticEvent)
break if propagationStopped
return invokedListener if propagationStopped
# Bubble phase: Invoke listeners registered via {::listen}, starting with
# the event target and moving upward towards the window. If the event's
# `.bubbles` property is false, we abort after dispatching on the target.
eventPhase = Event.BUBBLING_PHASE
for currentTarget in path
listeners = @listenersForNode(currentTarget, type)
for listener in listeners when not listener.useCapture
break if immediatePropagationStopped
invokedListener = true
listener.callback.call(currentTarget, syntheticEvent)
break if currentTarget is window
break unless bubbles
break if propagationStopped
currentTarget = currentTarget.parentNode ? window
matched
invokedListener
commandRegistered: (commandName) ->
commandRegistered: (commandName, inlineNode) ->
unless @registeredCommands[commandName]
window.addEventListener(commandName, @handleCommandEvent, true)
@addEventListener(window, commandName, @handleCommandEvent, true)
@registeredCommands[commandName] = true
if inlineNode? and not @registeredCommandsByInlineNode.get(inlineNode)?[commandName]
@addEventListener(inlineNode, commandName, @handleCommandEvent, true)
@registeredCommandsByInlineNode.set(inlineNode, {}) unless @registeredCommandsByInlineNode.has(inlineNode)
@registeredCommandsByInlineNode.get(inlineNode)[commandName] = true
getBubblePath: (target) ->
path = []
currentTarget = target
loop
path.push(currentTarget)
break if currentTarget is window
currentTarget = currentTarget.parentNode ? window
path
listenersForNode: (node, eventType) ->
listeners = @inlineListenersByCommandName[eventType]?.get(node) ? []
if node.matches?
selectorBasedListeners =
(@selectorBasedListenersByCommandName[eventType] ? [])
.filter (listener) -> node.matches(listener.selector)
.sort (a, b) -> a.compare(b)
listeners = listeners.concat(selectorBasedListeners)
listeners
class SelectorBasedListener
constructor: (@selector, @callback) ->
constructor: (@selector, @callback, @useCapture) ->
@specificity = (SpecificityCache[@selector] ?= specificity(@selector))
@sequenceNumber = SequenceCount++
@@ -243,4 +379,4 @@ class SelectorBasedListener
other.sequenceNumber - @sequenceNumber
class InlineListener
constructor: (@callback) ->
constructor: (@callback, @useCapture) ->
+1 -1
Ver Arquivo
@@ -375,7 +375,7 @@ class Package
do (selector, command) =>
# Add dummy command so it appears in menu.
# The real command will be registered on package activation
@activationCommandSubscriptions.add atom.commands.add selector, command, ->
@activationCommandSubscriptions.add atom.commands.listen selector, command, ->
@activationCommandSubscriptions.add atom.commands.onWillDispatch (event) =>
return unless event.type is command
currentTarget = event.target
+38
Ver Arquivo
@@ -0,0 +1,38 @@
{View} = require './space-pen-extensions'
# Extended: Represents a view that scrolls.
#
# Handles several core events to update scroll position:
#
# * `core:move-up` Scrolls the view up
# * `core:move-down` Scrolls the view down
# * `core:page-up` Scrolls the view up by the height of the page
# * `core:page-down` Scrolls the view down by the height of the page
# * `core:move-to-top` Scrolls the editor to the top
# * `core:move-to-bottom` Scroll the editor to the bottom
#
# Subclasses must call `super` if overriding the `initialize` method.
#
# ## Examples
#
# ```coffee
# {ScrollView} = require 'atom'
#
# class MyView extends ScrollView
# @content: ->
# @div()
#
# initialize: ->
# super
# @text('super long content that will scroll')
# ```
#
module.exports =
class ScrollView extends View
initialize: ->
@on 'core:move-up', => @scrollUp()
@on 'core:move-down', => @scrollDown()
@on 'core:page-up', => @pageUp()
@on 'core:page-down', => @pageDown()
@on 'core:move-to-top', => @scrollToTop()
@on 'core:move-to-bottom', => @scrollToBottom()
+312
Ver Arquivo
@@ -0,0 +1,312 @@
{$, View} = require './space-pen-extensions'
TextEditorView = require './text-editor-view'
fuzzyFilter = require('fuzzaldrin').filter
# Essential: Provides a view that renders a list of items with an editor that
# filters the items. Used by many packages such as the fuzzy-finder,
# command-palette, symbols-view and autocomplete.
#
# Subclasses must implement the following methods:
#
# * {::viewForItem}
# * {::confirmed}
#
# ## Requiring in packages
#
# ```coffee
# {SelectListView} = require 'atom'
#
# class MySelectListView extends SelectListView
# initialize: ->
# super
# @addClass('overlay from-top')
# @setItems(['Hello', 'World'])
# atom.workspaceView.append(this)
# @focusFilterEditor()
#
# viewForItem: (item) ->
# "<li>#{item}</li>"
#
# confirmed: (item) ->
# console.log("#{item} was selected")
# ```
module.exports =
class SelectListView extends View
@content: ->
@div class: 'select-list', =>
@subview 'filterEditorView', new TextEditorView(mini: true)
@div class: 'error-message', outlet: 'error'
@div class: 'loading', outlet: 'loadingArea', =>
@span class: 'loading-message', outlet: 'loading'
@span class: 'badge', outlet: 'loadingBadge'
@ol class: 'list-group', outlet: 'list'
maxItems: Infinity
scheduleTimeout: null
inputThrottle: 50
cancelling: false
###
Section: Construction
###
# Essential: Initialize the select list view.
#
# This method can be overridden by subclasses but `super` should always
# be called.
initialize: ->
@filterEditorView.getEditor().getBuffer().onDidChange =>
@schedulePopulateList()
@filterEditorView.hiddenInput.on 'focusout', =>
@cancel() unless @cancelling
# This prevents the focusout event from firing on the filter editor view
# when the list is scrolled by clicking the scrollbar and dragging.
@list.on 'mousedown', ({target}) =>
false if target is @list[0]
@on 'core:move-up', =>
@selectPreviousItemView()
@on 'core:move-down', =>
@selectNextItemView()
@on 'core:move-to-top', =>
@selectItemView(@list.find('li:first'))
@list.scrollToTop()
false
@on 'core:move-to-bottom', =>
@selectItemView(@list.find('li:last'))
@list.scrollToBottom()
false
@on 'core:confirm', => @confirmSelection()
@on 'core:cancel', => @cancel()
@list.on 'mousedown', 'li', (e) =>
@selectItemView($(e.target).closest('li'))
e.preventDefault()
@list.on 'mouseup', 'li', (e) =>
@confirmSelection() if $(e.target).closest('li').hasClass('selected')
e.preventDefault()
###
Section: Methods that must be overridden
###
# Essential: Create a view for the given model item.
#
# This method must be overridden by subclasses.
#
# This is called when the item is about to appended to the list view.
#
# * `item` The model item being rendered. This will always be one of the items
# previously passed to {::setItems}.
#
# Returns a String of HTML, DOM element, jQuery object, or View.
viewForItem: (item) ->
throw new Error("Subclass must implement a viewForItem(item) method")
# Essential: Callback function for when an item is selected.
#
# This method must be overridden by subclasses.
#
# * `item` The selected model item. This will always be one of the items
# previously passed to {::setItems}.
#
# Returns a DOM element, jQuery object, or {View}.
confirmed: (item) ->
throw new Error("Subclass must implement a confirmed(item) method")
###
Section: Managing the list of items
###
# Essential: Set the array of items to display in the list.
#
# This should be model items not actual views. {::viewForItem} will be
# called to render the item when it is being appended to the list view.
#
# * `items` The {Array} of model items to display in the list (default: []).
setItems: (@items=[]) ->
@populateList()
@setLoading()
# Essential: Get the model item that is currently selected in the list view.
#
# Returns a model item.
getSelectedItem: ->
@getSelectedItemView().data('select-list-item')
# Extended: Get the property name to use when filtering items.
#
# This method may be overridden by classes to allow fuzzy filtering based
# on a specific property of the item objects.
#
# For example if the objects you pass to {::setItems} are of the type
# `{"id": 3, "name": "Atom"}` then you would return `"name"` from this method
# to fuzzy filter by that property when text is entered into this view's
# editor.
#
# Returns the property name to fuzzy filter by.
getFilterKey: ->
# Extended: Get the filter query to use when fuzzy filtering the visible
# elements.
#
# By default this method returns the text in the mini editor but it can be
# overridden by subclasses if needed.
#
# Returns a {String} to use when fuzzy filtering the elements to display.
getFilterQuery: ->
@filterEditorView.getEditor().getText()
# Extended: Set the maximum numbers of items to display in the list.
#
# * `maxItems` The maximum {Number} of items to display.
setMaxItems: (@maxItems) ->
# Extended: Populate the list view with the model items previously set by
# calling {::setItems}.
#
# Subclasses may override this method but should always call `super`.
populateList: ->
return unless @items?
filterQuery = @getFilterQuery()
if filterQuery.length
filteredItems = fuzzyFilter(@items, filterQuery, key: @getFilterKey())
else
filteredItems = @items
@list.empty()
if filteredItems.length
@setError(null)
for i in [0...Math.min(filteredItems.length, @maxItems)]
item = filteredItems[i]
itemView = $(@viewForItem(item))
itemView.data('select-list-item', item)
@list.append(itemView)
@selectItemView(@list.find('li:first'))
else
@setError(@getEmptyMessage(@items.length, filteredItems.length))
###
Section: Messages to the user
###
# Essential: Set the error message to display.
#
# * `message` The {String} error message (default: '').
setError: (message='') ->
if message.length is 0
@error.text('').hide()
else
@setLoading()
@error.text(message).show()
# Essential: Set the loading message to display.
#
# * `message` The {String} loading message (default: '').
setLoading: (message='') ->
if message.length is 0
@loading.text("")
@loadingBadge.text("")
@loadingArea.hide()
else
@setError()
@loading.text(message)
@loadingArea.show()
# Extended: Get the message to display when there are no items.
#
# Subclasses may override this method to customize the message.
#
# * `itemCount` The {Number} of items in the array specified to {::setItems}
# * `filteredItemCount` The {Number} of items that pass the fuzzy filter test.
#
# Returns a {String} message (default: 'No matches found').
getEmptyMessage: (itemCount, filteredItemCount) -> 'No matches found'
###
Section: View Actions
###
# Essential: Cancel and close this select list view.
#
# This restores focus to the previously focused element if
# {::storeFocusedElement} was called prior to this view being attached.
cancel: ->
@list.empty()
@cancelling = true
filterEditorViewFocused = @filterEditorView.isFocused
@cancelled()
@detach()
@restoreFocus() if filterEditorViewFocused
@cancelling = false
clearTimeout(@scheduleTimeout)
# Extended: Focus the fuzzy filter editor view.
focusFilterEditor: ->
@filterEditorView.focus()
# Extended: Store the currently focused element. This element will be given
# back focus when {::cancel} is called.
storeFocusedElement: ->
@previouslyFocusedElement = $(':focus')
###
Section: Private
###
selectPreviousItemView: ->
view = @getSelectedItemView().prev()
view = @list.find('li:last') unless view.length
@selectItemView(view)
selectNextItemView: ->
view = @getSelectedItemView().next()
view = @list.find('li:first') unless view.length
@selectItemView(view)
selectItemView: (view) ->
return unless view.length
@list.find('.selected').removeClass('selected')
view.addClass('selected')
@scrollToItemView(view)
scrollToItemView: (view) ->
scrollTop = @list.scrollTop()
desiredTop = view.position().top + scrollTop
desiredBottom = desiredTop + view.outerHeight()
if desiredTop < scrollTop
@list.scrollTop(desiredTop)
else if desiredBottom > @list.scrollBottom()
@list.scrollBottom(desiredBottom)
restoreFocus: ->
if @previouslyFocusedElement?.isOnDom()
@previouslyFocusedElement.focus()
else
atom.workspaceView.focus()
cancelled: ->
@filterEditorView.getEditor().setText('')
getSelectedItemView: ->
@list.find('li.selected')
confirmSelection: ->
item = @getSelectedItem()
if item?
@confirmed(item)
else
@cancel()
schedulePopulateList: ->
clearTimeout(@scheduleTimeout)
populateCallback = =>
@populateList() if @isOnDom()
@scheduleTimeout = setTimeout(populateCallback, @inputThrottle)
+34 -27
Ver Arquivo
@@ -15,46 +15,53 @@ SpacePen.callRemoveHooks = (element) ->
view.unsubscribe() for view in SpacePen.viewsForElement(element)
SpacePenCallRemoveHooks(element)
NativeEventNames = new Set
NativeEventNames.add(nativeEvent) for nativeEvent in ["blur", "focus", "focusin",
"focusout", "load", "resize", "scroll", "unload", "click", "dblclick", "mousedown",
"mouseup", "mousemove", "mouseover", "mouseout", "mouseenter", "mouseleave", "change",
"select", "submit", "keydown", "keypress", "keyup", "error", "contextmenu", "textInput",
"textinput"]
JQueryTrigger = jQuery.fn.trigger
jQuery.fn.trigger = (eventName, data) ->
if NativeEventNames.has(eventName) or typeof eventName is 'object'
JQueryTrigger.call(this, eventName, data)
jQuery.fn.trigger = (event, data) ->
if typeof event is 'object'
{type, target, originalEvent} = event
if originalEvent?
originalEvent.type ?= type
event = originalEvent
else
type = event
specialTrigger = jQuery.event.special[event]?.trigger
# Don't deal with namespaces
return JQueryTrigger.apply(this, arguments) unless type.indexOf('.') is -1
if target?
atom.commands.dispatch(target, event, data)
else
for element in this
atom.commands.dispatch(element, eventName, data)
this
continue if specialTrigger?.apply(element) is false
atom.commands.dispatch(element, event, data)
this
# Allow command registry integration with focusin and focusout events
# Otherwise jQuery registers these event handlers in a special way for bubbling
# compatibility
delete jQuery.event.special.focusin
delete jQuery.event.special.focusout
HandlersByOriginalHandler = new WeakMap
CommandDisposablesByElement = new WeakMap
AddEventListener = (element, type, listener) ->
if NativeEventNames.has(type)
element.addEventListener(type, listener)
else
disposable = atom.commands.add(element, type, listener)
disposable = atom.commands.listen(element, type, listener)
unless disposablesByType = CommandDisposablesByElement.get(element)
disposablesByType = {}
CommandDisposablesByElement.set(element, disposablesByType)
unless disposablesByType = CommandDisposablesByElement.get(element)
disposablesByType = {}
CommandDisposablesByElement.set(element, disposablesByType)
unless disposablesByListener = disposablesByType[type]
disposablesByListener = new WeakMap
disposablesByType[type] = disposablesByListener
unless disposablesByListener = disposablesByType[type]
disposablesByListener = new WeakMap
disposablesByType[type] = disposablesByListener
disposablesByListener.set(listener, disposable)
disposablesByListener.set(listener, disposable)
RemoveEventListener = (element, type, listener) ->
if NativeEventNames.has(type)
element.removeEventListener(type, listener)
else
CommandDisposablesByElement.get(element)?[type]?.get(listener)?.dispose()
CommandDisposablesByElement.get(element)?[type]?.get(listener)?.dispose()
JQueryEventAdd = jQuery.event.add
jQuery.event.add = (elem, types, originalHandler, data, selector) ->
-1
Ver Arquivo
@@ -197,7 +197,6 @@ TextEditorComponent = React.createClass
parentView.__spacePenView.trigger 'editor:will-be-removed', [parentView.__spacePenView]
@unsubscribe()
@scopedConfigSubscriptions.dispose()
window.removeEventListener 'resize', @requestHeightAndWidthMeasurement
clearInterval(@domPollingIntervalId)
@domPollingIntervalId = null
+6 -23
Ver Arquivo
@@ -1,5 +1,4 @@
{callRemoveHooks} = require 'space-pen'
{Emitter} = require 'event-kit'
{View, $, callRemoveHooks} = require 'space-pen'
React = require 'react-atom-fork'
{defaults} = require 'underscore-plus'
TextBuffer = require 'text-buffer'
@@ -14,15 +13,8 @@ class TextEditorElement extends HTMLElement
lineOverdrawMargin: null
focusOnAttach: false
onDidAttach: (callback) ->
@emitter.on 'did-attach', callback
onDidDetach: (callback) ->
@emitter.on 'did-detach', callback
createdCallback: ->
@emitter = new Emitter
@subscriptions =
@initializeContent()
@createSpacePenShim()
@addEventListener 'focus', @focused.bind(this)
@@ -34,7 +26,7 @@ class TextEditorElement extends HTMLElement
@setAttribute('tabindex', -1)
createSpacePenShim: ->
TextEditorView ?= require('atom').TextEditorView
TextEditorView ?= require './text-editor-view'
@__spacePenView = new TextEditorView(this)
attachedCallback: ->
@@ -42,10 +34,6 @@ class TextEditorElement extends HTMLElement
@mountComponent() unless @component?.isMounted()
@component.checkForVisibilityChange()
@focus() if @focusOnAttach
@emitter.emit 'did-attach'
detachedCallback: ->
@emitter.emit 'did-detach'
setModel: (model) ->
throw new Error("Model already assigned on TextEditorElement") if @model?
@@ -55,8 +43,6 @@ class TextEditorElement extends HTMLElement
@mountComponent()
@addGrammarScopeAttribute()
@model.onDidChangeGrammar => @addGrammarScopeAttribute()
@addEncodingAttribute()
@model.onDidChangeEncoding => @addEncodingAttribute()
@model.onDidDestroy => @unmountComponent()
@__spacePenView.setModel(@model)
@model
@@ -103,10 +89,7 @@ class TextEditorElement extends HTMLElement
addGrammarScopeAttribute: ->
grammarScope = @model.getGrammar()?.scopeName?.replace(/\./g, ' ')
@dataset.grammar = grammarScope
addEncodingAttribute: ->
@dataset.encoding = @model.getEncoding()
@setAttribute('data-grammar', grammarScope)
hasFocus: ->
this is document.activeElement or @contains(document.activeElement)
@@ -120,7 +103,7 @@ stopCommandEventPropagation = (commandListeners) ->
commandListener.call(this, event)
newCommandListeners
atom.commands.add 'atom-text-editor', stopCommandEventPropagation(
atom.commands.listen 'atom-text-editor', stopCommandEventPropagation(
'core:move-left': -> @getModel().moveLeft()
'core:move-right': -> @getModel().moveRight()
'core:select-left': -> @getModel().selectLeft()
@@ -170,7 +153,7 @@ atom.commands.add 'atom-text-editor', stopCommandEventPropagation(
'editor:lower-case': -> @getModel().lowerCase()
)
atom.commands.add 'atom-text-editor:not(.mini)', stopCommandEventPropagation(
atom.commands.listen 'atom-text-editor:not(.mini)', stopCommandEventPropagation(
'core:move-up': -> @getModel().moveUp()
'core:move-down': -> @getModel().moveDown()
'core:move-to-top': -> @getModel().moveToTop()
+308
Ver Arquivo
@@ -0,0 +1,308 @@
{View, $} = require 'space-pen'
React = require 'react-atom-fork'
{defaults} = require 'underscore-plus'
TextBuffer = require 'text-buffer'
TextEditor = require './text-editor'
TextEditorElement = require './text-editor-element'
TextEditorComponent = require './text-editor-component'
{deprecate} = require 'grim'
# Public: Represents the entire visual pane in Atom.
#
# The TextEditorView manages the {TextEditor}, which manages the file buffers.
# `TextEditorView` is intentionally sparse. Most of the things you'll want
# to do are on {TextEditor}.
#
# ## Examples
#
# Requiring in packages
#
# ```coffee
# {TextEditorView} = require 'atom'
#
# miniEditorView = new TextEditorView(mini: true)
# ```
#
# Iterating over the open editor views
#
# ```coffee
# for editorView in atom.workspaceView.getEditorViews()
# console.log(editorView.getModel().getPath())
# ```
#
# Subscribing to every current and future editor
#
# ```coffee
# atom.workspace.eachEditorView (editorView) ->
# console.log(editorView.getModel().getPath())
# ```
module.exports =
class TextEditorView extends View
# The constructor for setting up an `TextEditorView` instance.
#
# * `modelOrParams` Either an {TextEditor}, or an object with one property, `mini`.
# If `mini` is `true`, a "miniature" `TextEditor` is constructed.
# Typically, this is ideal for scenarios where you need an Atom editor,
# but without all the chrome, like scrollbars, gutter, _e.t.c._.
#
constructor: (modelOrParams, props) ->
# Handle direct construction with an editor or params
unless modelOrParams instanceof HTMLElement
if modelOrParams instanceof TextEditor
model = modelOrParams
else
{editor, mini, placeholderText, attributes} = modelOrParams
model = editor ? new TextEditor
buffer: new TextBuffer
softWrapped: false
tabLength: 2
softTabs: true
mini: mini
placeholderText: placeholderText
element = new TextEditorElement
element.lineOverdrawMargin = props?.lineOverdrawMargin
element.setAttribute(name, value) for name, value of attributes if attributes?
element.setModel(model)
return element.__spacePenView
# Handle construction with an element
@element = modelOrParams
super
setModel: (@model) ->
@editor = @model
@scrollView = @find('.scroll-view')
@underlayer = @find('.highlights').addClass('underlayer')
@overlayer = @find('.lines').addClass('overlayer')
@hiddenInput = @.find('.hidden-input')
@subscribe atom.config.observe 'editor.showLineNumbers', =>
@gutter = @find('.gutter')
@gutter.removeClassFromAllLines = (klass) =>
deprecate('Use decorations instead: http://blog.atom.io/2014/07/24/decorations.html')
@gutter.find('.line-number').removeClass(klass)
@gutter.getLineNumberElement = (bufferRow) =>
deprecate('Use decorations instead: http://blog.atom.io/2014/07/24/decorations.html')
@gutter.find("[data-buffer-row='#{bufferRow}']")
@gutter.addClassToLine = (bufferRow, klass) =>
deprecate('Use decorations instead: http://blog.atom.io/2014/07/24/decorations.html')
lines = @gutter.find("[data-buffer-row='#{bufferRow}']")
lines.addClass(klass)
lines.length > 0
# Public: Get the underlying editor model for this view.
#
# Returns an {TextEditor}
getModel: -> @model
getEditor: -> @model
Object.defineProperty @::, 'lineHeight', get: -> @model.getLineHeightInPixels()
Object.defineProperty @::, 'charWidth', get: -> @model.getDefaultCharWidth()
Object.defineProperty @::, 'firstRenderedScreenRow', get: -> @component.getRenderedRowRange()[0]
Object.defineProperty @::, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1]
Object.defineProperty @::, 'active', get: -> @is(@getPaneView()?.activeView)
Object.defineProperty @::, 'isFocused', get: -> @component?.state.focused
Object.defineProperty @::, 'mini', get: -> @component?.props.mini
Object.defineProperty @::, 'component', get: -> @element?.component
afterAttach: (onDom) ->
return unless onDom
return if @attached
@attached = true
@trigger 'editor:attached', [this]
beforeRemove: ->
@trigger 'editor:detached', [this]
@attached = false
remove: (selector, keepData) ->
@model.destroy() unless keepData
super
scrollTop: (scrollTop) ->
if scrollTop?
@model.setScrollTop(scrollTop)
else
@model.getScrollTop()
scrollLeft: (scrollLeft) ->
if scrollLeft?
@model.setScrollLeft(scrollLeft)
else
@model.getScrollLeft()
scrollToBottom: ->
deprecate 'Use TextEditor::scrollToBottom instead. You can get the editor via editorView.getModel()'
@model.setScrollBottom(Infinity)
scrollToScreenPosition: (screenPosition, options) ->
deprecate 'Use TextEditor::scrollToScreenPosition instead. You can get the editor via editorView.getModel()'
@model.scrollToScreenPosition(screenPosition, options)
scrollToBufferPosition: (bufferPosition, options) ->
deprecate 'Use TextEditor::scrollToBufferPosition instead. You can get the editor via editorView.getModel()'
@model.scrollToBufferPosition(bufferPosition, options)
scrollToCursorPosition: ->
deprecate 'Use TextEditor::scrollToCursorPosition instead. You can get the editor via editorView.getModel()'
@model.scrollToCursorPosition()
pixelPositionForBufferPosition: (bufferPosition) ->
deprecate 'Use TextEditor::pixelPositionForBufferPosition instead. You can get the editor via editorView.getModel()'
@model.pixelPositionForBufferPosition(bufferPosition)
pixelPositionForScreenPosition: (screenPosition) ->
deprecate 'Use TextEditor::pixelPositionForScreenPosition instead. You can get the editor via editorView.getModel()'
@model.pixelPositionForScreenPosition(screenPosition)
appendToLinesView: (view) ->
view.css('position', 'absolute')
view.css('z-index', 1)
@find('.lines').prepend(view)
unmountComponent: ->
React.unmountComponentAtNode(@element) if @component.isMounted()
splitLeft: ->
deprecate """
Use Pane::splitLeft instead.
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitLeft(copyActiveItem: true)
"""
pane = @getPaneView()
pane?.splitLeft(pane?.copyActiveItem()).activeView
splitRight: ->
deprecate """
Use Pane::splitRight instead.
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitRight(copyActiveItem: true)
"""
pane = @getPaneView()
pane?.splitRight(pane?.copyActiveItem()).activeView
splitUp: ->
deprecate """
Use Pane::splitUp instead.
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitUp(copyActiveItem: true)
"""
pane = @getPaneView()
pane?.splitUp(pane?.copyActiveItem()).activeView
splitDown: ->
deprecate """
Use Pane::splitDown instead.
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitDown(copyActiveItem: true)
"""
pane = @getPaneView()
pane?.splitDown(pane?.copyActiveItem()).activeView
# Public: Get this {TextEditorView}'s {PaneView}.
#
# Returns a {PaneView}
getPaneView: ->
@parent('.item-views').parents('atom-pane').view()
getPane: ->
deprecate 'Use TextEditorView::getPaneView() instead'
@getPaneView()
show: ->
super
@component?.checkForVisibilityChange()
hide: ->
super
@component?.checkForVisibilityChange()
pageDown: ->
deprecate('Use editorView.getModel().pageDown()')
@model.pageDown()
pageUp: ->
deprecate('Use editorView.getModel().pageUp()')
@model.pageUp()
getFirstVisibleScreenRow: ->
deprecate 'Use TextEditor::getFirstVisibleScreenRow instead. You can get the editor via editorView.getModel()'
@model.getFirstVisibleScreenRow()
getLastVisibleScreenRow: ->
deprecate 'Use TextEditor::getLastVisibleScreenRow instead. You can get the editor via editorView.getModel()'
@model.getLastVisibleScreenRow()
getFontFamily: ->
deprecate 'This is going away. Use atom.config.get("editor.fontFamily") instead'
@component?.getFontFamily()
setFontFamily: (fontFamily) ->
deprecate 'This is going away. Use atom.config.set("editor.fontFamily", "my-font") instead'
@component?.setFontFamily(fontFamily)
getFontSize: ->
deprecate 'This is going away. Use atom.config.get("editor.fontSize") instead'
@component?.getFontSize()
setFontSize: (fontSize) ->
deprecate 'This is going away. Use atom.config.set("editor.fontSize", 12) instead'
@component?.setFontSize(fontSize)
setLineHeight: (lineHeight) ->
deprecate 'This is going away. Use atom.config.set("editor.lineHeight", 1.5) instead'
@component.setLineHeight(lineHeight)
setWidthInChars: (widthInChars) ->
@component.getDOMNode().style.width = (@model.getDefaultCharWidth() * widthInChars) + 'px'
setShowIndentGuide: (showIndentGuide) ->
deprecate 'This is going away. Use atom.config.set("editor.showIndentGuide", true|false) instead'
@component.setShowIndentGuide(showIndentGuide)
setSoftWrap: (softWrapped) ->
deprecate 'Use TextEditor::setSoftWrapped instead. You can get the editor via editorView.getModel()'
@model.setSoftWrapped(softWrapped)
setShowInvisibles: (showInvisibles) ->
deprecate 'This is going away. Use atom.config.set("editor.showInvisibles", true|false) instead'
@component.setShowInvisibles(showInvisibles)
getText: ->
@model.getText()
setText: (text) ->
@model.setText(text)
insertText: (text) ->
@model.insertText(text)
isInputEnabled: ->
@component.isInputEnabled()
setInputEnabled: (inputEnabled) ->
@component.setInputEnabled(inputEnabled)
requestDisplayUpdate: ->
deprecate('Please remove from your code. ::requestDisplayUpdate no longer does anything')
updateDisplay: ->
deprecate('Please remove from your code. ::updateDisplay no longer does anything')
resetDisplay: ->
deprecate('Please remove from your code. ::resetDisplay no longer does anything')
redraw: ->
deprecate('Please remove from your code. ::redraw no longer does anything')
setPlaceholderText: (placeholderText) ->
deprecate('Use TextEditor::setPlaceholderText instead. eg. editorView.getModel().setPlaceholderText(text)')
@model.setPlaceholderText(placeholderText)
lineElementForScreenRow: (screenRow) ->
$(@component.lineNodeForScreenRow(screenRow))
+2 -23
Ver Arquivo
@@ -6,7 +6,7 @@ Delegator = require 'delegato'
{Model} = require 'theorist'
EmitterMixin = require('emissary').Emitter
{CompositeDisposable, Emitter} = require 'event-kit'
{Point, Range} = TextBuffer = require 'text-buffer'
{Point, Range} = require 'text-buffer'
LanguageMode = require './language-mode'
DisplayBuffer = require './display-buffer'
Cursor = require './cursor'
@@ -84,7 +84,6 @@ class TextEditor extends Model
@cursors = []
@selections = []
buffer ?= new TextBuffer
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped})
@buffer = @displayBuffer.buffer
@softTabs = @usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true
@@ -135,11 +134,9 @@ class TextEditor extends Model
@emitter.emit 'did-change-title', @getTitle()
@emit "path-changed"
@emitter.emit 'did-change-path', @getPath()
@subscribe @buffer.onDidChangeEncoding =>
@emitter.emit 'did-change-encoding', @getEncoding()
@subscribe @buffer.onDidDestroy => @destroy()
# TODO: remove these when we remove the deprecations. They are old events.
# TODO: remove these thwne we remove the deprecations. They are old events.
@subscribe @buffer.onDidStopChanging => @emit "contents-modified"
@subscribe @buffer.onDidConflict => @emit "contents-conflicted"
@subscribe @buffer.onDidChangeModified => @emit "modified-status-changed"
@@ -263,14 +260,6 @@ class TextEditor extends Model
onDidChangeSoftWrapped: (callback) ->
@displayBuffer.onDidChangeSoftWrapped(callback)
# Extended: Calls your `callback` when the buffer's encoding has changed.
#
# * `callback` {Function}
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeEncoding: (callback) ->
@emitter.on 'did-change-encoding', callback
# Extended: Calls your `callback` when the grammar that interprets and
# colorizes the text has been changed. Immediately calls your callback with
# the current grammar.
@@ -579,16 +568,6 @@ class TextEditor extends Model
# Essential: Returns the {String} path of this editor's text buffer.
getPath: -> @buffer.getPath()
# Extended: Returns the {String} character set encoding of this editor's text
# buffer.
getEncoding: -> @buffer.getEncoding()
# Extended: Set the character set encoding to use in this editor's text
# buffer.
#
# * `encoding` The {String} character set encoding name such as 'utf8'
setEncoding: (encoding) -> @buffer.setEncoding(encoding)
# Essential: Returns {Boolean} `true` if this editor has been modified.
isModified: -> @buffer.isModified()
+4 -7
Ver Arquivo
@@ -159,14 +159,11 @@ class ThemeManager
themeNames = atom.config.get('core.themes') ? []
themeNames = [themeNames] unless _.isArray(themeNames)
themeNames = themeNames.filter (themeName) ->
if themeName and typeof themeName is 'string'
return true if atom.packages.resolvePackagePath(themeName)
console.warn("Enabled theme '#{themeName}' is not installed.")
false
themeName and typeof themeName is 'string'
# Use a built-in syntax and UI theme any time the configured themes are not
# available.
if themeNames.length < 2
# Use a built-in syntax and UI theme when in safe mode since themes
# installed to ~/.atom/packages will not be loaded.
if @safeMode
builtInThemeNames = [
'atom-dark-syntax'
'atom-dark-ui'
-100
Ver Arquivo
@@ -1,117 +1,17 @@
{Disposable} = require 'event-kit'
{jQuery} = require './space-pen-extensions'
# Essential: `ViewRegistry` handles the association between model and view
# types in Atom. We call this association a View Provider. As in, for a given
# model, this class can provide a view via {::getView}, as long as the
# model/view association was registered via {::addViewProvider}
#
# If you're adding your own kind of pane item, a good strategy for all but the
# simplest items is to separate the model and the view. The model handles
# application logic and is the primary point of API interaction. The view
# just handles presentation.
#
# View providers to inform the workspace how your model objects should be
# presented in the DOM. A view provider must always return a DOM node, which
# makes [HTML 5 custom elements](http://www.html5rocks.com/en/tutorials/webcomponents/customelements/)
# an ideal tool for implementing views in Atom.
#
# You can access the `ViewRegistry` object via `atom.views`.
#
# ## Examples
#
# ### Getting the workspace element
#
# ```coffee
# workspaceElement = atom.views.getView(atom.workspace)
# ```
#
# ### Getting An Editor Element
#
# ```coffee
# textEditor = atom.workspace.getActiveTextEditor()
# textEditorElement = atom.views.getView(textEditor)
# ```
#
# ### Getting A Pane Element
#
# ```coffee
# pane = atom.workspace.getActivePane()
# paneElement = atom.views.getView(pane)
# ```
module.exports =
class ViewRegistry
constructor: ->
@views = new WeakMap
@providers = []
# Essential: Add a provider that will be used to construct views in the
# workspace's view layer based on model objects in its model layer.
#
# ## Examples
#
# Text editors are divided into a model and a view layer, so when you interact
# with methods like `atom.workspace.getActiveTextEditor()` you're only going
# to get the model object. We display text editors on screen by teaching the
# workspace what view constructor it should use to represent them:
#
# ```coffee
# atom.views.addViewProvider
# modelConstructor: TextEditor
# viewConstructor: TextEditorElement
# ```
#
# * `providerSpec` {Object} containing the following keys:
# * `modelConstructor` Constructor {Function} for your model.
# * `viewConstructor` (Optional) Constructor {Function} for your view. It
# should be a subclass of `HTMLElement` (that is, your view should be a
# DOM node) and have a `::setModel()` method which will be called
# immediately after construction. If you don't supply this property, you
# must supply the `createView` property with a function that never returns
# `undefined`.
# * `createView` (Optional) Factory {Function} that must return a subclass
# of `HTMLElement` or `undefined`. If this property is not present or the
# function returns `undefined`, the view provider will fall back to the
# `viewConstructor` property. If you don't provide this property, you must
# provider a `viewConstructor` property.
#
# Returns a {Disposable} on which `.dispose()` can be called to remove the
# added provider.
addViewProvider: (providerSpec) ->
@providers.push(providerSpec)
new Disposable =>
@providers = @providers.filter (provider) -> provider isnt providerSpec
# Essential: Get the view associated with an object in the workspace.
#
# If you're just *using* the workspace, you shouldn't need to access the view
# layer, but view layer access may be necessary if you want to perform DOM
# manipulation that isn't supported via the model API.
#
# ## Examples
#
# ### Getting An Editor View
# ```coffee
# textEditor = atom.workspace.getActiveTextEditor()
# textEditorView = atom.views.getView(textEditor)
# ```
#
# ### Getting A Pane View
# ```coffee
# pane = atom.workspace.getActivePane()
# paneView = atom.views.getView(pane)
# ```
#
# ### Getting The Workspace View
#
# ```coffee
# workspaceView = atom.views.getView(atom.workspace)
# ```
#
# * `object` The object for which you want to retrieve a view. This can be a
# pane item, a pane, or the workspace itself.
#
# Returns a DOM element.
getView: (object) ->
return unless object?
+1 -1
Ver Arquivo
@@ -65,7 +65,7 @@ class WindowEventHandler
@subscribeToCommand $(document), 'core:focus-previous', @focusPrevious
document.addEventListener 'keydown', @onKeydown
atom.commands.listen window, 'keydown', @onKeydown
@subscribe $(document), 'drop', (e) ->
e.preventDefault()
+3 -3
Ver Arquivo
@@ -64,7 +64,7 @@ class WorkspaceElement extends HTMLElement
getModel: -> @model
setModel: (@model) ->
@paneContainer = atom.views.getView(@model.paneContainer)
@paneContainer = @model.getView(@model.paneContainer)
@verticalAxis.appendChild(@paneContainer)
@addEventListener 'focus', @handleFocus.bind(this)
@@ -114,7 +114,7 @@ class WorkspaceElement extends HTMLElement
focusPaneViewOnRight: -> @paneContainer.focusPaneViewOnRight()
atom.commands.add 'atom-workspace',
atom.commands.listen 'atom-workspace',
'window:increase-font-size': -> @getModel().increaseFontSize()
'window:decrease-font-size': -> @getModel().decreaseFontSize()
'window:reset-font-size': -> @getModel().resetFontSize()
@@ -160,6 +160,6 @@ atom.commands.add 'atom-workspace',
'core:save-as': -> @getModel().saveActivePaneItemAs()
if process.platform is 'darwin'
atom.commands.add 'atom-workspace', 'window:install-shell-commands', -> @getModel().installShellCommands()
atom.commands.listen 'atom-workspace', 'window:install-shell-commands', -> @getModel().installShellCommands()
module.exports = WorkspaceElement = document.registerElement 'atom-workspace', prototype: WorkspaceElement.prototype
+17 -1
Ver Arquivo
@@ -59,7 +59,7 @@ class WorkspaceView extends View
constructor: (@element) ->
unless @element?
return atom.views.getView(atom.workspace).__spacePenView
return atom.workspace.getView(atom.workspace).__spacePenView
super
@deprecateViewEvents()
@@ -262,6 +262,22 @@ class WorkspaceView extends View
deprecate('Use Workspace::onDidOpen instead')
originalWorkspaceViewOn.apply(this, arguments)
TextEditorView = require './text-editor-view'
originalEditorViewOn = TextEditorView::on
TextEditorView::on = (eventName) ->
switch eventName
when 'cursor:moved'
deprecate('Use TextEditor::onDidChangeCursorPosition instead')
when 'editor:attached'
deprecate('Use TextEditor::onDidAddTextEditor instead')
when 'editor:detached'
deprecate('Use TextEditor::onDidDestroy instead')
when 'editor:will-be-removed'
deprecate('Use TextEditor::onDidDestroy instead')
when 'selection:changed'
deprecate('Use TextEditor::onDidChangeSelectionRange instead')
originalEditorViewOn.apply(this, arguments)
originalPaneViewOn = PaneView::on
PaneView::on = (eventName) ->
switch eventName
+105 -19
Ver Arquivo
@@ -45,15 +45,15 @@ class Workspace extends Model
@emitter = new Emitter
@openers = []
viewRegistry = atom.views
@paneContainer ?= new PaneContainer({viewRegistry})
@viewRegistry ?= new ViewRegistry
@paneContainer ?= new PaneContainer({@viewRegistry})
@paneContainer.onDidDestroyPaneItem(@onPaneItemDestroyed)
@panelContainers =
top: new PanelContainer({viewRegistry, location: 'top'})
left: new PanelContainer({viewRegistry, location: 'left'})
right: new PanelContainer({viewRegistry, location: 'right'})
bottom: new PanelContainer({viewRegistry, location: 'bottom'})
top: new PanelContainer({@viewRegistry, location: 'top'})
left: new PanelContainer({@viewRegistry, location: 'left'})
right: new PanelContainer({@viewRegistry, location: 'right'})
bottom: new PanelContainer({@viewRegistry, location: 'bottom'})
@subscribeToActiveItem()
@@ -68,15 +68,15 @@ class Workspace extends Model
when 'atom://.atom/init-script'
@open(atom.getUserInitScriptPath())
atom.views.addViewProvider
@addViewProvider
modelConstructor: Workspace
viewConstructor: WorkspaceElement
atom.views.addViewProvider
@addViewProvider
modelConstructor: PanelContainer
viewConstructor: PanelContainerElement
atom.views.addViewProvider
@addViewProvider
modelConstructor: Panel
viewConstructor: PanelElement
@@ -85,7 +85,8 @@ class Workspace extends Model
for packageName in params.packagesWithActiveGrammars ? []
atom.packages.getLoadedPackage(packageName)?.loadGrammarsSync()
params.paneContainer.viewRegistry = atom.views
params.viewRegistry = new ViewRegistry
params.paneContainer.viewRegistry = params.viewRegistry
params.paneContainer = PaneContainer.deserialize(params.paneContainer)
params
@@ -401,6 +402,8 @@ class Workspace extends Model
item ?= opener(atom.project.resolve(uri), options) for opener in @getOpeners() when !item
item ?= atom.project.open(uri, options)
console.profile('open')
Q(item)
.then (item) =>
if not pane
@@ -412,6 +415,7 @@ class Workspace extends Model
index = pane.getActiveItemIndex()
@emit "uri-opened"
@emitter.emit 'did-open', {uri, pane, item, index}
console.profileEnd('open')
item
.catch (error) ->
console.error(error.stack ? error)
@@ -604,8 +608,8 @@ class Workspace extends Model
#
# * `options` {Object}
# * `item` Your panel content. It can be DOM element, a jQuery element, or
# a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the
# latter. See {ViewRegistry::addViewProvider} for more information.
# a model with a view registered via {::addViewProvider}. We recommend the
# latter. See {::addViewProvider} for more information.
# * `visible` (optional) {Boolean} false if you want the panel to initially be hidden
# (default: true)
# * `priority` (optional) {Number} Determines stacking order. Lower priority items are
@@ -619,8 +623,8 @@ class Workspace extends Model
#
# * `options` {Object}
# * `item` Your panel content. It can be DOM element, a jQuery element, or
# a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the
# latter. See {ViewRegistry::addViewProvider} for more information.
# a model with a view registered via {::addViewProvider}. We recommend the
# latter. See {::addViewProvider} for more information.
# * `visible` (optional) {Boolean} false if you want the panel to initially be hidden
# (default: true)
# * `priority` (optional) {Number} Determines stacking order. Lower priority items are
@@ -634,8 +638,8 @@ class Workspace extends Model
#
# * `options` {Object}
# * `item` Your panel content. It can be DOM element, a jQuery element, or
# a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the
# latter. See {ViewRegistry::addViewProvider} for more information.
# a model with a view registered via {::addViewProvider}. We recommend the
# latter. See {::addViewProvider} for more information.
# * `visible` (optional) {Boolean} false if you want the panel to initially be hidden
# (default: true)
# * `priority` (optional) {Number} Determines stacking order. Lower priority items are
@@ -649,8 +653,8 @@ class Workspace extends Model
#
# * `options` {Object}
# * `item` Your panel content. It can be DOM element, a jQuery element, or
# a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the
# latter. See {ViewRegistry::addViewProvider} for more information.
# a model with a view registered via {::addViewProvider}. We recommend the
# latter. See {::addViewProvider} for more information.
# * `visible` (optional) {Boolean} false if you want the panel to initially be hidden
# (default: true)
# * `priority` (optional) {Number} Determines stacking order. Lower priority items are
@@ -662,5 +666,87 @@ class Workspace extends Model
addPanel: (location, options) ->
options ?= {}
options.viewRegistry = atom.views
options.viewRegistry = @viewRegistry
@panelContainers[location].addPanel(new Panel(options))
###
Section: View Management
###
# Essential: Get the view associated with an object in the workspace.
#
# If you're just *using* the workspace, you shouldn't need to access the view
# layer, but view layer access may be necessary if you want to perform DOM
# manipulation that isn't supported via the model API.
#
# ## Examples
#
# ### Getting An Editor View
# ```coffee
# textEditor = atom.workspace.getActiveTextEditor()
# textEditorView = atom.workspace.getView(textEditor)
# ```
#
# ### Getting A Pane View
# ```coffee
# pane = atom.workspace.getActivePane()
# paneView = atom.workspace.getView(pane)
# ```
#
# ### Getting The Workspace View
#
# ```coffee
# workspaceView = atom.workspace.getView(atom.workspace)
# ```
#
# * `object` The object for which you want to retrieve a view. This can be a
# pane item, a pane, or the workspace itself.
#
# Returns a DOM element.
getView: (object) ->
@viewRegistry.getView(object)
# Essential: Add a provider that will be used to construct views in the
# workspace's view layer based on model objects in its model layer.
#
# If you're adding your own kind of pane item, a good strategy for all but the
# simplest items is to separate the model and the view. The model handles
# application logic and is the primary point of API interaction. The view
# just handles presentation.
#
# Use view providers to inform the workspace how your model objects should be
# presented in the DOM. A view provider must always return a DOM node, which
# makes [HTML 5 custom elements](http://www.html5rocks.com/en/tutorials/webcomponents/customelements/)
# an ideal tool for implementing views in Atom.
#
# ## Examples
#
# Text editors are divided into a model and a view layer, so when you interact
# with methods like `atom.workspace.getActiveTextEditor()` you're only going
# to get the model object. We display text editors on screen by teaching the
# workspace what view constructor it should use to represent them:
#
# ```coffee
# atom.workspace.addViewProvider
# modelConstructor: TextEditor
# viewConstructor: TextEditorElement
# ```
#
# * `providerSpec` {Object} containing the following keys:
# * `modelConstructor` Constructor {Function} for your model.
# * `viewConstructor` (Optional) Constructor {Function} for your view. It
# should be a subclass of `HTMLElement` (that is, your view should be a
# DOM node) and have a `::setModel()` method which will be called
# immediately after construction. If you don't supply this property, you
# must supply the `createView` property with a function that never returns
# `undefined`.
# * `createView` (Optional) Factory {Function} that must return a subclass
# of `HTMLElement` or `undefined`. If this property is not present or the
# function returns `undefined`, the view provider will fall back to the
# `viewConstructor` property. If you don't provide this property, you must
# provider a `viewConstructor` property.
#
# Returns a {Disposable} on which `.dispose()` can be called to remove the
# added provider.
addViewProvider: (providerSpec) ->
@viewRegistry.addViewProvider(providerSpec)
+1
Ver Arquivo
@@ -23,6 +23,7 @@
@import "messages";
@import "markdown";
@import "editor";
@import "select-list";
@import "syntax";
@import "utilities";
@import "octicons";
+1 -6
Ver Arquivo
@@ -2,15 +2,10 @@ window.onload = function() {
try {
var startTime = Date.now();
var path = require('path');
// Skip "?loadSettings=".
var loadSettings = JSON.parse(decodeURIComponent(location.search.substr(14)));
// Normalize to make sure drive letter case is consistent on Windows
process.resourcesPath = path.normalize(process.resourcesPath);
var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + path.sep);
var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + require('path').sep);
// Require before the module cache in dev mode
if (devMode) {
+40
Ver Arquivo
@@ -0,0 +1,40 @@
@import "ui-variables";
@import "octicon-mixins";
.select-list {
.loading {
.loading-message {
.octicon(hourglass);
&:before {
font-size: 1.1em;
width: 1.1em;
height: 1.1em;
margin-right: 5px;
}
}
.badge {
margin-left: 10px;
}
}
ol.list-group {
position: relative;
overflow-y: auto;
max-height: 312px;
margin: @component-padding 0 0 0;
padding: 0;
li {
display: block;
.primary-line,
.secondary-line {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
}
}
+1 -1
Ver Arquivo
@@ -141,7 +141,7 @@ jasmine.JQuery.matchersClass = {};
if (this.actual instanceof HTMLElement) {
this.actual = jQuery(this.actual);
}
if (this.actual instanceof jQuery || this.actual && this.actual.jquery) {
if (this.actual instanceof jQuery) {
var result = jQueryMatchers[methodName].apply(this, arguments);
this.actual = jasmine.JQuery.elementToString(this.actual);
return result;