rails_stackview 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -4
  3. data/lib/rails_stackview/version.rb +1 -1
  4. data/vendor/assets/README.md +16 -0
  5. data/vendor/assets/images/stackview/bookEnd-next.png +0 -0
  6. data/vendor/assets/images/stackview/bookEnd-prev.png +0 -0
  7. data/vendor/assets/images/stackview/gloss.png +0 -0
  8. data/vendor/assets/images/stackview/highGloss.png +0 -0
  9. data/vendor/assets/images/stackview/icon-globe.png +0 -0
  10. data/vendor/assets/images/stackview/icon-note.png +0 -0
  11. data/vendor/assets/images/stackview/nav.png +0 -0
  12. data/vendor/assets/images/stackview/placeholder.gif +0 -0
  13. data/vendor/assets/images/stackview/ribbonTab.png +0 -0
  14. data/vendor/assets/images/stackview/serials-edge.png +0 -0
  15. data/vendor/assets/images/stackview/serials.png +0 -0
  16. data/vendor/assets/images/stackview/superGloss.png +0 -0
  17. data/vendor/assets/javascripts/jquery.stackview.js +21 -0
  18. data/vendor/assets/javascripts/stackview/jquery.easing.1.3.js +205 -0
  19. data/vendor/assets/javascripts/stackview/jquery.stackview.base.js +561 -0
  20. data/vendor/assets/javascripts/stackview/jquery.stackview.infinite.js +46 -0
  21. data/vendor/assets/javascripts/stackview/jquery.stackview.ministack.js +33 -0
  22. data/vendor/assets/javascripts/stackview/jquery.stackview.navigation.js +71 -0
  23. data/vendor/assets/javascripts/stackview/jquery.stackview.stackcache.js +74 -0
  24. data/vendor/assets/javascripts/stackview/jquery.stackview.templates.js +31 -0
  25. data/vendor/assets/javascripts/stackview/microtemplating.js +40 -0
  26. data/vendor/assets/javascripts/stackview/types/book.js +184 -0
  27. data/vendor/assets/javascripts/stackview/types/my_plain.js +183 -0
  28. data/vendor/assets/javascripts/stackview/types/serial.js +40 -0
  29. data/vendor/assets/javascripts/stackview/types/soundrecording.js +42 -0
  30. data/vendor/assets/javascripts/stackview/types/videofilm.js +56 -0
  31. data/vendor/assets/javascripts/stackview/types/webpage.js +42 -0
  32. data/vendor/assets/stackview.sha +1 -0
  33. data/vendor/assets/stylesheets/stackview/_book.scss +66 -0
  34. data/vendor/assets/stylesheets/stackview/_heatmap.scss +154 -0
  35. data/vendor/assets/stylesheets/stackview/_ministack.scss +43 -0
  36. data/vendor/assets/stylesheets/stackview/_mixins.scss +100 -0
  37. data/vendor/assets/stylesheets/stackview/_navigation.scss +52 -0
  38. data/vendor/assets/stylesheets/stackview/_plain.scss +71 -0
  39. data/vendor/assets/stylesheets/stackview/_serial.scss +50 -0
  40. data/vendor/assets/stylesheets/stackview/_soundrecording.scss +83 -0
  41. data/vendor/assets/stylesheets/stackview/_videofilm.scss +74 -0
  42. data/vendor/assets/stylesheets/stackview/_webpage.scss +82 -0
  43. data/vendor/assets/stylesheets/stackview/jquery.stackview.scss +171 -0
  44. metadata +41 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1dcc75e8d87f6311a1b7c4bdca4f7b0705ed41db
4
- data.tar.gz: fda9b0a44729a94c66949106518e2b9bd7b77f48
3
+ metadata.gz: f90b15df352fff73c0c6ec5db8241438fcdca875
4
+ data.tar.gz: 4d8e7e3d5e59c6d9b9230a25974948a6802df5d0
5
5
  SHA512:
6
- metadata.gz: 2d7c495b8684b66d9e544643c1ae9ee8d1d855e951c77e135e1d44a55baa4341303894944249556195a4b6b964f58b89441eeaba4b22331d0106c0afb504e31b
7
- data.tar.gz: 920ce32703b2f2a27cb79b3385b8bd4a3f25d7944707236737014858c877dd3cbc6e8ad6f0e02c78b6e4b654acd9ae2d3fc8079d0432af3f955c3352a8ba57f6
6
+ metadata.gz: e9f76890644194095bb344aa0bc6fdb6c94df10f3e31d375d39191a090d40eb30a98e56da750768bb93db88147962df151ed85f55c13b062871661d9f4758cd5
7
+ data.tar.gz: 00bc0f53ebfa77f1402549e4e5639a4f23eedcf943abed79b9a0e1138546f67a0e0ac3d4e3c356434075af2f3dbc2f348dad5f3b857b46ae3b26dd652b753b1c
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
- # RailsStackview
2
-
3
- IN PROGRESS UNDER DEVELOPMENT NOT USABLE YET
1
+ [![Build Status](https://travis-ci.org/jrochkind/rails_stackview.svg?branch=master)](https://travis-ci.org/jrochkind/rails_stackview) [![Gem Version](https://badge.fury.io/rb/rails_stackview.svg)](http://badge.fury.io/rb/rails_stackview)
4
2
 
5
- **Tools** for integrating the Harvard Innovation Lab [stackview](https://github.com/harvard-lil/stackview) Javascript into a Rails app.
3
+ # RailsStackview
6
4
 
7
5
  This is not an out of the box solution, integrating it into your app will require some development.
8
6
 
@@ -1,3 +1,3 @@
1
1
  module RailsStackview
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -0,0 +1,16 @@
1
+ Asset files from stackview source are included in rails_stackview under
2
+ `./vendor/assets` subdirs.
3
+
4
+ To refresh with recent source, do a git checkout of stackview somewhere, then
5
+ from rails_stackview root dir, run:
6
+
7
+ RUBYLIB=./source_tools/ rails generate copy_stackview_assets path_to_stackview_source -f
8
+
9
+ The git SHA of stackview source that was copied into rails_stackview will be
10
+ saved at ./vendor/assets/stackview.sha
11
+
12
+ Part of the routine for copying stackview assets will also replace all
13
+ CSS `url()` in stackview CSS source with rails-sass `asset-url` calls, to
14
+ play well with the asset pipeline. To support this, the stackview
15
+ CSS will be copied as a `.sass` file, even though we are copying generated
16
+ stackview CSS, and it's not otherwise sass.
@@ -0,0 +1,21 @@
1
+ // Not copied from stackview directly, our own rails_stackview
2
+ // file to use sprockets to include JS src copied from stackview
3
+ //
4
+ // The list of assets is explicit below to preserve any neccesary ordering.
5
+ // If stackview adds more JS source files, you will have to update
6
+ // this list below, to keep it in sync with the list in stackview's
7
+ // own Makefile.
8
+ //
9
+ //= require ./stackview/microtemplating.js
10
+ //= require ./stackview/jquery.easing.1.3.js
11
+ //= require ./stackview/jquery.stackview.base.js
12
+ //= require ./stackview/jquery.stackview.infinite.js
13
+ //= require ./stackview/jquery.stackview.navigation.js
14
+ //= require ./stackview/jquery.stackview.ministack.js
15
+ //= require ./stackview/jquery.stackview.stackcache.js
16
+ //= require ./stackview/jquery.stackview.templates.js
17
+ //= require ./stackview/types/book.js
18
+ //= require ./stackview/types/serial.js
19
+ //= require ./stackview/types/soundrecording.js
20
+ //= require ./stackview/types/videofilm.js
21
+ //= require ./stackview/types/webpage.js
@@ -0,0 +1,205 @@
1
+ /*
2
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
3
+ *
4
+ * Uses the built in easing capabilities added In jQuery 1.1
5
+ * to offer multiple easing options
6
+ *
7
+ * TERMS OF USE - jQuery Easing
8
+ *
9
+ * Open source under the BSD License.
10
+ *
11
+ * Copyright © 2008 George McGinley Smith
12
+ * All rights reserved.
13
+ *
14
+ * Redistribution and use in source and binary forms, with or without modification,
15
+ * are permitted provided that the following conditions are met:
16
+ *
17
+ * Redistributions of source code must retain the above copyright notice, this list of
18
+ * conditions and the following disclaimer.
19
+ * Redistributions in binary form must reproduce the above copyright notice, this list
20
+ * of conditions and the following disclaimer in the documentation and/or other materials
21
+ * provided with the distribution.
22
+ *
23
+ * Neither the name of the author nor the names of contributors may be used to endorse
24
+ * or promote products derived from this software without specific prior written permission.
25
+ *
26
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
27
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
31
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
35
+ *
36
+ */
37
+
38
+ // t: current time, b: begInnIng value, c: change In value, d: duration
39
+ jQuery.easing['jswing'] = jQuery.easing['swing'];
40
+
41
+ jQuery.extend( jQuery.easing,
42
+ {
43
+ def: 'easeOutQuad',
44
+ swing: function (x, t, b, c, d) {
45
+ //alert(jQuery.easing.default);
46
+ return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
47
+ },
48
+ easeInQuad: function (x, t, b, c, d) {
49
+ return c*(t/=d)*t + b;
50
+ },
51
+ easeOutQuad: function (x, t, b, c, d) {
52
+ return -c *(t/=d)*(t-2) + b;
53
+ },
54
+ easeInOutQuad: function (x, t, b, c, d) {
55
+ if ((t/=d/2) < 1) return c/2*t*t + b;
56
+ return -c/2 * ((--t)*(t-2) - 1) + b;
57
+ },
58
+ easeInCubic: function (x, t, b, c, d) {
59
+ return c*(t/=d)*t*t + b;
60
+ },
61
+ easeOutCubic: function (x, t, b, c, d) {
62
+ return c*((t=t/d-1)*t*t + 1) + b;
63
+ },
64
+ easeInOutCubic: function (x, t, b, c, d) {
65
+ if ((t/=d/2) < 1) return c/2*t*t*t + b;
66
+ return c/2*((t-=2)*t*t + 2) + b;
67
+ },
68
+ easeInQuart: function (x, t, b, c, d) {
69
+ return c*(t/=d)*t*t*t + b;
70
+ },
71
+ easeOutQuart: function (x, t, b, c, d) {
72
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
73
+ },
74
+ easeInOutQuart: function (x, t, b, c, d) {
75
+ if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
76
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
77
+ },
78
+ easeInQuint: function (x, t, b, c, d) {
79
+ return c*(t/=d)*t*t*t*t + b;
80
+ },
81
+ easeOutQuint: function (x, t, b, c, d) {
82
+ return c*((t=t/d-1)*t*t*t*t + 1) + b;
83
+ },
84
+ easeInOutQuint: function (x, t, b, c, d) {
85
+ if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
86
+ return c/2*((t-=2)*t*t*t*t + 2) + b;
87
+ },
88
+ easeInSine: function (x, t, b, c, d) {
89
+ return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
90
+ },
91
+ easeOutSine: function (x, t, b, c, d) {
92
+ return c * Math.sin(t/d * (Math.PI/2)) + b;
93
+ },
94
+ easeInOutSine: function (x, t, b, c, d) {
95
+ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
96
+ },
97
+ easeInExpo: function (x, t, b, c, d) {
98
+ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
99
+ },
100
+ easeOutExpo: function (x, t, b, c, d) {
101
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
102
+ },
103
+ easeInOutExpo: function (x, t, b, c, d) {
104
+ if (t==0) return b;
105
+ if (t==d) return b+c;
106
+ if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
107
+ return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
108
+ },
109
+ easeInCirc: function (x, t, b, c, d) {
110
+ return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
111
+ },
112
+ easeOutCirc: function (x, t, b, c, d) {
113
+ return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
114
+ },
115
+ easeInOutCirc: function (x, t, b, c, d) {
116
+ if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
117
+ return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
118
+ },
119
+ easeInElastic: function (x, t, b, c, d) {
120
+ var s=1.70158;var p=0;var a=c;
121
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
122
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
123
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
124
+ return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
125
+ },
126
+ easeOutElastic: function (x, t, b, c, d) {
127
+ var s=1.70158;var p=0;var a=c;
128
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
129
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
130
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
131
+ return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
132
+ },
133
+ easeInOutElastic: function (x, t, b, c, d) {
134
+ var s=1.70158;var p=0;var a=c;
135
+ if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
136
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
137
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
138
+ if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
139
+ return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
140
+ },
141
+ easeInBack: function (x, t, b, c, d, s) {
142
+ if (s == undefined) s = 1.70158;
143
+ return c*(t/=d)*t*((s+1)*t - s) + b;
144
+ },
145
+ easeOutBack: function (x, t, b, c, d, s) {
146
+ if (s == undefined) s = 1.70158;
147
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
148
+ },
149
+ easeInOutBack: function (x, t, b, c, d, s) {
150
+ if (s == undefined) s = 1.70158;
151
+ if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
152
+ return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
153
+ },
154
+ easeInBounce: function (x, t, b, c, d) {
155
+ return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
156
+ },
157
+ easeOutBounce: function (x, t, b, c, d) {
158
+ if ((t/=d) < (1/2.75)) {
159
+ return c*(7.5625*t*t) + b;
160
+ } else if (t < (2/2.75)) {
161
+ return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
162
+ } else if (t < (2.5/2.75)) {
163
+ return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
164
+ } else {
165
+ return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
166
+ }
167
+ },
168
+ easeInOutBounce: function (x, t, b, c, d) {
169
+ if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
170
+ return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
171
+ }
172
+ });
173
+
174
+ /*
175
+ *
176
+ * TERMS OF USE - EASING EQUATIONS
177
+ *
178
+ * Open source under the BSD License.
179
+ *
180
+ * Copyright © 2001 Robert Penner
181
+ * All rights reserved.
182
+ *
183
+ * Redistribution and use in source and binary forms, with or without modification,
184
+ * are permitted provided that the following conditions are met:
185
+ *
186
+ * Redistributions of source code must retain the above copyright notice, this list of
187
+ * conditions and the following disclaimer.
188
+ * Redistributions in binary form must reproduce the above copyright notice, this list
189
+ * of conditions and the following disclaimer in the documentation and/or other materials
190
+ * provided with the distribution.
191
+ *
192
+ * Neither the name of the author nor the names of contributors may be used to endorse
193
+ * or promote products derived from this software without specific prior written permission.
194
+ *
195
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
196
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
197
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
198
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
199
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
200
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
201
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
202
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
203
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
204
+ *
205
+ */
@@ -0,0 +1,561 @@
1
+ /*!
2
+ Stack View - The jQuery virtual stack plugin
3
+ by The Harvard Library Innovation Lab
4
+
5
+ Dual licensed under MIT and GPL.
6
+ */
7
+ (function($, window, document, undefined) {
8
+ var events,
9
+ plugin = 'stackView',
10
+ StackView,
11
+ types = {};
12
+
13
+ events = {
14
+ init: 'stackview.init',
15
+ item_added: 'stackview.itemadded',
16
+ item_removed: 'stackview.itemremoved',
17
+ page_load: 'stackview.pageload'
18
+ };
19
+
20
+ /*
21
+ #get_type
22
+ */
23
+ var get_type = function(item) {
24
+ var type;
25
+
26
+ $.each(types, function(key, val) {
27
+ if (val.match(item)) {
28
+ type = val;
29
+ return false;
30
+ }
31
+ });
32
+
33
+ return type;
34
+ };
35
+
36
+ /*
37
+ #render_items(StackView, array [, jQuery]) - Private
38
+
39
+ Takes a StackView instance, an array of result items, and an optional
40
+ jQuery object. Renders a DOM element for each of the items and
41
+ appends it to the stack's item list. If [placeholder] is passed in the
42
+ items take the its spot in the DOM.
43
+ */
44
+ var render_items = function(stack, docs, $placeholder) {
45
+ var action = $placeholder ? 'before' : 'append',
46
+ $pivot = $placeholder ?
47
+ $placeholder :
48
+ stack.$element.find(stack.options.selectors.item_list);
49
+
50
+ $.each(docs, function(i, item) {
51
+ var type = get_type(item),
52
+ $item;
53
+
54
+ if (type == null) {
55
+ return true;
56
+ }
57
+
58
+ $item = $(tmpl(type.template, type.adapter(item, stack.options)));
59
+ $item.data('stackviewItem', item);
60
+ $pivot[action]($item);
61
+ });
62
+
63
+ if ($placeholder) {
64
+ $placeholder.remove();
65
+ }
66
+
67
+ };
68
+
69
+ /*
70
+ #calculate_params(StackView) - Private
71
+
72
+ Takes a StackView instance and returns the parameters for the next page.
73
+ If the Stack uses loc_sort_order, this adjusts the query for that case.
74
+ Returns a plain object with key:value params to be used by $.param.
75
+ */
76
+ var calculate_params = function(stack) {
77
+ var opts = stack.options,
78
+ params;
79
+
80
+ params = {
81
+ start: stack.page * stack.options.items_per_page,
82
+ limit: stack.options.items_per_page,
83
+ search_type: stack.options.search_type,
84
+ query: stack.options.query
85
+ };
86
+
87
+ if (params.search_type === 'loc_sort_order') {
88
+ params.start = 0;
89
+
90
+ if (stack.page === 0) {
91
+ stack.loc = {
92
+ low: opts.id - Math.floor(opts.items_per_page / 2),
93
+ high: opts.id + Math.floor(opts.items_per_page / 2)
94
+ };
95
+ params.query = [
96
+ '[',
97
+ stack.loc.low,
98
+ ' TO ',
99
+ stack.loc.high,
100
+ ']'
101
+ ].join('');
102
+ }
103
+ else if (stack.direction === 'down') {
104
+ params.query = [
105
+ '[',
106
+ stack.loc.high + 1,
107
+ ' TO ',
108
+ stack.loc.high + opts.items_per_page + 1,
109
+ ']'
110
+ ].join('');
111
+ stack.loc.high = stack.loc.high + opts.items_per_page + 1;
112
+ }
113
+ else if (stack.direction === 'up') {
114
+ params.query = [
115
+ '[',
116
+ stack.loc.low - opts.items_per_page - 1,
117
+ ' TO ',
118
+ stack.loc.low - 1,
119
+ ']'
120
+ ].join('');
121
+ stack.loc.low = stack.loc.low - opts.items_per_page - 1;
122
+ }
123
+ }
124
+
125
+ return params;
126
+ };
127
+
128
+ /*
129
+ #fetch_page(StackView, function) - Private
130
+
131
+ Takes a StackView instance and a callback function. Retrieves the
132
+ next page according to the URL and other options of the StackView
133
+ instance. When the page is finished fetching, the callback is
134
+ invoked, passing in the array of items.
135
+ */
136
+ var fetch_page = function(stack, callback) {
137
+ var params = calculate_params(stack),
138
+ querystring = $.param(params),
139
+ cachedResult;
140
+
141
+ stack.page++;
142
+ cachedResult = window.stackCache.get(stack.options.url + querystring);
143
+
144
+ if (cachedResult) {
145
+ callback(cachedResult);
146
+ }
147
+ else {
148
+ $.ajax({
149
+ url: stack.options.url,
150
+ data: querystring,
151
+ dataType: stack.options.jsonp ? 'jsonp' : 'json',
152
+ success: function(data) {
153
+ window.stackCache.set(
154
+ stack.options.url + params,
155
+ data,
156
+ stack.options.cache_ttl
157
+ );
158
+ callback(data);
159
+ }
160
+ });
161
+ }
162
+ };
163
+
164
+
165
+
166
+
167
+ /* StackView constructor, set up instance properties and call init. */
168
+ StackView = function(elem, opts) {
169
+ this.element = elem;
170
+ this.$element = $(elem);
171
+ this.options = $.extend(true, {}, StackView.defaults, opts);
172
+ this.page = 0;
173
+ this.finished = {
174
+ up: false,
175
+ down: false
176
+ };
177
+ this.loc = {
178
+ low: null,
179
+ high: null
180
+ };
181
+ this.direction = 'down';
182
+ this.init();
183
+ };
184
+
185
+ /* Static properties and functions */
186
+ $.extend(true, StackView, {
187
+
188
+ /*
189
+ The default options for a StackView instance.
190
+
191
+ cache_ttl
192
+ How long a request will stay in cache.
193
+
194
+ data
195
+ An alternative to URL, used for static data. Accepts a typical
196
+ URL response object or a simple array of item objects.
197
+
198
+ id
199
+ When using a search type of loc_sort_order, this is the id of
200
+ the item that the search centers around.
201
+
202
+ items_per_page
203
+ The number of items to request each page.
204
+
205
+ jsonp
206
+ If true, the URL will expect a JSONP request. callback=? will be
207
+ added to the request parameters.
208
+
209
+ query
210
+ The query passed to the script at URL. Passed as the
211
+ query parameter.
212
+
213
+ ribbon
214
+ The text of the ribbon at the top of the stack.
215
+
216
+ search_type
217
+ The type of search to be performed by the script at URL. This is
218
+ passed to the script as the search_type parameter.
219
+
220
+ selectors
221
+ A number of selectors that are frequently used by the code to
222
+ identify key structures.
223
+
224
+ item
225
+ A single item in the stack.
226
+
227
+ item_list
228
+ Container around all of the stack items.
229
+
230
+ ribbon
231
+ The text ribbon at the top of the stack.
232
+
233
+ url
234
+ The URL to send requests to for item data.
235
+ */
236
+ defaults: {
237
+ cache_ttl: 60,
238
+ data: '',
239
+ id: null,
240
+ items_per_page: 10,
241
+ jsonp: false,
242
+ query: '',
243
+ ribbon: 'Stack View',
244
+ search_type: 'keyword',
245
+ selectors: {
246
+ item: '.stack-item',
247
+ item_list: '.stack-items',
248
+ ribbon: '.ribbon'
249
+ },
250
+ url: 'basic.json'
251
+ },
252
+
253
+ /*
254
+ StackView.get_heat(number)
255
+
256
+ Takes a value between 0 and 100 and returns a number to be used with
257
+ heat classes to indicate popularity.
258
+ */
259
+ utils: {
260
+ get_heat: function(scaled_value) {
261
+ return scaled_value === 100 ? 10 : Math.floor(scaled_value / 10) + 1;
262
+ }
263
+ },
264
+
265
+ /*
266
+ StackView.register_type(object)
267
+
268
+ Registers an item type to be used by the stack. A Type object
269
+ has the following properties:
270
+
271
+ name: string
272
+ A unique, identifying name of the item type.
273
+
274
+ match: function(obj) -> obj
275
+ A function that takes a stack item and returns true if the
276
+ item matches this type. Example:
277
+
278
+ match: function(item) { return item.type === 'book' }
279
+
280
+ adapter: function(obj, obj) -> obj
281
+ This function allows the user to make transformations to the
282
+ item data before rendering it to the template. It takes as
283
+ parameters a raw item that matches the match function and the
284
+ options from the StackView instance. It should return an object
285
+ to render against "template." If no changes to the raw data need
286
+ to be made, the simplest value for this can be:
287
+
288
+ adapter: function(item) { return item; }
289
+
290
+ template: string
291
+ A microtemplating template to render for this type in the stack.
292
+ Receives as its data the return value from "adapter."
293
+
294
+ */
295
+ register_type: function(obj) {
296
+ types[obj.name] = obj;
297
+ },
298
+
299
+ /*
300
+ StackView.get_types()
301
+
302
+ Returns the hash of item types.
303
+ */
304
+ get_types: function() {
305
+ return types;
306
+ }
307
+ });
308
+
309
+ /*
310
+ StackView public methods
311
+ */
312
+ $.extend(true, StackView.prototype, {
313
+
314
+ /*
315
+ #init()
316
+
317
+ Sets up the initial states of a stack. Including:
318
+ - Creating the HTML skeleton.
319
+ - Binding zIndex ordering to the pageload event.
320
+ - Loading the first page.
321
+ - Firing the init event.
322
+ */
323
+ init: function() {
324
+ var that = this;
325
+
326
+ this.$element
327
+ .html(tmpl(StackView.templates.scaffold, {
328
+ ribbon: this.options.ribbon
329
+ }))
330
+ .addClass('stackview')
331
+ .bind(events.page_load, function() {
332
+ that.zIndex();
333
+ });
334
+
335
+ this.$element.data('stackviewObject', this);
336
+ this.$element.trigger(events.init);
337
+ this.next_page();
338
+ },
339
+
340
+ /*
341
+ #next_page()
342
+
343
+ Loads the next page of stack items. If we've already hit the
344
+ last page, this function does nothing.
345
+ */
346
+ next_page: function() {
347
+ var $placeholder = $(tmpl(StackView.templates.placeholder, {})),
348
+ that = this,
349
+ opts = this.options;
350
+
351
+ if (this.finished.down) {
352
+ return;
353
+ }
354
+
355
+ this.direction = 'down';
356
+ if (opts.data) {
357
+ render_items(this, opts.data.docs ? opts.data.docs : opts.data);
358
+ this.finished.down = true;
359
+ this.$element.trigger(events.page_load, [opts.data]);
360
+ }
361
+ else if (opts.url) {
362
+ this.$element
363
+ .find(opts.selectors.item_list)
364
+ .append($placeholder);
365
+ fetch_page(this, function(data) {
366
+ render_items(that, data.docs, $placeholder);
367
+ if (parseInt(data.start, 10) === -1) {
368
+ that.finished.down = true;
369
+ }
370
+ that.$element.trigger(events.page_load, [data]);
371
+ });
372
+ }
373
+ },
374
+
375
+ /*
376
+ #prev_page()
377
+
378
+ Loads the previous page of stack items. If we've already hit the
379
+ first page this function does nothing. This function only works
380
+ for stacks using the loc_sort_order search type.
381
+ */
382
+ prev_page: function() {
383
+ var $placeholder = $(tmpl(StackView.templates.placeholder, {})),
384
+ opts = this.options,
385
+ that = this,
386
+ $oldMarker = that.$element.find(opts.selectors.item).first();
387
+
388
+ if (opts.search_type !== 'loc_sort_order' || this.finished.up) {
389
+ return;
390
+ }
391
+
392
+ this.direction = 'up';
393
+ this.$element.find(opts.selectors.item_list).prepend($placeholder);
394
+ fetch_page(this, function(data) {
395
+ var oldTop = $oldMarker.position().top;
396
+
397
+ render_items(that, data.docs, $placeholder);
398
+ if (that.page > 1) {
399
+ that.$element.find(opts.selectors.item_list).animate({
400
+ 'scrollTop': '+=' + ($oldMarker.position().top - oldTop)
401
+ }, 0);
402
+ }
403
+ if (parseInt(data.start, 10) === -1) {
404
+ that.finished.up = true;
405
+ }
406
+ that.$element.trigger(events.page_load, [data]);
407
+ });
408
+ },
409
+
410
+ /*
411
+ #add([number,] object)
412
+
413
+ Adds the specified item object to the stack, at the given index if
414
+ provided or at the end (bottom) of the stack if index is not given.
415
+ */
416
+ add: function() {
417
+ var $items = this.$element.find(this.options.selectors.item),
418
+ index, item, type, action, $pivot, $item;
419
+
420
+ if (typeof(arguments[0]) === 'number') {
421
+ index = arguments[0];
422
+ item = arguments[1];
423
+ }
424
+ else {
425
+ index = $items.length;
426
+ item = arguments[0];
427
+ }
428
+
429
+ if (index > $items.length || index < 0) {
430
+ return;
431
+ }
432
+ else if (index === $items.length) {
433
+ $pivot = $items.last();
434
+ action = 'after';
435
+ }
436
+ else {
437
+ $pivot = $items.eq(index);
438
+ action = 'before';
439
+ }
440
+
441
+ type = get_type(item);
442
+ if (type == null) {
443
+ return;
444
+ }
445
+ $item = $(tmpl(type.template, type.adapter(item, this.options)));
446
+
447
+ $item.data('stackviewItem', item);
448
+ $pivot[action]($item);
449
+ this.zIndex();
450
+ this.$element.trigger(events.item_added);
451
+ },
452
+
453
+ /*
454
+ #remove(number | object)
455
+
456
+ If a number is given, it removes the item at that index. If an
457
+ object is given, this method finds the element that represents that
458
+ item and removes it.
459
+ */
460
+ remove: function(arg) {
461
+ var $items = this.$element.find(this.options.selectors.item),
462
+ $found, data, index;
463
+
464
+ if (typeof(arg) === 'number') {
465
+ $found = $items.eq(arg);
466
+ }
467
+ else if (arg.nodeType || arg.jquery){
468
+ $found = $(arg);
469
+ }
470
+ else {
471
+ $items.each(function(i, el) {
472
+ var $el = $(el);
473
+
474
+ if ($el.data('stackviewItem') === arg) {
475
+ $found = $el;
476
+ return false;
477
+ }
478
+ });
479
+ }
480
+
481
+ if ($found == null || !$found.length) {
482
+ return;
483
+ }
484
+
485
+ $found.detach();
486
+ data = $found.data('stackviewItem');
487
+ this.$element.trigger(events.item_removed, [data]);
488
+ return $found;
489
+ },
490
+
491
+
492
+ /*
493
+ #getData()
494
+
495
+ Returns an array of all the item objects currently in the stack.
496
+ */
497
+ getData: function() {
498
+ var data = [];
499
+
500
+ this.$element.find(this.options.selectors.item).each(function() {
501
+ data.push($(this).data('stackviewItem'));
502
+ });
503
+
504
+ return data;
505
+ },
506
+
507
+ /*
508
+ #zIndex(boolean)
509
+
510
+ Reverses the natural flow order of the stack items by giving those
511
+ earlier in the source (higher on the stack) a higher z-index. If
512
+ passed true, it will instead assign z-indexes in normal flow order.
513
+ */
514
+ zIndex: function(reverse) {
515
+ var $items = this.$element.find(this.options.selectors.item),
516
+ length = $items.length,
517
+ i = 0,
518
+ z = reverse ? 0 : $items.length - 1;
519
+
520
+ while (i < length) {
521
+ $items.eq(i).css('z-index', z);
522
+ z = z + (reverse ? 1 : -1);
523
+ i++;
524
+ }
525
+ }
526
+ });
527
+
528
+ /*
529
+ If .stackView has not been called on an element, the first call will
530
+ initialize the plugin. Subsequent calls expect a method from the
531
+ StackView class. Any method that returns undefined is assumed to
532
+ chain. If the method returns a value, only the value from the first
533
+ element in the jQuery set will be returned, the same as other getters
534
+ in jQuery.
535
+ */
536
+ $.fn[plugin] = function(method) {
537
+ var response,
538
+ args = Array.prototype.slice.call(arguments, 1);
539
+
540
+ this.each(function(i, el) {
541
+ var $el = $(el),
542
+ obj = $el.data('stackviewObject');
543
+
544
+ if (!obj) {
545
+ new StackView(el, method);
546
+ }
547
+ else if (obj[method]) {
548
+ var methodResponse = obj[method].apply(obj, args);
549
+
550
+ if (response === undefined && methodResponse !== undefined) {
551
+ response = methodResponse;
552
+ }
553
+ }
554
+ });
555
+
556
+ return response === undefined ? this : response;
557
+ };
558
+
559
+ /* Expose the StackView class for extension */
560
+ window.StackView = StackView;
561
+ })(jQuery, window, document);