-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathReuseView.js
More file actions
143 lines (112 loc) · 3.8 KB
/
ReuseView.js
File metadata and controls
143 lines (112 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
(function(){
var isImg = /^img/,
clearImgs = function(imgs)
{
len = imgs.length;
for(i=0; i<len; i++)
{
imgs[i].src = null;
imgs[i].src = '';
}
}
var ReuseView = Backbone.ReuseView = function(opts)
{
// call backbone constructor
Backbone.View.prototype.constructor.apply(this, [opts]);
this.model = opts.model || null;
this.forceGPUTexture = opts.forceGPUTexture || false;
this.render();
this.height = (this.height ? this.height : _.bind(this.$el.height, this.$el));
this.$el.css( (!this.forceGPUTexture ?
{position: 'absolute'} :
{webkitTransform: 'translate3d(0,0,0)'} ));
// console.log('alloced: '+this.$el.find('.first').html())
// cache DOM elements that need data updates
this._$cached = {};
for(var name in this.modelMap)
{
var selector = this.modelMap[name][0];
this._$cached[name] = this.$el.find(selector);
}
this._$imgs = this.$el.find('img');
// set the model, cache the template and add watch listeners
this._repurpose(this.model);
}
_.extend(ReuseView.prototype, {
model: null, // backbone model(s) are passed in on creation/repurpose
modelMap: {}, // { modelProperty: [selector, updateFunction]}
_reuseId: null,
_$imgs: null,
_$cached: {},
_idx: null,
_saveMemoryMode: false,
height: null, // replace this with a function that returns a static height for faster performance
forceGPUTexture: false,
_repurpose: function(model)
{
// dealloc the old model
if (model && this.model)
{
for (name in this.modelMap)
{
this.model.off('change:'+name);
}
this.model = model;
}
var sel, el, val, fnc;
for(name in this.modelMap)
{
sel = this.modelMap[name][0];
if (this._saveMemoryMode && isImg.exec(sel)) continue;
// register for new events if not saving memory
if (!this._saveMemoryMode)
{
this.model.on('change:'+name, _.bind(this._modelChanged, this));
}
// update the DOM
el = this._$cached[name];
val = this.model.get(name);
fnc = this.modelMap[name][1];
fnc.call(this, el, val)
}
},
// pool view triggers repaint when there is a new model and position
repaint: function( idx, position, backboneModel )
{
// set the position as absolute
var pos = (!this.forceGPUTexture ?
{'top': position} :
{'webkitTransform': 'translate3d(0, '+position+'px, 0)'}),
i, len, name;
// update the position
this.$el.css( pos );
// update the model and the dom
clearImgs(this._$imgs);
this._repurpose(backboneModel);
// allow the reflow/repaints to happend
},
staticHeight: function()
{
// override if poolView is set to staticHeights option
},
_modelChanged: function(evt)
{
this._updateModel(this.model, Object.keys(evt.changed)[0]);
},
_updateModel: function(model, name)
{
var fnc = this.modelMap[name][1];
fnc(this._$cached[name], model.get(name));
},
_freezeAllocations: function(shouldDelay)
{
var imgs;
this._saveMemoryMode = shouldDelay;
if (!shouldDelay) return clearImgs(this._$imgs);
// else when turning back on then draw images and listen for model events
this._repurpose();
}
});
_.extend(ReuseView.prototype, Backbone.View.prototype);
ReuseView.extend = Backbone.View.extend;
}());