integral 1.3.0 → 1.4.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 (205) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -30
  3. data/Rakefile +1 -1
  4. data/app/assets/images/integral/defaults/no_image_available.jpg +0 -0
  5. data/app/assets/javascripts/integral/backend.js +102 -11
  6. data/app/assets/javascripts/integral/frontend.js +37 -0
  7. data/app/assets/javascripts/integral/support/confirm_modal.coffee +2 -2
  8. data/app/assets/javascripts/integral/support/gallery.coffee +71 -54
  9. data/app/assets/javascripts/integral/support/lib/lazysizes.js +755 -0
  10. data/app/assets/javascripts/integral/support/lib/materialize-tags.js +49 -44
  11. data/app/assets/javascripts/integral/support/ls.instagram.js +57 -0
  12. data/app/assets/javascripts/integral/support/ls.twitter.js +66 -0
  13. data/app/assets/javascripts/integral/support/record_selector.coffee +1 -1
  14. data/app/assets/javascripts/integral/support/remote_form.coffee +5 -2
  15. data/app/assets/stylesheets/integral/backend.sass +2 -1
  16. data/app/assets/stylesheets/integral/backend/_foundation_settings.scss +3 -4
  17. data/app/assets/stylesheets/integral/backend/dashboard-layout.scss +4 -1
  18. data/app/assets/stylesheets/integral/backend/materialize-tags.sass +1 -1
  19. data/app/assets/stylesheets/integral/backend/modules/timeline.scss +214 -0
  20. data/app/assets/stylesheets/integral/backend/shared.sass +80 -11
  21. data/app/assets/stylesheets/integral/frontend.scss +45 -0
  22. data/app/assets/stylesheets/integral/frontend/_foundation_settings.scss +2 -2
  23. data/app/assets/stylesheets/integral/frontend/blog.sass +155 -142
  24. data/app/assets/stylesheets/integral/frontend/layout.sass +3 -3
  25. data/app/assets/stylesheets/integral/frontend/modules/article-footer.scss +55 -0
  26. data/app/assets/stylesheets/integral/frontend/modules/article.scss +34 -0
  27. data/app/assets/stylesheets/integral/frontend/modules/horizontal-post.scss +44 -0
  28. data/app/assets/stylesheets/integral/frontend/modules/inline-articles.scss +23 -0
  29. data/app/assets/stylesheets/integral/frontend/modules/latest-post.scss +37 -0
  30. data/app/assets/stylesheets/integral/frontend/modules/list-widget.scss +50 -0
  31. data/app/assets/stylesheets/integral/frontend/modules/piped-list.scss +33 -0
  32. data/app/assets/stylesheets/integral/frontend/modules/post-tags.scss +19 -0
  33. data/app/assets/stylesheets/integral/frontend/modules/scroll-container.scss +9 -0
  34. data/app/assets/stylesheets/integral/frontend/modules/sidebar-articles.scss +42 -0
  35. data/app/assets/stylesheets/integral/frontend/modules/sidebar-tags.scss +6 -0
  36. data/app/assets/stylesheets/integral/frontend/modules/sidebar-widget.scss +47 -0
  37. data/app/assets/stylesheets/integral/frontend/modules/vertical-post.scss +31 -0
  38. data/app/assets/stylesheets/integral/frontend/share_modal.sass +0 -5
  39. data/app/assets/stylesheets/integral/support/gallery.sass +8 -0
  40. data/app/assets/stylesheets/integral/support/media-query-indicator.sass +6 -0
  41. data/app/controllers/integral/application_controller.rb +7 -1
  42. data/app/controllers/integral/backend/activities_controller.rb +13 -2
  43. data/app/controllers/integral/backend/base_controller.rb +60 -7
  44. data/app/controllers/integral/backend/categories_controller.rb +49 -0
  45. data/app/controllers/integral/backend/pages_controller.rb +7 -2
  46. data/app/controllers/integral/backend/posts_controller.rb +8 -3
  47. data/app/controllers/integral/backend/static_pages_controller.rb +4 -0
  48. data/app/controllers/integral/backend/users_controller.rb +13 -7
  49. data/app/controllers/integral/categories_controller.rb +31 -0
  50. data/app/controllers/integral/pages_controller.rb +1 -1
  51. data/app/controllers/integral/posts_controller.rb +5 -3
  52. data/app/decorators/integral/category_decorator.rb +30 -0
  53. data/app/decorators/integral/category_version_decorator.rb +7 -0
  54. data/app/decorators/integral/image_version_decorator.rb +7 -0
  55. data/app/decorators/integral/list_decorator.rb +1 -1
  56. data/app/decorators/integral/list_version_decorator.rb +7 -0
  57. data/app/decorators/integral/page_version_decorator.rb +7 -0
  58. data/app/decorators/integral/post_decorator.rb +9 -1
  59. data/app/decorators/integral/post_version_decorator.rb +7 -0
  60. data/app/decorators/integral/user_decorator.rb +1 -1
  61. data/app/decorators/integral/user_version_decorator.rb +7 -0
  62. data/app/decorators/integral/version_decorator.rb +51 -12
  63. data/app/helpers/integral/backend/base_helper.rb +56 -2
  64. data/app/helpers/integral/blog_helper.rb +21 -4
  65. data/app/jobs/integral/webhook/delivery_job.rb +37 -0
  66. data/app/mailers/integral/contact_mailer.rb +4 -1
  67. data/app/models/concerns/integral/lazy_contentable.rb +54 -0
  68. data/app/models/concerns/integral/webhook/delivery.rb +30 -0
  69. data/app/models/concerns/integral/webhook/observable.rb +23 -0
  70. data/app/models/integral/category.rb +20 -0
  71. data/app/models/integral/category_version.rb +8 -0
  72. data/app/models/integral/list_item.rb +1 -2
  73. data/app/models/integral/page.rb +18 -3
  74. data/app/models/integral/post.rb +28 -1
  75. data/app/models/integral/version.rb +2 -2
  76. data/app/models/integral/webhook/endpoint.rb +40 -0
  77. data/app/models/integral/webhook/event.rb +20 -0
  78. data/app/policies/integral/base_policy.rb +1 -0
  79. data/app/policies/integral/category_policy.rb +9 -0
  80. data/app/serializers/integral/post_serializer.rb +24 -0
  81. data/app/uploaders/integral/avatar_uploader.rb +1 -1
  82. data/app/views/integral/backend/activities/_activity.haml +21 -0
  83. data/app/views/integral/backend/activities/_grid.haml +1 -2
  84. data/app/views/integral/backend/activities/shared/_grid.haml +3 -2
  85. data/app/views/integral/backend/activities/shared/{_listing.haml → index.haml} +1 -0
  86. data/app/views/integral/backend/activities/shared/{_log.haml → show.haml} +0 -0
  87. data/app/views/integral/backend/categories/_modal.haml +25 -0
  88. data/app/views/integral/backend/lists/_child_fields.haml +1 -1
  89. data/app/views/integral/backend/lists/_item_container.haml +1 -1
  90. data/app/views/integral/backend/lists/_item_modal.haml +1 -1
  91. data/app/views/integral/backend/lists/_list_item_fields.haml +1 -1
  92. data/app/views/integral/backend/pages/_form.haml +1 -4
  93. data/app/views/integral/backend/pages/_grid.haml +34 -9
  94. data/app/views/integral/backend/pages/edit.haml +9 -3
  95. data/app/views/integral/backend/pages/index.haml +11 -21
  96. data/app/views/integral/backend/pages/list.haml +22 -0
  97. data/app/views/integral/backend/pages/show.haml +48 -0
  98. data/app/views/integral/backend/posts/_form.haml +8 -6
  99. data/app/views/integral/backend/posts/_grid.haml +33 -7
  100. data/app/views/integral/backend/posts/index.haml +13 -19
  101. data/app/views/integral/backend/posts/list.haml +20 -0
  102. data/app/views/integral/backend/posts/show.haml +54 -0
  103. data/app/views/integral/backend/shared/_activity_modal.haml +13 -0
  104. data/app/views/integral/backend/shared/cards/_categories.haml +34 -0
  105. data/app/views/integral/backend/{static_pages/_card.haml → shared/cards/_object.haml} +0 -0
  106. data/app/views/integral/backend/shared/cards/_recent_activity.haml +20 -0
  107. data/app/views/integral/backend/shared/cards/_recent_pages.haml +19 -0
  108. data/app/views/integral/backend/shared/cards/_recent_posts.haml +18 -0
  109. data/app/views/integral/backend/shared/cards/_recent_user_activity.haml +1 -0
  110. data/app/views/integral/backend/shared/cards/_recent_users.haml +19 -0
  111. data/app/views/integral/backend/shared/cards/_top_post_authors.haml +19 -0
  112. data/app/views/integral/backend/shared/record_selector/_record.haml +6 -4
  113. data/app/views/integral/backend/static_pages/dashboard.haml +13 -11
  114. data/app/views/integral/backend/users/_grid.haml +24 -7
  115. data/app/views/integral/backend/users/index.haml +11 -17
  116. data/app/views/integral/backend/users/list.haml +18 -0
  117. data/app/views/integral/backend/users/show.haml +5 -11
  118. data/app/views/integral/categories/show.haml +5 -0
  119. data/app/views/integral/posts/_article_footer.haml +17 -0
  120. data/app/views/integral/posts/_card.haml +11 -0
  121. data/app/views/integral/posts/_latest_post.haml +8 -0
  122. data/app/views/integral/posts/_most_read_section.haml +8 -0
  123. data/app/views/integral/posts/_post.haml +11 -0
  124. data/app/views/integral/posts/_similar_posts.haml +5 -0
  125. data/app/views/integral/posts/index.haml +6 -5
  126. data/app/views/integral/posts/templates/default.haml +34 -33
  127. data/app/views/integral/shared/_subscribe_modal.haml +14 -0
  128. data/app/views/integral/shared/blog/_categories.haml +15 -0
  129. data/app/views/integral/shared/blog/_layout.haml +9 -0
  130. data/app/views/integral/shared/blog/_sidebar.haml +10 -0
  131. data/app/views/integral/shared/gallery/_placeholder.haml +1 -1
  132. data/app/views/integral/shared/gallery/_slide.haml +2 -2
  133. data/app/views/integral/shared/gallery/gallery.haml +5 -2
  134. data/app/views/integral/shared/sidebar/_item.haml +8 -0
  135. data/app/views/integral/shared/sidebar/_newsletter_signup.haml +7 -0
  136. data/app/views/integral/shared/sidebar/_popular_posts.haml +7 -0
  137. data/app/views/integral/shared/sidebar/_popular_tags.haml +7 -0
  138. data/app/views/integral/shared/sidebar/_recent_posts.haml +7 -0
  139. data/app/views/integral/tags/index.haml +2 -2
  140. data/app/views/integral/tags/show.haml +3 -6
  141. data/app/views/layouts/integral/backend.html.haml +3 -0
  142. data/app/views/layouts/integral/backend/_main_menu_items.haml +10 -0
  143. data/app/views/layouts/integral/frontend.html.haml +3 -3
  144. data/config/locales/en.yml +52 -49
  145. data/db/migrate/20190414172018_create_webhook_endpoints.rb +10 -0
  146. data/db/migrate/20190929191412_add_integral_post_categories.rb +13 -0
  147. data/db/migrate/20191203090008_add_image_to_integral_categories.rb +6 -0
  148. data/db/migrate/20200401210442_create_category_versions.rb +20 -0
  149. data/db/seeds.rb +3 -1
  150. data/lib/generators/integral/assets_generator.rb +2 -2
  151. data/lib/generators/integral/install_generator.rb +1 -1
  152. data/lib/generators/integral/views_generator.rb +1 -1
  153. data/lib/generators/templates/integral.rb +5 -0
  154. data/lib/integral.rb +3 -30
  155. data/lib/integral/acts_as_listable.rb +2 -2
  156. data/lib/integral/chart_renderer/base.rb +2 -0
  157. data/lib/integral/content_renderer.rb +2 -2
  158. data/lib/integral/engine.rb +2 -2
  159. data/lib/integral/grids/activities_grid.rb +15 -1
  160. data/lib/integral/list_item_renderer.rb +4 -2
  161. data/lib/integral/list_renderer.rb +1 -0
  162. data/lib/integral/middleware/page_router.rb +15 -6
  163. data/lib/integral/router.rb +19 -3
  164. data/lib/integral/version.rb +1 -1
  165. data/lib/integral/widgets/swiper_list.rb +3 -2
  166. data/public/images/integral/demo/continous-integration.png +0 -0
  167. data/public/images/integral/demo/foundation-frontend-framework.jpg +0 -0
  168. data/public/images/integral/demo/heroku.png +0 -0
  169. data/public/images/integral/demo/integral-cms-without-hassle.jpg +0 -0
  170. data/public/images/integral/demo/integral-features-activity-tracking.jpg +0 -0
  171. data/public/images/integral/demo/integral-features-contact-form.png +0 -0
  172. data/public/images/integral/demo/integral-features-design.jpg +0 -0
  173. data/public/images/integral/demo/integral-features-dynamic-pages.jpg +0 -0
  174. data/public/images/integral/demo/integral-features-image-management.jpg +0 -0
  175. data/public/images/integral/demo/integral-features-integrated-blog.jpg +0 -0
  176. data/public/images/integral/demo/integral-features-list-management.jpg +0 -0
  177. data/public/images/integral/demo/integral-features-seo-ready.jpg +0 -0
  178. data/public/images/integral/demo/integral-features-user-management.jpg +0 -0
  179. data/public/images/integral/demo/integral-presentation.png +0 -0
  180. data/spec/factories.rb +15 -7
  181. metadata +110 -98
  182. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/copywidget.png +0 -0
  183. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/editwidget.png +0 -0
  184. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/hidpi/copywidget.png +0 -0
  185. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/hidpi/editwidget.png +0 -0
  186. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/hidpi/removewidget.png +0 -0
  187. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/hidpi/widget.png +0 -0
  188. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/removewidget.png +0 -0
  189. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/widget.png +0 -0
  190. data/app/assets/javascripts/ckeditor/plugins/integral-card/plugin.js +0 -86
  191. data/app/assets/javascripts/ckeditor/plugins/integralrecentposts/dialogs/integralrecentposts.js +0 -40
  192. data/app/assets/javascripts/ckeditor/plugins/integralrecentposts/plugin.js +0 -32
  193. data/app/assets/javascripts/ckeditor/plugins/numericinput/LICENSE.md +0 -363
  194. data/app/assets/javascripts/ckeditor/plugins/numericinput/README.md +0 -16
  195. data/app/assets/javascripts/ckeditor/plugins/numericinput/plugin.js +0 -354
  196. data/app/assets/stylesheets/integral/frontend.sass +0 -25
  197. data/app/views/integral/backend/pages/activities.haml +0 -2
  198. data/app/views/integral/backend/pages/activity.haml +0 -1
  199. data/app/views/integral/backend/posts/activities.haml +0 -3
  200. data/app/views/integral/backend/posts/activity.haml +0 -1
  201. data/app/views/integral/posts/_collection.haml +0 -4
  202. data/app/views/integral/posts/_item.haml +0 -16
  203. data/app/views/integral/shared/_blog_layout.haml +0 -15
  204. data/app/views/integral/shared/_blog_sidebar.haml +0 -49
  205. data/lib/integral/slack_bot.rb +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7a76c7625e0d568743ac3d46253e00ca55949cb6
4
- data.tar.gz: 5ea751e58f06074824da0d95106c9f1757923629
3
+ metadata.gz: 79d9ffb78cf456a49d8dc4b6c41ff99bb94d473a
4
+ data.tar.gz: 7691ba54679f3c1b0dd8e7fadb20f1ff3f22601d
5
5
  SHA512:
6
- metadata.gz: 501c8ca1f8cf1cb6212e53923c1dc8e51d7d30cc60a48c7b339134d2af2043c59d84b8e37942e7dadb7c03f876e5d2f515d801a3ec5db6413c2b2c07aa112314
7
- data.tar.gz: 9f2569eb03fac519a228958c2188dec8e4ebf1ef21943d4e4cfb33e79d541ee347664fca71fd7122e8d7e833eac402e063845febd7c8e6aca319d9f251308bb3
6
+ metadata.gz: 6852ebaa96f6d6b6e2aaa3aaa61ef02063ba54ce3ebb1740859e94ce229c0c5b2c78a1ab51a610c8faf01d9945c69761f753f36aaecdefa7de9aef611913fc48
7
+ data.tar.gz: d4a8027d77dc2a8e19fa297c0d0b1146c8aa598023a30efb808d5bfec7cbf0432746814e37587dbedc0e6e852cb2bc921c705b8501bc2627bf7baa47dd3e66e8
data/README.md CHANGED
@@ -27,44 +27,16 @@ Out of the box integral provides;
27
27
 
28
28
  ## Getting Started
29
29
 
30
- 1. Create a new Rails application
31
- ```
32
- rails new example_app --database=postgresql -T
33
- ```
34
- 2. Add Integral to your Gemfile and run `bundle install`
35
- ```
36
- gem 'integral'
37
- ```
38
- 3. Run Integral install rake task (adds configuration initializers, installs routes & sets up database)
39
- ```
40
- rails generate integral:install
41
- ```
42
- 4. Set the default host within the development environment, used for URL generation
43
- ```
44
- # config/environments/development.rb
45
-
46
- Rails.application.routes.default_url_options[:host] = 'http://localhost:3000'
47
- ```
48
-
49
- Voila! Start your rails server and you're ready to go! You can access the user only area at `/admin`
50
-
51
- Integral requires Rails 5.1 or higher and Ruby 2.4.1 or higher.
30
+ Get a professional website up and running in minutes - Check out our [documentation website](https://integralrails.com/docs) for installation instructions and guides.
52
31
 
53
32
  ## Information
54
33
 
55
34
  * [Integral Website][integral-cms]
35
+ * [Integral Docs](https://integralrails.com/docs)
56
36
  * [CHANGELOG](https://github.com/yamasolutions/integral/blob/master/CHANGELOG.md)
57
37
  * [Code Documentation][docs-website]
58
38
  * [Wish list](https://github.com/yamasolutions/integral/wiki/Wish-List)
59
39
 
60
- ### Guides
61
- * [Deploying to production](https://github.com/yamasolutions/integral/blob/master/docs/deploying_to_production.md)
62
- * [Integral <3 Heroku](https://github.com/yamasolutions/integral/blob/master/docs/heroku.md)
63
- * [Extending Integral](https://github.com/yamasolutions/integral/blob/master/docs/extending_integral.md)
64
- * [Integral Lists](https://github.com/yamasolutions/integral/blob/master/docs/integral_lists.md)
65
- * [Integral Pages](https://github.com/yamasolutions/integral/blob/master/docs/integral_pages.md)
66
- * [Integral Widgets](https://github.com/yamasolutions/integral/blob/master/docs/integral_widgets.md)
67
- * [WYSIWYG Editor](https://github.com/yamasolutions/integral/blob/master/docs/wysiwyg_editor.md)
68
40
 
69
41
  ### Bug reporting
70
42
  If you discover a problem with Integral, we would love to know about it. Please use the [GitHub issue tracker][github-issue-tracker] to contact us about it.
data/Rakefile CHANGED
@@ -14,7 +14,7 @@ RDoc::Task.new(:rdoc) do |rdoc|
14
14
  rdoc.rdoc_files.include('lib/**/*.rb')
15
15
  end
16
16
 
17
- APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
17
+ APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
18
18
  load 'rails/tasks/engine.rake'
19
19
 
20
20
  load 'rails/tasks/statistics.rake'
@@ -50,8 +50,90 @@ function ready() {
50
50
  new ChartManager();
51
51
  NotificationManager.flash();
52
52
  ImageUploader.init();
53
+ new RemoteForm($('.remote-form'));
53
54
  Grid.init();
54
55
 
56
+ // Recent activity 'view more' behaviour
57
+ $("[data-recent-activity]").on("click", function(ev) {
58
+ $button = $(ev.currentTarget);
59
+ modalId = $button.data('container-id');
60
+
61
+ $modal = $('#' + modalId);
62
+ if ($modal.length > 0) {
63
+ $modal.foundation('open');
64
+ } else {
65
+ $modal = $('#activity-placeholder').clone().appendTo('body')
66
+ $form = $modal.find('form')
67
+ $modal.attr('id', modalId)
68
+ $modal.foundation()
69
+
70
+ // Populate modal with content & filters
71
+ $modal.find('[data-title]').html($button.data('recent-activity-title'))
72
+ $modal.find('[data-timeline]').html($button.closest('.card').find('.timeline').html())
73
+ $form.find("input[name='grid[user]']").val($button.data('recent-activity-user'))
74
+ $form.find("input[name='grid[object]']").val($button.data('recent-activity-object'))
75
+ $form.find("input[name='grid[created_at]']").val($button.data('recent-activity-created-at'))
76
+ $form.find("input[name='grid[item_id]']").val($button.data('recent-activity-item-id'))
77
+
78
+ $form.on( "ajax:success", function(event, response) {
79
+ if (response.last_created_at != null) {
80
+ $modal.find('[data-timeline]').append(response.content)
81
+ $form.find("input[name='grid[created_at]']").val(response.last_created_at)
82
+ } else {
83
+ $form.find("input[type='submit']").hide()
84
+ }
85
+ });
86
+
87
+ $modal.foundation('open')
88
+ $form.submit()
89
+ }
90
+ });
91
+
92
+ // Hijack context menu click for rows which have a URL
93
+ $("tr[data-href]").on("contextmenu", function(ev) {
94
+ $('#' + ev.currentTarget.dataset.contextMenu).foundation('open');
95
+
96
+ return false;
97
+ });
98
+
99
+ // Capture clicks on rows which have a URL and visit that URL
100
+ $("tr[data-href]").on("click", function(ev) {
101
+ // Do not follow if the click is within a data-toggle
102
+ if (($(ev.target).closest('[data-toggle]').length == 0) && ($(ev.target).closest('[data-dropdown]').length == 0)) {
103
+ document.location = $(ev.currentTarget).data('href');
104
+ }
105
+ });
106
+
107
+ $("[data-button-delete-category]").on("ajax:success", function(ev) {
108
+ $(ev.currentTarget).closest('tr').fadeOut();
109
+ });
110
+
111
+ $("[data-button-delete-category]").on("ajax:error", function(ev) {
112
+ toastr["error"](I18n.t('integral.remote_form.error'));
113
+ });
114
+
115
+ $("#new_category_modal").on("open.zf.reveal", function(ev) {
116
+ $(ev.currentTarget).find('form').enableClientSideValidations();
117
+ });
118
+
119
+ $("[data-button-edit-category]").on( "click", function(ev) {
120
+ modalId = '#' + ev.currentTarget.dataset.buttonEditCategory;
121
+ modalUrl = ev.currentTarget.dataset.modalUrl;
122
+
123
+ if ($(modalId).length == 0) {
124
+ $.ajax({url: modalUrl, success: function(response){
125
+ $('body').append(response.content);
126
+ modal = $(modalId);
127
+ modal.foundation().foundation('open');
128
+ modal.find('form').enableClientSideValidations();
129
+ new RemoteForm(modal.find('form'));
130
+ SlugGenerator.check_for_slugs();
131
+ }});
132
+ } else {
133
+ $(modalId).foundation('open');
134
+ }
135
+ });
136
+
55
137
  if (($('body.lists.new').length > 0) || ($('body.lists.show').length > 0) || ($('body.lists.edit').length > 0)) {
56
138
  new List();
57
139
  }
@@ -226,25 +308,34 @@ function ready() {
226
308
  };
227
309
 
228
310
  // Material Tags
229
- $("input[data-role=materialtags]").each(function( index ) {
230
- suggestableInput = $(this)
231
- typeaheadSuggestions = suggestableInput.data('typeahead').split(' ')
232
-
233
- // Initialize suggest engine
234
- suggestEngine = new Bloodhound({
235
- datumTokenizer: Bloodhound.tokenizers.whitespace,
236
- queryTokenizer: Bloodhound.tokenizers.whitespace,
237
- local: typeaheadSuggestions
238
- });
311
+ $("[data-suggest-tags]").each(function( index ) {
312
+ suggestableInput = $(this);
313
+ typeaheadSuggestions = suggestableInput.data('suggestTagsTypeahead').split(' ');
314
+ freeInput = suggestableInput.data('suggestTagsFreeInput');
315
+
316
+ if (typeof freeInput === 'undefined') {
317
+ freeInput = true;
318
+ }
319
+
320
+ // Initialize suggest engine
321
+ suggestEngine = new Bloodhound({
322
+ datumTokenizer: Bloodhound.tokenizers.whitespace,
323
+ queryTokenizer: Bloodhound.tokenizers.whitespace,
324
+ local: typeaheadSuggestions
325
+ });
239
326
 
240
327
  // Initialize materialtags
241
328
  suggestableInput.materialtags({
329
+ freeInput: freeInput,
242
330
  typeaheadjs: {
243
331
  source: function(query, cb) {
244
332
  suggestEngine.search(query, function(suggestions) {
245
333
  cb(filterSuggestions(suggestableInput, suggestions));
246
334
  });
247
- }
335
+ },
336
+ // TODO: These two options don't currently work but would be nice to add in
337
+ autoselect: true,
338
+ highlight: true
248
339
  }
249
340
  });
250
341
  });
@@ -9,6 +9,10 @@
9
9
  //= require toastr
10
10
  //= require rails.validations
11
11
  //= require rails.validations.simple_form
12
+ //= require integral/support/lib/lazysizes
13
+ //= require integral/support/ls.twitter
14
+ //= require integral/support/ls.instagram
15
+ //= require integral/support/date_picker
12
16
  //= require integral/support/date_picker
13
17
  //= require integral/support/click_to_copy
14
18
  //= require integral/support/google_analytics
@@ -33,6 +37,39 @@ function ready() {
33
37
  new RemoteForm($('.remote-form'));
34
38
  new DatePicker('.datepicker');
35
39
  GoogleAnalytics.trackRead();
40
+
41
+ // Move most read posts widget to middle of post listing (can't do this serverside due to caching)
42
+ $mostReadWidget = $('[data-most-read-posts]');
43
+ if ($mostReadWidget.length == 1) {
44
+ $('[data-most-read-posts]').insertAfter('[data-post-list] div:nth-child(5)');
45
+ }
46
+
47
+ // Scroll Container
48
+ // TODO
49
+ // in future allow to configure each scroll-container how it activiates
50
+ // also update when changing size
51
+ $(".scroll-container").each(function( index ) {
52
+ container = $(this);
53
+ wrapper = container.find('.scroll-wrapper');
54
+ visibleChildren = wrapper.children(':visible');
55
+ //elementWidth = '250';
56
+ elementWidth = parseInt(container.data('item-width'))
57
+
58
+ validSizes = ['small', 'medium']
59
+ //if (Foundation.MediaQuery.current == 'small') {
60
+ if (validSizes.includes(Foundation.MediaQuery.current)) {
61
+
62
+ visibleChildren.each(function(index) {
63
+ $(this).css('width', elementWidth);
64
+ $(this).css('max-width', 'unset');
65
+ });
66
+
67
+ firstChild = visibleChildren.first()
68
+ wrapperWidth = (elementWidth + (parseInt(firstChild.css('marginLeft')) + parseInt(firstChild.css('marginRight')))) * visibleChildren.size();
69
+ widthCss = wrapperWidth + 'px';
70
+ wrapper.css('width', widthCss);
71
+ }
72
+ });
36
73
  };
37
74
 
38
75
  // Initial Page load event handler
@@ -16,8 +16,8 @@ $.rails.buildConfirmationDialog = (message, modalId, confirmBtnId, cancelBtnId)
16
16
  </div>
17
17
 
18
18
  <div class='modal-footer'>
19
- <a id='#{cancelBtnId}' class='button secondary hollow'>#{I18n.t('integral.actions.cancel')}</a>
20
- <a id='#{confirmBtnId}' class='button primary'>#{I18n.t('integral.actions.confirm')}</a>
19
+ <button id='#{cancelBtnId}' class='button secondary hollow'>#{I18n.t('integral.actions.cancel')}</button>
20
+ <button id='#{confirmBtnId}' class='button primary'>#{I18n.t('integral.actions.confirm')}</button>
21
21
  </div>
22
22
  <button class='close-button' data-close aria-label='Close modal' type='button'>
23
23
  <span aria-hidden='true'>&times;</span>
@@ -1,68 +1,65 @@
1
1
  # Handles interaction with galleries
2
2
  class this.Gallery
3
3
  @init: ->
4
- new Gallery()
5
-
6
- # Initiate a Gallery
7
- #
8
- # @usage new Gallery($('form'))
9
- constructor: (opts={}) ->
10
- @placeholder = $('#gallery-placeholder')
11
- @_setupEvents()
12
-
13
-
14
- # Create listeners and handlers for form events
15
- _setupEvents: =>
16
4
  # Watch for when a user opens a gallery
17
5
  $('.js-gallery-link').on "click", (event) =>
18
- @_open_or_create_gallery(event)
6
+ target = event.currentTarget.dataset.target
7
+ url = event.currentTarget.dataset.url
8
+ @open_or_create_gallery(target, url)
19
9
 
20
- # Open Gallery or create it and open placeholder
21
- _open_or_create_gallery: (event) =>
22
- galleryId = event.currentTarget.dataset.target
23
- return @_handleError() if galleryId == undefined
10
+ # Open Gallery or create new one
11
+ @open_or_create_gallery: (id, url) =>
12
+ return Gallery.handleError() if id == undefined
24
13
 
25
- gallery = $("##{galleryId}")
14
+ gallery = $("##{id}")
26
15
  if gallery.length > 0
27
16
  gallery.foundation('open')
28
17
  else
29
- url = event.currentTarget.dataset.url
30
- return @_handleError() if url == undefined
31
- @_createGallery(galleryId, url)
18
+ return Gallery.handleError() if url == undefined
19
+ new Gallery(id, url)
20
+
21
+ @handleError: =>
22
+ toastr['error']('Sorry, an unexpected error occurred. Please try again later.')
23
+
24
+ # Initiate a Gallery
25
+ #
26
+ # @usage new Gallery('myGallery', 'link-to-gallery-content')
27
+ constructor: (id, url, opts={}) ->
28
+ placeholder = $('#gallery-placeholder')
32
29
 
33
- # What happens after AJAX request is complete
34
- _createGallery: (id, url) =>
35
30
  # Copy placeholder gallery, set ID, initialize & open
36
- gallery = @placeholder.clone().appendTo('body')
37
- gallery.attr('id', id)
38
- gallery.foundation()
39
- gallery.foundation('open')
31
+ @$container = placeholder.clone().appendTo('body')
32
+ @youtubeEmbeds = []
33
+ @$container.attr('id', id)
34
+ @$container.foundation()
35
+ @$container.foundation('open')
40
36
 
41
37
  # Download gallery content
42
38
  $.ajax
43
39
  url: url,
44
- context: gallery
45
40
  .success (data, textStatus, jqXHR) =>
46
- @_setupGallery(gallery, data)
41
+ @_setupGallery(data)
47
42
  .error (e, data, status, xhr) =>
48
- @_handleError()
43
+ Gallery.handleError()
49
44
 
50
- _setupGallery: (gallery, data) =>
45
+ _setupGallery: (data) =>
51
46
  # Copy gallery into Modal
52
- gallery.find('.content').html(data)
53
- galleryContent = gallery.find('.content')
47
+ @$container.find('.content').html(data)
48
+ @$galleryContent = @$container.find('.content')
54
49
 
55
- mainSwiper = galleryContent.find('.main-swiper')
56
- # Setup galleries
57
- if mainSwiper.length > 0
58
- projectGalleryTop = new Swiper(mainSwiper[0], {
50
+ @_setupYoutube()
51
+
52
+ @$mainSwiper = @$galleryContent.find('.main-swiper')
53
+ # Setup galleries (when present)
54
+ if @$mainSwiper.length > 0
55
+ projectGalleryTop = new Swiper(@$mainSwiper[0], {
59
56
  spaceBetween: 10,
60
57
  navigation: {
61
58
  nextEl: '.swiper-button-next',
62
59
  prevEl: '.swiper-button-prev',
63
60
  },
64
61
  })
65
- projectGalleryThumbs = new Swiper(galleryContent.find('.thumb-swiper'), {
62
+ projectGalleryThumbs = new Swiper(@$galleryContent.find('.thumb-swiper'), {
66
63
  spaceBetween: 10,
67
64
  centeredSlides: true,
68
65
  slidesPerView: 'auto',
@@ -72,22 +69,14 @@ class this.Gallery
72
69
  projectGalleryTop.controller.control = projectGalleryThumbs
73
70
  projectGalleryThumbs.controller.control = projectGalleryTop
74
71
 
75
- # Set main swiper size
76
- revealHeight = gallery.height()
77
- thumbSwiperHeight = galleryContent.find('.thumb-swiper').height()
78
- revealAvailableHeight = revealHeight - thumbSwiperHeight
79
- mainSwiper.height(revealAvailableHeight)
72
+ @_setSwiperSize()
80
73
 
81
74
  window.addEventListener 'resize', =>
82
- # TODO: Tidy up this duplication
83
- revealHeight = gallery.height()
84
- thumbSwiperHeight = galleryContent.find('.thumb-swiper').height()
85
- revealAvailableHeight = revealHeight - thumbSwiperHeight
86
- mainSwiper.height(revealAvailableHeight)
75
+ @_setSwiperSize()
87
76
 
88
77
  # Listen for arrow keys
89
78
  $(document).keydown (event) =>
90
- return unless gallery.is(':focus')
79
+ return unless @$container.is(':focus')
91
80
 
92
81
  switch event.which
93
82
  when 37 # Left
@@ -98,10 +87,38 @@ class this.Gallery
98
87
  return # Exit this handler for other keys
99
88
 
100
89
  # Show/hide content and placeholder
101
- gallery.find('.placeholder').css('display', 'none')
102
- galleryContent.css('visibility', 'initial')
103
-
104
- _handleError: =>
105
- toastr['error']('Sorry, an unexpected error occurred. Please try again later.')
90
+ @$container.find('.placeholder').css('display', 'none')
91
+ @$galleryContent.css('visibility', 'initial')
106
92
 
93
+ _setSwiperSize: =>
94
+ revealHeight = @$container.height()
95
+ if @$mainSwiper.length > 0
96
+ thumbSwiperHeight = @$galleryContent.find('.thumb-swiper').height()
97
+ revealAvailableHeight = revealHeight - thumbSwiperHeight
98
+ @$mainSwiper.height(revealAvailableHeight)
99
+ else
100
+ @$galleryContent.height(revealHeight)
101
+
102
+ _setupYoutube: =>
103
+ embeds = @$container.find('iframe')
104
+ if embeds.length > 0
105
+ if typeof YT == 'undefined'
106
+ # Download YT script and wait until API is ready
107
+ # TODO: Clean up wait hack
108
+ console.log('Downloading YT script')
109
+ $.getScript "https://www.youtube.com/iframe_api", =>
110
+ setTimeout =>
111
+ @_setupEmbeds(embeds)
112
+ , 1500
113
+ else
114
+ @_setupEmbeds(embeds)
115
+
116
+ _setupEmbeds: (embeds) =>
117
+ embeds.each (index, element) =>
118
+ player = new YT.Player(element)
119
+ @youtubeEmbeds.push(player)
120
+
121
+ @$container.on 'closed.zf.reveal', =>
122
+ @youtubeEmbeds.forEach (element) =>
123
+ element.pauseVideo()
107
124
 
@@ -0,0 +1,755 @@
1
+ /* 5.2.0 - https://github.com/aFarkas/lazysizes */
2
+ (function(window, factory) {
3
+ var lazySizes = factory(window, window.document, Date);
4
+ window.lazySizes = lazySizes;
5
+ if(typeof module == 'object' && module.exports){
6
+ module.exports = lazySizes;
7
+ }
8
+ }(typeof window != 'undefined' ?
9
+ window : {}, function l(window, document, Date) { // Pass in the windoe Date function also for SSR because the Date class can be lost
10
+ 'use strict';
11
+ /*jshint eqnull:true */
12
+
13
+ var lazysizes, lazySizesCfg;
14
+
15
+ (function(){
16
+ var prop;
17
+
18
+ var lazySizesDefaults = {
19
+ lazyClass: 'lazyload',
20
+ loadedClass: 'lazyloaded',
21
+ loadingClass: 'lazyloading',
22
+ preloadClass: 'lazypreload',
23
+ errorClass: 'lazyerror',
24
+ //strictClass: 'lazystrict',
25
+ autosizesClass: 'lazyautosizes',
26
+ srcAttr: 'data-src',
27
+ srcsetAttr: 'data-srcset',
28
+ sizesAttr: 'data-sizes',
29
+ //preloadAfterLoad: false,
30
+ minSize: 40,
31
+ customMedia: {},
32
+ init: true,
33
+ expFactor: 1.5,
34
+ hFac: 0.8,
35
+ loadMode: 2,
36
+ loadHidden: true,
37
+ ricTimeout: 0,
38
+ throttleDelay: 125,
39
+ };
40
+
41
+ lazySizesCfg = window.lazySizesConfig || window.lazysizesConfig || {};
42
+
43
+ for(prop in lazySizesDefaults){
44
+ if(!(prop in lazySizesCfg)){
45
+ lazySizesCfg[prop] = lazySizesDefaults[prop];
46
+ }
47
+ }
48
+ })();
49
+
50
+ if (!document || !document.getElementsByClassName) {
51
+ return {
52
+ init: function () {},
53
+ cfg: lazySizesCfg,
54
+ noSupport: true,
55
+ };
56
+ }
57
+
58
+ var docElem = document.documentElement;
59
+
60
+ var supportPicture = window.HTMLPictureElement;
61
+
62
+ var _addEventListener = 'addEventListener';
63
+
64
+ var _getAttribute = 'getAttribute';
65
+
66
+ /**
67
+ * Update to bind to window because 'this' becomes null during SSR
68
+ * builds.
69
+ */
70
+ var addEventListener = window[_addEventListener].bind(window);
71
+
72
+ var setTimeout = window.setTimeout;
73
+
74
+ var requestAnimationFrame = window.requestAnimationFrame || setTimeout;
75
+
76
+ var requestIdleCallback = window.requestIdleCallback;
77
+
78
+ var regPicture = /^picture$/i;
79
+
80
+ var loadEvents = ['load', 'error', 'lazyincluded', '_lazyloaded'];
81
+
82
+ var regClassCache = {};
83
+
84
+ var forEach = Array.prototype.forEach;
85
+
86
+ var hasClass = function(ele, cls) {
87
+ if(!regClassCache[cls]){
88
+ regClassCache[cls] = new RegExp('(\\s|^)'+cls+'(\\s|$)');
89
+ }
90
+ return regClassCache[cls].test(ele[_getAttribute]('class') || '') && regClassCache[cls];
91
+ };
92
+
93
+ var addClass = function(ele, cls) {
94
+ if (!hasClass(ele, cls)){
95
+ ele.setAttribute('class', (ele[_getAttribute]('class') || '').trim() + ' ' + cls);
96
+ }
97
+ };
98
+
99
+ var removeClass = function(ele, cls) {
100
+ var reg;
101
+ if ((reg = hasClass(ele,cls))) {
102
+ ele.setAttribute('class', (ele[_getAttribute]('class') || '').replace(reg, ' '));
103
+ }
104
+ };
105
+
106
+ var addRemoveLoadEvents = function(dom, fn, add){
107
+ var action = add ? _addEventListener : 'removeEventListener';
108
+ if(add){
109
+ addRemoveLoadEvents(dom, fn);
110
+ }
111
+ loadEvents.forEach(function(evt){
112
+ dom[action](evt, fn);
113
+ });
114
+ };
115
+
116
+ var triggerEvent = function(elem, name, detail, noBubbles, noCancelable){
117
+ var event = document.createEvent('Event');
118
+
119
+ if(!detail){
120
+ detail = {};
121
+ }
122
+
123
+ detail.instance = lazysizes;
124
+
125
+ event.initEvent(name, !noBubbles, !noCancelable);
126
+
127
+ event.detail = detail;
128
+
129
+ elem.dispatchEvent(event);
130
+ return event;
131
+ };
132
+
133
+ var updatePolyfill = function (el, full){
134
+ var polyfill;
135
+ if( !supportPicture && ( polyfill = (window.picturefill || lazySizesCfg.pf) ) ){
136
+ if(full && full.src && !el[_getAttribute]('srcset')){
137
+ el.setAttribute('srcset', full.src);
138
+ }
139
+ polyfill({reevaluate: true, elements: [el]});
140
+ } else if(full && full.src){
141
+ el.src = full.src;
142
+ }
143
+ };
144
+
145
+ var getCSS = function (elem, style){
146
+ return (getComputedStyle(elem, null) || {})[style];
147
+ };
148
+
149
+ var getWidth = function(elem, parent, width){
150
+ width = width || elem.offsetWidth;
151
+
152
+ while(width < lazySizesCfg.minSize && parent && !elem._lazysizesWidth){
153
+ width = parent.offsetWidth;
154
+ parent = parent.parentNode;
155
+ }
156
+
157
+ return width;
158
+ };
159
+
160
+ var rAF = (function(){
161
+ var running, waiting;
162
+ var firstFns = [];
163
+ var secondFns = [];
164
+ var fns = firstFns;
165
+
166
+ var run = function(){
167
+ var runFns = fns;
168
+
169
+ fns = firstFns.length ? secondFns : firstFns;
170
+
171
+ running = true;
172
+ waiting = false;
173
+
174
+ while(runFns.length){
175
+ runFns.shift()();
176
+ }
177
+
178
+ running = false;
179
+ };
180
+
181
+ var rafBatch = function(fn, queue){
182
+ if(running && !queue){
183
+ fn.apply(this, arguments);
184
+ } else {
185
+ fns.push(fn);
186
+
187
+ if(!waiting){
188
+ waiting = true;
189
+ (document.hidden ? setTimeout : requestAnimationFrame)(run);
190
+ }
191
+ }
192
+ };
193
+
194
+ rafBatch._lsFlush = run;
195
+
196
+ return rafBatch;
197
+ })();
198
+
199
+ var rAFIt = function(fn, simple){
200
+ return simple ?
201
+ function() {
202
+ rAF(fn);
203
+ } :
204
+ function(){
205
+ var that = this;
206
+ var args = arguments;
207
+ rAF(function(){
208
+ fn.apply(that, args);
209
+ });
210
+ }
211
+ ;
212
+ };
213
+
214
+ var throttle = function(fn){
215
+ var running;
216
+ var lastTime = 0;
217
+ var gDelay = lazySizesCfg.throttleDelay;
218
+ var rICTimeout = lazySizesCfg.ricTimeout;
219
+ var run = function(){
220
+ running = false;
221
+ lastTime = Date.now();
222
+ fn();
223
+ };
224
+ var idleCallback = requestIdleCallback && rICTimeout > 49 ?
225
+ function(){
226
+ requestIdleCallback(run, {timeout: rICTimeout});
227
+
228
+ if(rICTimeout !== lazySizesCfg.ricTimeout){
229
+ rICTimeout = lazySizesCfg.ricTimeout;
230
+ }
231
+ } :
232
+ rAFIt(function(){
233
+ setTimeout(run);
234
+ }, true)
235
+ ;
236
+
237
+ return function(isPriority){
238
+ var delay;
239
+
240
+ if((isPriority = isPriority === true)){
241
+ rICTimeout = 33;
242
+ }
243
+
244
+ if(running){
245
+ return;
246
+ }
247
+
248
+ running = true;
249
+
250
+ delay = gDelay - (Date.now() - lastTime);
251
+
252
+ if(delay < 0){
253
+ delay = 0;
254
+ }
255
+
256
+ if(isPriority || delay < 9){
257
+ idleCallback();
258
+ } else {
259
+ setTimeout(idleCallback, delay);
260
+ }
261
+ };
262
+ };
263
+
264
+ //based on http://modernjavascript.blogspot.de/2013/08/building-better-debounce.html
265
+ var debounce = function(func) {
266
+ var timeout, timestamp;
267
+ var wait = 99;
268
+ var run = function(){
269
+ timeout = null;
270
+ func();
271
+ };
272
+ var later = function() {
273
+ var last = Date.now() - timestamp;
274
+
275
+ if (last < wait) {
276
+ setTimeout(later, wait - last);
277
+ } else {
278
+ (requestIdleCallback || run)(run);
279
+ }
280
+ };
281
+
282
+ return function() {
283
+ timestamp = Date.now();
284
+
285
+ if (!timeout) {
286
+ timeout = setTimeout(later, wait);
287
+ }
288
+ };
289
+ };
290
+
291
+ var loader = (function(){
292
+ var preloadElems, isCompleted, resetPreloadingTimer, loadMode, started;
293
+
294
+ var eLvW, elvH, eLtop, eLleft, eLright, eLbottom, isBodyHidden;
295
+
296
+ var regImg = /^img$/i;
297
+ var regIframe = /^iframe$/i;
298
+
299
+ var supportScroll = ('onscroll' in window) && !(/(gle|ing)bot/.test(navigator.userAgent));
300
+
301
+ var shrinkExpand = 0;
302
+ var currentExpand = 0;
303
+
304
+ var isLoading = 0;
305
+ var lowRuns = -1;
306
+
307
+ var resetPreloading = function(e){
308
+ isLoading--;
309
+ if(!e || isLoading < 0 || !e.target){
310
+ isLoading = 0;
311
+ }
312
+ };
313
+
314
+ var isVisible = function (elem) {
315
+ if (isBodyHidden == null) {
316
+ isBodyHidden = getCSS(document.body, 'visibility') == 'hidden';
317
+ }
318
+
319
+ return isBodyHidden || !(getCSS(elem.parentNode, 'visibility') == 'hidden' && getCSS(elem, 'visibility') == 'hidden');
320
+ };
321
+
322
+ var isNestedVisible = function(elem, elemExpand){
323
+ var outerRect;
324
+ var parent = elem;
325
+ var visible = isVisible(elem);
326
+
327
+ eLtop -= elemExpand;
328
+ eLbottom += elemExpand;
329
+ eLleft -= elemExpand;
330
+ eLright += elemExpand;
331
+
332
+ while(visible && (parent = parent.offsetParent) && parent != document.body && parent != docElem){
333
+ visible = ((getCSS(parent, 'opacity') || 1) > 0);
334
+
335
+ if(visible && getCSS(parent, 'overflow') != 'visible'){
336
+ outerRect = parent.getBoundingClientRect();
337
+ visible = eLright > outerRect.left &&
338
+ eLleft < outerRect.right &&
339
+ eLbottom > outerRect.top - 1 &&
340
+ eLtop < outerRect.bottom + 1
341
+ ;
342
+ }
343
+ }
344
+
345
+ return visible;
346
+ };
347
+
348
+ var checkElements = function() {
349
+ var eLlen, i, rect, autoLoadElem, loadedSomething, elemExpand, elemNegativeExpand, elemExpandVal,
350
+ beforeExpandVal, defaultExpand, preloadExpand, hFac;
351
+ var lazyloadElems = lazysizes.elements;
352
+
353
+ if((loadMode = lazySizesCfg.loadMode) && isLoading < 8 && (eLlen = lazyloadElems.length)){
354
+
355
+ i = 0;
356
+
357
+ lowRuns++;
358
+
359
+ for(; i < eLlen; i++){
360
+
361
+ if(!lazyloadElems[i] || lazyloadElems[i]._lazyRace){continue;}
362
+
363
+ if(!supportScroll || (lazysizes.prematureUnveil && lazysizes.prematureUnveil(lazyloadElems[i]))){unveilElement(lazyloadElems[i]);continue;}
364
+
365
+ if(!(elemExpandVal = lazyloadElems[i][_getAttribute]('data-expand')) || !(elemExpand = elemExpandVal * 1)){
366
+ elemExpand = currentExpand;
367
+ }
368
+
369
+ if (!defaultExpand) {
370
+ defaultExpand = (!lazySizesCfg.expand || lazySizesCfg.expand < 1) ?
371
+ docElem.clientHeight > 500 && docElem.clientWidth > 500 ? 500 : 370 :
372
+ lazySizesCfg.expand;
373
+
374
+ lazysizes._defEx = defaultExpand;
375
+
376
+ preloadExpand = defaultExpand * lazySizesCfg.expFactor;
377
+ hFac = lazySizesCfg.hFac;
378
+ isBodyHidden = null;
379
+
380
+ if(currentExpand < preloadExpand && isLoading < 1 && lowRuns > 2 && loadMode > 2 && !document.hidden){
381
+ currentExpand = preloadExpand;
382
+ lowRuns = 0;
383
+ } else if(loadMode > 1 && lowRuns > 1 && isLoading < 6){
384
+ currentExpand = defaultExpand;
385
+ } else {
386
+ currentExpand = shrinkExpand;
387
+ }
388
+ }
389
+
390
+ if(beforeExpandVal !== elemExpand){
391
+ eLvW = innerWidth + (elemExpand * hFac);
392
+ elvH = innerHeight + elemExpand;
393
+ elemNegativeExpand = elemExpand * -1;
394
+ beforeExpandVal = elemExpand;
395
+ }
396
+
397
+ rect = lazyloadElems[i].getBoundingClientRect();
398
+
399
+ if ((eLbottom = rect.bottom) >= elemNegativeExpand &&
400
+ (eLtop = rect.top) <= elvH &&
401
+ (eLright = rect.right) >= elemNegativeExpand * hFac &&
402
+ (eLleft = rect.left) <= eLvW &&
403
+ (eLbottom || eLright || eLleft || eLtop) &&
404
+ (lazySizesCfg.loadHidden || isVisible(lazyloadElems[i])) &&
405
+ ((isCompleted && isLoading < 3 && !elemExpandVal && (loadMode < 3 || lowRuns < 4)) || isNestedVisible(lazyloadElems[i], elemExpand))){
406
+ unveilElement(lazyloadElems[i]);
407
+ loadedSomething = true;
408
+ if(isLoading > 9){break;}
409
+ } else if(!loadedSomething && isCompleted && !autoLoadElem &&
410
+ isLoading < 4 && lowRuns < 4 && loadMode > 2 &&
411
+ (preloadElems[0] || lazySizesCfg.preloadAfterLoad) &&
412
+ (preloadElems[0] || (!elemExpandVal && ((eLbottom || eLright || eLleft || eLtop) || lazyloadElems[i][_getAttribute](lazySizesCfg.sizesAttr) != 'auto')))){
413
+ autoLoadElem = preloadElems[0] || lazyloadElems[i];
414
+ }
415
+ }
416
+
417
+ if(autoLoadElem && !loadedSomething){
418
+ unveilElement(autoLoadElem);
419
+ }
420
+ }
421
+ };
422
+
423
+ var throttledCheckElements = throttle(checkElements);
424
+
425
+ var switchLoadingClass = function(e){
426
+ var elem = e.target;
427
+
428
+ if (elem._lazyCache) {
429
+ delete elem._lazyCache;
430
+ return;
431
+ }
432
+
433
+ resetPreloading(e);
434
+ addClass(elem, lazySizesCfg.loadedClass);
435
+ removeClass(elem, lazySizesCfg.loadingClass);
436
+ addRemoveLoadEvents(elem, rafSwitchLoadingClass);
437
+ triggerEvent(elem, 'lazyloaded');
438
+ };
439
+ var rafedSwitchLoadingClass = rAFIt(switchLoadingClass);
440
+ var rafSwitchLoadingClass = function(e){
441
+ rafedSwitchLoadingClass({target: e.target});
442
+ };
443
+
444
+ var changeIframeSrc = function(elem, src){
445
+ try {
446
+ elem.contentWindow.location.replace(src);
447
+ } catch(e){
448
+ elem.src = src;
449
+ }
450
+ };
451
+
452
+ var handleSources = function(source){
453
+ var customMedia;
454
+
455
+ var sourceSrcset = source[_getAttribute](lazySizesCfg.srcsetAttr);
456
+
457
+ if( (customMedia = lazySizesCfg.customMedia[source[_getAttribute]('data-media') || source[_getAttribute]('media')]) ){
458
+ source.setAttribute('media', customMedia);
459
+ }
460
+
461
+ if(sourceSrcset){
462
+ source.setAttribute('srcset', sourceSrcset);
463
+ }
464
+ };
465
+
466
+ var lazyUnveil = rAFIt(function (elem, detail, isAuto, sizes, isImg){
467
+ var src, srcset, parent, isPicture, event, firesLoad;
468
+
469
+ if(!(event = triggerEvent(elem, 'lazybeforeunveil', detail)).defaultPrevented){
470
+
471
+ if(sizes){
472
+ if(isAuto){
473
+ addClass(elem, lazySizesCfg.autosizesClass);
474
+ } else {
475
+ elem.setAttribute('sizes', sizes);
476
+ }
477
+ }
478
+
479
+ srcset = elem[_getAttribute](lazySizesCfg.srcsetAttr);
480
+ src = elem[_getAttribute](lazySizesCfg.srcAttr);
481
+
482
+ if(isImg) {
483
+ parent = elem.parentNode;
484
+ isPicture = parent && regPicture.test(parent.nodeName || '');
485
+ }
486
+
487
+ firesLoad = detail.firesLoad || (('src' in elem) && (srcset || src || isPicture));
488
+
489
+ event = {target: elem};
490
+
491
+ addClass(elem, lazySizesCfg.loadingClass);
492
+
493
+ if(firesLoad){
494
+ clearTimeout(resetPreloadingTimer);
495
+ resetPreloadingTimer = setTimeout(resetPreloading, 2500);
496
+ addRemoveLoadEvents(elem, rafSwitchLoadingClass, true);
497
+ }
498
+
499
+ if(isPicture){
500
+ forEach.call(parent.getElementsByTagName('source'), handleSources);
501
+ }
502
+
503
+ if(srcset){
504
+ elem.setAttribute('srcset', srcset);
505
+ } else if(src && !isPicture){
506
+ if(regIframe.test(elem.nodeName)){
507
+ changeIframeSrc(elem, src);
508
+ } else {
509
+ elem.src = src;
510
+ }
511
+ }
512
+
513
+ if(isImg && (srcset || isPicture)){
514
+ updatePolyfill(elem, {src: src});
515
+ }
516
+ }
517
+
518
+ if(elem._lazyRace){
519
+ delete elem._lazyRace;
520
+ }
521
+ removeClass(elem, lazySizesCfg.lazyClass);
522
+
523
+ rAF(function(){
524
+ // Part of this can be removed as soon as this fix is older: https://bugs.chromium.org/p/chromium/issues/detail?id=7731 (2015)
525
+ var isLoaded = elem.complete && elem.naturalWidth > 1;
526
+
527
+ if( !firesLoad || isLoaded){
528
+ if (isLoaded) {
529
+ addClass(elem, 'ls-is-cached');
530
+ }
531
+ switchLoadingClass(event);
532
+ elem._lazyCache = true;
533
+ setTimeout(function(){
534
+ if ('_lazyCache' in elem) {
535
+ delete elem._lazyCache;
536
+ }
537
+ }, 9);
538
+ }
539
+ if (elem.loading == 'lazy') {
540
+ isLoading--;
541
+ }
542
+ }, true);
543
+ });
544
+
545
+ var unveilElement = function (elem){
546
+ if (elem._lazyRace) {return;}
547
+ var detail;
548
+
549
+ var isImg = regImg.test(elem.nodeName);
550
+
551
+ //allow using sizes="auto", but don't use. it's invalid. Use data-sizes="auto" or a valid value for sizes instead (i.e.: sizes="80vw")
552
+ var sizes = isImg && (elem[_getAttribute](lazySizesCfg.sizesAttr) || elem[_getAttribute]('sizes'));
553
+ var isAuto = sizes == 'auto';
554
+
555
+ if( (isAuto || !isCompleted) && isImg && (elem[_getAttribute]('src') || elem.srcset) && !elem.complete && !hasClass(elem, lazySizesCfg.errorClass) && hasClass(elem, lazySizesCfg.lazyClass)){return;}
556
+
557
+ detail = triggerEvent(elem, 'lazyunveilread').detail;
558
+
559
+ if(isAuto){
560
+ autoSizer.updateElem(elem, true, elem.offsetWidth);
561
+ }
562
+
563
+ elem._lazyRace = true;
564
+ isLoading++;
565
+
566
+ lazyUnveil(elem, detail, isAuto, sizes, isImg);
567
+ };
568
+
569
+ var afterScroll = debounce(function(){
570
+ lazySizesCfg.loadMode = 3;
571
+ throttledCheckElements();
572
+ });
573
+
574
+ var altLoadmodeScrollListner = function(){
575
+ if(lazySizesCfg.loadMode == 3){
576
+ lazySizesCfg.loadMode = 2;
577
+ }
578
+ afterScroll();
579
+ };
580
+
581
+ var onload = function(){
582
+ if(isCompleted){return;}
583
+ if(Date.now() - started < 999){
584
+ setTimeout(onload, 999);
585
+ return;
586
+ }
587
+
588
+
589
+ isCompleted = true;
590
+
591
+ lazySizesCfg.loadMode = 3;
592
+
593
+ throttledCheckElements();
594
+
595
+ addEventListener('scroll', altLoadmodeScrollListner, true);
596
+ };
597
+
598
+ return {
599
+ _: function(){
600
+ started = Date.now();
601
+
602
+ lazysizes.elements = document.getElementsByClassName(lazySizesCfg.lazyClass);
603
+ preloadElems = document.getElementsByClassName(lazySizesCfg.lazyClass + ' ' + lazySizesCfg.preloadClass);
604
+
605
+ addEventListener('scroll', throttledCheckElements, true);
606
+
607
+ addEventListener('resize', throttledCheckElements, true);
608
+
609
+ addEventListener('pageshow', function (e) {
610
+ if (e.persisted) {
611
+ var loadingElements = document.querySelectorAll('.' + lazySizesCfg.loadingClass);
612
+
613
+ if (loadingElements.length && loadingElements.forEach) {
614
+ requestAnimationFrame(function () {
615
+ loadingElements.forEach( function (img) {
616
+ if (img.complete) {
617
+ unveilElement(img);
618
+ }
619
+ });
620
+ });
621
+ }
622
+ }
623
+ });
624
+
625
+ if(window.MutationObserver){
626
+ new MutationObserver( throttledCheckElements ).observe( docElem, {childList: true, subtree: true, attributes: true} );
627
+ } else {
628
+ docElem[_addEventListener]('DOMNodeInserted', throttledCheckElements, true);
629
+ docElem[_addEventListener]('DOMAttrModified', throttledCheckElements, true);
630
+ setInterval(throttledCheckElements, 999);
631
+ }
632
+
633
+ addEventListener('hashchange', throttledCheckElements, true);
634
+
635
+ //, 'fullscreenchange'
636
+ ['focus', 'mouseover', 'click', 'load', 'transitionend', 'animationend'].forEach(function(name){
637
+ document[_addEventListener](name, throttledCheckElements, true);
638
+ });
639
+
640
+ if((/d$|^c/.test(document.readyState))){
641
+ onload();
642
+ } else {
643
+ addEventListener('load', onload);
644
+ document[_addEventListener]('DOMContentLoaded', throttledCheckElements);
645
+ setTimeout(onload, 20000);
646
+ }
647
+
648
+ if(lazysizes.elements.length){
649
+ checkElements();
650
+ rAF._lsFlush();
651
+ } else {
652
+ throttledCheckElements();
653
+ }
654
+ },
655
+ checkElems: throttledCheckElements,
656
+ unveil: unveilElement,
657
+ _aLSL: altLoadmodeScrollListner,
658
+ };
659
+ })();
660
+
661
+
662
+ var autoSizer = (function(){
663
+ var autosizesElems;
664
+
665
+ var sizeElement = rAFIt(function(elem, parent, event, width){
666
+ var sources, i, len;
667
+ elem._lazysizesWidth = width;
668
+ width += 'px';
669
+
670
+ elem.setAttribute('sizes', width);
671
+
672
+ if(regPicture.test(parent.nodeName || '')){
673
+ sources = parent.getElementsByTagName('source');
674
+ for(i = 0, len = sources.length; i < len; i++){
675
+ sources[i].setAttribute('sizes', width);
676
+ }
677
+ }
678
+
679
+ if(!event.detail.dataAttr){
680
+ updatePolyfill(elem, event.detail);
681
+ }
682
+ });
683
+ var getSizeElement = function (elem, dataAttr, width){
684
+ var event;
685
+ var parent = elem.parentNode;
686
+
687
+ if(parent){
688
+ width = getWidth(elem, parent, width);
689
+ event = triggerEvent(elem, 'lazybeforesizes', {width: width, dataAttr: !!dataAttr});
690
+
691
+ if(!event.defaultPrevented){
692
+ width = event.detail.width;
693
+
694
+ if(width && width !== elem._lazysizesWidth){
695
+ sizeElement(elem, parent, event, width);
696
+ }
697
+ }
698
+ }
699
+ };
700
+
701
+ var updateElementsSizes = function(){
702
+ var i;
703
+ var len = autosizesElems.length;
704
+ if(len){
705
+ i = 0;
706
+
707
+ for(; i < len; i++){
708
+ getSizeElement(autosizesElems[i]);
709
+ }
710
+ }
711
+ };
712
+
713
+ var debouncedUpdateElementsSizes = debounce(updateElementsSizes);
714
+
715
+ return {
716
+ _: function(){
717
+ autosizesElems = document.getElementsByClassName(lazySizesCfg.autosizesClass);
718
+ addEventListener('resize', debouncedUpdateElementsSizes);
719
+ },
720
+ checkElems: debouncedUpdateElementsSizes,
721
+ updateElem: getSizeElement
722
+ };
723
+ })();
724
+
725
+ var init = function(){
726
+ if(!init.i && document.getElementsByClassName){
727
+ init.i = true;
728
+ autoSizer._();
729
+ loader._();
730
+ }
731
+ };
732
+
733
+ setTimeout(function(){
734
+ if(lazySizesCfg.init){
735
+ init();
736
+ }
737
+ });
738
+
739
+ lazysizes = {
740
+ cfg: lazySizesCfg,
741
+ autoSizer: autoSizer,
742
+ loader: loader,
743
+ init: init,
744
+ uP: updatePolyfill,
745
+ aC: addClass,
746
+ rC: removeClass,
747
+ hC: hasClass,
748
+ fire: triggerEvent,
749
+ gW: getWidth,
750
+ rAF: rAF,
751
+ };
752
+
753
+ return lazysizes;
754
+ }
755
+ ));