warclight 0.1.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.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.eslintrc +12 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +66 -0
  6. data/.solr_wrapper +5 -0
  7. data/.travis.yml +31 -0
  8. data/CONTRIBUTING.md +53 -0
  9. data/Gemfile +42 -0
  10. data/LICENSE.txt +11 -0
  11. data/README.md +79 -0
  12. data/Rakefile +16 -0
  13. data/app/assets/images/blacklight/compact.svg +25 -0
  14. data/app/assets/images/blacklight/logo.png +0 -0
  15. data/app/assets/javascripts/warclight/oembed_viewer.js +39 -0
  16. data/app/assets/javascripts/warclight/warclight.js +4 -0
  17. data/app/assets/stylesheets/warclight/application.scss +1 -0
  18. data/app/assets/stylesheets/warclight/warclight.scss +1 -0
  19. data/app/controllers/concerns/warclight/field_config_helpers.rb +11 -0
  20. data/app/helpers/warclight/application_helper.rb +8 -0
  21. data/app/jobs/warclight/application_job.rb +6 -0
  22. data/app/models/concerns/warclight/catalog.rb +8 -0
  23. data/app/models/concerns/warclight/search_behavior.rb +9 -0
  24. data/app/models/concerns/warclight/solr_document.rb +9 -0
  25. data/app/views/layouts/warclight/application.html.erb +14 -0
  26. data/bin/rails +14 -0
  27. data/config/routes.rb +4 -0
  28. data/lib/generators/warclight/install_generator.rb +55 -0
  29. data/lib/generators/warclight/templates/catalog_controller.rb +129 -0
  30. data/lib/generators/warclight/templates/warclight.js +2 -0
  31. data/lib/generators/warclight/templates/warclight.scss +3 -0
  32. data/lib/generators/warclight/update_generator.rb +22 -0
  33. data/lib/warclight.rb +7 -0
  34. data/lib/warclight/engine.rb +105 -0
  35. data/lib/warclight/version.rb +5 -0
  36. data/package.json +24 -0
  37. data/solr/conf/elevate.xml +42 -0
  38. data/solr/conf/lang/contractions_ca.txt +8 -0
  39. data/solr/conf/lang/contractions_fr.txt +15 -0
  40. data/solr/conf/lang/contractions_ga.txt +5 -0
  41. data/solr/conf/lang/contractions_it.txt +23 -0
  42. data/solr/conf/lang/hyphenations_ga.txt +5 -0
  43. data/solr/conf/lang/stemdict_nl.txt +6 -0
  44. data/solr/conf/lang/stoptags_ja.txt +420 -0
  45. data/solr/conf/lang/stopwords_ar.txt +125 -0
  46. data/solr/conf/lang/stopwords_bg.txt +193 -0
  47. data/solr/conf/lang/stopwords_ca.txt +220 -0
  48. data/solr/conf/lang/stopwords_cz.txt +172 -0
  49. data/solr/conf/lang/stopwords_da.txt +110 -0
  50. data/solr/conf/lang/stopwords_de.txt +294 -0
  51. data/solr/conf/lang/stopwords_el.txt +78 -0
  52. data/solr/conf/lang/stopwords_en.txt +54 -0
  53. data/solr/conf/lang/stopwords_es.txt +356 -0
  54. data/solr/conf/lang/stopwords_eu.txt +99 -0
  55. data/solr/conf/lang/stopwords_fa.txt +313 -0
  56. data/solr/conf/lang/stopwords_fi.txt +97 -0
  57. data/solr/conf/lang/stopwords_fr.txt +186 -0
  58. data/solr/conf/lang/stopwords_ga.txt +110 -0
  59. data/solr/conf/lang/stopwords_gl.txt +161 -0
  60. data/solr/conf/lang/stopwords_hi.txt +235 -0
  61. data/solr/conf/lang/stopwords_hu.txt +211 -0
  62. data/solr/conf/lang/stopwords_hy.txt +46 -0
  63. data/solr/conf/lang/stopwords_id.txt +359 -0
  64. data/solr/conf/lang/stopwords_it.txt +303 -0
  65. data/solr/conf/lang/stopwords_ja.txt +127 -0
  66. data/solr/conf/lang/stopwords_lv.txt +172 -0
  67. data/solr/conf/lang/stopwords_nl.txt +119 -0
  68. data/solr/conf/lang/stopwords_no.txt +194 -0
  69. data/solr/conf/lang/stopwords_pt.txt +253 -0
  70. data/solr/conf/lang/stopwords_ro.txt +233 -0
  71. data/solr/conf/lang/stopwords_ru.txt +243 -0
  72. data/solr/conf/lang/stopwords_sv.txt +133 -0
  73. data/solr/conf/lang/stopwords_th.txt +119 -0
  74. data/solr/conf/lang/stopwords_tr.txt +212 -0
  75. data/solr/conf/lang/userdict_ja.txt +29 -0
  76. data/solr/conf/managed-schema +1045 -0
  77. data/solr/conf/params.json +20 -0
  78. data/solr/conf/protwords.txt +21 -0
  79. data/solr/conf/schema.xml +350 -0
  80. data/solr/conf/solrconfig.xml +1361 -0
  81. data/solr/conf/stopwords.txt +14 -0
  82. data/solr/conf/synonyms.txt +29 -0
  83. data/tasks/warclight.rake +61 -0
  84. data/template.rb +15 -0
  85. data/vendor/assets/javascripts/responsiveTruncator.js +69 -0
  86. data/vendor/assets/javascripts/stickyfill.js +480 -0
  87. data/warclight.gemspec +38 -0
  88. metadata +312 -0
@@ -0,0 +1,14 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright ownership.
4
+ # The ASF licenses this file to You under the Apache License, Version 2.0
5
+ # (the "License"); you may not use this file except in compliance with
6
+ # the License. You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
@@ -0,0 +1,29 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ #-----------------------------------------------------------------------
14
+ #some test synonym mappings unlikely to appear in real input text
15
+ aaafoo => aaabar
16
+ bbbfoo => bbbfoo bbbbar
17
+ cccfoo => cccbar cccbaz
18
+ fooaaa,baraaa,bazaaa
19
+
20
+ # Some synonym groups specific to this example
21
+ GB,gib,gigabyte,gigabytes
22
+ MB,mib,megabyte,megabytes
23
+ Television, Televisions, TV, TVs
24
+ #notice we use "gib" instead of "GiB" so any WordDelimiterGraphFilter coming
25
+ #after us won't split it into two words.
26
+
27
+ # Synonym mappings can be used for spelling correction too
28
+ pixima => pixma
29
+
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solr_wrapper'
4
+ require 'engine_cart/rake_task'
5
+ require 'rspec/core/rake_task'
6
+ require 'warclight'
7
+
8
+ EngineCart.fingerprint_proc = EngineCart.rails_fingerprint_proc
9
+
10
+ desc 'Run test suite'
11
+ task ci: %w[warclight:generate] do
12
+ SolrWrapper.wrap do |solr|
13
+ solr.with_collection do
14
+ Rake::Task['warclight:seed'].invoke
15
+ within_test_app do
16
+ ## Do stuff inside warclight app here
17
+ end
18
+ Rake::Task['spec'].invoke
19
+ end
20
+ end
21
+ end
22
+
23
+ desc 'Run Eslint'
24
+ task :eslint do
25
+ system './node_modules/.bin/eslint app/assets/javascripts'
26
+ end
27
+
28
+ namespace :warclight do
29
+ desc 'Generate a test application'
30
+ task generate: %w[engine_cart:generate]
31
+
32
+ desc 'Run Solr and Blacklight for interactive development'
33
+ task :server, %i[rails_server_args] do |_t, args|
34
+ if File.exist? EngineCart.destination
35
+ within_test_app do
36
+ system 'bundle update'
37
+ end
38
+ else
39
+ Rake::Task['engine_cart:generate'].invoke
40
+ end
41
+
42
+ print 'Starting Solr...'
43
+ SolrWrapper.wrap do |solr|
44
+ puts 'done.'
45
+ solr.with_collection do
46
+ Rake::Task['warclight:seed'].invoke
47
+ within_test_app do
48
+ system "bundle exec rails s #{args[:rails_server_args]}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ desc 'Seed fixture data to Solr'
55
+ task :seed do
56
+ puts 'Seeding index with data from spec/fixtures/warcs/...'
57
+ # rubocop:disable Metrics/LineLength
58
+ system('curl -o ".internal_test_app/tmp/warc-indexer.jar" "http://alpha.library.yorku.ca/warc-indexer-3.0.0-SNAPSHOT-jar-with-dependencies.jar"')
59
+ system('java -Djava.io.tmpdir=.internal_test_app/tmp -jar .internal_test_app/tmp/warc-indexer.jar -i "York University Libraries" -n "Test Collection" -u "12345" -s http://localhost:8983/solr/blacklight-core spec/fixtures/warcs/*.gz')
60
+ end
61
+ end
data/template.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # We can remove `blacklight` and `blacklight_range_limit` once they are released
4
+ # since they are already dependents of Arclight (but we need to pin to particular branches)
5
+ gem 'blacklight', github: 'projectblacklight/blacklight'
6
+ gem 'blacklight_range_limit', github: 'projectblacklight/blacklight_range_limit', branch: 'blacklight-7'
7
+
8
+ gem 'warclight', github: 'archivesunleashed/warclight'
9
+
10
+ run 'bundle install'
11
+
12
+ generate 'blacklight:install', '--devise'
13
+ generate 'warclight:install', '-f'
14
+
15
+ rake 'db:migrate'
@@ -0,0 +1,69 @@
1
+ /*
2
+ * jQuery Responsive Truncator Plugin
3
+ *
4
+ * https://github.com/jkeck/responsiveTruncator
5
+ *
6
+ * VERSION 0.0.2
7
+ *
8
+ **/
9
+ (function( $ ){
10
+ $.fn.responsiveTruncate = function(options){
11
+ var $this = this;
12
+ $(window).bind("resize", function(){
13
+ removeTruncation($this);
14
+ addTruncation($this);
15
+ });
16
+
17
+ addTruncation($this);
18
+
19
+ function addTruncation(el){
20
+ el.each(function(){
21
+ if($(".responsiveTruncate", $(this)).length == 0){
22
+ var parent = $(this);
23
+ var fontSize = $(this).css('font-size');
24
+ var lineHeight = $(this).css("line-height") ? $(this).css("line-height").replace('px','') : Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
25
+ var total_lines = Math.ceil(parent.height() / lineHeight);
26
+ var settings = $.extend({
27
+ 'lines' : 3,
28
+ 'height' : null,
29
+ 'more' : 'more',
30
+ 'less' : 'less'
31
+ }, options);
32
+ var truncate_height;
33
+ if(settings.height){
34
+ truncate_height = settings.height;
35
+ }else{
36
+ truncate_height = (lineHeight * settings.lines);
37
+ }
38
+ if(parent.height() > truncate_height) {
39
+ var orig_content = parent.html();
40
+ parent.html("<div style='height: " + truncate_height + "px; overflow: hidden;' class='responsiveTruncate'></div>");
41
+ var truncate = $(".responsiveTruncate", parent);
42
+ truncate.html(orig_content);
43
+ truncate.after("<a class='responsiveTruncatorToggle' href='#'>" + settings.more + "</a>");
44
+ var toggle_link = $(".responsiveTruncatorToggle", parent);
45
+ toggle_link.click(function(){
46
+ var text = toggle_link.text() == settings.more ? settings.less : settings.more;
47
+ toggle_link.text(text);
48
+ if(truncate.height() == truncate_height){
49
+ truncate.css({height: '100%'})
50
+ }else{
51
+ truncate.css({height: truncate_height})
52
+ }
53
+ return false;
54
+ });
55
+ }
56
+ }
57
+ });
58
+ }
59
+
60
+ function removeTruncation(el){
61
+ el.each(function(){
62
+ if($(".responsiveTruncate", $(this)).length > 0){
63
+ $(this).html($(".responsiveTruncate", $(this)).html());
64
+ $(".responsiveTruncatorToggle", $(this)).remove();
65
+ }
66
+ });
67
+ }
68
+ };
69
+ })( jQuery );
@@ -0,0 +1,480 @@
1
+ /*!
2
+ * Stickyfill -- `position: sticky` polyfill
3
+ * v. 1.1.4 | https://github.com/wilddeer/stickyfill
4
+ * Copyright Oleg Korsunsky | http://wd.dizaina.net/
5
+ *
6
+ * MIT License
7
+ */
8
+ (function(doc, win) {
9
+ var watchArray = [],
10
+ scroll,
11
+ initialized = false,
12
+ html = doc.documentElement,
13
+ noop = function() {},
14
+ checkTimer,
15
+
16
+ //visibility API strings
17
+ hiddenPropertyName = 'hidden',
18
+ visibilityChangeEventName = 'visibilitychange';
19
+
20
+ //fallback to prefixed names in old webkit browsers
21
+ if (doc.webkitHidden !== undefined) {
22
+ hiddenPropertyName = 'webkitHidden';
23
+ visibilityChangeEventName = 'webkitvisibilitychange';
24
+ }
25
+
26
+ //test getComputedStyle
27
+ if (!win.getComputedStyle) {
28
+ seppuku();
29
+ }
30
+
31
+ //test for native support
32
+ var prefixes = ['', '-webkit-', '-moz-', '-ms-'],
33
+ block = document.createElement('div');
34
+
35
+ for (var i = prefixes.length - 1; i >= 0; i--) {
36
+ try {
37
+ block.style.position = prefixes[i] + 'sticky';
38
+ }
39
+ catch(e) {}
40
+ if (block.style.position != '') {
41
+ seppuku();
42
+ }
43
+ }
44
+
45
+ updateScrollPos();
46
+
47
+ //commit seppuku!
48
+ function seppuku() {
49
+ init = add = rebuild = pause = stop = kill = noop;
50
+ }
51
+
52
+ function mergeObjects(targetObj, sourceObject) {
53
+ for (var key in sourceObject) {
54
+ if (sourceObject.hasOwnProperty(key)) {
55
+ targetObj[key] = sourceObject[key];
56
+ }
57
+ }
58
+ }
59
+
60
+ function parseNumeric(val) {
61
+ return parseFloat(val) || 0;
62
+ }
63
+
64
+ function updateScrollPos() {
65
+ scroll = {
66
+ top: win.pageYOffset,
67
+ left: win.pageXOffset
68
+ };
69
+ }
70
+
71
+ function onScroll() {
72
+ if (win.pageXOffset != scroll.left) {
73
+ updateScrollPos();
74
+ rebuild();
75
+ return;
76
+ }
77
+
78
+ if (win.pageYOffset != scroll.top) {
79
+ updateScrollPos();
80
+ recalcAllPos();
81
+ }
82
+ }
83
+
84
+ //fixes flickering
85
+ function onWheel(event) {
86
+ setTimeout(function() {
87
+ if (win.pageYOffset != scroll.top) {
88
+ scroll.top = win.pageYOffset;
89
+ recalcAllPos();
90
+ }
91
+ }, 0);
92
+ }
93
+
94
+ function recalcAllPos() {
95
+ for (var i = watchArray.length - 1; i >= 0; i--) {
96
+ recalcElementPos(watchArray[i]);
97
+ }
98
+ }
99
+
100
+ function recalcElementPos(el) {
101
+ if (!el.inited) return;
102
+
103
+ var currentMode = (scroll.top <= el.limit.start? 0: scroll.top >= el.limit.end? 2: 1);
104
+
105
+ if (el.mode != currentMode) {
106
+ switchElementMode(el, currentMode);
107
+ }
108
+ }
109
+
110
+ //checks whether stickies start or stop positions have changed
111
+ function fastCheck() {
112
+ for (var i = watchArray.length - 1; i >= 0; i--) {
113
+ if (!watchArray[i].inited) continue;
114
+
115
+ var deltaTop = Math.abs(getDocOffsetTop(watchArray[i].clone) - watchArray[i].docOffsetTop),
116
+ deltaHeight = Math.abs(watchArray[i].parent.node.offsetHeight - watchArray[i].parent.height);
117
+
118
+ if (deltaTop >= 2 || deltaHeight >= 2) return false;
119
+ }
120
+ return true;
121
+ }
122
+
123
+ function initElement(el) {
124
+ if (isNaN(parseFloat(el.computed.top)) || el.isCell || el.computed.display == 'none') return;
125
+
126
+ el.inited = true;
127
+
128
+ if (!el.clone) clone(el);
129
+ if (el.parent.computed.position != 'absolute' &&
130
+ el.parent.computed.position != 'relative') el.parent.node.style.position = 'relative';
131
+
132
+ recalcElementPos(el);
133
+
134
+ el.parent.height = el.parent.node.offsetHeight;
135
+ el.docOffsetTop = getDocOffsetTop(el.clone);
136
+ }
137
+
138
+ function deinitElement(el) {
139
+ var deinitParent = true;
140
+
141
+ el.clone && killClone(el);
142
+ mergeObjects(el.node.style, el.css);
143
+
144
+ //check whether element's parent is used by other stickies
145
+ for (var i = watchArray.length - 1; i >= 0; i--) {
146
+ if (watchArray[i].node !== el.node && watchArray[i].parent.node === el.parent.node) {
147
+ deinitParent = false;
148
+ break;
149
+ }
150
+ };
151
+
152
+ if (deinitParent) el.parent.node.style.position = el.parent.css.position;
153
+ el.mode = -1;
154
+ }
155
+
156
+ function initAll() {
157
+ for (var i = watchArray.length - 1; i >= 0; i--) {
158
+ initElement(watchArray[i]);
159
+ }
160
+ }
161
+
162
+ function deinitAll() {
163
+ for (var i = watchArray.length - 1; i >= 0; i--) {
164
+ deinitElement(watchArray[i]);
165
+ }
166
+ }
167
+
168
+ function switchElementMode(el, mode) {
169
+ var nodeStyle = el.node.style;
170
+
171
+ switch (mode) {
172
+ case 0:
173
+ nodeStyle.position = 'absolute';
174
+ nodeStyle.left = el.offset.left + 'px';
175
+ nodeStyle.right = el.offset.right + 'px';
176
+ nodeStyle.top = el.offset.top + 'px';
177
+ nodeStyle.bottom = 'auto';
178
+ nodeStyle.width = 'auto';
179
+ nodeStyle.marginLeft = 0;
180
+ nodeStyle.marginRight = 0;
181
+ nodeStyle.marginTop = 0;
182
+ break;
183
+
184
+ case 1:
185
+ nodeStyle.position = 'fixed';
186
+ nodeStyle.left = el.box.left + 'px';
187
+ nodeStyle.right = el.box.right + 'px';
188
+ nodeStyle.top = el.css.top;
189
+ nodeStyle.bottom = 'auto';
190
+ nodeStyle.width = 'auto';
191
+ nodeStyle.marginLeft = 0;
192
+ nodeStyle.marginRight = 0;
193
+ nodeStyle.marginTop = 0;
194
+ break;
195
+
196
+ case 2:
197
+ nodeStyle.position = 'absolute';
198
+ nodeStyle.left = el.offset.left + 'px';
199
+ nodeStyle.right = el.offset.right + 'px';
200
+ nodeStyle.top = 'auto';
201
+ nodeStyle.bottom = 0;
202
+ nodeStyle.width = 'auto';
203
+ nodeStyle.marginLeft = 0;
204
+ nodeStyle.marginRight = 0;
205
+ break;
206
+ }
207
+
208
+ el.mode = mode;
209
+ }
210
+
211
+ function clone(el) {
212
+ el.clone = document.createElement('div');
213
+
214
+ var refElement = el.node.nextSibling || el.node,
215
+ cloneStyle = el.clone.style;
216
+
217
+ cloneStyle.height = el.height + 'px';
218
+ cloneStyle.width = el.width + 'px';
219
+ cloneStyle.marginTop = el.computed.marginTop;
220
+ cloneStyle.marginBottom = el.computed.marginBottom;
221
+ cloneStyle.marginLeft = el.computed.marginLeft;
222
+ cloneStyle.marginRight = el.computed.marginRight;
223
+ cloneStyle.padding = cloneStyle.border = cloneStyle.borderSpacing = 0;
224
+ cloneStyle.fontSize = '1em';
225
+ cloneStyle.position = 'static';
226
+ cloneStyle.cssFloat = el.computed.cssFloat;
227
+
228
+ el.node.parentNode.insertBefore(el.clone, refElement);
229
+ }
230
+
231
+ function killClone(el) {
232
+ el.clone.parentNode.removeChild(el.clone);
233
+ el.clone = undefined;
234
+ }
235
+
236
+ function getElementParams(node) {
237
+ var computedStyle = getComputedStyle(node),
238
+ parentNode = node.parentNode,
239
+ parentComputedStyle = getComputedStyle(parentNode),
240
+ cachedPosition = node.style.position;
241
+
242
+ node.style.position = 'relative';
243
+
244
+ var computed = {
245
+ top: computedStyle.top,
246
+ marginTop: computedStyle.marginTop,
247
+ marginBottom: computedStyle.marginBottom,
248
+ marginLeft: computedStyle.marginLeft,
249
+ marginRight: computedStyle.marginRight,
250
+ cssFloat: computedStyle.cssFloat,
251
+ display: computedStyle.display
252
+ },
253
+ numeric = {
254
+ top: parseNumeric(computedStyle.top),
255
+ marginBottom: parseNumeric(computedStyle.marginBottom),
256
+ paddingLeft: parseNumeric(computedStyle.paddingLeft),
257
+ paddingRight: parseNumeric(computedStyle.paddingRight),
258
+ borderLeftWidth: parseNumeric(computedStyle.borderLeftWidth),
259
+ borderRightWidth: parseNumeric(computedStyle.borderRightWidth)
260
+ };
261
+
262
+ node.style.position = cachedPosition;
263
+
264
+ var css = {
265
+ position: node.style.position,
266
+ top: node.style.top,
267
+ bottom: node.style.bottom,
268
+ left: node.style.left,
269
+ right: node.style.right,
270
+ width: node.style.width,
271
+ marginTop: node.style.marginTop,
272
+ marginLeft: node.style.marginLeft,
273
+ marginRight: node.style.marginRight
274
+ },
275
+ nodeOffset = getElementOffset(node),
276
+ parentOffset = getElementOffset(parentNode),
277
+
278
+ parent = {
279
+ node: parentNode,
280
+ css: {
281
+ position: parentNode.style.position
282
+ },
283
+ computed: {
284
+ position: parentComputedStyle.position
285
+ },
286
+ numeric: {
287
+ borderLeftWidth: parseNumeric(parentComputedStyle.borderLeftWidth),
288
+ borderRightWidth: parseNumeric(parentComputedStyle.borderRightWidth),
289
+ borderTopWidth: parseNumeric(parentComputedStyle.borderTopWidth),
290
+ borderBottomWidth: parseNumeric(parentComputedStyle.borderBottomWidth)
291
+ }
292
+ },
293
+
294
+ el = {
295
+ node: node,
296
+ box: {
297
+ left: nodeOffset.win.left,
298
+ right: html.clientWidth - nodeOffset.win.right
299
+ },
300
+ offset: {
301
+ top: nodeOffset.win.top - parentOffset.win.top - parent.numeric.borderTopWidth,
302
+ left: nodeOffset.win.left - parentOffset.win.left - parent.numeric.borderLeftWidth,
303
+ right: -nodeOffset.win.right + parentOffset.win.right - parent.numeric.borderRightWidth
304
+ },
305
+ css: css,
306
+ isCell: computedStyle.display == 'table-cell',
307
+ computed: computed,
308
+ numeric: numeric,
309
+ width: nodeOffset.win.right - nodeOffset.win.left,
310
+ height: nodeOffset.win.bottom - nodeOffset.win.top,
311
+ mode: -1,
312
+ inited: false,
313
+ parent: parent,
314
+ limit: {
315
+ start: nodeOffset.doc.top - numeric.top,
316
+ end: parentOffset.doc.top + parentNode.offsetHeight - parent.numeric.borderBottomWidth -
317
+ node.offsetHeight - numeric.top - numeric.marginBottom
318
+ }
319
+ };
320
+
321
+ return el;
322
+ }
323
+
324
+ function getDocOffsetTop(node) {
325
+ var docOffsetTop = 0;
326
+
327
+ while (node) {
328
+ docOffsetTop += node.offsetTop;
329
+ node = node.offsetParent;
330
+ }
331
+
332
+ return docOffsetTop;
333
+ }
334
+
335
+ function getElementOffset(node) {
336
+ var box = node.getBoundingClientRect();
337
+
338
+ return {
339
+ doc: {
340
+ top: box.top + win.pageYOffset,
341
+ left: box.left + win.pageXOffset
342
+ },
343
+ win: box
344
+ };
345
+ }
346
+
347
+ function startFastCheckTimer() {
348
+ checkTimer = setInterval(function() {
349
+ !fastCheck() && rebuild();
350
+ }, 500);
351
+ }
352
+
353
+ function stopFastCheckTimer() {
354
+ clearInterval(checkTimer);
355
+ }
356
+
357
+ function handlePageVisibilityChange() {
358
+ if (!initialized) return;
359
+
360
+ if (document[hiddenPropertyName]) {
361
+ stopFastCheckTimer();
362
+ }
363
+ else {
364
+ startFastCheckTimer();
365
+ }
366
+ }
367
+
368
+ function init() {
369
+ if (initialized) return;
370
+
371
+ updateScrollPos();
372
+ initAll();
373
+
374
+ win.addEventListener('scroll', onScroll);
375
+ win.addEventListener('wheel', onWheel);
376
+
377
+ //watch for width changes
378
+ win.addEventListener('resize', rebuild);
379
+ win.addEventListener('orientationchange', rebuild);
380
+
381
+ //watch for page visibility
382
+ doc.addEventListener(visibilityChangeEventName, handlePageVisibilityChange);
383
+
384
+ startFastCheckTimer();
385
+
386
+ initialized = true;
387
+ }
388
+
389
+ function rebuild() {
390
+ if (!initialized) return;
391
+
392
+ deinitAll();
393
+
394
+ for (var i = watchArray.length - 1; i >= 0; i--) {
395
+ watchArray[i] = getElementParams(watchArray[i].node);
396
+ }
397
+
398
+ initAll();
399
+ }
400
+
401
+ function pause() {
402
+ win.removeEventListener('scroll', onScroll);
403
+ win.removeEventListener('wheel', onWheel);
404
+ win.removeEventListener('resize', rebuild);
405
+ win.removeEventListener('orientationchange', rebuild);
406
+ doc.removeEventListener(visibilityChangeEventName, handlePageVisibilityChange);
407
+
408
+ stopFastCheckTimer();
409
+
410
+ initialized = false;
411
+ }
412
+
413
+ function stop() {
414
+ pause();
415
+ deinitAll();
416
+ }
417
+
418
+ function kill() {
419
+ stop();
420
+
421
+ //empty the array without loosing the references,
422
+ //the most performant method according to http://jsperf.com/empty-javascript-array
423
+ while (watchArray.length) {
424
+ watchArray.pop();
425
+ }
426
+ }
427
+
428
+ function add(node) {
429
+ //check if Stickyfill is already applied to the node
430
+ for (var i = watchArray.length - 1; i >= 0; i--) {
431
+ if (watchArray[i].node === node) return;
432
+ };
433
+
434
+ var el = getElementParams(node);
435
+
436
+ watchArray.push(el);
437
+
438
+ if (!initialized) {
439
+ init();
440
+ }
441
+ else {
442
+ initElement(el);
443
+ }
444
+ }
445
+
446
+ function remove(node) {
447
+ for (var i = watchArray.length - 1; i >= 0; i--) {
448
+ if (watchArray[i].node === node) {
449
+ deinitElement(watchArray[i]);
450
+ watchArray.splice(i, 1);
451
+ }
452
+ };
453
+ }
454
+
455
+ //expose Stickyfill
456
+ win.Stickyfill = {
457
+ stickies: watchArray,
458
+ add: add,
459
+ remove: remove,
460
+ init: init,
461
+ rebuild: rebuild,
462
+ pause: pause,
463
+ stop: stop,
464
+ kill: kill
465
+ };
466
+ })(document, window);
467
+
468
+
469
+ //if jQuery is available -- create a plugin
470
+ if (window.jQuery) {
471
+ (function($) {
472
+ $.fn.Stickyfill = function(options) {
473
+ this.each(function() {
474
+ Stickyfill.add(this);
475
+ });
476
+
477
+ return this;
478
+ };
479
+ })(window.jQuery);
480
+ }