Permalink
Browse files

Init and next_page for URL data

  • Loading branch information...
imakewebthings committed Feb 19, 2012
1 parent 3cf2019 commit 07a55df351a2d738761003553491a2271b2cc9c0
Showing with 189 additions and 17 deletions.
  1. +2 −1 .gitignore
  2. +71 −8 src/js/jquery.stackview.base.js
  3. +3 −1 src/js/jquery.stackview.templates.js
  4. +13 −0 test/mocks/json.php
  5. +100 −7 test/spec/stackview.base.spec.js
View
@@ -1,4 +1,5 @@
# Ignore file containing API keys
keys.php
.DS_Store
-.sass-cache/
+.sass-cache/
+.jshintrc
@@ -93,12 +93,19 @@
};
/*
- Takes a StackView instance and array of result items. Renders a
- DOM element for each of the items and appends it to the stack's
- item list.
+ #render_items(StackView, array [, jQuery])
+
+ Takes a StackView instance, an array of result items, and an optional
+ jQuery object. Renders a DOM element for each of the items and
+ appends it to the stack's item list. If [placeholder] is passed in the
+ items take the its spot in the DOM.
*/
- utils.render_items = function(stack, docs) {
- var $list = stack.$element.find(stack.options.selectors.item_list);
+ utils.render_items = function(stack, docs, $placeholder) {
+ var action = $placeholder ? 'after' : 'append',
+ $pivot = $placeholder ?
+ $placeholder :
+ stack.$element.find(stack.options.selectors.item_list);
+
$.each(docs, function(i, item) {
var $item = $(tmpl(StackView.templates.book, {
@@ -112,8 +119,47 @@
}));
$item.data('stackviewItem', item);
- $list.append($item);
+ $pivot[action]($item);
});
+
+ if ($placeholder) {
+ $placeholder.remove();
+ }
+ };
+
+ /*
+ #fetch_page(StackView, function)
+
+ Takes a StackView instance and a callback function. Retrieves the
+ next page according to the URL and other options of the StackView
+ instance. When the page is finished fetching, the callback is
+ invoked, passing in the array of items.
+ */
+ utils.fetch_page = function(stack, callback) {
+ var params,
+ cachedResult,
+ querystring;
+
+ params = {
+ start: stack.page * stack.options.items_per_page,
+ limit: stack.options.items_per_page,
+ search_type: stack.options.search_type,
+ query: stack.options.query
+ };
+ if (stack.options.jsonp) {
+ params.callback = '?';
+ }
+ querystring = $.param(params);
+
+ stack.page++;
+ cachedResult = window.stackCache.get(stack.options.url + params);
+
+ if (cachedResult) {
+ callback(cachedResult);
+ }
+ else {
+ $.getJSON(stack.options.url, querystring, callback);
+ }
};
@@ -188,14 +234,31 @@
Loads the next page of stack items. If we've already hit the
last page, this function does nothing.
*/
- next_page: function(arg) {
- if (this.finished) return;
+ next_page: function() {
+ var $placeholder = $(tmpl(StackView.templates.placeholder, {})),
+ that = this;
+
+ if (this.finished) {
+ return;
+ }
if (this.options.data) {
utils.render_items(this, this.options.data.docs);
this.finished = true;
this.$element.trigger(events.page_load);
}
+ else if (this.options.url) {
+ this.$element
+ .find(this.options.selectors.item_list)
+ .append($placeholder);
+ utils.fetch_page(this, function(data) {
+ utils.render_items(that, data.docs, $placeholder);
+ if (parseInt(data.start, 10) === -1) {
+ that.finished = true;
+ }
+ that.$element.trigger(events.page_load);
+ });
+ }
}
});
@@ -23,6 +23,8 @@
<span class="spine-author"><%= author %></span>\
<span class="spine-year"><%= year %></span>\
</a>\
- </li>'
+ </li>',
+
+ placeholder: '<li class="stackview-placeholder"></li>'
}
})();
View
@@ -1,8 +1,21 @@
<?php
+$offset = $_GET['start'];
+$limit = $_GET['limit'];
// Simulate wait, load and return JSON or JSONP accordingly.
sleep(1);
+
$results = file_get_contents('static.json');
+$json = json_decode($results, true);
+$slice = $offset == -1 ? $json['docs'] : array_slice($json['docs'], $offset, $limit);
+$numfound = count($slice);
+
+$json['start'] = $numfound < $limit ? -1 : $offset;
+$json['limit'] = $limit;
+$json['num_found'] = $numfound;
+$json['docs'] = $slice;
+$results = json_encode($json);
+
echo isset($_GET['callback']) ? "{$_GET['callback']}($results)" : $results;
?>
@@ -43,7 +43,7 @@ describe('StackView Base', function() {
it('should fire a pageload event (async)', function() {
waitsFor(function() {
return pageload_fired;
- }, 'pageload event not firing', 5000);
+ }, 'pageload event to fire', 5000);
});
it('should return the jQuery object for chaining', function() {
@@ -64,18 +64,28 @@ describe('StackView Base', function() {
});
});
- describe('with AJAX loaded data', function() {
- it('needs specs', function() {
- expect('implemented').toBeFalsy();
+ describe('with AJAX/PHP loaded data', function() {
+ beforeEach(function() {
+ $stack.stackview({
+ url: 'mocks/json.php'
+ });
+ });
+
+ it('should load the first page', function() {
+ waitsFor(function() {
+ return $stack.find(opts.selectors.item).length;
+ }, 'items to render', 5000);
+
+ runs(function() {
+ expect($stack.find(opts.selectors.item).length).toEqual(opts.items_per_page);
+ });
});
});
});
describe('#next_page()', function() {
describe('data source independent behavior', function() {
- it('needs specs', function() {
- expect('implemented').toBeFalsy();
- });
+ // NONE, YET
});
describe('with static inline data', function() {
@@ -87,9 +97,92 @@ describe('StackView Base', function() {
});
it('should do nothing', function() {
+ var oldLength = $stack.find(opts.selectors.item);
+
$stack.stackview('next_page');
+ expect($stack.find(opts.selectors.item)).toEqual(oldLength);
expect('stackview.pageload').not.toHaveBeenTriggeredOn($stack);
});
});
+
+ describe('with AJAX/PHP loaded data', function() {
+ var ipp = 13,
+ loadCount;
+
+ beforeEach(function() {
+ loadCount = 0;
+ $stack.stackview({
+ url: 'mocks/json.php',
+ items_per_page: ipp
+ });
+ $stack.bind('stackview.pageload', function() {
+ loadCount++;
+ });
+ });
+
+ it('should fire the pageload event', function() {
+ $stack.stackview('next_page');
+ waitsFor(function() {
+ return loadCount === 2;
+ }, 'pageload event to fire', 5000);
+ });
+
+ it('should load the next page of items', function() {
+ runs(function() {
+ $stack.stackview('next_page');
+ });
+
+ waitsFor(function() {
+ return loadCount == 2;
+ }, 'the next page to load', 5000);
+
+ runs(function() {
+ expect($stack.find(opts.selectors.item).length).toEqual(ipp * 2);
+ });
+ });
+
+ it('should stop at the end', function() {
+ runs(function() {
+ $stack.data('stackviewObject').options.beacon = true;
+ $stack.stackview('next_page'); // 26
+ $stack.stackview('next_page'); // 39
+ $stack.stackview('next_page'); // end (50)
+ });
+
+ waitsFor(function() {
+ return loadCount === 4;
+ }, 'all pages to load', 5000);
+
+ runs(function() {
+ expect($stack.find(opts.selectors.item).length).toEqual(50);
+ $stack.stackview('next_page'); // do nothing!
+ });
+
+ waits(1500);
+
+ runs(function() {
+ expect(loadCount).toEqual(4);
+ });
+ });
+
+ it('should insert placeholder element, remove on load', function() {
+ waitsFor(function() {
+ return loadCount === 1;
+ }, 'init load to finish');
+
+ runs(function() {
+ $stack.stackview('next_page');
+ expect($('.stackview-placeholder')).toExist();
+ });
+
+ waitsFor(function() {
+ return loadCount === 2;
+ }, 'second page to finish loading', 5000);
+
+ runs(function() {
+ expect($('.stackview-placeholder')).not.toExist();
+ });
+ });
+ });
});
});

0 comments on commit 07a55df

Please sign in to comment.