forked from instructure/canvas-lms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPaginatedCollection.coffee
More file actions
89 lines (74 loc) · 2.98 KB
/
Copy pathPaginatedCollection.coffee
File metadata and controls
89 lines (74 loc) · 2.98 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
define [
'Backbone'
'underscore'
], (Backbone, _) ->
capitalize = (string = '') ->
string.charAt(0).toUpperCase() + string.substring(1).toLowerCase()
class @PaginatedCollection extends Backbone.Collection
# Matches the name of each link: "next," "prev," "first," or "last."
nameRegex: /rel="([a-z]+)/
# Matches the full link, e.g. "/api/v1/accounts/1/users?page=1&per_page=15"
linkRegex: /^<([^>]+)/
pageRegex: /\Wpage=(\d+)/
perPageRegex: /\per_page=(\d+)/
##
# have to do this stuff here or else 'reset' and other events are fired
# before _setStateAfterFetch has happened, so the state is just barely off
parse: (response, xhr) ->
@_urlCache ?= []
@_lastFetchOptions ?= {}
@_setStateAfterFetch xhr, @_lastFetchOptions
@_urlCache.push @_lastFetchOptions.url unless @_lastFetchOptions.url in @_urlCache
delete @_lastFetchOptions
super
##
# options.page: 'next', 'prev', 'first', 'last', 'top', 'bottom'
fetch: (options = {}) ->
@["fetching#{capitalize options.page}Page"] = true
if options.page?
options.url = @urls[options.page] if @urls?
options.add = true unless options.add?
# API keeps params intact, kill data here to avoid appending in super
options.data = ''
@_lastFetchOptions = options
@trigger 'beforeFetch', this, options
@trigger "beforeFetch:#{options.page}", this, options if options.page?
super(options).done (response, text, xhr) =>
@["fetching#{capitalize options.page}Page"] = false
@fetchingNextPage = false
@trigger 'fetch', this, response, options
@trigger "fetch:#{options.page}", this, response, options if options.page?
@trigger 'fetched:last', arguments... unless @urls.next
canFetch: (page) ->
@urls? and @urls[page]?
_setStateAfterFetch: (xhr, options={}) =>
urlIsNotCached = options.url not in @_urlCache
firstRequest = !@urls?
setBottom = firstRequest or (options.page in ['next', 'bottom'] and urlIsNotCached)
setTop = firstRequest or (options.page in ['prev', 'top'] and urlIsNotCached)
oldUrls = @urls
@urls = @_parsePageLinks xhr
if setBottom and @urls.next?
@urls.bottom = @urls.next
else if !@urls.next
delete @urls.bottom
else
@urls.bottom = oldUrls.bottom
if setTop and @urls.prev?
@urls.top = @urls.prev
else if !@urls.prev
delete @urls.top
else
@urls.top = oldUrls.top
perPage = parseInt(@urls.first.match(@perPageRegex)[1], 10)
(@options.params ?= {}).per_page = perPage
@totalPages = parseInt(@urls.last?.match(@pageRegex)[1], 10)
@atLeastOnePageFetched = true
_parsePageLinks: (xhr) ->
linkHeader = xhr.getResponseHeader('link').split(',')
_.reduce linkHeader, (links, link) =>
key = link.match(@nameRegex)[1]
val = link.match(@linkRegex)[1]
links[key] = val
links
, {}