From b02aa369cad4b8ce99639574db254237d68faeb5 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 19 Sep 2017 13:24:46 -0500 Subject: [PATCH] rebase atom.commands.onDidFinish --- spec/command-registry-spec.js | 82 +++++++++++++++++++++++++++++++++-- src/command-registry.js | 23 +++++++--- 2 files changed, 94 insertions(+), 11 deletions(-) diff --git a/spec/command-registry-spec.js b/spec/command-registry-spec.js index a0ac86c08..eccac3de3 100644 --- a/spec/command-registry-spec.js +++ b/spec/command-registry-spec.js @@ -191,9 +191,11 @@ describe("CommandRegistry", () => { expect(calls).toEqual([]); }); - it("invokes callbacks registered with ::onWillDispatch and ::onDidDispatch", () => { + it("invokes callbacks registered with ::onWillDispatch and ::onDidDispatch and ::onDidFinish", () => { const sequence = []; + registry.onDidFinish(event => sequence.push(['onDidFinish', event])); + registry.onDidDispatch(event => sequence.push(['onDidDispatch', event])); registry.add('.grandchild', 'command', event => sequence.push(['listener', event])); @@ -206,9 +208,81 @@ describe("CommandRegistry", () => { expect(sequence[1][0]).toBe('listener'); expect(sequence[2][0]).toBe('onDidDispatch'); - expect(sequence[0][1] === sequence[1][1] && sequence[1][1] === sequence[2][1]).toBe(true); - expect(sequence[0][1].constructor).toBe(CustomEvent); - expect(sequence[0][1].target).toBe(grandchild); + waitsFor(() => sequence.length === 4), "onDidFinish never called"); + + runs(() => { + expect(sequence[3][0]).toBe 'onDidFinish' + + expect(sequence[0][1] === sequence[1][1] && sequence[1][1] === sequence[2][1] && sequence[2][1] === sequence[3][1]).toBe(true); + expect(sequence[0][1].constructor).toBe(CustomEvent); + expect(sequence[0][1].target).toBe(grandchild); + }); + }); + + it("invokes callbacks registered with ::onDidFinish on resolve", () => { + const sequence = []; + + registry.onDidFinish(event => { + sequence.push(['onDidFinish', event]); + }); + + registry.add('.grandchild', 'command', event => { + sequence.push(['listener', event]); + return new Promise(resolve => { + setTimeout(() => { + sequence.push(['resolve', event]); + resolve(); + }, 100); + }); + }); + + grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true})); + advanceClock(100); + + waitsFor(() => sequence.length === 3, "onDidFinish never called for resolve"); + + runs(() => { + expect(sequence[0][0]).toBe('listener') + expect(sequence[1][0]).toBe('resolve') + expect(sequence[2][0]).toBe('onDidFinish') + + expect(sequence[0][1] === sequence[1][1] && sequence[1][1] === sequence[2][1]).toBe(true) + expect(sequence[0][1].constructor).toBe(CustomEvent) + expect(sequence[0][1].target).toBe(grandchild) + }); + }); + + it("invokes callbacks registered with ::onDidFinish on reject", () => { + const sequence = []; + + registry.onDidFinish(event => { + sequence.push(['onDidFinish', event]); + }); + + registry.add('.grandchild', 'command', event => { + sequence.push(['listener', event]); + return new Promise((_, reject) => { + setTimeout(() => { + sequence.push(['reject', event]); + reject(); + }, 100); + }); + }); + + grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true})); + advanceClock(100); + + waitsFor(() => sequence.length === 3, "onDidFinish never called for reject"); + + runs(() => { + expect(sequence[0][0]).toBe('listener') + expect(sequence[1][0]).toBe('reject') + expect(sequence[2][0]).toBe('onDidFinish') + + expect(sequence[0][1] === sequence[1][1] && sequence[1][1] === sequence[2][1]).toBe(true) + expect(sequence[0][1].constructor).toBe(CustomEvent) + expect(sequence[0][1].target).toBe(grandchild) + }); }); }); diff --git a/src/command-registry.js b/src/command-registry.js index 9e6d8c2e1..e87c6a8d8 100644 --- a/src/command-registry.js +++ b/src/command-registry.js @@ -289,6 +289,14 @@ module.exports = class CommandRegistry { return this.emitter.on('did-dispatch', callback) } + // Public: Invoke the given callback after finishing a command event. + // + // * `callback` {Function} to be called after finishing each command + // * `event` The Event that was dispatched + onDidFinish (callback) { + return this.emitter.on('did-finish', callback) + } + getSnapshot () { const snapshot = {} for (const commandName in this.selectorBasedListenersByCommandName) { @@ -309,7 +317,7 @@ module.exports = class CommandRegistry { handleCommandEvent (event) { let propagationStopped = false let immediatePropagationStopped = false - let matched = false + let matched = [] let currentTarget = event.target const dispatchedEvent = new CustomEvent(event.type, { @@ -373,10 +381,6 @@ module.exports = class CommandRegistry { listeners = selectorBasedListeners.concat(listeners) } - if (listeners.length > 0) { - matched = true - } - // Call inline listeners first in reverse registration order, // and selector-based listeners by specificity and reverse // registration order. @@ -385,7 +389,7 @@ module.exports = class CommandRegistry { if (immediatePropagationStopped) { break } - listener.didDispatch.call(currentTarget, dispatchedEvent) + matched.push(listener.didDispatch.call(currentTarget, dispatchedEvent)) } if (currentTarget === window) { @@ -399,7 +403,12 @@ module.exports = class CommandRegistry { this.emitter.emit('did-dispatch', dispatchedEvent) - return matched + Promise.all(matched).then( + _ => this.emitter.emit('did-finish', dispatchedEvent), + _ => this.emitter.emit('did-finish', dispatchedEvent) + ) + + return matched.length > 0 } commandRegistered (commandName) {