-
Notifications
You must be signed in to change notification settings - Fork 120
Client restore #338
Client restore #338
Changes from all commits
b833c26
e784d98
0f63f0e
641f5c4
3e14222
6da7841
dd0974b
935c37f
c37d677
d92b75b
28cb768
14d4f63
e99ef85
8a84829
33cdf17
f3db3c1
e7472c5
5d722cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
/*global assignView, assignTemplate, createRegistryWrapper, dataObject, getValue, modelCidAttributeName, viewCidAttributeName */ | ||
/*global | ||
$serverSide, | ||
assignView, assignTemplate, createRegistryWrapper, dataObject, getValue, | ||
modelCidAttributeName, modelIdAttributeName, viewCidAttributeName | ||
*/ | ||
var _fetch = Backbone.Collection.prototype.fetch, | ||
_set = Backbone.Collection.prototype.set, | ||
_replaceHTML = Thorax.View.prototype._replaceHTML, | ||
|
@@ -107,6 +111,51 @@ Thorax.CollectionView = Thorax.View.extend({ | |
} | ||
}, | ||
|
||
restore: function(el) { | ||
var self = this, | ||
children = this.$el.children(), | ||
toRemove = []; | ||
|
||
if (!Thorax.View.prototype.restore.call(this, el)) { | ||
// If we had to rerender for other reasons then we don't need to do anything as it | ||
// was already all blown away | ||
return; | ||
} | ||
|
||
this._lookupCollectionElement(); | ||
|
||
// Find any items annotated with server info and restore. Else rerender | ||
$('[' + modelIdAttributeName + ']', el).each(function() { | ||
var id = this.getAttribute(modelIdAttributeName), | ||
model = self.collection.get(id); | ||
if (!model) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry to be sense but if the collection item was rendered for a model in the collection, what would be the case where the model would no longer exist? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two cases: the there is no constant id value and somehow the data changed between data sources between the time that the client and server data was rendered. The later generally shouldn't happen but we want to play it safe. |
||
toRemove.push(this); | ||
} else { | ||
self.restoreItem(model, children.index(this), this); | ||
} | ||
}); | ||
$('[data-view-empty]', el).each(function() { | ||
self.restoreEmpty(this); | ||
}); | ||
|
||
if (toRemove.length) { | ||
// TODO : Is it better to just rerender the whole thing since we don't necessarily | ||
// know what state the list is in at this point? | ||
// Kill off any now invalid nodes | ||
_.each(toRemove, function(el) { | ||
el.parentNode.removeChild(el); | ||
}); | ||
|
||
// Render anything that we might have locally but was missed | ||
var $el = this._collectionElement; | ||
this.collection.each(function(model) { | ||
if (!$el.find('[' + modelCidAttributeName + '="' + model.cid + '"]').length) { | ||
self.appendItem(model); | ||
} | ||
}); | ||
} | ||
}, | ||
|
||
//appendItem(model [,index]) | ||
//appendItem(html_string, index) | ||
//appendItem(view, index) | ||
|
@@ -154,7 +203,10 @@ Thorax.CollectionView = Thorax.View.extend({ | |
}); | ||
|
||
if (model) { | ||
itemElement.attr(modelCidAttributeName, model.cid); | ||
itemElement.attr({ | ||
'data-model-id': model.id, | ||
'data-model-cid': model.cid | ||
}); | ||
} | ||
var previousModel = index > 0 ? collection.at(index - 1) : false; | ||
if (!previousModel) { | ||
|
@@ -166,7 +218,10 @@ Thorax.CollectionView = Thorax.View.extend({ | |
} | ||
|
||
this.trigger('append', null, function($el) { | ||
$el.attr(modelCidAttributeName, model.cid); | ||
$el.attr({ | ||
'data-model-cid': model.cid, | ||
'data-model-id': model.id, | ||
}); | ||
}); | ||
|
||
if (!options || !options.silent) { | ||
|
@@ -258,12 +313,20 @@ Thorax.CollectionView = Thorax.View.extend({ | |
viewOptions.template = this.emptyTemplate; | ||
} | ||
var view = Thorax.Util.getViewInstance(this.emptyView, viewOptions); | ||
view.ensureRendered(); | ||
view.$el.attr('data-view-empty', 'true'); | ||
return view; | ||
} else { | ||
return this.emptyTemplate && this.renderTemplate(this.emptyTemplate); | ||
} | ||
}, | ||
restoreEmpty: function(el) { | ||
var child = this.renderEmpty(); | ||
|
||
child.restore(el); | ||
this._addChild(child); | ||
return child; | ||
}, | ||
|
||
renderItem: function(model, i) { | ||
if (!this.itemView) { | ||
assignView.call(this, 'itemView', { | ||
|
@@ -294,6 +357,18 @@ Thorax.CollectionView = Thorax.View.extend({ | |
return this.renderTemplate(this.itemTemplate, this.itemContext.call(this, model, i)); | ||
} | ||
}, | ||
restoreItem: function(model, i, el) { | ||
// Associate the element with the proper model. | ||
el.setAttribute(modelCidAttributeName, model.cid); | ||
|
||
// If we are dealing with something other than a template then reinstantiate the view. | ||
if (this.itemView || this.renderItem !== Thorax.CollectionView.prototype.renderItem) { | ||
var child = this.renderItem(model, i); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will this work correctly with the old style ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should but let me add a test case to ensure coverage there. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does work. Test case added. |
||
|
||
child.restore(el); | ||
this._addChild(child); | ||
} | ||
}, | ||
itemContext: function(model /*, i */) { | ||
return model.attributes; | ||
}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,7 +121,7 @@ _.extend(Thorax.View.prototype, { | |
} else if (!$serverSide) { | ||
// DOM Events | ||
if (!params.nested) { | ||
boundHandler = containHandlerToCurentView(boundHandler, this.cid); | ||
boundHandler = containHandlerToCurentView(boundHandler, this); | ||
} | ||
|
||
var name = params.name + '.delegateEvents' + this.cid; | ||
|
@@ -168,10 +168,12 @@ pushDomEvents([ | |
'focus', 'blur' | ||
]); | ||
|
||
function containHandlerToCurentView(handler, cid) { | ||
function containHandlerToCurentView(handler, current) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this change? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the cid is stored directly in a closure variable then the changes that On Thu, Mar 13, 2014 at 1:29 PM, Roman Bataev [email protected]:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, gotcha |
||
// Passing the current view rather than just a cid to allow for updates to the view's cid | ||
// caused by the restore process. | ||
return function(event) { | ||
var view = $(event.target).view({helper: false}); | ||
if (view && view.cid === cid) { | ||
if (view && view.cid === current.cid) { | ||
event.originalContext = this; | ||
return handler(event); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will each collection element have
data-model-id
anddata-model-cid
now?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct.