arclight 0.0.1 → 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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc +12 -0
  3. data/.gitignore +5 -0
  4. data/.rubocop.yml +66 -0
  5. data/.solr_wrapper +5 -0
  6. data/.travis.yml +30 -2
  7. data/CONTRIBUTING.md +43 -0
  8. data/Gemfile +36 -0
  9. data/LICENSE.txt +1 -0
  10. data/README.md +85 -12
  11. data/Rakefile +14 -3
  12. data/app/assets/images/blacklight/compact.svg +25 -0
  13. data/app/assets/images/blacklight/logo.png +0 -0
  14. data/app/assets/javascripts/arclight/arclight.js +9 -0
  15. data/app/assets/javascripts/arclight/collection_context.js +18 -0
  16. data/app/assets/javascripts/arclight/collection_navigation.js +114 -0
  17. data/app/assets/javascripts/arclight/collection_scrollspy.js +6 -0
  18. data/app/assets/javascripts/arclight/component_ancestors.js +56 -0
  19. data/app/assets/javascripts/arclight/oembed_viewer.js +39 -0
  20. data/app/assets/javascripts/arclight/truncator.js.erb +23 -0
  21. data/app/assets/stylesheets/arclight/application.scss +13 -0
  22. data/app/assets/stylesheets/arclight/bootstrap_overrides.scss +3 -0
  23. data/app/assets/stylesheets/arclight/modules/collection_search.scss +3 -0
  24. data/app/assets/stylesheets/arclight/modules/hierarchy_and_online_contents.scss +174 -0
  25. data/app/assets/stylesheets/arclight/modules/highlights.scss +10 -0
  26. data/app/assets/stylesheets/arclight/modules/layout.scss +33 -0
  27. data/app/assets/stylesheets/arclight/modules/mastheads.scss +60 -0
  28. data/app/assets/stylesheets/arclight/modules/repositories.scss +29 -0
  29. data/app/assets/stylesheets/arclight/modules/repository_card.scss +54 -0
  30. data/app/assets/stylesheets/arclight/modules/search_results.scss +75 -0
  31. data/app/assets/stylesheets/arclight/modules/show_collection.scss +78 -0
  32. data/app/assets/stylesheets/arclight/modules/sidebar.scss +16 -0
  33. data/app/assets/stylesheets/arclight/variables.scss +2 -0
  34. data/app/controllers/arclight/repositories_controller.rb +40 -0
  35. data/app/controllers/concerns/arclight/field_config_helpers.rb +86 -0
  36. data/app/factories/blacklight_field_configuration_factory.rb +29 -0
  37. data/app/helpers/arclight_helper.rb +173 -0
  38. data/app/models/arclight/parent.rb +24 -0
  39. data/app/models/arclight/parents.rb +34 -0
  40. data/app/models/arclight/requests/google_form.rb +44 -0
  41. data/app/models/concerns/arclight/catalog.rb +22 -0
  42. data/app/models/concerns/arclight/search_behavior.rb +46 -0
  43. data/app/models/concerns/arclight/solr_document.rb +131 -0
  44. data/app/presenters/arclight/index_presenter.rb +10 -0
  45. data/app/presenters/arclight/show_presenter.rb +27 -0
  46. data/app/views/arclight/.keep +0 -0
  47. data/app/views/arclight/repositories/_in_person_repository.html.erb +19 -0
  48. data/app/views/arclight/repositories/_repository.html.erb +62 -0
  49. data/app/views/arclight/repositories/index.html.erb +4 -0
  50. data/app/views/arclight/repositories/show.html.erb +38 -0
  51. data/app/views/arclight/requests/_google_form.html.erb +11 -0
  52. data/app/views/arclight/viewers/_oembed.html.erb +7 -0
  53. data/app/views/catalog/_arclight_document_index_header.html.erb +13 -0
  54. data/app/views/catalog/_arclight_document_index_header_hierarchy_default.html.erb +0 -0
  55. data/app/views/catalog/_arclight_document_index_header_online_contents_default.html.erb +0 -0
  56. data/app/views/catalog/_arclight_document_show_header.html.erb +15 -0
  57. data/app/views/catalog/_arclight_document_show_header_collection.html.erb +12 -0
  58. data/app/views/catalog/_arclight_index_compact_default.html.erb +15 -0
  59. data/app/views/catalog/_arclight_online_content_indicator.html.erb +5 -0
  60. data/app/views/catalog/_arclight_rangelimit.html.erb +24 -0
  61. data/app/views/catalog/_arclight_viewer_default.html.erb +1 -0
  62. data/app/views/catalog/_collection_contents.html.erb +12 -0
  63. data/app/views/catalog/_collection_count.html.erb +7 -0
  64. data/app/views/catalog/_collection_downloads.html.erb +17 -0
  65. data/app/views/catalog/_collection_online_contents.html.erb +17 -0
  66. data/app/views/catalog/_collection_overview.html.erb +7 -0
  67. data/app/views/catalog/_component_overview.html.erb +46 -0
  68. data/app/views/catalog/_context_card.html.erb +27 -0
  69. data/app/views/catalog/_context_sidebar.html.erb +8 -0
  70. data/app/views/catalog/_custom_metadata.html.erb +16 -0
  71. data/app/views/catalog/_home.html.erb +1 -0
  72. data/app/views/catalog/_index_breadcrumb_default.html.erb +3 -0
  73. data/app/views/catalog/_index_default.html.erb +17 -0
  74. data/app/views/catalog/_index_header.html.erb +7 -0
  75. data/app/views/catalog/_index_header_hierarchy_default.html.erb +42 -0
  76. data/app/views/catalog/_index_header_online_contents_default.html.erb +1 -0
  77. data/app/views/catalog/_index_hierarchy_default.html.erb +28 -0
  78. data/app/views/catalog/_index_online_contents_default.html.erb +6 -0
  79. data/app/views/catalog/_results_histogram.html.erb +10 -0
  80. data/app/views/catalog/_search_results.html.erb +31 -0
  81. data/app/views/catalog/_search_results_repository.html.erb +6 -0
  82. data/app/views/catalog/_search_within_form.html.erb +16 -0
  83. data/app/views/catalog/_show_breadcrumbs_default.html.erb +7 -0
  84. data/app/views/catalog/_show_collection.html.erb +40 -0
  85. data/app/views/catalog/_show_component_sidebar.html.erb +12 -0
  86. data/app/views/catalog/_show_default.html.erb +32 -0
  87. data/app/views/catalog/_show_header.html.erb +5 -0
  88. data/app/views/catalog/_show_sidebar.html.erb +30 -0
  89. data/app/views/catalog/index.html.erb +8 -0
  90. data/app/views/layouts/catalog_result.html.erb +7 -0
  91. data/app/views/shared/_breadcrumbs.html.erb +15 -0
  92. data/app/views/shared/_context_sidebar.html.erb +8 -0
  93. data/app/views/shared/_header_navbar.html.erb +54 -0
  94. data/app/views/shared/_main_menu_links.html.erb +6 -0
  95. data/arclight.gemspec +17 -4
  96. data/bin/rails +13 -0
  97. data/config/locales/arclight.en.yml +65 -0
  98. data/config/routes.rb +6 -0
  99. data/lib/arclight.rb +5 -0
  100. data/lib/arclight/custom_component.rb +98 -0
  101. data/lib/arclight/custom_document.rb +93 -0
  102. data/lib/arclight/digital_object.rb +26 -0
  103. data/lib/arclight/engine.rb +55 -0
  104. data/lib/arclight/exceptions.rb +18 -0
  105. data/lib/arclight/indexer.rb +9 -0
  106. data/lib/arclight/normalized_date.rb +45 -0
  107. data/lib/arclight/normalized_id.rb +25 -0
  108. data/lib/arclight/normalized_title.rb +30 -0
  109. data/lib/arclight/repository.rb +91 -0
  110. data/lib/arclight/shared_indexing_behavior.rb +97 -0
  111. data/lib/arclight/shared_terminology_behavior.rb +65 -0
  112. data/lib/arclight/solr_ead_indexer_ext.rb +159 -0
  113. data/lib/arclight/version.rb +3 -1
  114. data/lib/arclight/viewer.rb +45 -0
  115. data/lib/arclight/viewers/oembed.rb +56 -0
  116. data/lib/arclight/year_range.rb +102 -0
  117. data/lib/generators/arclight/install_generator.rb +63 -0
  118. data/lib/generators/arclight/templates/arclight.js +2 -0
  119. data/lib/generators/arclight/templates/arclight.scss +3 -0
  120. data/lib/generators/arclight/templates/catalog_controller.rb +347 -0
  121. data/lib/generators/arclight/templates/config/downloads.yml +13 -0
  122. data/lib/generators/arclight/templates/config/repositories.yml +42 -0
  123. data/lib/generators/arclight/update_generator.rb +22 -0
  124. data/lib/tasks/index.rake +87 -0
  125. data/package.json +24 -0
  126. data/solr/conf/_rest_managed.json +3 -0
  127. data/solr/conf/admin-extra.html +31 -0
  128. data/solr/conf/elevate.xml +36 -0
  129. data/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  130. data/solr/conf/protwords.txt +21 -0
  131. data/solr/conf/schema.xml +631 -0
  132. data/solr/conf/scripts.conf +24 -0
  133. data/solr/conf/solrconfig.xml +393 -0
  134. data/solr/conf/spellings.txt +2 -0
  135. data/solr/conf/stopwords.txt +58 -0
  136. data/solr/conf/stopwords_en.txt +58 -0
  137. data/solr/conf/synonyms.txt +31 -0
  138. data/solr/conf/xslt/example.xsl +132 -0
  139. data/solr/conf/xslt/example_atom.xsl +67 -0
  140. data/solr/conf/xslt/example_rss.xsl +66 -0
  141. data/solr/conf/xslt/luke.xsl +337 -0
  142. data/tasks/arclight.rake +68 -0
  143. data/template.rb +15 -0
  144. data/vendor/assets/javascripts/responsiveTruncator.js +69 -0
  145. data/vendor/assets/javascripts/stickyfill.js +480 -0
  146. metadata +301 -6
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solr_wrapper'
4
+ require 'engine_cart/rake_task'
5
+ require 'rspec/core/rake_task'
6
+ require 'arclight'
7
+
8
+ EngineCart.fingerprint_proc = EngineCart.rails_fingerprint_proc
9
+
10
+ desc 'Run test suite'
11
+ task ci: %w[arclight:generate] do
12
+ SolrWrapper.wrap do |solr|
13
+ solr.with_collection do
14
+ Rake::Task['arclight:seed'].invoke
15
+ within_test_app do
16
+ ## Do stuff inside arclight 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 :arclight 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['arclight: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/ead...'
57
+ Dir.glob('spec/fixtures/ead/*.xml').each do |file|
58
+ system("FILE=#{file} rake arclight:index") # no REPOSITORY_ID
59
+ end
60
+ Dir.glob('spec/fixtures/ead/*').each do |dir|
61
+ next unless File.directory?(dir)
62
+ system("REPOSITORY_ID=#{File.basename(dir)} " \
63
+ 'REPOSITORY_FILE=spec/fixtures/config/repositories.yml ' \
64
+ "DIR=#{dir} " \
65
+ 'rake arclight:index_dir')
66
+ end
67
+ end
68
+ 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 'arclight', github: 'sul-dlss/arclight'
9
+
10
+ run 'bundle install'
11
+
12
+ generate 'blacklight:install', '--devise'
13
+ generate 'arclight: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
+ }