1
1
2
2
// Available under the MIT License (MIT)
3
3
4
- ( function ( root , factory ) {
5
- if ( typeof define === 'function' && define . amd ) {
6
- define ( [ 'backbone' , 'underscore' ] , function ( Backbone , _ ) {
7
- Backbone . VirtualCollection = factory ( root , Backbone , _ ) ;
8
- root . VirtualCollection = Backbone . VirtualCollection ;
9
- } ) ;
10
- } else if ( typeof exports !== 'undefined' ) {
11
- var Backbone = require ( 'backbone' ) ;
12
- var _ = require ( 'underscore' ) ;
13
- module . exports = factory ( root , Backbone , _ ) ;
14
- } else {
15
- root . Backbone . VirtualCollection = factory ( root , root . Backbone , root . _ ) ;
16
- root . VirtualCollection = root . Backbone . VirtualCollection ;
17
- }
18
- } ( this , function ( root , Backbone , _ ) {
19
- var VirtualCollection = Backbone . Collection . extend ( {
20
-
21
- constructor : function ( collection , options ) {
22
- options = options || { } ;
23
- this . collection = collection ;
24
-
25
- if ( options . comparator !== undefined ) this . comparator = options . comparator ;
26
- if ( options . close_with ) this . bindLifecycle ( options . close_with , 'close' ) ; // Marionette 1.*
27
- if ( options . destroy_with ) this . bindLifecycle ( options . destroy_with , 'destroy' ) ; // Marionette 2.*
28
- if ( ! this . model ) this . model = collection . model ;
29
-
30
- this . accepts = VirtualCollection . buildFilter ( options . filter ) ;
31
- this . _rebuildIndex ( ) ;
32
- this . listenTo ( this . collection , 'add' , this . _onAdd ) ;
33
- this . listenTo ( this . collection , 'remove' , this . _onRemove ) ;
34
- this . listenTo ( this . collection , 'change' , this . _onChange ) ;
35
- this . listenTo ( this . collection , 'reset' , this . _onReset ) ;
36
- this . listenTo ( this . collection , 'sort' , this . _onSort ) ;
37
-
38
- this . initialize . apply ( this , arguments ) ;
39
- } ,
40
-
41
- // Marionette 1.*
42
- bindLifecycle : function ( view , method_name ) {
43
- view . on ( method_name , _ . bind ( this . stopListening , this ) ) ;
44
- } ,
45
-
46
- updateFilter : function ( filter ) {
47
- this . accepts = VirtualCollection . buildFilter ( filter ) ;
48
- this . _rebuildIndex ( ) ;
49
- this . trigger ( 'filter' , this , filter ) ;
50
- this . trigger ( 'reset' , this , filter ) ;
51
- return this ;
52
- } ,
53
-
54
- _rebuildIndex : function ( ) {
55
- for ( idx in this . models ) {
56
- this . models [ idx ] . off ( 'all' , this . _onModelEvent , this ) ;
4
+ var VirtualCollection ,
5
+ Backbone = require ( 'backbone' ) ,
6
+ _ = require ( 'underscore' ) ;
7
+
8
+ VirtualCollection = Backbone . Collection . extend ( {
9
+
10
+ constructor : function ( collection , options ) {
11
+ options = options || { } ;
12
+ this . collection = collection ;
13
+
14
+ if ( options . comparator !== undefined ) this . comparator = options . comparator ;
15
+ if ( options . close_with ) this . bindLifecycle ( options . close_with , 'close' ) ; // Marionette 1.*
16
+ if ( options . destroy_with ) this . bindLifecycle ( options . destroy_with , 'destroy' ) ; // Marionette 2.*
17
+ if ( ! this . model ) this . model = collection . model ;
18
+
19
+ this . accepts = VirtualCollection . buildFilter ( options . filter ) ;
20
+ this . _rebuildIndex ( ) ;
21
+ this . listenTo ( this . collection , 'add' , this . _onAdd ) ;
22
+ this . listenTo ( this . collection , 'remove' , this . _onRemove ) ;
23
+ this . listenTo ( this . collection , 'change' , this . _onChange ) ;
24
+ this . listenTo ( this . collection , 'reset' , this . _onReset ) ;
25
+ this . listenTo ( this . collection , 'sort' , this . _onSort ) ;
26
+
27
+ this . initialize . apply ( this , arguments ) ;
28
+ } ,
29
+
30
+ // Marionette 1.*
31
+ bindLifecycle : function ( view , method_name ) {
32
+ view . on ( method_name , _ . bind ( this . stopListening , this ) ) ;
33
+ } ,
34
+
35
+ updateFilter : function ( filter ) {
36
+ this . accepts = VirtualCollection . buildFilter ( filter ) ;
37
+ this . _rebuildIndex ( ) ;
38
+ this . trigger ( 'filter' , this , filter ) ;
39
+ this . trigger ( 'reset' , this , filter ) ;
40
+ return this ;
41
+ } ,
42
+
43
+ _rebuildIndex : function ( ) {
44
+ for ( idx in this . models ) {
45
+ this . models [ idx ] . off ( 'all' , this . _onModelEvent , this ) ;
46
+ }
47
+ this . _reset ( ) ;
48
+ this . collection . each ( function ( model , i ) {
49
+ if ( this . accepts ( model , i ) ) {
50
+ model . on ( 'all' , this . _onModelEvent , this ) ;
51
+ this . models . push ( model ) ;
52
+ this . _byId [ model . cid ] = model ;
53
+ if ( model . id ) this . _byId [ model . id ] = model ;
57
54
}
58
- this . _reset ( ) ;
59
- this . collection . each ( function ( model , i ) {
60
- if ( this . accepts ( model , i ) ) {
61
- model . on ( 'all' , this . _onModelEvent , this ) ;
62
- this . models . push ( model ) ;
63
- this . _byId [ model . cid ] = model ;
64
- if ( model . id ) this . _byId [ model . id ] = model ;
65
- }
66
- } , this ) ;
67
- this . length = this . models . length ;
55
+ } , this ) ;
56
+ this . length = this . models . length ;
57
+
58
+ if ( this . comparator ) this . sort ( { silent : true } ) ;
59
+ } ,
60
+
61
+ orderViaParent : function ( options ) {
62
+ this . models = this . collection . filter ( function ( model ) {
63
+ return ( this . _byId [ model . cid ] !== undefined ) ;
64
+ } , this ) ;
65
+ if ( ! options . silent ) this . trigger ( 'sort' , this , options ) ;
66
+ } ,
67
+
68
+ _onSort : function ( collection , options ) {
69
+ if ( this . comparator !== undefined ) return ;
70
+ this . orderViaParent ( options ) ;
71
+ } ,
72
+
73
+ _onAdd : function ( model , collection , options ) {
74
+ var already_here = this . get ( model ) ;
75
+ if ( ! already_here && this . accepts ( model , options . index ) ) {
76
+ this . _indexAdd ( model ) ;
77
+ model . on ( 'all' , this . _onModelEvent , this ) ;
78
+ this . trigger ( 'add' , model , this , options ) ;
79
+ }
80
+ } ,
68
81
69
- if ( this . comparator ) this . sort ( { silent : true } ) ;
70
- } ,
82
+ _onRemove : function ( model , collection , options ) {
83
+ if ( ! this . get ( model ) ) return ;
71
84
72
- orderViaParent : function ( options ) {
73
- this . models = this . collection . filter ( function ( model ) {
74
- return ( this . _byId [ model . cid ] !== undefined ) ;
75
- } , this ) ;
76
- if ( ! options . silent ) this . trigger ( 'sort ' , this , options ) ;
77
- } ,
85
+ var i = this . _indexRemove ( model )
86
+ , options_clone = _ . clone ( options ) ;
87
+ options_clone . index = i ;
88
+ model . off ( 'all' , this . _onModelEvent , this ) ;
89
+ this . trigger ( 'remove ' , model , this , options_clone ) ;
90
+ } ,
78
91
79
- _onSort : function ( collection , options ) {
80
- if ( this . comparator !== undefined ) return ;
81
- this . orderViaParent ( options ) ;
82
- } ,
92
+ _onChange : function ( model , options ) {
93
+ if ( ! model || ! options ) return ; // ignore malformed arguments coming from custom events
94
+ var already_here = this . get ( model ) ;
83
95
84
- _onAdd : function ( model , collection , options ) {
85
- var already_here = this . get ( model ) ;
86
- if ( ! already_here && this . accepts ( model , options . index ) ) {
96
+ if ( this . accepts ( model , options . index ) ) {
97
+ if ( already_here ) {
98
+ this . trigger ( 'change' , model , this , options ) ;
99
+ } else {
87
100
this . _indexAdd ( model ) ;
88
- model . on ( 'all' , this . _onModelEvent , this ) ;
89
101
this . trigger ( 'add' , model , this , options ) ;
90
102
}
91
- } ,
92
-
93
- _onRemove : function ( model , collection , options ) {
94
- if ( ! this . get ( model ) ) return ;
95
-
96
- var i = this . _indexRemove ( model )
97
- , options_clone = _ . clone ( options ) ;
98
- options_clone . index = i ;
99
- model . off ( 'all' , this . _onModelEvent , this ) ;
100
- this . trigger ( 'remove' , model , this , options_clone ) ;
101
- } ,
102
-
103
- _onChange : function ( model , options ) {
104
- if ( ! model || ! options ) return ; // ignore malformed arguments coming from custom events
105
- var already_here = this . get ( model ) ;
106
-
107
- if ( this . accepts ( model , options . index ) ) {
108
- if ( already_here ) {
109
- this . trigger ( 'change' , model , this , options ) ;
110
- } else {
111
- this . _indexAdd ( model ) ;
112
- this . trigger ( 'add' , model , this , options ) ;
113
- }
114
- } else {
115
- if ( already_here ) {
116
- var i = this . _indexRemove ( model )
117
- , options_clone = _ . clone ( options ) ;
118
- options_clone . index = i ;
119
- this . trigger ( 'remove' , model , this , options_clone ) ;
120
- }
103
+ } else {
104
+ if ( already_here ) {
105
+ var i = this . _indexRemove ( model )
106
+ , options_clone = _ . clone ( options ) ;
107
+ options_clone . index = i ;
108
+ this . trigger ( 'remove' , model , this , options_clone ) ;
121
109
}
122
- } ,
110
+ }
111
+ } ,
123
112
124
- _onReset : function ( collection , options ) {
125
- this . _rebuildIndex ( ) ;
126
- this . trigger ( 'reset' , this , options ) ;
127
- } ,
113
+ _onReset : function ( collection , options ) {
114
+ this . _rebuildIndex ( ) ;
115
+ this . trigger ( 'reset' , this , options ) ;
116
+ } ,
128
117
129
- sortedIndex : function ( model , value , context ) {
130
- var iterator = _ . isFunction ( value ) ? value : function ( target ) {
131
- return target . get ( value ) ;
132
- } ;
118
+ sortedIndex : function ( model , value , context ) {
119
+ var iterator = _ . isFunction ( value ) ? value : function ( target ) {
120
+ return target . get ( value ) ;
121
+ } ;
133
122
134
- if ( iterator . length == 1 ) {
135
- return _ . sortedIndex ( this . models , model , iterator , context ) ;
136
- } else {
137
- return sortedIndexTwo ( this . models , model , iterator , context ) ;
138
- }
139
- } ,
140
-
141
- _indexAdd : function ( model ) {
142
- if ( this . get ( model ) ) return ;
143
- var i ;
144
- // uses a binsearch to find the right index
145
- if ( this . comparator ) {
146
- i = this . sortedIndex ( model , this . comparator , this ) ;
147
- } else if ( this . comparator === undefined ) {
148
- i = this . sortedIndex ( model , function ( target ) {
149
- //TODO: indexOf traverses the array every time the iterator is called
150
- return this . collection . indexOf ( target ) ;
151
- } , this ) ;
152
- } else {
153
- i = this . length ;
154
- }
155
- this . models . splice ( i , 0 , model ) ;
156
- this . _byId [ model . cid ] = model ;
157
- if ( model . id ) this . _byId [ model . id ] = model ;
158
- this . length += 1 ;
159
- } ,
160
-
161
- _indexRemove : function ( model ) {
162
- model . off ( 'all' , this . _onModelEvent , this ) ;
163
- var i = this . indexOf ( model ) ;
164
- if ( i === - 1 ) return i ;
165
- this . models . splice ( i , 1 ) ;
166
- delete this . _byId [ model . cid ] ;
167
- if ( model . id ) delete this . _byId [ model . id ] ;
168
- this . length -= 1 ;
169
- return i ;
123
+ if ( iterator . length == 1 ) {
124
+ return _ . sortedIndex ( this . models , model , iterator , context ) ;
125
+ } else {
126
+ return sortedIndexTwo ( this . models , model , iterator , context ) ;
127
+ }
128
+ } ,
129
+
130
+ _indexAdd : function ( model ) {
131
+ if ( this . get ( model ) ) return ;
132
+ var i ;
133
+ // uses a binsearch to find the right index
134
+ if ( this . comparator ) {
135
+ i = this . sortedIndex ( model , this . comparator , this ) ;
136
+ } else if ( this . comparator === undefined ) {
137
+ i = this . sortedIndex ( model , function ( target ) {
138
+ //TODO: indexOf traverses the array every time the iterator is called
139
+ return this . collection . indexOf ( target ) ;
140
+ } , this ) ;
141
+ } else {
142
+ i = this . length ;
170
143
}
144
+ this . models . splice ( i , 0 , model ) ;
145
+ this . _byId [ model . cid ] = model ;
146
+ if ( model . id ) this . _byId [ model . id ] = model ;
147
+ this . length += 1 ;
148
+ } ,
149
+
150
+ _indexRemove : function ( model ) {
151
+ model . off ( 'all' , this . _onModelEvent , this ) ;
152
+ var i = this . indexOf ( model ) ;
153
+ if ( i === - 1 ) return i ;
154
+ this . models . splice ( i , 1 ) ;
155
+ delete this . _byId [ model . cid ] ;
156
+ if ( model . id ) delete this . _byId [ model . id ] ;
157
+ this . length -= 1 ;
158
+ return i ;
159
+ }
171
160
172
- } , { // static props
173
-
174
- buildFilter : function ( options ) {
175
- if ( ! options ) {
176
- return function ( ) {
177
- return true ;
178
- } ;
179
- } else if ( _ . isFunction ( options ) ) {
180
- return options ;
181
- } else if ( options . constructor === Object ) {
182
- return function ( model ) {
183
- return ! Boolean ( _ ( Object . keys ( options ) ) . detect ( function ( key ) {
184
- return model . get ( key ) !== options [ key ] ;
185
- } ) ) ;
186
- } ;
187
- }
161
+ } , { // static props
162
+
163
+ buildFilter : function ( options ) {
164
+ if ( ! options ) {
165
+ return function ( ) {
166
+ return true ;
167
+ } ;
168
+ } else if ( _ . isFunction ( options ) ) {
169
+ return options ;
170
+ } else if ( options . constructor === Object ) {
171
+ return function ( model ) {
172
+ return ! Boolean ( _ ( Object . keys ( options ) ) . detect ( function ( key ) {
173
+ return model . get ( key ) !== options [ key ] ;
174
+ } ) ) ;
175
+ } ;
188
176
}
189
- } ) ;
177
+ }
178
+ } ) ;
190
179
191
- // methods that alter data should proxy to the parent collection
192
- _ . each ( [ 'add' , 'remove' , 'set' , 'reset' , 'push' , 'pop' , 'unshift' , 'shift' , 'slice' , 'sync' , 'fetch' ] , function ( method_name ) {
193
- VirtualCollection . prototype [ method_name ] = function ( ) {
194
- return this . collection [ method_name ] . apply ( this . collection , _ . toArray ( arguments ) ) ;
195
- } ;
196
- } ) ;
180
+ // methods that alter data should proxy to the parent collection
181
+ _ . each ( [ 'add' , 'remove' , 'set' , 'reset' , 'push' , 'pop' , 'unshift' , 'shift' , 'slice' , 'sync' , 'fetch' ] , function ( method_name ) {
182
+ VirtualCollection . prototype [ method_name ] = function ( ) {
183
+ return this . collection [ method_name ] . apply ( this . collection , _ . toArray ( arguments ) ) ;
184
+ } ;
185
+ } ) ;
197
186
198
- /**
187
+ /**
199
188
200
- Equivalent to _.sortedIndex, but for comparators with two arguments
189
+ Equivalent to _.sortedIndex, but for comparators with two arguments
201
190
202
- **/
203
- function sortedIndexTwo ( array , obj , iterator , context ) {
204
- var low = 0 , high = array . length ;
205
- while ( low < high ) {
206
- var mid = ( low + high ) >>> 1 ;
207
- iterator . call ( context , obj , array [ mid ] ) > 0 ? low = mid + 1 : high = mid ;
208
- }
209
- return low ;
191
+ **/
192
+ function sortedIndexTwo ( array , obj , iterator , context ) {
193
+ var low = 0 , high = array . length ;
194
+ while ( low < high ) {
195
+ var mid = ( low + high ) >>> 1 ;
196
+ iterator . call ( context , obj , array [ mid ] ) > 0 ? low = mid + 1 : high = mid ;
210
197
}
198
+ return low ;
199
+ }
211
200
212
- _ . extend ( VirtualCollection . prototype , Backbone . Events ) ;
201
+ _ . extend ( VirtualCollection . prototype , Backbone . Events ) ;
213
202
214
- return VirtualCollection ;
215
- } ) ) ;
203
+ module . exports = VirtualCollection ;
0 commit comments