From 641a0d43cc3d5a0f011d0532e2b824dd613fbe4d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki & Nathan Sobo Date: Wed, 6 Feb 2013 22:43:45 -0800 Subject: [PATCH] Retrigger event after package module is activated The event that triggers the package module to be activated is now retriggered after the package module is initialized but without any previously registered handlers. Instead only the handlers registered by the package module will be triggered. The prior event handlers are then restored after the event is retriggered. This allows package modules to bind event handlers during initialization that will be triggered by the same event that caused the package module intialization to occur. This simplifies the common case of having the same event cause a package module to initialize and attach. --- spec/app/atom-package-spec.coffee | 36 ++++++++++++++++ .../main.coffee | 6 +++ .../package.cson | 2 + src/app/atom-package.coffee | 41 +++++++++++++++---- .../go-to-line/lib/go-to-line-view.coffee | 2 +- src/packages/go-to-line/package.cson | 2 +- .../strip-trailing-whitespace/package.cson | 2 +- 7 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 spec/app/atom-package-spec.coffee create mode 100644 spec/fixtures/packages/package-with-activation-events/main.coffee create mode 100644 spec/fixtures/packages/package-with-activation-events/package.cson diff --git a/spec/app/atom-package-spec.coffee b/spec/app/atom-package-spec.coffee new file mode 100644 index 000000000..ab6a8bbb6 --- /dev/null +++ b/spec/app/atom-package-spec.coffee @@ -0,0 +1,36 @@ +RootView = require 'root-view' +AtomPackage = require 'atom-package' +fs = require 'fs' + +describe "AtomPackage", -> + describe ".load()", -> + [packageMainModule, pack, rootView] = [] + beforeEach -> + rootView = new RootView(fixturesProject.getPath()) + pack = new AtomPackage(fs.resolve(config.packageDirPaths..., 'package-with-activation-events')) + packageMainModule = require 'fixtures/packages/package-with-activation-events/main' + spyOn(packageMainModule, 'activate').andCallThrough() + pack.load() + + afterEach -> + rootView.deactivate() + + describe "when the package metadata includes activation events", -> + it "defers activating the package until an activation event bubbles to the root view", -> + expect(packageMainModule.activate).not.toHaveBeenCalled() + rootView.trigger 'activation-event' + expect(packageMainModule.activate).toHaveBeenCalled() + + it "triggers the activation event on all handlers registered during activation", -> + rootView.open('sample.js') + editor = rootView.getActiveEditor() + eventHandler = jasmine.createSpy("activation-event") + editor.command 'activation-event', eventHandler + editor.trigger 'activation-event' + expect(packageMainModule.activate.callCount).toBe 1 + expect(packageMainModule.activationEventCallCount).toBe 1 + expect(eventHandler.callCount).toBe 1 + editor.trigger 'activation-event' + expect(packageMainModule.activationEventCallCount).toBe 2 + expect(eventHandler.callCount).toBe 2 + expect(packageMainModule.activate.callCount).toBe 1 diff --git a/spec/fixtures/packages/package-with-activation-events/main.coffee b/spec/fixtures/packages/package-with-activation-events/main.coffee new file mode 100644 index 000000000..fc2588ef9 --- /dev/null +++ b/spec/fixtures/packages/package-with-activation-events/main.coffee @@ -0,0 +1,6 @@ +module.exports = + activationEventCallCount: 0 + + activate: -> + rootView.getActiveEditor()?.command 'activation-event', => + @activationEventCallCount++ diff --git a/spec/fixtures/packages/package-with-activation-events/package.cson b/spec/fixtures/packages/package-with-activation-events/package.cson new file mode 100644 index 000000000..80903d6f4 --- /dev/null +++ b/spec/fixtures/packages/package-with-activation-events/package.cson @@ -0,0 +1,2 @@ +'activationEvents': ['activation-event'] +'main': 'main' diff --git a/src/app/atom-package.coffee b/src/app/atom-package.coffee index e355d5483..f174e9cce 100644 --- a/src/app/atom-package.coffee +++ b/src/app/atom-package.coffee @@ -1,6 +1,7 @@ Package = require 'package' fs = require 'fs' _ = require 'underscore' +$ = require 'jquery' module.exports = class AtomPackage extends Package @@ -25,16 +26,40 @@ class AtomPackage extends Package console.warn "Failed to load package named '#{@name}'", e.stack this - subscribeToActivationEvents: (activationEvents) -> + disableEventHandlersOnBubblePath: (event) -> + bubblePathEventHandlers = [] + element = $(event.target) + while element.length + if eventHandlers = element.data('events')?[event.type] + for eventHandler in eventHandlers + eventHandler.disabledHandler = eventHandler.handler + eventHandler.handler = -> + bubblePathEventHandlers.push(eventHandler) + element = element.parent() + bubblePathEventHandlers + + restoreEventHandlersOnBubblePath: (eventHandlers) -> + for eventHandler in eventHandlers + eventHandler.handler = eventHandler.disabledHandler + delete eventHandler.disabledHandler + + unsubscribeFromActivationEvents: (activationEvents, activateHandler) -> + if _.isArray(activationEvents) + rootView.off(event, activateHandler) for event in activationEvents + else + rootView.off(event, selector, activateHandler) for event, selector of activationEvents + + subscribeToActivationEvents: (activationEvents) -> + activateHandler = (event) => + bubblePathEventHandlers = @disableEventHandlersOnBubblePath(event) + @activatePackageMain() + $(event.target).trigger(event) + @restoreEventHandlersOnBubblePath(bubblePathEventHandlers) + @unsubscribeFromActivationEvents(activationEvents, activateHandler) + if _.isArray(activationEvents) - activateHandler = => - @activatePackageMain() - rootView.off(event, activateHandler) for event in activationEvents rootView.command(event, activateHandler) for event in activationEvents else - activateHandler = => - @activatePackageMain() - rootView.off(event, selector, activateHandler) for event, selector of activationEvents rootView.command(event, selector, activateHandler) for event, selector of activationEvents activatePackageMain: -> @@ -42,7 +67,7 @@ class AtomPackage extends Package rootView?.activatePackage(@name, packageMain) getPackageMain: -> - mainPath = require.resolve(@metadata.main) if @metadata.main + mainPath = require.resolve(fs.join(@path, @metadata.main)) if @metadata.main if mainPath require(mainPath) else if require.resolve(@path) diff --git a/src/packages/go-to-line/lib/go-to-line-view.coffee b/src/packages/go-to-line/lib/go-to-line-view.coffee index ae2370521..ef734aa3b 100644 --- a/src/packages/go-to-line/lib/go-to-line-view.coffee +++ b/src/packages/go-to-line/lib/go-to-line-view.coffee @@ -6,7 +6,7 @@ Point = require 'point' module.exports = class GoToLineView extends View - @activate: (rootView) -> new GoToLineView(rootView).attach() + @activate: (rootView) -> new GoToLineView(rootView) @content: -> @div class: 'go-to-line overlay from-top mini', => diff --git a/src/packages/go-to-line/package.cson b/src/packages/go-to-line/package.cson index 6fdbc5937..4711ed56c 100644 --- a/src/packages/go-to-line/package.cson +++ b/src/packages/go-to-line/package.cson @@ -1,3 +1,3 @@ 'activationEvents': 'editor:go-to-line': '.editor' -'main': 'go-to-line/lib/go-to-line-view' +'main': './lib/go-to-line-view' diff --git a/src/packages/strip-trailing-whitespace/package.cson b/src/packages/strip-trailing-whitespace/package.cson index 25e3026d8..0daeeb412 100644 --- a/src/packages/strip-trailing-whitespace/package.cson +++ b/src/packages/strip-trailing-whitespace/package.cson @@ -1 +1 @@ -'main': 'strip-trailing-whitespace/lib/strip-trailing-whitespace' +'main': './lib/strip-trailing-whitespace'