├── README.md
├── demo
└── index.html
└── loadmore.js
/README.md:
--------------------------------------------------------------------------------
1 | loadMore.js
2 | =======
3 |
4 | loadMore.js is a jQuery plugin for easily adding an AJAX-based "more"-link pagination to an element on ones site.
5 |
6 | ## Usage
7 |
8 | Simple:
9 |
10 | $('.list').loadmore('/path/to/more/html');
11 |
12 | Advanced:
13 |
14 | $('.list').loadmore('/path/to/more/html', {
15 | 'className' : '',
16 | text : 'More',
17 | loadingText : 'Loading',
18 | page : 0,
19 | pageSize : false,
20 | 'pageParam' : 'page'
21 | });
22 |
23 | ## Advanced options
24 |
25 | * **id** - a string identifier for this particular pager to make it easier for the History API integration to restore the correct pager.
26 | * **className** - extra classes to add to the more-link container
27 | * **text** - text to use in the more-link - should be either a string or a function
28 | * **loadingText** - text to use in the more-link when it is loading - should be either a string or a function
29 | * **page** - the current page in the list
30 | * **rowsPerPage** - how many elements should be expected on a new page? If less than this amount is received we've reached the end and will remove the pager
31 | * **maxPageCount** - the maximum numbers of pages to fetch at once - used by the History API integration
32 | * **pageParam** - the query parameter used to specify which page to fetch. If set to `false` no param will be specified.
33 | * **pageStartParam** - when more than one page is fetched at once this is the query parameter used to specify the page to start from. If set to `false` no param will be specified.
34 | * **complete** - a function to execute once a new page has been loaded, return false if the pager should be removed
35 | * **useHistoryAPI** - whether to use the History API in supported browsers or not
36 | * **useOffset** – whether to use offsets rather than page numbers
37 | * **useExistingButton** – rather than creating a new button, use an existing one matching this selector / element
38 | * **filterResult** – filter the received result by these selectors
39 | * **itemSelector** – the selector used to count items
40 | * **baseOffset** – an offset to add to all offsets. Will be parsed from any `pageParam` or `pageStartParam` query params on an existing button.
41 | * **processUrl** – for complex URL cases, define a method that will be sent `url` and `params` and returns either an object with a `url` and `params` key or a `url` string if no params should be used anymore.
42 | * **interpretUrl** – if one uses both `processUrl` and `useExistingButton` then one will likely have to have a custom method to extract the modfied `baseOffset` from the existing button. Receives `Location` object, `itemCount` and `options`.
43 |
44 | ### Events
45 |
46 | * **loadmore:last** - triggered on the pager when the last page has been fetched
47 |
48 | ## In action on
49 |
50 | * **Flattr.com**, eg. https://flattr.com/profile/voxpelli
51 |
52 | ## Support
53 |
54 | [](https://flattr.com/submit/auto?user_id=voxpelli&url=https://github.com/voxpelli/jquery-loadmore&title=loadmore.js&language=en_GB&tags=github&category=software)
55 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ').append($newData);
72 |
73 | itemCount = (options.itemSelector ? $(options.itemSelector, $newData) : $newData).length;
74 |
75 | if (options.useExistingButton) {
76 | $newData.children().appendTo($this.data('loadmore-container'));
77 | } else {
78 | $newData.children().insertBefore($this);
79 | }
80 |
81 | if (options.rowsPerPage !== false && itemCount < (options.useOffset ? 1 : options.rowsPerPage) * (pageTarget - currentPage)) {
82 | $this.trigger('loadmore:last').remove();
83 | }
84 |
85 | if (options.complete && options.complete.call($newData) === false && $this.parent().length) {
86 | $this.trigger('loadmore:last').remove();
87 | }
88 | });
89 | return false;
90 | };
91 |
92 | getItemCount = function ($this, options) {
93 | return (options.itemSelector ? $(options.itemSelector, $this.data('loadmore-container')) : $this.siblings()).length;
94 | };
95 |
96 | moreClick = function (e) {
97 | var page, $this = $(this), options = $this.data('loadmore-options');
98 | if (options.useOffset) {
99 | page = getItemCount($this, options) + options.rowsPerPage;
100 | }
101 | else
102 | {
103 | page = $this.data('loadmore-page') + 1;
104 | }
105 | return update.call(this, page);
106 | };
107 |
108 | $.fn.loadmore = function (url, options) {
109 | if (typeof url === 'object') {
110 | options = $.extend({}, $.fn.loadmore.defaults, url);
111 | } else {
112 | options = $.extend({}, $.fn.loadmore.defaults, options);
113 | options.url = url;
114 | }
115 |
116 | this.each(function () {
117 | var $more, $text, id, itemCount, moreBaseOffset, idDuplicates = 0;
118 |
119 | itemCount = (options.itemSelector ? $(options.itemSelector, this) : $(this).children()).length;
120 |
121 | if (options.id) {
122 | id = options.id;
123 | while ($('#' + id).length) {
124 | idDuplicates += 1;
125 | id = options.id + '-' + idDuplicates;
126 | }
127 | } else {
128 | idCount += 1;
129 | id = 'loadmore-' + idCount;
130 | }
131 |
132 | if (options.useExistingButton) {
133 | $more = $(options.useExistingButton);
134 |
135 | options.text = $more.text();
136 |
137 | moreBaseOffset = options.interpretUrl ? options.interpretUrl($more.get(0), itemCount, options): undefined;
138 |
139 | if (moreBaseOffset) {
140 | options.baseOffset = moreBaseOffset;
141 | }
142 | } else {
143 | $more = $('
', {
144 | 'id' : id,
145 | 'class' : options.className,
146 | 'href' : '#'
147 | });
148 |
149 | $text = $('
', {'class' : 'text'});
150 | $text.appendTo($more)
151 | .text(maybeCall(options.text, $text[0]));
152 | }
153 |
154 | $more.data('loadmore-options', options);
155 | $more.data('loadmore-container', this);
156 |
157 | if (!options.useOffset) {
158 | $more.data('loadmore-page', options.page);
159 | }
160 |
161 | if (!options.useExistingButton) {
162 | if (options.rowsPerPage !== false && itemCount < options.rowsPerPage) {
163 | return;
164 | }
165 |
166 | $more.appendTo(this);
167 | }
168 |
169 | $more.click(moreClick);
170 |
171 | if (supportsHistory && options.useHistoryAPI && window.history.state && window.history.state.loadmore && window.history.state.loadmore[id]) {
172 | update.call($more[0], window.history.state.loadmore[id]);
173 | }
174 | });
175 |
176 | return this;
177 | };
178 |
179 | $.fn.loadmore.defaults = {
180 | id : null,
181 | className : 'more',
182 | useExistingButton: false,
183 | text : 'More',
184 | loadingText : 'Loading',
185 | page : 0,
186 | rowsPerPage : false,
187 | maxPageCount : false,
188 | pageParam : 'page',
189 | pageStartParam : 'start',
190 | filterResult: '*',
191 | complete : false,
192 | useHistoryAPI : true,
193 | useOffset : false,
194 | baseOffset: 0,
195 | processUrl: false,
196 | interpretUrl: function (loc, itemCount, options) {
197 | var result;
198 |
199 | loc.search.substr(1).split('&').some(function (pair) {
200 | pair = pair.split('=');
201 | if (pair[0] === options.pageParam) {
202 | result = parseInt(pair[1]) + options.baseOffset;
203 | return true;
204 | } else if (pair[0] === options.pageStartParam) {
205 | result = parseInt(pair[1]) + options.baseOffset - itemCount;
206 | return true;
207 | }
208 | });
209 |
210 | return result;
211 | }
212 | };
213 |
214 | // Below partly taken from jquery.pjax.js
215 | supportsHistory =
216 | window.history && window.history.pushState && window.history.replaceState
217 | // History API isn't reliable on iOS yet and Safari and Chrome doesn't implement history.state
218 | && !navigator.userAgent.match(/(iPod|iPhone|iPad|Safari\/|Chrome\/|WebApps\/.+CFNetwork)/);
219 |
220 | if (supportsHistory) {
221 | // Below taken from jquery.pjax.js
222 | // Add the state property to jQuery's event object so we can use it in
223 | // $(window).bind('popstate')
224 | if ($.inArray('state', $.event.props) < 0) {
225 | $.event.props.push('state');
226 | }
227 |
228 | $(window).on('popstate', function (event) {
229 | var id, $elem, state = (event.state || {}).loadmore || {};
230 | for (id in state) {
231 | if (state.hasOwnProperty(id)) {
232 | $elem = $('#' + id);
233 | if ($elem.length) {
234 | update.call($elem[0], state[id]);
235 | }
236 | }
237 | }
238 | });
239 | }
240 |
241 | $.loadmore = {
242 | supportsHistory : supportsHistory,
243 | removeHistoryState : function (id) {
244 | if (supportsHistory && window.history.state && window.history.state.loadmore && window.history.state.loadmore[id]) {
245 | var state = window.history.state;
246 | delete state.loadmore[id];
247 | window.history.replaceState(state, document.title);
248 | }
249 | }
250 | };
251 | }(jQuery));
252 |
--------------------------------------------------------------------------------