1/** 2 * @file glightbox.init.js 3 * 4 * JS File to init image and link lightboxes. 5 */ 6(function (Drupal, once) { 7 8 /** 9 * Return custom HTML markup for a glightbox slider for accessibility. 10 * @returns HTML markup. 11 */ 12 const getSlideHtml = (ariaLabel = Drupal.t('Image gallery')) => { 13 return `<div id="glightbox-body" class="glightbox-container" aria-label="${ariaLabel}" tabindex="-1" role="dialog" aria-hidden="false" aria-modal="true"> 14 <div class="gloader visible"></div> 15 <div class="goverlay"></div> 16 <div class="gcontainer"> 17 <div id="glightbox-slider" class="gslider"></div> 18 <button class="gclose gbtn" aria-label="${Drupal.t('Close')}" tabindex="3" data-taborder="3">{closeSVG}</button> 19 <button class="gprev gbtn" aria-label="${Drupal.t('Previous')}" tabindex="2" data-taborder="2">{prevSVG}</button> 20 <button class="gnext gbtn" aria-label="${Drupal.t('Next')}" tabindex="1" data-taborder="1">{nextSVG}</button> 21 </div> 22 </div>`; 23 } 24 25 /** 26 * Focus the first focusable element inside the GLightbox container. 27 */ 28 const focusFirstFocusableInLightbox = (candidates = []) => { 29 const container = document.querySelector('.glightbox-container'); 30 if (!container) { 31 return; 32 } 33 for (const selector of candidates) { 34 const el = container.querySelector(selector); 35 if (!el) { 36 break; 37 } 38 const style = window.getComputedStyle(el); 39 if (style.visibility !== 'hidden' && style.display !== 'none' && el.offsetParent !== null) { 40 el.focus(); 41 break; 42 } 43 } 44 }; 45 46 Drupal.atixTools = Drupal.atixTools || {}; 47 Drupal.atixTools.glightbox = Drupal.atixTools.glightbox || {}; 48 Drupal.atixTools.glightbox.getSlideHtml = getSlideHtml; 49 Drupal.atixTools.glightbox.focusFirstFocusableInLightbox = focusFirstFocusableInLightbox; 50 51 /** 52 * @Behavior Image lightbox 53 */ 54 Drupal.behaviors.lightboxImagesLinks = { 55 selector: '[data-lightbox], [data-lightbox-link]', 56 onceName: 'lightbox', 57 attach(context) { 58 once(this.onceName, context.querySelectorAll(this.selector), context).forEach(function (el) { 59 let uniqueId = el.getAttribute('data-lightbox'); 60 let triggerEle = null; 61 62 const lightbox = GLightbox({ 63 selector: `[data-lightbox="${uniqueId}"] img, [data-lightbox-link]`, 64 lightboxHTML: getSlideHtml(Drupal.t('Image viewer')), 65 }); 66 67 // Open with keyboard on non-interactive default elements (e.g. <div>). 68 if (el.tagName != 'A') { 69 el.addEventListener('keydown', function (event) { 70 switch (event.key) { 71 case 'Enter': 72 case ' ': 73 event.preventDefault(); 74 lightbox.open(); 75 break; 76 } 77 }); 78 } 79 lightbox.on('open', () => { 80 triggerEle = document.activeElement; 81 // Ensure focus moves inside the modal to the first focusable control 82 focusFirstFocusableInLightbox([ 83 '.gclose.gbtn', 84 ]); 85 }); 86 // Focus original link when lightbox is closed 87 lightbox.on('close', () => { 88 if (triggerEle) { 89 triggerEle.focus(); 90 } 91 }); 92 }); 93 }, 94 detach: function detach(context, settings, trigger) { 95 if (trigger === "unload") { 96 once.remove(this.onceName, context.querySelectorAll(this.selector)); 97 } 98 }, 99 }; 100})(Drupal, once);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.