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

307 строки
10 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" aria-hidden="true">' + first.data('copyright') + '</span>').appendTo(a);
  66. $('<span class="sr-only">' + first.data('copyright') + '</span>').appendTo(a);
  67. }
  68. first.find('.image-description').appendTo(this.wrapper);
  69. this.isLoaded = false;
  70. img.one('load', () => {
  71. this.section.addClass('loaded');
  72. first.removeClass('loading');
  73. });
  74. if (this.items.length > 1) {
  75. a.append($('<span class="btn has-icon icon-right icon-galerie" />').text(this.items.length + ' Bilder'));
  76. first.find('.image-description').hide();
  77. }
  78. if (this.section.data('type') === 'single-image') {
  79. const ratio = (Math.round(first.data('height') / first.data('width') * 1000) / 10) + '%';
  80. a.css('padding-top', ratio);
  81. first.find('.copyright').appendTo(a).css('max-width', ratio);
  82. }
  83. this.section.closest('.main-col').addClass('clearfix');
  84. }
  85. initThumbs() {
  86. this.items.each(function (i) {
  87. const item = $(this);
  88. $('<a href="' + item.data('full') + '" />').attr('tabindex', '-1').attr('data-index', i).appendTo(item);
  89. })
  90. }
  91. initMasonry() {
  92. this.items.each(function (i) {
  93. const item = $(this);
  94. const a = $('<a href="' + item.data('full') + '" />').attr('data-index', i).appendTo(item);
  95. a.css('padding-top', Math.round(item.data('height') / item.data('width') * 10000) / 100 + '%');
  96. // Copyright für Masonry-Element vorbereiten
  97. if (item.data('copyright')) {
  98. a.append('<span class="copyright">' + item.data('copyright') + '</span>');
  99. }
  100. })
  101. const btnText = window.ihk.translations.loadMoreImages;
  102. new Masonry(
  103. this.wrapper,
  104. btnText,
  105. [
  106. {minWidth: 0, batchSize: 6},
  107. {minWidth: 0, batchSize: 6},
  108. {minWidth: 567, batchSize: 9},
  109. {minWidth: 1000, batchSize: 12}
  110. ],
  111. 'primary-light');
  112. }
  113. initLoading() {
  114. const imagesPerPage = this.section.data('per-page');
  115. const buttonWrapper = $('<div class="button-wrapper" />').appendTo(this.section);
  116. const buttonText = window.ihk.translations.loadMoreImages;
  117. if (this.items.length > imagesPerPage) {
  118. this.moreButton = $('<button href="#" class="btn primary-light btn-regular icon-right icon-laden" />').text(buttonText).appendTo(buttonWrapper);
  119. }
  120. if (this.moreButton) {
  121. this.moreButton.on('click', (e) => {
  122. e.preventDefault();
  123. this.currentPage++;
  124. this.loadThumbs();
  125. })
  126. }
  127. }
  128. initTabIndex() {
  129. const focusable = 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]';
  130. const unfocusable = '[tabindex=-1], [disabled], :hidden';
  131. const prevFocusable = this.section.prevAll().find(focusable).not(unfocusable).last();
  132. const nextFocusable = this.section.nextAll().find(focusable).not(unfocusable).first();
  133. this.items.find('a').focus((e) => {
  134. const focusElement = $(e.currentTarget);
  135. const currentIndex = parseInt(focusElement.attr('data-index'));
  136. prevFocusable.attr('tabindex', 1);
  137. this.items.eq(currentIndex - 1).find('a').attr('tabindex', 2);
  138. focusElement.attr('tabindex', 3);
  139. this.items.eq(currentIndex + 1).find('a').attr('tabindex', 4);
  140. nextFocusable.attr('tabindex', 5);
  141. })
  142. this.items.find('a').on('focusout', () => {
  143. this.items.find('a').removeAttr('tabindex');
  144. prevFocusable.removeAttr('tabindex');
  145. nextFocusable.removeAttr('tabindex');
  146. })
  147. nextFocusable.focus(() => {
  148. this.items.find('a').attr('tabindex', -1);
  149. this.visibleItems[this.visibleItems.length - 1].find('a').attr('tabindex', 0);
  150. })
  151. }
  152. loadThumbs() {
  153. const pp = this.section.data('per-page');
  154. const first = this.currentPage * pp;
  155. const last = first + pp < this.items.length ? first + pp : this.items.length;
  156. //const newItems = [];
  157. for (let i = first; i < last; i++) {
  158. const item = this.items.eq(i).addClass('loading');
  159. const img = $('<img />').one('load', function () {
  160. item.removeClass('loading').addClass('loaded');
  161. });
  162. img.attr('src', (this.section.data('type') === 'masonry' ? item.data('full') : item.data('thumb'))).appendTo(item.find('a'));
  163. img.attr('alt', item.attr('alt')).attr('title', item.attr("title"));
  164. if (item.data('copyright')) {
  165. $('<span class="copyright">').html(item.data('copyright')).appendTo(item.find('a'));
  166. }
  167. this.visibleItems.push(item);
  168. item.find('a').removeAttr('tabindex');
  169. //newItems.push(item);
  170. }
  171. if ( this.moreButton && last === this.items.length) {
  172. this.moreButton.hide();
  173. }
  174. }
  175. initPopup() {
  176. this.popup = $('<div class="gallery-popup" tabindex="-1" />').appendTo($('body'));
  177. const slides = $('<div class="slider" />').appendTo(this.popup);
  178. const closer = $('<button class="closer" aria-label="Schließen" />').prependTo(this.popup);
  179. if (this.items.length === 1) {
  180. slides.addClass('single-slide');
  181. }
  182. this.items.each((i, element) => {
  183. const item = $(element);
  184. const slide = $('<div class="slide preload" />').appendTo(slides);
  185. const imgElement = $('<div class="image-box" />').attr('data-src', item.data('full')).attr('data-copyright', item.data('copyright')).attr("title", item.attr("title"));
  186. if (this.section.data("render-download") === true) {
  187. imgElement.attr('data-download', item.data('download'));
  188. }
  189. imgElement.appendTo(slide);
  190. if (item.find('span').length > 0) {
  191. $('<div class="text-box" />').appendTo(slide).append(item.find('span.image-description,span.copyright').clone());
  192. }
  193. })
  194. closer.on('click', (e) => {
  195. e.preventDefault();
  196. this.popup.removeClass('open');
  197. this.popup.find('button, a').attr('tabindex', -1);
  198. this.unbindPopupKeys();
  199. this.toggleContentScroll();
  200. })
  201. this.slider = new Slider(slides);
  202. this.popup.find('button, a').attr('tabindex', -1);
  203. this.wrapper.on('click', 'a', (e) => {
  204. e.preventDefault();
  205. const index = parseInt($(e.currentTarget).attr('data-index'));
  206. this.popup.addClass('open');
  207. this.bindPopupKeys();
  208. this.popup.find('button, a').attr('tabindex', 0);
  209. this.popup.focus();
  210. this.slider.goTo(index, false);
  211. this.toggleContentScroll();
  212. });
  213. if (this.section.data('render-download')) {
  214. const download = $('<a href="#" download class="download" />').prependTo(this.popup);
  215. $(download).attr('href', this.slider.slides.eq(this.slider.currentSlide).find('.image-box').attr('data-download'));
  216. }
  217. slides.on('slide-change', () => {
  218. this.slider.loadImage();
  219. const download = this.popup.find(".download");
  220. if (download.length) {
  221. $(download).attr('href', this.slider.slides.eq(this.slider.currentSlide).find('.image-box').attr('data-download'));
  222. }
  223. })
  224. }
  225. bindPopupKeys() {
  226. $('body').on('keydown.gallery', (e) => {
  227. if (e.keyCode === 27) {
  228. this.popup.find('.closer').trigger('click');
  229. } else if (e.keyCode === 37) {
  230. this.slider.onPrev();
  231. } else if (e.keyCode === 39) {
  232. this.slider.onNext();
  233. }
  234. })
  235. }
  236. unbindPopupKeys() {
  237. $('body').off('keydown.gallery');
  238. }
  239. toggleContentScroll() {
  240. const body = $('body');
  241. const win = $(window);
  242. if (this.popup.hasClass('open')) {
  243. body.css('top', (win.scrollTop() * -1) + 'px').addClass('nav-open');
  244. } else {
  245. const top = Math.abs(parseInt(body.css('top')));
  246. body.removeClass('nav-open').removeAttr('style');
  247. win.scrollTop(top);
  248. }
  249. }
  250. }
  251. export default IHKGallery;
  252. $('body').on('ihk-init dynamic-component-loaded gfi-dynamic-init', () => {
  253. $('.gallery:not(.initiated)').each(function () {
  254. new IHKGallery($(this));
  255. });
  256. });