correct event handler order in nested DomRanges

this completes Meteor UI Events (except for
unbind on removal)
This commit is contained in:
David Greenspan
2013-09-02 18:40:46 -07:00
parent bca0d2ec1e
commit a5bada71a8
3 changed files with 65 additions and 8 deletions

View File

@@ -34,6 +34,7 @@ if (Meteor.isClient) {
},
// `selector` is non-null. `type` is one type (but
// may be in backend-specific form, e.g. have namespaces).
// Order fired must be order bound.
delegateEvents: function (elem, type, selector, handler) {
$(elem).on(type, selector, handler);
},

View File

@@ -881,19 +881,20 @@ var HandlerRec = function (elem, type, selector, handler, $ui) {
}
};
HandlerRec.prototype.setup = function () {
if (this.mode === EVENT_MODE_TBD) {
HandlerRec.prototype.bind = function () {
if (this.mode !== EVENT_MODE_BUBBLING) {
DomBackend.bindEventCapturer(
this.elem, this.type,
this.capturingHandler);
}
DomBackend.delegateEvents(
this.elem, this.type,
this.selector || '*', this.delegatedHandler);
if (this.mode !== EVENT_MODE_CAPTURING)
DomBackend.delegateEvents(
this.elem, this.type,
this.selector || '*', this.delegatedHandler);
};
HandlerRec.prototype.teardown = function () {
HandlerRec.prototype.unbind = function () {
if (this.mode !== EVENT_MODE_BUBBLING)
DomBackend.unbindEventCapturer(this.elem, this.type,
this.capturingHandler);
@@ -903,6 +904,7 @@ HandlerRec.prototype.teardown = function () {
this.delegatedHandler);
};
// XXX could write the form of arguments for this function
// in several different ways, including simply as an event map.
DomRange.prototype.on = function (events, selector, handler) {
@@ -940,10 +942,28 @@ DomRange.prototype.on = function (events, selector, handler) {
info = eventDict[type] = {};
info.handlers = [];
}
var handlerList = info.handlers;
var handlerRec = new HandlerRec(
parentNode, type, selector, handler, this.component);
handlerRec.setup();
info.handlers.push(handlerRec);
handlerRec.bind();
handlerList.push(handlerRec);
// move handlers of enclosing ranges to end
for (var r = (this.owner && this.owner.dom);
r; r = (r.owner && r.owner.dom)) {
// r is an enclosing DomRange
for (var j = 0, Nj = handlerList.length;
j < Nj; j++) {
var h = handlerList[j];
if (h.$ui && h.$ui.dom === r) {
h.unbind();
h.bind();
handlerList.splice(j, 1); // remove handlerList[j]
handlerList.push(h);
j--; // account for removed handler
Nj--; // don't visit appended handlers
}
}
}
}
};

View File

@@ -896,6 +896,42 @@ Tinytest.add("ui - DomRange - events in tables", function (test) {
});
});
Tinytest.add("ui - DomRange - nested event order", function (test) {
inDocument(new DomRange, function (r) {
var a = new DomRange;
var b = new DomRange;
var c = new DomRange;
var d = new DomRange;
r.add(a);
a.add(b);
b.add(c);
c.add(d);
var div = document.createElement("DIV");
d.add(div);
var buf = [];
var appender = function (str) {
return function (evt) {
buf.push(str);
};
};
b.on('click', 'div', appender("B"));
a.on('click', 'div', appender("A"));
d.on('click', appender("D"));
c.on('click', 'div', appender("C"));
test.equal(buf, []);
div.click();
test.equal(buf, ['D', 'C', 'B', 'A']);
buf.length = 0;
b.on('click', appender("B2"));
d.on('click', 'div', appender("D2"));
div.click();
test.equal(buf, ['D', 'D2', 'C', 'B', 'B2', 'A']);
});
});
// TO TEST STILL:
// - external remove element
// - double-add, double-remove