Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

297 строки
9.7 KiB

  1. import $ from 'jquery';
  2. import Slider from "../../sections/slider/slider";
  3. import Masonry from "../../_global/scripts/masonry";
  4. class IHKGallery {
  5. constructor(section) {
  6. this.section = section.addClass('initiated');
  7. this.wrapper = section.find('.gallery-wrapper');
  8. this.items = this.wrapper.children('.image');
  9. this.gridInitialized = false;
  10. this.currentPage = -1;
  11. this.visibleItems = [];
  12. this.type = section.attr('data-type');
  13. this.initPopup();
  14. if (this.type === 'first-image' || this.type === 'single-image') {
  15. this.initSingleThumb();
  16. } else if (this.type === 'grid') {
  17. this.initThumbs();
  18. this.initLoading();
  19. } else if (this.type === 'masonry') {
  20. this.initMasonry();
  21. }
  22. this.initScrollCheck();
  23. $('body').on('lazyload-gallery-image', () => {
  24. this.lazyLoadSingleImages.call(this);
  25. })
  26. }
  27. initScrollCheck() {
  28. window.addEventListener("scroll", () => {
  29. window.requestAnimationFrame(() => {
  30. this.scrollCheck();
  31. })
  32. }, {passive: true});
  33. this.scrollCheck();
  34. }
  35. scrollCheck() {
  36. const w = $(window);
  37. if (this.type === 'first-image' || this.type === 'single-image') {
  38. if (!this.isLoaded && w.scrollTop() + w.height() + 100 > this.section.offset().top) {
  39. const thumb = this.items.first();
  40. thumb.find('img').attr('src', thumb.data(this.type === 'first-image' ? 'thumb' : 'full'));
  41. this.isLoaded = true;
  42. }
  43. } else if (this.type === 'grid') {
  44. if (!this.gridInitialized && this.items.length > this.visibleItems.length && w.scrollTop() + w.height() + 300 > ($(this.section).offset().top + $(this.section).height())) {
  45. this.currentPage++;
  46. this.loadThumbs();
  47. this.gridInitialized = true;
  48. }
  49. }
  50. }
  51. lazyLoadSingleImages() {
  52. if (this.type === 'first-image' || this.type === 'single-image') {
  53. if (!this.isLoaded) {
  54. const thumb = this.items.first();
  55. thumb.find('img').attr('src', thumb.data(this.type === 'first-image' ? 'thumb' : 'full'));
  56. this.isLoaded = true;
  57. }
  58. }
  59. }
  60. initSingleThumb() {
  61. const first = this.items.first().addClass('loading');
  62. const a = $('<a href="' + first.data('full') + '" />').attr('data-index', 0).appendTo(first);
  63. const img = $('<img alt="' + first.attr("alt") + '" />').appendTo(a);
  64. if (first.data('copyright')) {
  65. $('<span class="copyright">' + first.data('copyright') + '</span>').appendTo(a);
  66. }
  67. first.find('.image-description').appendTo(this.wrapper);
  68. this.isLoaded = false;
  69. img.one('load', () => {
  70. this.section.addClass('loaded');
  71. first.removeClass('loading');
  72. });
  73. if (this.items.length > 1) {
  74. a.append($('<span class="btn has-icon icon-right icon-galerie" />').text(this.items.length + ' Bilder'));
  75. first.find('.image-description').hide();
  76. }
  77. if (this.section.data('type') === 'single-image') {
  78. const ratio = (Math.round(first.data('height') / first.data('width') * 1000) / 10) + '%';
  79. a.css('padding-top', ratio);
  80. first.find('.copyright').appendTo(a).css('max-width', ratio);
  81. }
  82. this.section.closest('.main-col').addClass('clearfix');
  83. }
  84. initThumbs() {
  85. this.items.each(function (i) {
  86. const item = $(this);
  87. $('<a href="' + item.data('full') + '" />').attr('tabindex', '-1').attr('data-index', i).appendTo(item);
  88. })
  89. }
  90. initMasonry() {
  91. this.items.each(function (i) {
  92. const item = $(this);
  93. const a = $('<a href="' + item.data('full') + '" />').attr('data-index', i).appendTo(item);
  94. a.css('padding-top', Math.round(item.data('height') / item.data('width') * 10000) / 100 + '%');
  95. })
  96. const btnText = window.ihk.translations.loadMoreImages;
  97. new Masonry(
  98. this.wrapper,
  99. btnText,
  100. [
  101. {minWidth: 0, batchSize: 6},
  102. {minWidth: 0, batchSize: 6},
  103. {minWidth: 567, batchSize: 9},
  104. {minWidth: 1000, batchSize: 12}
  105. ],
  106. 'primary-light');
  107. }
  108. initLoading() {
  109. const imagesPerPage = this.section.data('per-page');
  110. const buttonWrapper = $('<div class="button-wrapper" />').appendTo(this.section);
  111. const buttonText = window.ihk.translations.loadMoreImages;
  112. if (this.items.length > imagesPerPage) {
  113. this.moreButton = $('<button href="#" class="btn primary-light btn-regular icon-right icon-laden" />').text(buttonText).appendTo(buttonWrapper);
  114. }
  115. if (this.moreButton) {
  116. this.moreButton.on('click', (e) => {
  117. e.preventDefault();
  118. this.currentPage++;
  119. this.loadThumbs();
  120. })
  121. }
  122. }
  123. initTabIndex() {
  124. const focusable = 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]';
  125. const unfocusable = '[tabindex=-1], [disabled], :hidden';
  126. const prevFocusable = this.section.prevAll().find(focusable).not(unfocusable).last();
  127. const nextFocusable = this.section.nextAll().find(focusable).not(unfocusable).first();
  128. this.items.find('a').focus((e) => {
  129. const focusElement = $(e.currentTarget);
  130. const currentIndex = parseInt(focusElement.attr('data-index'));
  131. prevFocusable.attr('tabindex', 1);
  132. this.items.eq(currentIndex - 1).find('a').attr('tabindex', 2);
  133. focusElement.attr('tabindex', 3);
  134. this.items.eq(currentIndex + 1).find('a').attr('tabindex', 4);
  135. nextFocusable.attr('tabindex', 5);
  136. })
  137. this.items.find('a').on('focusout', () => {
  138. this.items.find('a').removeAttr('tabindex');
  139. prevFocusable.removeAttr('tabindex');
  140. nextFocusable.removeAttr('tabindex');
  141. })
  142. nextFocusable.focus(() => {
  143. this.items.find('a').attr('tabindex', -1);
  144. this.visibleItems[this.visibleItems.length - 1].find('a').attr('tabindex', 0);
  145. })
  146. }
  147. loadThumbs() {
  148. const pp = this.section.data('per-page');
  149. const first = this.currentPage * pp;
  150. const last = first + pp < this.items.length ? first + pp : this.items.length;
  151. //const newItems = [];
  152. for (let i = first; i < last; i++) {
  153. const item = this.items.eq(i).addClass('loading');
  154. const img = $('<img />').one('load', function () {
  155. item.removeClass('loading').addClass('loaded');
  156. });
  157. img.attr('src', (this.section.data('type') === 'masonry' ? item.data('full') : item.data('thumb'))).appendTo(item.find('a'));
  158. img.attr('alt', item.attr('alt')).attr('title', item.attr("title")).appendTo(item.find('a'));
  159. this.visibleItems.push(item);
  160. item.find('a').removeAttr('tabindex');
  161. //newItems.push(item);
  162. }
  163. if ( this.moreButton && last === this.items.length) {
  164. this.moreButton.hide();
  165. }
  166. }
  167. initPopup() {
  168. this.popup = $('<div class="gallery-popup" tabindex="-1" />').appendTo($('body'));
  169. const slides = $('<div class="slider" />').appendTo(this.popup);
  170. const closer = $('<button class="closer" />').prependTo(this.popup);
  171. if (this.items.length === 1) {
  172. slides.addClass('single-slide');
  173. }
  174. this.items.each((i, element) => {
  175. const item = $(element);
  176. const slide = $('<div class="slide preload" />').appendTo(slides);
  177. const imgElement = $('<div class="image-box" />').attr('data-src', item.data('full')).attr("title", item.attr("title"));
  178. if (this.section.data("render-download") === true) {
  179. imgElement.attr('data-download', item.data('download'));
  180. }
  181. imgElement.appendTo(slide);
  182. if (item.find('span').length > 0) {
  183. $('<div class="text-box" />').appendTo(slide).append(item.find('span.image-description,span.copyright').clone());
  184. }
  185. })
  186. closer.on('click', (e) => {
  187. e.preventDefault();
  188. this.popup.removeClass('open');
  189. this.popup.find('button, a').attr('tabindex', -1);
  190. this.unbindPopupKeys();
  191. this.toggleContentScroll();
  192. })
  193. this.slider = new Slider(slides);
  194. this.popup.find('button, a').attr('tabindex', -1);
  195. this.wrapper.on('click', 'a', (e) => {
  196. e.preventDefault();
  197. const index = parseInt($(e.currentTarget).attr('data-index'));
  198. this.popup.addClass('open');
  199. this.bindPopupKeys();
  200. this.popup.find('button, a').attr('tabindex', 0);
  201. this.popup.focus();
  202. this.slider.goTo(index, false);
  203. this.toggleContentScroll();
  204. });
  205. if (this.section.data('render-download')) {
  206. const download = $('<a href="#" download class="download" />').prependTo(this.popup);
  207. $(download).attr('href', this.slider.slides.eq(this.slider.currentSlide).find('.image-box').attr('data-download'));
  208. }
  209. slides.on('slide-change', () => {
  210. this.slider.loadImage();
  211. const download = this.popup.find(".download");
  212. if (download.length) {
  213. $(download).attr('href', this.slider.slides.eq(this.slider.currentSlide).find('.image-box').attr('data-download'));
  214. }
  215. })
  216. }
  217. bindPopupKeys() {
  218. $('body').on('keydown.gallery', (e) => {
  219. if (e.keyCode === 27) {
  220. this.popup.find('.closer').trigger('click');
  221. } else if (e.keyCode === 37) {
  222. this.slider.onPrev();
  223. } else if (e.keyCode === 39) {
  224. this.slider.onNext();
  225. }
  226. })
  227. }
  228. unbindPopupKeys() {
  229. $('body').off('keydown.gallery');
  230. }
  231. toggleContentScroll() {
  232. const body = $('body');
  233. const win = $(window);
  234. if (this.popup.hasClass('open')) {
  235. body.css('top', (win.scrollTop() * -1) + 'px').addClass('nav-open');
  236. } else {
  237. const top = Math.abs(parseInt(body.css('top')));
  238. body.removeClass('nav-open').removeAttr('style');
  239. win.scrollTop(top);
  240. }
  241. }
  242. }
  243. export default IHKGallery;
  244. $('body').on('ihk-init dynamic-component-loaded gfi-dynamic-init', () => {
  245. $('.gallery:not(.initiated)').each(function () {
  246. new IHKGallery($(this));
  247. });
  248. });