Skip to content

Instantly share code, notes, and snippets.

@ItsAsbreuk
Forked from lsmith/gist:6664382
Last active December 23, 2015 18:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ItsAsbreuk/6676361 to your computer and use it in GitHub Desktop.
Save ItsAsbreuk/6676361 to your computer and use it in GitHub Desktop.
/*global SM:true*/
'use strict';
// Publish a very special, promise-compatible event that supports the default
// function behavior to chain on internally created promises before executing
// the after() subs. on() subs can still e.preventDefault(), which will
// reject the promise and thus skip the default behavior and after() subs.
var asyncEvent = eventTarget.publish('foo');
asyncEvent._firing = new Y.Promise(function (resolve) { resolve(); });
asyncEvent.fire = function (data) {
var event = this,
args = Y.Array(arguments, 0, true);
event._firing = event._firing.then(function () {
event.details = args;
// Execute on() subscribers
var subs = event._subscribers,
dataArray = [],
e = event._createFacade(dataArray.push.apply(dataArray, data)),
i, len, stack;
if (subs) {
for (i = 0, len = subs.length; i < len; ++i) {
// TODO: try/catch?
subs[i].fn.call(subs[i].context, e);
}
}
// Execute on() subscribers for each bubble target and their respective targets:
if (event.bubbles && !event.stopped) {
stack = event.stack || event;
eventTarget.bubble(event, args, null, stack);
e.prevented = Math.max(e.prevented, stack.prevented);
}
// Resolve the _firing promise with either false if it was prevented, or with a promise for
// the result of the defaultFn followed by the execution of the after subs.
return e.prevented ?
Y.when(event.preventedFn(e).then(null, function (err) {
Y.log("Error in preventedFn: " + (err && (err.message || err)), 'error');
return false;
})
:
Y.when(event.defaultFn(e).then(function (response) {
// Execute after() subscribers
subs = event._afters;
if (subs) {
for (i = 0, len = subs.length; i < len; ++i) {
subs[i].fn.call(subs[i].context, e);
}
}
// Execute after() subscribers for each bubble target and their respective targets:
// CODE DOES NOT WORK: on-subscribers are called again!
eventTarget.bubble(event, args, null, stack);
// Catch errors/preventions and reset the promise state to fulfilled for
// the next call to fire();
}).then(null, function (err) {
Y.log("Error in defaultFn or after subscriber: " + (err && (err.message || err)), 'error');
return false;
});
});
};
asyncEvent._fire = function (args) {
return this.fire(args[0]);
};
@lsmith
Copy link

lsmith commented Sep 25, 2013

  • Add on line 15
stack = {
    id: event.id,
    next: event,
    silent: event.silent,
    stopped: 0,
    prevented: 0,
    bubbling: null,
    type: event.type,
    defaultTargetOnly: event.defaultTargetOnly
}, next;
  • Remove line 35
  • Replace lines 56-60 with
if (stack.afterQueue) {
    while ((next = stack.afterQueue.last())) {
        next();
    }
}

The bubble method accumulates after subscribers in the event stack's afterQueue property. This A) might not work, and B) doesn't support recursive bubbling of the same event.

@ItsAsbreuk
Copy link
Author

Luke, thanks!

I got the final code working: created Y.Model.prototype.publishAsync
https://gist.github.com/ItsAsbreuk/6712217

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment