Comparing version 0.10.19 to 0.10.20
@@ -137,50 +137,63 @@ var derbyTemplates = require('derby-templates'); | ||
if (!model) return; | ||
// Registering model listeners with the *Immediate events helps to prevent | ||
// a bug with binding updates where a model listener causes a change to the | ||
// path being listened on, directly or indirectly. | ||
if (model.get('$derbyFlags.immediateModelListeners')) { | ||
// Registering model listeners with the *Immediate events helps to prevent | ||
// a bug with binding updates where a model listener causes a change to the | ||
// path being listened on, directly or indirectly. This flag will go away | ||
// after a month or so of private testing, and if everything looks fine, | ||
// we'll switch unconditionally to *Immediate listeners. | ||
return this._addModelListenersImmediate(eventModel); | ||
// TODO: Remove this when upgrading Racer to the next major version. Feature | ||
// detect which type of event listener to register by emitting a test event | ||
if (useLegacyListeners(model)) { | ||
return this._addModelListenersLegacy(eventModel); | ||
} | ||
var context = this.context; | ||
var changeListener = model.on('change', '**', function onChange(path, value, previous, pass) { | ||
var segments = util.castSegments(path.split('.')); | ||
// `util.castSegments(segments)` is needed to cast string segments into | ||
// numbers, since EventModel#child does typeof checks against segments. This | ||
// could be done once in Racer's Model#emit, instead of in every listener. | ||
var changeListener = model.on('changeImmediate', function onChange(segments, event) { | ||
// The pass parameter is passed in for special handling of updates | ||
// resulting from stringInsert or stringRemove | ||
eventModel.set(segments, previous, pass); | ||
segments = util.castSegments(segments.slice()); | ||
eventModel.set(segments, event.previous, event.pass); | ||
}); | ||
var loadListener = model.on('load', '**', function onLoad(path) { | ||
var segments = util.castSegments(path.split('.')); | ||
var loadListener = model.on('loadImmediate', function onLoad(segments) { | ||
segments = util.castSegments(segments.slice()); | ||
eventModel.set(segments); | ||
}); | ||
var unloadListener = model.on('unload', '**', function onUnload(path) { | ||
var segments = util.castSegments(path.split('.')); | ||
eventModel.set(segments); | ||
var unloadListener = model.on('unloadImmediate', function onUnload(segments, event) { | ||
segments = util.castSegments(segments.slice()); | ||
eventModel.set(segments, event.previous); | ||
}); | ||
var insertListener = model.on('insert', '**', function onInsert(path, index, values) { | ||
var segments = util.castSegments(path.split('.')); | ||
eventModel.insert(segments, index, values.length); | ||
var insertListener = model.on('insertImmediate', function onInsert(segments, event) { | ||
segments = util.castSegments(segments.slice()); | ||
eventModel.insert(segments, event.index, event.values.length); | ||
}); | ||
var removeListener = model.on('remove', '**', function onRemove(path, index, values) { | ||
var segments = util.castSegments(path.split('.')); | ||
eventModel.remove(segments, index, values.length); | ||
var removeListener = model.on('removeImmediate', function onRemove(segments, event) { | ||
segments = util.castSegments(segments.slice()); | ||
eventModel.remove(segments, event.index, event.values.length); | ||
}); | ||
var moveListener = model.on('move', '**', function onMove(path, from, to, howMany) { | ||
var segments = util.castSegments(path.split('.')); | ||
eventModel.move(segments, from, to, howMany); | ||
var moveListener = model.on('moveImmediate', function onMove(segments, event) { | ||
segments = util.castSegments(segments.slice()); | ||
eventModel.move(segments, event.from, event.to, event.howMany); | ||
}); | ||
this._removeModelListeners = function() { | ||
model.removeListener('change', changeListener); | ||
model.removeListener('load', loadListener); | ||
model.removeListener('unload', unloadListener); | ||
model.removeListener('insert', insertListener); | ||
model.removeListener('remove', removeListener); | ||
model.removeListener('move', moveListener); | ||
model.removeListener('changeImmediate', changeListener); | ||
model.removeListener('loadImmediate', loadListener); | ||
model.removeListener('unloadImmediate', unloadListener); | ||
model.removeListener('insertImmediate', insertListener); | ||
model.removeListener('removeImmediate', removeListener); | ||
model.removeListener('moveImmediate', moveListener); | ||
}; | ||
}; | ||
Page.prototype._addModelListenersImmediate = function(eventModel) { | ||
function useLegacyListeners(model) { | ||
var useLegacy = true; | ||
// model.once is broken in older racer, so manually remove event | ||
var listener = model.on('changeImmediate', function(segments, event) { | ||
model.removeListener('changeImmediate', listener); | ||
// Older Racer emits an array of eventArgs, whereas newer racer emits an event object | ||
useLegacy = Array.isArray(event); | ||
}); | ||
model.set('$derby.testEvent', true); | ||
return useLegacy; | ||
} | ||
Page.prototype._addModelListenersLegacy = function(eventModel) { | ||
var model = this.model; | ||
@@ -187,0 +200,0 @@ if (!model) return; |
{ | ||
"name": "derby", | ||
"description": "MVC framework making it easy to write realtime, collaborative applications that run in both Node.js and browsers.", | ||
"version": "0.10.19", | ||
"version": "0.10.20", | ||
"homepage": "http://derbyjs.com/", | ||
@@ -6,0 +6,0 @@ "repository": { |
@@ -420,3 +420,2 @@ var expect = require('chai').expect; | ||
); | ||
app.model.set('$derbyFlags.immediateModelListeners', true); | ||
app.model.on('insert', '_data.items', function(index, values) { | ||
@@ -423,0 +422,0 @@ if (values[0] == 'B') { |
173923
4445