stackview_acorn_tester 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +291 -0
- data/Rakefile +37 -0
- data/app/assets/javascripts/rails_stackview/auto_init.js +15 -0
- data/app/assets/javascripts/rails_stackview/browser.js +161 -0
- data/app/assets/javascripts/rails_stackview/plain.js +128 -0
- data/app/assets/javascripts/rails_stackview.js +11 -0
- data/app/assets/stylesheets/rails_stackview/_plain.scss +119 -0
- data/app/assets/stylesheets/rails_stackview/browser.scss +116 -0
- data/app/assets/stylesheets/rails_stackview.scss +10 -0
- data/app/controllers/stackview_data_controller.rb +91 -0
- data/app/fetch_adapters/rails_stackview/db_window_fetcher.rb +88 -0
- data/app/fetch_adapters/rails_stackview/mock_fetcher.rb +27 -0
- data/app/models/stackview_call_number.rb +2 -0
- data/app/views/rails_stackview/browser.html.erb +42 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20150602210254_create_stackview_call_numbers.rb +34 -0
- data/lib/rails_stackview/engine.rb +7 -0
- data/lib/rails_stackview/version.rb +3 -0
- data/lib/rails_stackview.rb +20 -0
- data/lib/tasks/rails_stackview_tasks.rake +4 -0
- data/test/controllers/stackview_data_controller_test.rb +55 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +17 -0
- data/test/dummy/app/assets/stylesheets/application.css +20 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/demo_controller.rb +14 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/demo/index.html.erb +14 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +67 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/test_fixture.yaml +433 -0
- data/test/fetch_adapters/db_window_fetcher_test.rb +106 -0
- data/test/fixtures/stackview_call_numbers.yml +473 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/rails_stackview_test.rb +7 -0
- data/test/test_helper.rb +42 -0
- data/vendor/assets/README.md +16 -0
- data/vendor/assets/images/stackview/bookEnd-next.png +0 -0
- data/vendor/assets/images/stackview/bookEnd-prev.png +0 -0
- data/vendor/assets/images/stackview/gloss.png +0 -0
- data/vendor/assets/images/stackview/highGloss.png +0 -0
- data/vendor/assets/images/stackview/icon-globe.png +0 -0
- data/vendor/assets/images/stackview/icon-note.png +0 -0
- data/vendor/assets/images/stackview/nav.png +0 -0
- data/vendor/assets/images/stackview/placeholder.gif +0 -0
- data/vendor/assets/images/stackview/ribbonTab.png +0 -0
- data/vendor/assets/images/stackview/serials-edge.png +0 -0
- data/vendor/assets/images/stackview/serials.png +0 -0
- data/vendor/assets/images/stackview/superGloss.png +0 -0
- data/vendor/assets/javascripts/jquery.stackview.js +21 -0
- data/vendor/assets/javascripts/stackview/jquery.easing.1.3.js +205 -0
- data/vendor/assets/javascripts/stackview/jquery.stackview.base.js +561 -0
- data/vendor/assets/javascripts/stackview/jquery.stackview.infinite.js +46 -0
- data/vendor/assets/javascripts/stackview/jquery.stackview.ministack.js +33 -0
- data/vendor/assets/javascripts/stackview/jquery.stackview.navigation.js +71 -0
- data/vendor/assets/javascripts/stackview/jquery.stackview.stackcache.js +74 -0
- data/vendor/assets/javascripts/stackview/jquery.stackview.templates.js +31 -0
- data/vendor/assets/javascripts/stackview/microtemplating.js +40 -0
- data/vendor/assets/javascripts/stackview/types/book.js +184 -0
- data/vendor/assets/javascripts/stackview/types/my_plain.js +183 -0
- data/vendor/assets/javascripts/stackview/types/serial.js +40 -0
- data/vendor/assets/javascripts/stackview/types/soundrecording.js +42 -0
- data/vendor/assets/javascripts/stackview/types/videofilm.js +56 -0
- data/vendor/assets/javascripts/stackview/types/webpage.js +42 -0
- data/vendor/assets/stackview.sha +1 -0
- data/vendor/assets/stylesheets/stackview/_book.scss +66 -0
- data/vendor/assets/stylesheets/stackview/_heatmap.scss +154 -0
- data/vendor/assets/stylesheets/stackview/_ministack.scss +43 -0
- data/vendor/assets/stylesheets/stackview/_mixins.scss +100 -0
- data/vendor/assets/stylesheets/stackview/_navigation.scss +52 -0
- data/vendor/assets/stylesheets/stackview/_plain.scss +71 -0
- data/vendor/assets/stylesheets/stackview/_serial.scss +50 -0
- data/vendor/assets/stylesheets/stackview/_soundrecording.scss +83 -0
- data/vendor/assets/stylesheets/stackview/_videofilm.scss +74 -0
- data/vendor/assets/stylesheets/stackview/_webpage.scss +82 -0
- data/vendor/assets/stylesheets/stackview/jquery.stackview.scss +171 -0
- metadata +233 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 52758b9ebe7d5f834d3070d4c9fc86763711d797ecd597c5bde9e6799d21352a
|
4
|
+
data.tar.gz: 2842d6cb9f1f5df3cae85118bdcb02626ee66e533d9183538c3dda9249451f59
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 455b4b57d0852282cc9ee469f6330b2ff0b0bed3c185512467c986cc168fae0e9fc0ce1d177a1b49e887dfd65e438ea6bf93a9dfb55b6b798d86feedd81156ab
|
7
|
+
data.tar.gz: ce2ce5119dfd29e8c7494370d5b939ea41cd78fb8840541c702706c04a83fd93b0877b3f7a9254f317d765890860471d498300528fe5ae780220518bd1f2bacb
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2015 Jonathan Rochkind
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
[](https://travis-ci.org/jrochkind/rails_stackview) [](http://badge.fury.io/rb/rails_stackview)
|
2
|
+
|
3
|
+
# RailsStackview
|
4
|
+
|
5
|
+
Packages the assets from the Harvard Library Innovation Lab's [stackview](https://github.com/harvard-lil/stackview) for the Rails asset pipeline, and provides additional optional integration support with a controller and a template.
|
6
|
+
|
7
|
+
This is not an out of the box solution, integrating it into your app will require some development.
|
8
|
+
|
9
|
+
The hardest part, for call-number browse, is typically arranging your call numbers somewhere
|
10
|
+
so they can be accessed in sorted order.
|
11
|
+
|
12
|
+
RailsStackview contains the original stackview assets, arranged for the Rails asset pipeline. Along with some higher-level components. These higher-level have been created for my own use cases and needs; while I've tried to give a nod to future expandability, they haven't been created to be fully robust and configurable for all use cases. In this project, for a change, I've tried to be guided by keeping it simple and [YAGNI](http://martinfowler.com/bliki/Yagni.html).
|
13
|
+
|
14
|
+
My focused use case is 'shelf browse', browse through a very long list of ordered
|
15
|
+
items, starting at a specified point in the middle.
|
16
|
+
|
17
|
+
## Requirements
|
18
|
+
|
19
|
+
The Stackview code needs JQuery, so you should have JQuery loaded in your app.
|
20
|
+
|
21
|
+
This code is meant for integration with a Rails app. It does not assume Blacklight,
|
22
|
+
although is usable with Blacklight.
|
23
|
+
|
24
|
+
Add it to your app like any other gem, by listing in the Gemfile.
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
### Stackview assets are available.
|
29
|
+
|
30
|
+
To use the stackview assets directly, include them in your asset pipeline.
|
31
|
+
|
32
|
+
You can include just the original stackview JS and CSS:
|
33
|
+
|
34
|
+
~~~ruby
|
35
|
+
# app/assets/javascripts/application.js
|
36
|
+
//= require jquery.stackview.js
|
37
|
+
~~~
|
38
|
+
|
39
|
+
~~~ruby
|
40
|
+
# app/assets/stylesheets/application.css
|
41
|
+
*= require stackview/jquery.stackview.scss
|
42
|
+
~~~
|
43
|
+
|
44
|
+
Now Stackview will be available in your app, via the asset pipeline,
|
45
|
+
using the documented stackview API. (eg `$(something).stackView(something)`)
|
46
|
+
|
47
|
+
Or alternatley you can include all RailsStackview JS/CSS, which provides some
|
48
|
+
support for higher level features, along with the original stackview assets:
|
49
|
+
|
50
|
+
~~~ruby
|
51
|
+
# app/assets/javascripts/application.js
|
52
|
+
//= require rails_stackview
|
53
|
+
~~~
|
54
|
+
|
55
|
+
~~~ruby
|
56
|
+
# app/assets/stylesheets/application.css
|
57
|
+
*= require rails_stackview
|
58
|
+
~~~
|
59
|
+
|
60
|
+
One additional feature included is an automatic application of stackview
|
61
|
+
to any `<div>` with a `data-stackview-init` attribute, containing JSON
|
62
|
+
serialization of stackview init arguments.
|
63
|
+
|
64
|
+
This can be convenient for integrating with Rails, letting you for instance
|
65
|
+
specify your own rails controller as a data provider to stackview:
|
66
|
+
|
67
|
+
~~~erb
|
68
|
+
<%= content_tag("div", "",
|
69
|
+
:id => "whatever_you_want",
|
70
|
+
:class => "whatever you want",
|
71
|
+
:data => {
|
72
|
+
:stackview_init => {
|
73
|
+
:id => 0,
|
74
|
+
:url => your_route_helper(some_args),
|
75
|
+
:search_type => "loc_sort_order"
|
76
|
+
}
|
77
|
+
})
|
78
|
+
%>
|
79
|
+
~~~
|
80
|
+
|
81
|
+
The data-stackview-init hash can be whatever you like, as initialization
|
82
|
+
arguments for the original stackview.
|
83
|
+
|
84
|
+
### Back-End Support: The StackviewDataController to feed data to stackview
|
85
|
+
|
86
|
+
The [StackviewDataController](./app/controllers/stackview_data_controller.rb) is provided
|
87
|
+
to feed data to a stackview UI,
|
88
|
+
with the use case of 'call number browse', or starting at an arbitrary
|
89
|
+
point in a very long list of items, and paging both back and forwards.
|
90
|
+
|
91
|
+
The current implementation of the StackviewDataController counts
|
92
|
+
on a table of individual call numbers existing in your database.
|
93
|
+
It is difficult to get the querries we need out of Solr directly, and
|
94
|
+
we opted to create a duplicate 'denormalized' database table with
|
95
|
+
exactly the info needed to support the front-end.
|
96
|
+
|
97
|
+
Once you've added `rails_stackview` to your Gemfile, you can
|
98
|
+
install a migration into your app to create the `stackview_call_numbers` table,
|
99
|
+
with:
|
100
|
+
|
101
|
+
bundle exec rake rails_stackview_engine:install:migrations
|
102
|
+
|
103
|
+
It is up to you to fill this table with call number data. If you
|
104
|
+
use [traject](https://github.com/traject/traject) to index
|
105
|
+
MARC to Solr, you can look at [this example of how I handle
|
106
|
+
creating the stackview_call_numbers table at the same time
|
107
|
+
I do my Solr indexing](./docs/traject-indexing.example.rb)
|
108
|
+
|
109
|
+
Here are the elements of the `stackview_call_numbers` table:
|
110
|
+
|
111
|
+
* `system_id` (string), the primary key of the original item
|
112
|
+
in your overall system, used for linking from stackview
|
113
|
+
to your system.
|
114
|
+
* `sort_key` (string), a _sortable_ representation of your call
|
115
|
+
number or other ordering. Used for sorting the stack. If you
|
116
|
+
are using LC Call Numbers and populating this table in ruby,
|
117
|
+
we suggest the [Lcsort](https://github.com/pulibrary/lcsort) gem for turning a call number
|
118
|
+
into a sortable representation. Some features will end up less confusing if
|
119
|
+
sort_keys are unique, although they aren't required to be -- I append
|
120
|
+
the bibID to the end of each sort_key, to make them unique even if two
|
121
|
+
bibs share the same call number.
|
122
|
+
* `sort_key_display` (string, optional), the original human-displayable
|
123
|
+
call number, can be used for display.
|
124
|
+
* `title` (string), title to use in stackview representation.
|
125
|
+
* `creator` (string, optional), author to use in stackview representation.
|
126
|
+
* `pub_date` (string, optional), publication year (as string) to use in stackview representation.
|
127
|
+
* `measurement_page_numeric` (int, optional), page count, passed to stackview for represnetation width.
|
128
|
+
* `measurement_height_numeric` (int, optional), item height (usually in cm), passed to stackview for representation height
|
129
|
+
* `shelfrank` (int, optional), 1-100, passed to stackview for "heatmap" intensity coloring of representation. Normally a count of number of times checked out.
|
130
|
+
* `created_at` (datetime, optional), can set to row creation date for your administrative convenience.
|
131
|
+
* `format`: Passed to stackview to choose a format-specific view template, should be one of magic words from stackview's own source (case-sensitive, not entirely consistent): `book` `Serial`, `Sound Recording`, `Video/Film`, `webpage`. Also our own special `plain` format, which can also take a specific description etc `plain:VHS`. See more at "Custom Plain Format" below.
|
132
|
+
* `sort_key_type` (string): Eventually we plan to support multiple separate call number runs, which will
|
133
|
+
be identified by `sort_key_type`. We have the beginnings of such an architecture, but
|
134
|
+
it may not be fully fleshed out and may have performance implications. For now recommend always setting
|
135
|
+
this to the default, `lc`.
|
136
|
+
|
137
|
+
Once you've filled this database, you can use it with our Browser front-end, or you can construct your own stackview front-end telling stackview to use this to use this controller as a source for:
|
138
|
+
|
139
|
+
Add routing to the StackviewDataController in your own `./config/routes.rb`
|
140
|
+
|
141
|
+
~~~ruby
|
142
|
+
get 'stackview_data/:call_number_type', :to => "stackview_data#fetch", :as => "stackview_data"
|
143
|
+
~~~
|
144
|
+
|
145
|
+
(That specific `:as => 'stackview_data'` is needed if you are using our Browser front-end)
|
146
|
+
|
147
|
+
When you initialize a stackview UI element, you have to tell it what item to start at, by giving it a `sort_key` (normalized sortable call number representation) value. One way to get a sort_key for
|
148
|
+
a known item, is simply to look it up from the existing `stackview_call_numbers` table:
|
149
|
+
|
150
|
+
~~~ruby
|
151
|
+
# may be nil if no such system_id recorded
|
152
|
+
origin_sort_key = StackviewCallNumber.where(:system_id => document.id).order("created_at").pluck(:sort_key).first
|
153
|
+
~~~
|
154
|
+
|
155
|
+
Now you can initialize a stackview UI element, using the RailsStackview feature
|
156
|
+
to automatically init a stackview from a data-stackview-init attribute:
|
157
|
+
|
158
|
+
~~~erb
|
159
|
+
<%= content_tag("div", "",
|
160
|
+
:id => "my_stackview",
|
161
|
+
:data => {
|
162
|
+
:stackview_init => {
|
163
|
+
:id => 0,
|
164
|
+
:url => stackview_data_path("lc", :origin_sort_key => origin_sort_key),
|
165
|
+
:search_type => "loc_sort_order"
|
166
|
+
}
|
167
|
+
})
|
168
|
+
%>
|
169
|
+
~~~
|
170
|
+
|
171
|
+
If you pass an :origin_sort_key that doesn't actually exist in the database,
|
172
|
+
the StackviewDataController will still put the user into the stacks at the closest
|
173
|
+
point to that theoretical call number.
|
174
|
+
|
175
|
+
#### Set the link URL
|
176
|
+
|
177
|
+
To set the `link` property on the JS objects passed to stackview, which will be used
|
178
|
+
as the `href` on stackview item hyperlinks, set a lambda/proc as configuration, perhaps
|
179
|
+
in an initializer. The proc gets the already constructed stackview hash as a parameter,
|
180
|
+
and will be executed in the context of the controller so you can use controller
|
181
|
+
methods, such as Rails route helpers.
|
182
|
+
|
183
|
+
StackviewDataController.set_config_for_type("default", {
|
184
|
+
:link => lambda do |hash|
|
185
|
+
catalog_path(hash["system_id"])
|
186
|
+
end
|
187
|
+
})
|
188
|
+
|
189
|
+
Above is similar to the default, which should work for at least some versions
|
190
|
+
of Blacklight by default.
|
191
|
+
|
192
|
+
|
193
|
+
#### What's it doing then?
|
194
|
+
|
195
|
+
To use the current stackview API (as far as what it fetches from it's back-end), in
|
196
|
+
a flexible and high-performance way, we do something a bit odd.
|
197
|
+
|
198
|
+
The URL fixes the controller to have an 'origin' you specify. Stackview, in "search_type: loc_sort_order" (stackview's terminology) will then send it negative and positive offsets as the user browses -- eg asking
|
199
|
+
for items 10 to 20, or -25 to -35. The controller will use SQL `OFFSET` to page forwards and backwards
|
200
|
+
around the origin. This ends up pretty performant, although it is odd.
|
201
|
+
|
202
|
+
The Stackview `loc_sort_order` mode is under-documented on stackview's site, but it's meant
|
203
|
+
for 'infinite' scrolling both forwards and back around an origin. Stackview assumes
|
204
|
+
you're initialize it to the actual i-index `id` where you want to start; but we set
|
205
|
+
a "logical" id starting point of 0, and encode our actual origin in the URL instead. Then
|
206
|
+
we can consider stackview's indexes to actually be offsets from our origin.
|
207
|
+
|
208
|
+
Weird, but it works, without major changes to the stackview JS code itself.
|
209
|
+
|
210
|
+
|
211
|
+
#### Don't want to use the stackview_call_numbers table?
|
212
|
+
|
213
|
+
It is kind of hacky. Do you have another source for your call numbers? Do you want
|
214
|
+
to try to get them via Solr directly using the ndushay/stanford hack?
|
215
|
+
|
216
|
+
The code extracts out the actual fetch logic into a [RailsStackview::DbWindowFetcher](./app/fetch_adapters/rails_stackview/db_window_fetcher.rb) adapter.
|
217
|
+
We intend to let you replace it with your own adapter, that takes the HTTP params sent by
|
218
|
+
stackview itself, and returns a list of hashes to be given back to it.
|
219
|
+
|
220
|
+
This architecture isn't neccesarily fully fleshed out, some parts of RailsStackview
|
221
|
+
may be hard-coded in unpleasant ways, but the beginnings are there.
|
222
|
+
|
223
|
+
|
224
|
+
### Front-end Support: The Browser Template
|
225
|
+
|
226
|
+
You can write your own Rails template with the stackview element on it. It turns
|
227
|
+
out it's a bit tricky to get right for common cases.
|
228
|
+
|
229
|
+
`rails_stackview` provides a 'browser' template you can use, which is a two-column
|
230
|
+
display with stackview on the left, and an item detail panel on the right. It
|
231
|
+
takes care of a lot of odd edge cases and details, especially focused again on
|
232
|
+
an 'infinite' shelf browser use case.
|
233
|
+
|
234
|
+
You can use this template in your own controller action method. It needs to be
|
235
|
+
initialized with an starting point sortkey, which the stack will center on. It's
|
236
|
+
recommended you use a query parameter to pass in the sort key -- the browser
|
237
|
+
javascript includes some code to update such a query param with JS replaceState(),
|
238
|
+
to keep back button working well.
|
239
|
+
|
240
|
+
render :template => 'rails_stackview/browser', :locals => {:origin_sort_key => params["origin_sort_key"]}
|
241
|
+
|
242
|
+
You may want to customize your Rails layout template to work best with the browser template.
|
243
|
+
The browser template is designed best to work with _no_ padding or spacing
|
244
|
+
underneath it -- Javascript will set the stackview element to stretch to the bottom
|
245
|
+
of the browser. A small header is okay. No right or left margin or padding is best.
|
246
|
+
|
247
|
+
The browser template does use the back-end StackviewDataController, you will need
|
248
|
+
to have that set up properly as above.
|
249
|
+
|
250
|
+
If you want a click on a stack item to load information in the right panel, then you need
|
251
|
+
to define your own Rails route with a `stackview_browser_item`, which returns partial
|
252
|
+
HTML that should be loaded (via AJAX) in the item detail panel on a click.
|
253
|
+
|
254
|
+
We have [an example of how I implemented the `stackview_browser_item` action in a
|
255
|
+
Blacklight app](./docs/stackview_browser_item.example.md).
|
256
|
+
|
257
|
+
After an item is loaded by the browser JS, a custom `stackview-item-load` JS event is
|
258
|
+
triggered, with the item panel div as the target.
|
259
|
+
|
260
|
+
On very small screens, the browser is only a single column without the item detail panel,
|
261
|
+
and clicks on items will follow the href set on the items, see above under `Set the link URL`.
|
262
|
+
|
263
|
+
|
264
|
+
### Custom format plain
|
265
|
+
|
266
|
+
`rails_stackview` adds it's own custom "plain" format, which we use for items
|
267
|
+
that are neither books, CDs, DVDs, etc. Or where we can't be sure what format they are.
|
268
|
+
|
269
|
+
The design isn't too sophisticated, but is meant to look kind of like a plain
|
270
|
+
box with a printed label. It does implement stackview heatmap coloring.
|
271
|
+
|
272
|
+
If you have included `rails_stackview` CSS and JS, the plain format is available.
|
273
|
+
|
274
|
+
Set format format property to `plain` to trigger. Or, you can set
|
275
|
+
additional format description after a colon: `plain:LP`, or `plain:Whatever we want`,
|
276
|
+
and the additional format description will be included on the label.
|
277
|
+
|
278
|
+
## Development
|
279
|
+
|
280
|
+
### Vendored stackview assets
|
281
|
+
|
282
|
+
Stackview assets (JS, CSS, images) are included directly in source here,
|
283
|
+
under [./vendor/assets](./vendor/assets).
|
284
|
+
|
285
|
+
The original stackview is not versioned, but the git SHA hash of
|
286
|
+
the currently vendored assets is included at
|
287
|
+
[./vendor/assets/stackview.sha](./vendor/assets/stackview.sha)
|
288
|
+
|
289
|
+
There is a script for refreshing these assets in rails_stackview source,
|
290
|
+
see [./vendor/assets/README.md](./vendor/assets/README.md).
|
291
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'RailsStackview'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
task default: :test
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// On page load, look for any elements with a data-stackview-init attribute.
|
2
|
+
// That data attribute is expected to include a JSON serialized hash that
|
3
|
+
// is an init argument to the stackView() initializer.
|
4
|
+
|
5
|
+
// We will initialize element with that argument.
|
6
|
+
(function( $ ) {
|
7
|
+
// page:load for turbolinks too, not sure if it really works right.
|
8
|
+
$(document).on('ready page:load', function () {
|
9
|
+
$("[data-stackview-init]").each(function(i, element) {
|
10
|
+
element = $(element);
|
11
|
+
element.stackView(element.data("stackviewInit"));
|
12
|
+
});
|
13
|
+
});
|
14
|
+
|
15
|
+
})( jQuery );
|
@@ -0,0 +1,161 @@
|
|
1
|
+
(function($, undefined) {
|
2
|
+
|
3
|
+
function fitToWindowHeight() {
|
4
|
+
var shelfbrowser = $(".shelfbrowser");
|
5
|
+
|
6
|
+
if (shelfbrowser.size() > 0) {
|
7
|
+
var topOffset = shelfbrowser.offset().top;
|
8
|
+
var height = $(window).innerHeight() - topOffset;
|
9
|
+
|
10
|
+
shelfbrowser.css("height", height);
|
11
|
+
// set a bunch of elements to have same height, CSS tricks
|
12
|
+
// to make it expand to fit weren't working esp in IE.
|
13
|
+
$(".shelfbrowser-stackview").css("height", height);
|
14
|
+
$(".shelfbrowser-browser-column").css("height", height);
|
15
|
+
$(".shelfbrowser-info-column").css("height", height);
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
window.doit = true;
|
20
|
+
|
21
|
+
function loadItem(base_url, panel, item) {
|
22
|
+
// Fade out the existing content with a pretty cheesy effect,
|
23
|
+
// ends up less confusing when load is slowish. Cheesy implementation.
|
24
|
+
panel.wrapInner("<div class='rails-stackview-panel-wrap'></div>");
|
25
|
+
panel.find(".rails-stackview-panel-wrap").delay(400).fadeTo(600, 0.2);
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
if (window.doit) {
|
30
|
+
$.ajax({
|
31
|
+
url: base_url,
|
32
|
+
data: {
|
33
|
+
'id': item.system_id,
|
34
|
+
'sort_key': item.sort_key,
|
35
|
+
'sort_key_display': item.sort_key_display,
|
36
|
+
'sort_key_type': item.sort_key_type
|
37
|
+
},
|
38
|
+
dataType: "html",
|
39
|
+
success: function(html, status, xhr) {
|
40
|
+
panel.html( html );
|
41
|
+
panel.trigger("stackview-item-load");
|
42
|
+
},
|
43
|
+
error: function(xhr, status, error) {
|
44
|
+
panel.html(errorPanel(error));
|
45
|
+
},
|
46
|
+
complete: function(xhr, status) {
|
47
|
+
// Some kind of bug in chrome/webkit is sometimes making
|
48
|
+
// parts of the info column be not properly painted, especially
|
49
|
+
// on retina screens. Think we trigger it by changing DOM inside an
|
50
|
+
// overflow:auto section.
|
51
|
+
// This seems to work around it hackily:
|
52
|
+
$(".shelfbrowser-info-column").fadeTo(1, .99).fadeTo(1, 1);
|
53
|
+
|
54
|
+
// If the info column was previously scrolled, we want
|
55
|
+
// to go to top for this new content.
|
56
|
+
$(".shelfbrowser-info-column").scrollTop(0);
|
57
|
+
}
|
58
|
+
});
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
function errorPanel(text) {
|
63
|
+
return '<div class="alert alert-warning" role="alert">Sorry, we can not display this item.' +
|
64
|
+
(text ? (' (' + text + ')') : '') +
|
65
|
+
'</div>';
|
66
|
+
}
|
67
|
+
|
68
|
+
// We add origin_sort_key=$sort_key into the current
|
69
|
+
// URL using pushState, if in a browser that supports.
|
70
|
+
//
|
71
|
+
// The intention is to 'remember' the currently selected
|
72
|
+
// item on browser back button to this page, etc.
|
73
|
+
//
|
74
|
+
// It does assume the host app is supporting ?origin_sort_key=$sort_key
|
75
|
+
// and passing it to template, to work. Could make more configurable
|
76
|
+
// later.
|
77
|
+
function replaceSelectedState(item) {
|
78
|
+
if ('history' in window && 'replaceState' in history && 'sort_key' in item) {
|
79
|
+
var query = location.search;
|
80
|
+
if (query.length == 0)
|
81
|
+
query = '?';
|
82
|
+
|
83
|
+
// replace origin_sort_key only if it exists
|
84
|
+
var re = new RegExp("([\\?&])origin_sort_key=([^&#]*)");
|
85
|
+
query = query.replace(re, '$1origin_sort_key=' + encodeURIComponent(item.sort_key));
|
86
|
+
|
87
|
+
history.replaceState({}, '', query + location.hash);
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
$( document ).on("ready", function() {
|
92
|
+
if ($(".shelfbrowser").length > 0) {
|
93
|
+
fitToWindowHeight();
|
94
|
+
|
95
|
+
$( window ).on("resize orientationchange", function() {
|
96
|
+
fitToWindowHeight();
|
97
|
+
});
|
98
|
+
|
99
|
+
// If stackview_browser_item_path is defined, click on item
|
100
|
+
// should load partial via AJAX, and preventDefault.
|
101
|
+
$(document).on("click", ".shelfbrowser .stack-item a", function(event) {
|
102
|
+
var target = $(event.target);
|
103
|
+
var item_load_url = target.closest(".shelfbrowser-browse-column").data('stackviewBrowserItemPath');
|
104
|
+
var panel = target.closest(".shelfbrowser").find(".shelfbrowser-info-column .stack-item-panel").filter(":visible");
|
105
|
+
|
106
|
+
var item_attribute_hash = target.closest(".stack-item").data("stackviewItem");
|
107
|
+
|
108
|
+
replaceSelectedState(item_attribute_hash);
|
109
|
+
|
110
|
+
if(item_load_url && panel.length > 0) {
|
111
|
+
event.preventDefault();
|
112
|
+
|
113
|
+
loadItem(item_load_url, panel, item_attribute_hash );
|
114
|
+
|
115
|
+
$('.active-item').removeClass('active-item');
|
116
|
+
$(this).parent().addClass('active-item');
|
117
|
+
}
|
118
|
+
});
|
119
|
+
|
120
|
+
// Catch stackview.page the FIRST time, so we can find the origin
|
121
|
+
// document and add a special class to it, which we'll use to click
|
122
|
+
// on it immediately, and set the scroll view so it's centered.
|
123
|
+
$(document).on("stackview.pageload.initial-select", function(event) {
|
124
|
+
// Find the .stack-item which has data origin:true set, and click it.
|
125
|
+
// Since we're only executing on first load, this shouldn't be
|
126
|
+
// that many items.
|
127
|
+
|
128
|
+
var item_load_url = $(event.target).closest(".shelfbrowser-browse-column").data('stackviewBrowserItemPath');
|
129
|
+
|
130
|
+
var $origin_item;
|
131
|
+
|
132
|
+
// Add .origin-item to origin, so we can do things with it....
|
133
|
+
$(event.target).find(".stack-item").each(function(index, item) {
|
134
|
+
if($(item).data("stackviewItem").is_origin_item) {
|
135
|
+
$origin_item = $(item);
|
136
|
+
// We add stackview-origin class to allow us to
|
137
|
+
// find it and position the scroll properly on load.
|
138
|
+
$origin_item.addClass("stackview-origin");
|
139
|
+
}
|
140
|
+
});
|
141
|
+
|
142
|
+
//... we want to simulate clicking the origin, if we have a load url,
|
143
|
+
// so we can load it.
|
144
|
+
if (item_load_url) {
|
145
|
+
$origin_item.find("a").trigger('click');
|
146
|
+
}
|
147
|
+
|
148
|
+
//... we want to try to set the scroll such that our origin item is
|
149
|
+
// centered.
|
150
|
+
// stackview out of the box doesn't quite get this right, it's tricky,
|
151
|
+
// we seem to be doing okay.
|
152
|
+
var container = $origin_item.closest("ul.stack-items");
|
153
|
+
container.scrollTop( $origin_item.get(0).offsetTop - (container.height() / 2) + ($origin_item.height() / 2) )
|
154
|
+
|
155
|
+
// Remove our handler, we only want to do this once.
|
156
|
+
$(document).off("stackview.pageload.initial-select");
|
157
|
+
});
|
158
|
+
}
|
159
|
+
});
|
160
|
+
|
161
|
+
})(jQuery);
|
@@ -0,0 +1,128 @@
|
|
1
|
+
(function($, window, undefined) {
|
2
|
+
/*
|
3
|
+
A very poorly-designed type meant for 'other', meant to look
|
4
|
+
sort of like a simple box with a typed sticky label.
|
5
|
+
|
6
|
+
Trigger with "format: 'plain'", OR add a format label on the end
|
7
|
+
too:
|
8
|
+
|
9
|
+
format: "plain: VHS"
|
10
|
+
|
11
|
+
The 'title' and extra format info will be displayed, along with pub_date.
|
12
|
+
Author display not currently included.
|
13
|
+
|
14
|
+
measurement_height_numeric can control box height, like 'book'
|
15
|
+
type. Box width is fixed though.
|
16
|
+
*/
|
17
|
+
$.extend(true, window.StackView.defaults, {
|
18
|
+
selectors: {
|
19
|
+
plain: '.stack-plain'
|
20
|
+
},
|
21
|
+
plain: {
|
22
|
+
max_height_percentage: 100,
|
23
|
+
max_height: 39,
|
24
|
+
min_height_percentage: 20,
|
25
|
+
min_height: 10
|
26
|
+
}
|
27
|
+
});
|
28
|
+
|
29
|
+
/*
|
30
|
+
#translate(number, number, number, number, number) - Private
|
31
|
+
|
32
|
+
Takes a value (the first argument) and two ranges of numbers. Translates
|
33
|
+
this value from the first range to the second range. E.g.:
|
34
|
+
|
35
|
+
translate(0, 0, 10, 50, 100) returns 50.
|
36
|
+
translate(10, 0, 10, 50, 100) returns 100.
|
37
|
+
translate(5, 0, 10, 50, 100) returns 75.
|
38
|
+
|
39
|
+
http://stackoverflow.com/questions/1969240/mapping-a-range-of-values-to-another
|
40
|
+
*/
|
41
|
+
var translate = function(value, start_min, start_max, end_min, end_max) {
|
42
|
+
var start_range = start_max - start_min,
|
43
|
+
end_range = end_max - end_min,
|
44
|
+
scale = (value - start_min) / (start_range);
|
45
|
+
|
46
|
+
return end_min + scale * end_range;
|
47
|
+
};
|
48
|
+
|
49
|
+
/*
|
50
|
+
#get_height(StackView, object) - Private
|
51
|
+
|
52
|
+
Takes a StackView options object and a book object. Returns a
|
53
|
+
normalized book height percentage, taking into account the minimum
|
54
|
+
height, maximum height, height multiple, and translating them onto
|
55
|
+
the percentage range specified in the stack options.
|
56
|
+
*/
|
57
|
+
var get_height = function(options, book) {
|
58
|
+
var height = parseInt(book.measurement_height_numeric, 10),
|
59
|
+
min = options.book.min_height,
|
60
|
+
max = options.book.max_height;
|
61
|
+
|
62
|
+
if (isNaN(height)) {
|
63
|
+
height = min;
|
64
|
+
}
|
65
|
+
height = Math.min(Math.max(height, min), max);
|
66
|
+
height = translate(
|
67
|
+
height,
|
68
|
+
options.plain.min_height,
|
69
|
+
options.plain.max_height,
|
70
|
+
options.plain.min_height_percentage,
|
71
|
+
options.plain.max_height_percentage
|
72
|
+
);
|
73
|
+
return height + '%';
|
74
|
+
};
|
75
|
+
|
76
|
+
/*
|
77
|
+
#get_author(object) - Private
|
78
|
+
|
79
|
+
Takes an item and returns the item's author, taking the first
|
80
|
+
author if an array of authors is defined.
|
81
|
+
*/
|
82
|
+
var get_author = function(item) {
|
83
|
+
var author = item.creator && item.creator.length ? item.creator[0] : '';
|
84
|
+
|
85
|
+
if(/^([^,]*)/.test(author)) {
|
86
|
+
author = author.match(/^[^,]*/);
|
87
|
+
}
|
88
|
+
|
89
|
+
return author;
|
90
|
+
};
|
91
|
+
|
92
|
+
|
93
|
+
window.StackView.register_type({
|
94
|
+
name: 'plain',
|
95
|
+
|
96
|
+
match: function(item) {
|
97
|
+
return item.format === 'plain' || item.format.match(/^plain\:/);
|
98
|
+
},
|
99
|
+
|
100
|
+
adapter: function(item, options) {
|
101
|
+
return {
|
102
|
+
heat: window.StackView.utils.get_heat(item.shelfrank),
|
103
|
+
box_height: get_height(options, item),
|
104
|
+
link: item.link,
|
105
|
+
title: item.title,
|
106
|
+
author: get_author(item),
|
107
|
+
year: item.pub_date,
|
108
|
+
format_descr: item.format.match(/^plain\:/) ? item.format.replace(/^plain\:/, '') : undefined
|
109
|
+
};
|
110
|
+
},
|
111
|
+
|
112
|
+
template: '\
|
113
|
+
<li class="stack-item stack-plain heat<%= heat %>" style="width:<%= box_height %>">\
|
114
|
+
<a href="<%= link %>" target="_blank">\
|
115
|
+
<span class="label-container">\
|
116
|
+
<span class="spine-text">\
|
117
|
+
<p class="plain-title"><%= title %></p>\
|
118
|
+
<p class="plain-format"><%= format_descr %></p>\
|
119
|
+
<p class="plain-author"><%= author %></p>\
|
120
|
+
</span>\
|
121
|
+
</span>\
|
122
|
+
<span class="spine-year"><%= year %></span>\
|
123
|
+
<span class="plain-top item-colors"></span>\
|
124
|
+
<span class="plain-edge item-colors"></span>\
|
125
|
+
</a>\
|
126
|
+
</li>'
|
127
|
+
});
|
128
|
+
})(jQuery, window);
|
@@ -0,0 +1,11 @@
|
|
1
|
+
// rails_stackview sprockets JS manifest that includes vendored stackview JS as well as custom JS
|
2
|
+
//
|
3
|
+
//= require jquery.stackview.js
|
4
|
+
//= require ./rails_stackview/plain.js
|
5
|
+
//
|
6
|
+
// Important to load browser, which adjusts the size of the stackview div,
|
7
|
+
// BEFORE auto-init, to make sure the div is the right size when stackview
|
8
|
+
// gets init'd, since it will base some things on the size of the div.
|
9
|
+
//= require ./rails_stackview/browser.js
|
10
|
+
//
|
11
|
+
//= require ./rails_stackview/auto_init.js
|