gallery.js

  1. import { queryOne, queryAll } from '@ecl/dom-utils';
  2. import { createFocusTrap } from 'focus-trap';
  3. /**
  4. * @param {HTMLElement} element DOM element for component instantiation and scope
  5. * @param {Object} options
  6. * @param {String} options.galleryItemSelector Selector for gallery element
  7. * @param {String} options.descriptionSelector Selector for gallery description element
  8. * @param {String} options.metaSelector Selector for gallery meta info element
  9. * @param {String} options.closeButtonSelector Selector for close button element
  10. * @param {String} options.allButtonSelector Selector for view all button element
  11. * @param {String} options.overlaySelector Selector for gallery overlay element
  12. * @param {String} options.overlayHeaderSelector Selector for gallery overlay header element
  13. * @param {String} options.overlayFooterSelector Selector for gallery overlay footer element
  14. * @param {String} options.overlayMediaSelector Selector for gallery overlay media element
  15. * @param {String} options.overlayCounterCurrentSelector Selector for gallery overlay current number element
  16. * @param {String} options.overlayCounterMaxSelector Selector for display of number of elements in the gallery overlay
  17. * @param {String} options.overlayDownloadSelector Selector for gallery overlay download element
  18. * @param {String} options.overlayShareSelector Selector for gallery overlay share element
  19. * @param {String} options.overlayDescriptionSelector Selector for gallery overlay description element
  20. * @param {String} options.overlayMetaSelector Selector for gallery overlay meta info element
  21. * @param {String} options.overlayPreviousSelector Selector for gallery overlay previous link element
  22. * @param {String} options.overlayNextSelector Selector for gallery overlay next link element
  23. * @param {Boolean} options.attachClickListener Whether or not to bind click events
  24. * @param {Boolean} options.attachKeyListener Whether or not to bind keyup events
  25. */
  26. export class Gallery {
  27. /**
  28. * @static
  29. * Shorthand for instance creation and initialisation.
  30. *
  31. * @param {HTMLElement} root DOM element for component instantiation and scope
  32. *
  33. * @return {Gallery} An instance of Gallery.
  34. */
  35. static autoInit(root, { GALLERY: defaultOptions = {} } = {}) {
  36. const gallery = new Gallery(root, defaultOptions);
  37. gallery.init();
  38. root.ECLGallery = gallery;
  39. return gallery;
  40. }
  41. constructor(
  42. element,
  43. {
  44. expandableSelector = 'data-ecl-gallery-not-expandable',
  45. galleryItemSelector = '[data-ecl-gallery-item]',
  46. descriptionSelector = '[data-ecl-gallery-description]',
  47. noOverlaySelector = 'data-ecl-gallery-no-overlay',
  48. metaSelector = '[data-ecl-gallery-meta]',
  49. itemsLimitSelector = 'data-ecl-gallery-visible-items',
  50. closeButtonSelector = '[data-ecl-gallery-close]',
  51. viewAllSelector = '[data-ecl-gallery-all]',
  52. viewAllLabelSelector = 'data-ecl-gallery-collapsed-label',
  53. viewAllExpandedLabelSelector = 'data-ecl-gallery-expanded-label',
  54. countSelector = '[data-ecl-gallery-count]',
  55. overlaySelector = '[data-ecl-gallery-overlay]',
  56. overlayHeaderSelector = '[data-ecl-gallery-overlay-header]',
  57. overlayFooterSelector = '[data-ecl-gallery-overlay-footer]',
  58. overlayMediaSelector = '[data-ecl-gallery-overlay-media]',
  59. overlayCounterCurrentSelector = '[data-ecl-gallery-overlay-counter-current]',
  60. overlayCounterMaxSelector = '[data-ecl-gallery-overlay-counter-max]',
  61. overlayDownloadSelector = '[data-ecl-gallery-overlay-download]',
  62. overlayShareSelector = '[data-ecl-gallery-overlay-share]',
  63. overlayDescriptionSelector = '[data-ecl-gallery-overlay-description]',
  64. overlayMetaSelector = '[data-ecl-gallery-overlay-meta]',
  65. overlayPreviousSelector = '[data-ecl-gallery-overlay-previous]',
  66. overlayNextSelector = '[data-ecl-gallery-overlay-next]',
  67. attachClickListener = true,
  68. attachKeyListener = true,
  69. attachResizeListener = true,
  70. } = {},
  71. ) {
  72. // Check element
  73. if (!element || element.nodeType !== Node.ELEMENT_NODE) {
  74. throw new TypeError(
  75. 'DOM element should be given to initialize this widget.',
  76. );
  77. }
  78. this.element = element;
  79. // Options
  80. this.galleryItemSelector = galleryItemSelector;
  81. this.descriptionSelector = descriptionSelector;
  82. this.metaSelector = metaSelector;
  83. this.closeButtonSelector = closeButtonSelector;
  84. this.viewAllSelector = viewAllSelector;
  85. this.countSelector = countSelector;
  86. this.itemsLimitSelector = itemsLimitSelector;
  87. this.overlaySelector = overlaySelector;
  88. this.noOverlaySelector = noOverlaySelector;
  89. this.overlayHeaderSelector = overlayHeaderSelector;
  90. this.overlayFooterSelector = overlayFooterSelector;
  91. this.overlayMediaSelector = overlayMediaSelector;
  92. this.overlayCounterCurrentSelector = overlayCounterCurrentSelector;
  93. this.overlayCounterMaxSelector = overlayCounterMaxSelector;
  94. this.overlayDownloadSelector = overlayDownloadSelector;
  95. this.overlayShareSelector = overlayShareSelector;
  96. this.overlayDescriptionSelector = overlayDescriptionSelector;
  97. this.overlayMetaSelector = overlayMetaSelector;
  98. this.overlayPreviousSelector = overlayPreviousSelector;
  99. this.overlayNextSelector = overlayNextSelector;
  100. this.attachClickListener = attachClickListener;
  101. this.attachKeyListener = attachKeyListener;
  102. this.attachResizeListener = attachResizeListener;
  103. this.viewAllLabelSelector = viewAllLabelSelector;
  104. this.viewAllExpandedLabelSelector = viewAllExpandedLabelSelector;
  105. this.expandableSelector = expandableSelector;
  106. // Private variables
  107. this.galleryItems = null;
  108. this.meta = null;
  109. this.closeButton = null;
  110. this.viewAll = null;
  111. this.count = null;
  112. this.overlay = null;
  113. this.overlayHeader = null;
  114. this.overlayFooter = null;
  115. this.overlayMedia = null;
  116. this.overlayCounterCurrent = null;
  117. this.overlayCounterMax = null;
  118. this.overlayDownload = null;
  119. this.overlayShare = null;
  120. this.overlayDescription = null;
  121. this.overlayMeta = null;
  122. this.overlayPrevious = null;
  123. this.overlayNext = null;
  124. this.selectedItem = null;
  125. this.focusTrap = null;
  126. this.isDesktop = false;
  127. this.resizeTimer = null;
  128. this.visibleItems = 0;
  129. this.breakpointMd = 768;
  130. this.breakpointLg = 996;
  131. this.imageHeight = 185;
  132. this.imageHeightBig = 260;
  133. // Bind `this` for use in callbacks
  134. this.iframeResize = this.iframeResize.bind(this);
  135. this.handleClickOnCloseButton = this.handleClickOnCloseButton.bind(this);
  136. this.handleClickOnViewAll = this.handleClickOnViewAll.bind(this);
  137. this.handleClickOnItem = this.handleClickOnItem.bind(this);
  138. this.preventClickOnItem = this.preventClickOnItem.bind(this);
  139. this.handleKeyPressOnItem = this.handleKeyPressOnItem.bind(this);
  140. this.handleClickOnPreviousButton =
  141. this.handleClickOnPreviousButton.bind(this);
  142. this.handleClickOnNextButton = this.handleClickOnNextButton.bind(this);
  143. this.handleKeyboard = this.handleKeyboard.bind(this);
  144. this.handleResize = this.handleResize.bind(this);
  145. }
  146. /**
  147. * Initialise component.
  148. */
  149. init() {
  150. if (!ECL) {
  151. throw new TypeError('Called init but ECL is not present');
  152. }
  153. ECL.components = ECL.components || new Map();
  154. // Query elements
  155. this.expandable = !this.element.hasAttribute(this.expandableSelector);
  156. this.visibleItems = this.element.getAttribute(this.itemsLimitSelector);
  157. this.galleryItems = queryAll(this.galleryItemSelector, this.element);
  158. this.closeButton = queryOne(this.closeButtonSelector, this.element);
  159. this.noOverlay = this.element.hasAttribute(this.noOverlaySelector);
  160. if (this.expandable) {
  161. this.viewAll = queryOne(this.viewAllSelector, this.element);
  162. this.viewAllLabel =
  163. this.viewAll.getAttribute(this.viewAllLabelSelector) ||
  164. this.viewAll.innerText;
  165. this.viewAllLabelExpanded =
  166. this.viewAll.getAttribute(this.viewAllExpandedLabelSelector) ||
  167. this.viewAllLabel;
  168. }
  169. this.count = queryOne(this.countSelector, this.element);
  170. // Bind click event on view all (open first item)
  171. if (this.attachClickListener && this.viewAll) {
  172. this.viewAll.addEventListener('click', this.handleClickOnViewAll);
  173. }
  174. if (!this.noOverlay) {
  175. this.overlay = queryOne(this.overlaySelector, this.element);
  176. this.overlayHeader = queryOne(this.overlayHeaderSelector, this.overlay);
  177. this.overlayFooter = queryOne(this.overlayFooterSelector, this.overlay);
  178. this.overlayMedia = queryOne(this.overlayMediaSelector, this.overlay);
  179. this.overlayCounterCurrent = queryOne(
  180. this.overlayCounterCurrentSelector,
  181. this.overlay,
  182. );
  183. this.overlayCounterMax = queryOne(
  184. this.overlayCounterMaxSelector,
  185. this.overlay,
  186. );
  187. this.overlayDownload = queryOne(
  188. this.overlayDownloadSelector,
  189. this.overlay,
  190. );
  191. this.overlayShare = queryOne(this.overlayShareSelector, this.overlay);
  192. this.overlayDescription = queryOne(
  193. this.overlayDescriptionSelector,
  194. this.overlay,
  195. );
  196. this.overlayMeta = queryOne(this.overlayMetaSelector, this.overlay);
  197. this.overlayPrevious = queryOne(
  198. this.overlayPreviousSelector,
  199. this.overlay,
  200. );
  201. this.overlayNext = queryOne(this.overlayNextSelector, this.overlay);
  202. // Create focus trap
  203. this.focusTrap = createFocusTrap(this.overlay, {
  204. escapeDeactivates: false,
  205. returnFocusOnDeactivate: false,
  206. });
  207. // Polyfill to support <dialog>
  208. this.isDialogSupported = true;
  209. if (!window.HTMLDialogElement) {
  210. this.isDialogSupported = false;
  211. }
  212. // Bind click event on close button
  213. if (this.attachClickListener && this.closeButton) {
  214. this.closeButton.addEventListener(
  215. 'click',
  216. this.handleClickOnCloseButton,
  217. );
  218. }
  219. // Bind click event on gallery items
  220. if (this.attachClickListener && this.galleryItems) {
  221. this.galleryItems.forEach((galleryItem) => {
  222. if (this.attachClickListener) {
  223. galleryItem.addEventListener('click', this.handleClickOnItem);
  224. }
  225. if (this.attachKeyListener) {
  226. galleryItem.addEventListener('keyup', this.handleKeyPressOnItem);
  227. }
  228. });
  229. }
  230. // Bind click event on previous button
  231. if (this.attachClickListener && this.overlayPrevious) {
  232. this.overlayPrevious.addEventListener(
  233. 'click',
  234. this.handleClickOnPreviousButton,
  235. );
  236. }
  237. // Bind click event on next button
  238. if (this.attachClickListener && this.overlayNext) {
  239. this.overlayNext.addEventListener(
  240. 'click',
  241. this.handleClickOnNextButton,
  242. );
  243. }
  244. // Bind other close event
  245. if (!this.isDialogSupported && this.attachKeyListener && this.overlay) {
  246. this.overlay.addEventListener('keyup', this.handleKeyboard);
  247. }
  248. if (this.isDialogSupported && this.overlay) {
  249. this.overlay.addEventListener('close', this.handleClickOnCloseButton);
  250. }
  251. } else {
  252. this.galleryItems.forEach((galleryItem) => {
  253. galleryItem.classList.add('ecl-gallery__item__link--frozen');
  254. galleryItem.addEventListener('click', this.preventClickOnItem);
  255. });
  256. }
  257. // Bind resize events
  258. if (this.attachResizeListener) {
  259. window.addEventListener('resize', this.handleResize);
  260. }
  261. // Init display of gallery items
  262. if (this.expandable) {
  263. this.checkScreen();
  264. this.hideItems();
  265. }
  266. // Add number to gallery items
  267. this.galleryItems.forEach((galleryItem, key) => {
  268. galleryItem.setAttribute('data-ecl-gallery-item-id', key);
  269. });
  270. // Update counter
  271. if (this.count) {
  272. this.count.innerHTML = this.galleryItems.length;
  273. }
  274. // Set ecl initialized attribute
  275. this.element.setAttribute('data-ecl-auto-initialized', 'true');
  276. ECL.components.set(this.element, this);
  277. }
  278. /**
  279. * Destroy component.
  280. */
  281. destroy() {
  282. if (this.attachClickListener && this.closeButton) {
  283. this.closeButton.removeEventListener(
  284. 'click',
  285. this.handleClickOnCloseButton,
  286. );
  287. }
  288. if (this.attachClickListener && this.viewAll) {
  289. this.viewAll.removeEventListener('click', this.handleClickOnViewAll);
  290. }
  291. if (this.attachClickListener && this.galleryItems) {
  292. this.galleryItems.forEach((galleryItem) => {
  293. galleryItem.removeEventListener('click', this.handleClickOnItem);
  294. });
  295. }
  296. if (this.attachClickListener && this.overlayPrevious) {
  297. this.overlayPrevious.removeEventListener(
  298. 'click',
  299. this.handleClickOnPreviousButton,
  300. );
  301. }
  302. if (this.attachClickListener && this.overlayNext) {
  303. this.overlayNext.removeEventListener(
  304. 'click',
  305. this.handleClickOnNextButton,
  306. );
  307. }
  308. if (!this.isDialogSupported && this.attachKeyListener && this.overlay) {
  309. this.overlay.removeEventListener('keyup', this.handleKeyboard);
  310. }
  311. if (this.isDialogSupported && this.overlay) {
  312. this.overlay.removeEventListener('close', this.handleClickOnCloseButton);
  313. }
  314. if (this.attachResizeListener) {
  315. window.removeEventListener('resize', this.handleResize);
  316. }
  317. if (this.element) {
  318. this.element.removeAttribute('data-ecl-auto-initialized');
  319. ECL.components.delete(this.element);
  320. }
  321. }
  322. /**
  323. * Check if current display is desktop or mobile
  324. */
  325. checkScreen() {
  326. if (window.innerWidth > this.breakpointMd) {
  327. this.isDesktop = true;
  328. } else {
  329. this.isDesktop = false;
  330. }
  331. if (window.innerWidth > this.breakpointLg) {
  332. this.isLarge = true;
  333. }
  334. }
  335. iframeResize(iframe) {
  336. if (!iframe && this.overlay) {
  337. iframe = queryOne('iframe', this.overlay);
  338. }
  339. if (iframe) {
  340. const width = window.innerWidth;
  341. setTimeout(() => {
  342. const height =
  343. this.overlay.clientHeight -
  344. this.overlayHeader.clientHeight -
  345. this.overlayFooter.clientHeight;
  346. if (width > height) {
  347. iframe.setAttribute('height', `${height}px`);
  348. if ((height * 16) / 9 > width) {
  349. iframe.setAttribute('width', `${width - 0.05 * width}px`);
  350. } else {
  351. iframe.setAttribute('width', `${(height * 16) / 9}px`);
  352. }
  353. } else {
  354. iframe.setAttribute('width', `${width}px`);
  355. if ((width * 4) / 3 > height) {
  356. iframe.setAttribute('height', `${height - 0.05 * height}px`);
  357. } else {
  358. iframe.setAttribute('height', `${(width * 4) / 3}px`);
  359. }
  360. }
  361. }, 0);
  362. }
  363. }
  364. /**
  365. * @param {Int} rows/item number
  366. *
  367. * Hide several gallery items by default
  368. * - 2 "lines" of items on desktop
  369. * - only 3 items on mobile or the desired rows or items
  370. * when using the view more button.
  371. */
  372. hideItems(plus = 0) {
  373. if (!this.viewAll || this.viewAll.expanded) return;
  374. if (this.isDesktop) {
  375. let hiddenItemIds = [];
  376. // We should browse the list first to mark the items to be hidden, and hide them later
  377. // otherwise, it will interfer with the calculus
  378. this.galleryItems.forEach((galleryItem, key) => {
  379. galleryItem.parentNode.classList.remove('ecl-gallery__item--hidden');
  380. if (key >= Number(this.visibleItems) + Number(plus)) {
  381. hiddenItemIds = [...hiddenItemIds, key];
  382. }
  383. });
  384. hiddenItemIds.forEach((id) => {
  385. this.galleryItems[id].parentNode.classList.add(
  386. 'ecl-gallery__item--hidden',
  387. );
  388. });
  389. return;
  390. }
  391. this.galleryItems.forEach((galleryItem, key) => {
  392. if (key > 2 + Number(plus)) {
  393. galleryItem.parentNode.classList.add('ecl-gallery__item--hidden');
  394. } else {
  395. galleryItem.parentNode.classList.remove('ecl-gallery__item--hidden');
  396. }
  397. });
  398. }
  399. /**
  400. * Trigger events on resize
  401. * Uses a debounce, for performance
  402. */
  403. handleResize() {
  404. clearTimeout(this.resizeTimer);
  405. this.resizeTimer = setTimeout(() => {
  406. this.checkScreen();
  407. this.hideItems();
  408. this.iframeResize();
  409. }, 200);
  410. }
  411. /**
  412. * @param {HTMLElement} selectedItem Media element
  413. */
  414. updateOverlay(selectedItem) {
  415. this.selectedItem = selectedItem;
  416. const embeddedVideo = selectedItem.getAttribute(
  417. 'data-ecl-gallery-item-embed-src',
  418. );
  419. const video = queryOne('video', selectedItem);
  420. let mediaElement = null;
  421. // Update media
  422. if (embeddedVideo != null) {
  423. // Media is a embedded video
  424. mediaElement = document.createElement('div');
  425. mediaElement.classList.add('ecl-gallery__slider-embed');
  426. const mediaIframe = document.createElement('iframe');
  427. mediaIframe.setAttribute('src', embeddedVideo);
  428. mediaIframe.setAttribute('frameBorder', '0');
  429. if (this.overlayMedia) {
  430. mediaElement.appendChild(mediaIframe);
  431. this.overlayMedia.innerHTML = '';
  432. this.overlayMedia.appendChild(mediaElement);
  433. }
  434. this.iframeResize(mediaIframe);
  435. } else if (video != null) {
  436. // Media is a video
  437. mediaElement = document.createElement('video');
  438. mediaElement.setAttribute('poster', video.poster);
  439. mediaElement.setAttribute('controls', 'controls');
  440. mediaElement.classList.add('ecl-gallery__slider-video');
  441. if (this.overlayMedia) {
  442. this.overlayMedia.innerHTML = '';
  443. this.overlayMedia.appendChild(mediaElement);
  444. }
  445. // Get sources
  446. const sources = queryAll('source', video);
  447. sources.forEach((source) => {
  448. const sourceTag = document.createElement('source');
  449. sourceTag.setAttribute('src', source.getAttribute('src'));
  450. sourceTag.setAttribute('type', source.getAttribute('type'));
  451. mediaElement.appendChild(sourceTag);
  452. });
  453. // Get tracks
  454. const tracks = queryAll('track', video);
  455. tracks.forEach((track) => {
  456. const trackTag = document.createElement('track');
  457. trackTag.setAttribute('src', track.getAttribute('src'));
  458. trackTag.setAttribute('kind', track.getAttribute('kind'));
  459. trackTag.setAttribute('srclang', track.getAttribute('srcLang'));
  460. trackTag.setAttribute('label', track.getAttribute('label'));
  461. mediaElement.appendChild(trackTag);
  462. });
  463. mediaElement.load();
  464. } else {
  465. // Media is an image
  466. const image = queryOne('img', selectedItem);
  467. const picture = queryOne('picture', selectedItem);
  468. if (picture) {
  469. image.classList.remove('ecl-gallery__image');
  470. mediaElement = picture.cloneNode(true);
  471. } else {
  472. // backward compatibility
  473. mediaElement = document.createElement('img');
  474. mediaElement.setAttribute('src', image.getAttribute('src'));
  475. mediaElement.setAttribute('alt', image.getAttribute('alt'));
  476. }
  477. mediaElement.classList.add('ecl-gallery__slider-image');
  478. if (this.overlayMedia) {
  479. this.overlayMedia.innerHTML = '';
  480. this.overlayMedia.appendChild(mediaElement);
  481. }
  482. }
  483. // Update counter
  484. this.overlayCounterCurrent.innerHTML =
  485. +selectedItem.getAttribute('data-ecl-gallery-item-id') + 1;
  486. this.overlayCounterMax.innerHTML = this.galleryItems.length;
  487. // Update share link
  488. const shareHref = this.selectedItem.getAttribute(
  489. 'data-ecl-gallery-item-share',
  490. );
  491. if (shareHref != null) {
  492. this.overlayShare.href = shareHref;
  493. this.overlayShare.hidden = false;
  494. } else {
  495. this.overlayShare.hidden = true;
  496. }
  497. // Update download link
  498. if (this.overlayDownload !== null && embeddedVideo === null) {
  499. this.overlayDownload.href = this.selectedItem.href;
  500. this.overlayDownload.hidden = false;
  501. } else if (this.overlayDownload !== null) {
  502. this.overlayDownload.hidden = true;
  503. }
  504. // Update meta
  505. const meta = queryOne(this.metaSelector, selectedItem);
  506. this.overlayMeta.innerHTML = meta.innerHTML;
  507. // Update description
  508. const description = queryOne(this.descriptionSelector, selectedItem);
  509. this.overlayDescription.innerHTML = description.innerHTML;
  510. }
  511. /**
  512. * Handles keyboard events such as Escape and navigation.
  513. *
  514. * @param {Event} e
  515. */
  516. handleKeyboard(e) {
  517. // Detect press on Escape
  518. // Only used if the browser do not support <dialog>
  519. if (e.key === 'Escape' || e.key === 'Esc') {
  520. this.handleClickOnCloseButton();
  521. }
  522. }
  523. /**
  524. * Invoke listeners for close events.
  525. */
  526. handleClickOnCloseButton() {
  527. if (this.isDialogSupported) {
  528. this.overlay.close();
  529. } else {
  530. this.overlay.removeAttribute('open');
  531. }
  532. // Remove iframe
  533. const embeddedVideo = queryOne('iframe', this.overlayMedia);
  534. if (embeddedVideo) embeddedVideo.remove();
  535. // Stop video
  536. const video = queryOne('video', this.overlayMedia);
  537. if (video) video.pause();
  538. // Untrap focus
  539. this.focusTrap.deactivate();
  540. // Focus item
  541. this.selectedItem.focus();
  542. // Enable scroll on body
  543. document.body.classList.remove('ecl-u-disablescroll');
  544. }
  545. /**
  546. * Invoke listeners for on pressing the spacebar button.
  547. *
  548. * @param {Event} e
  549. */
  550. handleKeyPressOnItem(e) {
  551. if (e.keyCode === 32) {
  552. // If spacebar trigger the modal
  553. this.handleClickOnItem(e);
  554. }
  555. }
  556. /**
  557. * Invoke listeners for on click events on view all.
  558. *
  559. * @param {Event} e
  560. */
  561. handleClickOnViewAll(e) {
  562. e.preventDefault();
  563. if (!this.viewAll) return;
  564. if (this.viewAll.expanded) {
  565. delete this.viewAll.expanded;
  566. this.checkScreen();
  567. this.hideItems();
  568. this.viewAll.textContent = this.viewAllLabel;
  569. } else {
  570. this.galleryItems.forEach((item) => {
  571. this.viewAll.expanded = true;
  572. item.parentNode.classList.remove('ecl-gallery__item--hidden');
  573. this.viewAll.textContent = this.viewAllLabelExpanded;
  574. });
  575. }
  576. }
  577. /**
  578. * Invoke listeners for on click events on the given gallery item.
  579. *
  580. * @param {Event} e
  581. */
  582. handleClickOnItem(e) {
  583. e.preventDefault();
  584. // Disable scroll on body
  585. document.body.classList.add('ecl-u-disablescroll');
  586. // Display overlay
  587. if (this.isDialogSupported) {
  588. this.overlay.showModal();
  589. } else {
  590. this.overlay.setAttribute('open', '');
  591. }
  592. // Update overlay
  593. this.updateOverlay(e.currentTarget);
  594. // Trap focus
  595. this.focusTrap.activate();
  596. }
  597. /**
  598. * handle click event on gallery items when no overlay.
  599. *
  600. * @param {Event} e
  601. */
  602. // eslint-disable-next-line class-methods-use-this
  603. preventClickOnItem(e) {
  604. e.preventDefault();
  605. e.stopPropagation();
  606. }
  607. /**
  608. * Invoke listeners for on click events on previous navigation link.
  609. */
  610. handleClickOnPreviousButton() {
  611. // Get current id
  612. const currentId = this.selectedItem.getAttribute(
  613. 'data-ecl-gallery-item-id',
  614. );
  615. // Get previous id
  616. let previousId = +currentId - 1;
  617. if (previousId < 0) previousId = this.galleryItems.length - 1;
  618. // Stop video
  619. const video = queryOne('video', this.selectedItem);
  620. if (video) video.pause();
  621. // Update overlay
  622. this.updateOverlay(this.galleryItems[previousId]);
  623. this.selectedItem = this.galleryItems[previousId];
  624. return this;
  625. }
  626. /**
  627. * Invoke listeners for on click events on next navigation link.
  628. */
  629. handleClickOnNextButton() {
  630. // Get current id
  631. const currentId = this.selectedItem.getAttribute(
  632. 'data-ecl-gallery-item-id',
  633. );
  634. // Get next id
  635. let nextId = +currentId + 1;
  636. if (nextId >= this.galleryItems.length) nextId = 0;
  637. // Stop video
  638. const video = queryOne('video', this.selectedItem);
  639. if (video) video.pause();
  640. // Update overlay
  641. this.updateOverlay(this.galleryItems[nextId]);
  642. this.selectedItem = this.galleryItems[nextId];
  643. return this;
  644. }
  645. }
  646. export default Gallery;