@@ -125,43 +125,46 @@ angular.module('ui.scroll', [])
125
125
div = table .find (' div' )
126
126
result = table .find (' tr' )
127
127
else
128
- result = angular .element (' <' + repeaterType + ' ></' + repeaterType + ' >' )
128
+ result = angular .element (' <' + tagName + ' ></' + tagName + ' >' )
129
129
result
130
130
131
131
132
132
133
133
Viewport = (element , controllers ) ->
134
134
135
- self = this
136
-
137
135
viewport = if controllers[0 ] and controllers[0 ].viewport then controllers[0 ].viewport else angular .element (window )
138
136
viewport .css ({' overflow-y' : ' auto' , ' display' : ' block' })
139
137
140
138
topPadding = null
141
139
142
140
bottomPadding = null
143
141
144
- self .createPaddingElements = (template ) ->
142
+ viewport .createPaddingElements = (template ) ->
145
143
146
144
topPadding = new Padding template .localName
147
145
element .before topPadding
148
- self .topPadding = topPadding .height
146
+ viewport .topPadding = -> topPadding .height arguments
149
147
150
148
bottomPadding = new Padding template .localName
151
149
element .after bottomPadding
152
- self .bottomPadding = bottomPadding .height
150
+ viewport .bottomPadding = -> bottomPadding .height arguments
151
+
152
+ viewport .bottomDataPos = ->
153
+ (viewport[0 ].scrollHeight ? viewport[0 ].document .documentElement .scrollHeight ) - bottomPadding .height ()
153
154
154
- self .bottomDataPos = ->
155
- (viewport .scrollHeight ? viewport .document .documentElement .scrollHeight ) - bottomPadding .height ()
155
+ viewport .topDataPos = -> topPadding .height ()
156
156
157
- self .topDataPos = -> topPadding .height ()
157
+ viewport .bottomVisiblePos = ->
158
+ viewport .scrollTop () + viewport .outerHeight ()
158
159
159
- self .insertElement = (e , sibling ) -> insertElement (e, sibling || topPadding)
160
+ viewport .topVisiblePos = ->
161
+ viewport .scrollTop ()
160
162
161
- self . insertElementAnimated = (e , sibling ) -> insertElementAnimated (e, sibling || topPadding)
163
+ viewport . insertElement = (e , sibling ) -> insertElement (e, sibling || topPadding)
162
164
163
- return
165
+ viewport . insertElementAnimated = ( e , sibling ) -> insertElementAnimated (e, sibling || topPadding)
164
166
167
+ viewport
165
168
166
169
167
170
require : [' ?^uiScrollViewport' ]
@@ -192,8 +195,6 @@ angular.module('ui.scroll', [])
192
195
193
196
bufferSize = Math .max (3 , + $attr .bufferSize || 10 )
194
197
bufferPadding = -> viewport .outerHeight () * Math .max (0.1 , + $attr .padding || 0.1 ) # some extra space to initiate preload
195
- scrollHeight = (elem ) -> elem[0 ].scrollHeight ? elem[0 ].document .documentElement .scrollHeight
196
-
197
198
198
199
# initial settings
199
200
@@ -206,53 +207,22 @@ angular.module('ui.scroll', [])
206
207
eof = false
207
208
bof = false
208
209
210
+ viewport = new Viewport element, controllers
211
+
209
212
# Padding element builder
210
213
#
211
214
# Calling linker is the only way I found to get access to the tag name of the template
212
215
# to prevent the directive scope from pollution a new scope is created and destroyed
213
216
# right after the builder creation is completed
214
217
linker $scope .$new (), (template , scope ) ->
215
- # Destroy template's scope to remove any watchers on it.
216
- scope .$destroy ()
217
-
218
- repeaterType = template[0 ].localName
219
- if repeaterType in [' dl' ]
220
- throw new Error ' ui-scroll directive does not support <' + template[0 ].localName + ' > as a repeating tag: ' + template[0 ].outerHTML
221
- repeaterType = ' div' if repeaterType not in [' li' , ' tr' ]
222
-
223
- viewport = if controllers[0 ] and controllers[0 ].viewport then controllers[0 ].viewport else angular .element (window )
224
- viewport .css ({' overflow-y' : ' auto' , ' display' : ' block' })
225
-
226
- padding = (repeaterType )->
227
- switch repeaterType
228
- when ' tr'
229
- table = angular .element (' <table><tr><td><div></div></td></tr></table>' )
230
- div = table .find (' div' )
231
- result = table .find (' tr' )
232
- result .paddingHeight = -> div .height .apply (div, arguments )
233
- else
234
- result = angular .element (' <' + repeaterType + ' ></' + repeaterType + ' >' )
235
- result .paddingHeight = result .height
236
- result
237
-
238
- topPadding = padding (repeaterType)
239
- element .before topPadding
240
218
241
- bottomPadding = padding (repeaterType)
242
- element .after bottomPadding
219
+ viewport .createPaddingElements (template[0 ])
243
220
221
+ # Destroy template's scope to remove any watchers on it.
222
+ scope .$destroy ()
223
+ # also remove the template when the directive scope is destroyed
244
224
$scope .$on ' $destroy' , -> template .remove ()
245
225
246
- builder =
247
- viewport : viewport
248
- topPadding : -> topPadding .paddingHeight .apply (topPadding, arguments )
249
- bottomPadding : -> bottomPadding .paddingHeight .apply (bottomPadding, arguments )
250
- bottomDataPos : -> scrollHeight (viewport) - bottomPadding .paddingHeight ()
251
- topDataPos : -> topPadding .paddingHeight ()
252
- insertElement : (e , sibling ) -> insertElement (e, sibling || topPadding)
253
- insertElementAnimated : (e , sibling ) -> insertElementAnimated (e, sibling || topPadding)
254
-
255
- viewport = builder .viewport
256
226
viewportScope = viewport .scope () || $rootScope
257
227
258
228
# v = new Viewport element, controllers
@@ -280,25 +250,19 @@ angular.module('ui.scroll', [])
280
250
first = 1
281
251
next = 1
282
252
buffer .clear ()
283
- builder .topPadding (0 )
284
- builder .bottomPadding (0 )
253
+ viewport .topPadding (0 )
254
+ viewport .bottomPadding (0 )
285
255
eof = false
286
256
bof = false
287
257
adjustBuffer ridActual
288
258
289
- bottomVisiblePos = ->
290
- viewport .scrollTop () + viewport .outerHeight ()
291
-
292
- topVisiblePos = ->
293
- viewport .scrollTop ()
294
-
295
259
shouldLoadBottom = ->
296
- # log "bottom pos #{builder .bottomDataPos()} < bottom visible #{bottomVisiblePos()} + padding #{bufferPadding()} "
297
- ! eof && builder .bottomDataPos () < bottomVisiblePos () + bufferPadding ()
260
+ # log "bottom pos #{viewport .bottomDataPos()} < bottom visible #{bottomVisiblePos()} + padding #{bufferPadding()} "
261
+ ! eof && viewport .bottomDataPos () < viewport . bottomVisiblePos () + bufferPadding ()
298
262
299
263
clipBottom = ->
300
264
# clip the invisible items off the bottom
301
- bottomHeight = 0 # builder.bottomPadding()
265
+ bottomHeight = 0
302
266
overage = 0
303
267
304
268
for i in [buffer .length - 1 .. 0 ]
@@ -307,7 +271,7 @@ angular.module('ui.scroll', [])
307
271
newRow = rowTop isnt itemTop
308
272
rowTop = itemTop
309
273
itemHeight = item .element .outerHeight (true ) if newRow
310
- if (builder .bottomDataPos () - bottomHeight - itemHeight > bottomVisiblePos () + bufferPadding ())
274
+ if (viewport .bottomDataPos () - bottomHeight - itemHeight > viewport . bottomVisiblePos () + bufferPadding ())
311
275
bottomHeight += itemHeight if newRow
312
276
overage++
313
277
eof = false
@@ -316,14 +280,14 @@ angular.module('ui.scroll', [])
316
280
overage++
317
281
318
282
if overage > 0
319
- builder .bottomPadding (builder .bottomPadding () + bottomHeight)
283
+ viewport .bottomPadding (viewport .bottomPadding () + bottomHeight)
320
284
buffer .remove (buffer .length - overage, buffer .length )
321
285
next -= overage
322
- # log 'clipped off bottom ' + overage + ' bottom padding ' + builder .bottomPadding()
286
+ # log 'clipped off bottom ' + overage + ' bottom padding ' + viewport .bottomPadding()
323
287
324
288
shouldLoadTop = ->
325
- # log "top pos #{builder .topDataPos()} > top visible #{topVisiblePos()} - padding #{bufferPadding()}"
326
- ! bof && (builder .topDataPos () > topVisiblePos () - bufferPadding ())
289
+ # log "top pos #{viewport .topDataPos()} > top visible #{topVisiblePos()} - padding #{bufferPadding()}"
290
+ ! bof && (viewport .topDataPos () > viewport . topVisiblePos () - bufferPadding ())
327
291
328
292
clipTop = ->
329
293
# clip the invisible items off the top
@@ -334,15 +298,15 @@ angular.module('ui.scroll', [])
334
298
newRow = rowTop isnt itemTop
335
299
rowTop = itemTop
336
300
itemHeight = item .element .outerHeight (true ) if newRow
337
- if (builder .topDataPos () + topHeight + itemHeight < topVisiblePos () - bufferPadding ())
301
+ if (viewport .topDataPos () + topHeight + itemHeight < viewport . topVisiblePos () - bufferPadding ())
338
302
topHeight += itemHeight if newRow
339
303
overage++
340
304
bof = false
341
305
else
342
306
break if newRow
343
307
overage++
344
308
if overage > 0
345
- builder .topPadding (builder .topPadding () + topHeight)
309
+ viewport .topPadding (viewport .topPadding () + topHeight)
346
310
buffer .remove (0 , overage)
347
311
first += overage
348
312
# log 'clipped off top ' + overage + ' top padding ' + builder.topPadding()
@@ -364,7 +328,7 @@ angular.module('ui.scroll', [])
364
328
adjustBuffer ()
365
329
366
330
insertWrapperContent = (wrapper , sibling ) ->
367
- builder .insertElement wrapper .element , sibling
331
+ viewport .insertElement wrapper .element , sibling
368
332
return true if isElementVisible (wrapper)
369
333
wrapper .unregisterVisibilityWatcher = wrapper .scope .$watch () -> visibilityWatcher (wrapper)
370
334
false
@@ -374,7 +338,7 @@ angular.module('ui.scroll', [])
374
338
toBePrepended = []
375
339
toBeRemoved = []
376
340
377
- bottomPos = builder .bottomDataPos ()
341
+ bottomPos = viewport .bottomDataPos ()
378
342
for wrapper, i in buffer
379
343
switch wrapper .op
380
344
when ' prepend' then toBePrepended .unshift wrapper
@@ -386,30 +350,30 @@ angular.module('ui.scroll', [])
386
350
wrapper .op = ' none'
387
351
when ' insert'
388
352
if (i == 0 )
389
- promises = promises .concat (builder .insertElementAnimated wrapper .element )
353
+ promises = promises .concat (viewport .insertElementAnimated wrapper .element )
390
354
else
391
- promises = promises .concat (builder .insertElementAnimated wrapper .element , buffer[i- 1 ].element )
355
+ promises = promises .concat (viewport .insertElementAnimated wrapper .element , buffer[i- 1 ].element )
392
356
wrapper .op = ' none'
393
357
when ' remove' then toBeRemoved .push wrapper
394
358
395
359
for wrapper in toBeRemoved
396
360
promises = promises .concat (buffer .remove wrapper)
397
361
398
362
# for anything other than prepend adjust the bottomPadding height
399
- builder .bottomPadding (Math .max (0 ,builder .bottomPadding () - (builder .bottomDataPos () - bottomPos)))
363
+ viewport .bottomPadding (Math .max (0 ,viewport .bottomPadding () - (viewport .bottomDataPos () - bottomPos)))
400
364
401
365
if toBePrepended .length
402
- bottomPos = builder .bottomDataPos ()
366
+ bottomPos = viewport .bottomDataPos ()
403
367
for wrapper in toBePrepended
404
368
keepFetching = insertWrapperContent (wrapper) || keepFetching
405
369
wrapper .op = ' none'
406
370
407
- heightIncrement = builder .bottomDataPos () - bottomPos
371
+ heightIncrement = viewport .bottomDataPos () - bottomPos
408
372
409
373
# adjust padding to prevent it from visually pushing everything down
410
- if builder .topPadding () >= heightIncrement
374
+ if viewport .topPadding () >= heightIncrement
411
375
# if possible, reduce topPadding
412
- builder .topPadding (builder .topPadding () - heightIncrement)
376
+ viewport .topPadding (viewport .topPadding () - heightIncrement)
413
377
else
414
378
# if not, increment scrollTop
415
379
viewport .scrollTop (viewport .scrollTop () + heightIncrement)
@@ -432,7 +396,7 @@ angular.module('ui.scroll', [])
432
396
newRow = rowTop isnt itemTop
433
397
rowTop = itemTop
434
398
itemHeight = item .element .outerHeight (true ) if newRow
435
- if newRow and (builder .topDataPos () + topHeight + itemHeight < topVisiblePos ())
399
+ if newRow and (viewport .topDataPos () + topHeight + itemHeight < viewport . topVisiblePos ())
436
400
topHeight += itemHeight
437
401
else
438
402
topVisible (item) if newRow
@@ -489,7 +453,7 @@ angular.module('ui.scroll', [])
489
453
return if (rid and rid isnt ridActual) or $scope .$$destroyed
490
454
if result .length < bufferSize
491
455
eof = true
492
- builder .bottomPadding (0 )
456
+ viewport .bottomPadding (0 )
493
457
# log 'eof is reached'
494
458
if result .length > 0
495
459
clipTop ()
@@ -508,7 +472,7 @@ angular.module('ui.scroll', [])
508
472
return if (rid and rid isnt ridActual) or $scope .$$destroyed
509
473
if result .length < bufferSize
510
474
bof = true
511
- builder .topPadding (0 )
475
+ viewport .topPadding (0 )
512
476
# log 'bof is reached'
513
477
if result .length > 0
514
478
clipBottom () if buffer .length
0 commit comments