1/**� 2 * Modal jquery code� 3 * 11/13/2021 - do not scroll to first focusable field� 4 * 8/2/2021 - add code to allow timer modal to optionally display only once via the use of a cookie� 5 * 8/17/2021 - do not allow timer modal to display if another modal already open� 6 * 11/1/2021 - when setting focus on first element do not scroll� 7 * 2/15/2022 - disable close modal on escape if disabled in the frontend� 8 * 4/5/2022 - Do not scroll when returning focus on modal close � 9 * 5/5/2022 - Allow for modals to call other modals� 10 * 6/28/2022 - Allow for checking url for text before triggering modal� 11 * 11/22/2022 - custom events for open and close� 12 * 1/11/2023 - Provide ability to manually trigger initialization of modals on page. Also only initialize modals when document is ready.� 13 */� 14� 15 � 16var bodModalBlock = function(){� 17 "use strict";� 18 � 19 var $ = jQuery.noConflict();� 20� 21 const focusableElements =� 22 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';� 23� 24 var bodModalCount = 0; // global count of modals� 25 var bodModalActive = false;� 26 var bodModals = [];� 27� 28 var initElements = function(){� 29 � 30 bodModalCount = 0; // global count of modals� 31 bodModalActive = false;� 32 bodModals = [];� 33� 34 // if we have already inited this type of element� 35 $('.wp-block-bod-modal-block').each(function(){� 36 // for the identified modal we add an instance of the class BodModal � 37 // to the data element � 38 // $(this).data('bod-block-popup', new BodModal(this));� 39 bodModals.push(new BodModal(this));� 40� 41 });� 42 };� 43� 44 var checkForCookie = function(cookieName){� 45 let name = cookieName + "=";� 46 let decodedCookie = decodeURIComponent(document.cookie);� 47 let ca = decodedCookie.split(';');� 48 for(let i = 0; i <ca.length; i++) {� 49 let c = ca[i];� 50 while (c.charAt(0) == ' ') {� 51 c = c.substring(1);� 52 }� 53 if (c.indexOf(name) == 0) {� 54 return c.substring(name.length, c.length);� 55 }� 56 }� 57 return "";� 58 }� 59� 60� 61 // class used to manipulate the modal, there will be a seperate instance of the � 62 // class for each modal on the page� 63 // container - DOM object for modal � 64 var BodModal = function (container) {� 65 // convert passed in DOM modal container to jquery object so we can apply jquery methods� 66 this.$container = $(container);� 67 this.$trigger = this.$container.find('.bod-block-popup-trigger');� 68 this.$overlay = this.$container.find('.bod-block-popup-overlay');� 69� 70 // Markup the aria labels� 71� 72 bodModalCount ++; // get modal number to append to get unique id� 73 this.$container.find('.bod-block-popup-wrap').attr('aria-labelledby','bodModalAriaTitle' + bodModalCount);� 74 this.$container.find('.bod-modal-title').attr('id' , 'bodModalAriaTitle' + bodModalCount);� 75 this.$container.find('.bod-block-popup-wrap').attr('aria-describedby','bodModalAriaContent' + bodModalCount);� 76 this.$container.find('.bod-modal-content').attr('id' , 'bodModalAriaContent' + bodModalCount);� 77� 78� 79 // bind our functions to this so we use current rather than event version of this� 80 � 81 this.show = this.show.bind(this);� 82 this.afterShow = this.afterShow.bind(this);� 83 this.hide = this.hide.bind(this);� 84 this.keyPress = this.keyPress.bind(this);� 85� 86 // we need a timer for fading in and out the modal and for show on page load� 87� 88 this.timer = null;� 89� 90 // assign trigger event depending upon trigger type which is � 91 // stored has a class� 92� 93 if (this.$trigger.hasClass('type_selector')) {� 94 var triggerSelector = this.$trigger.attr('data-selector');� 95 if (triggerSelector) {� 96 $('.' + triggerSelector).css('cursor','pointer').on('click', this.show); // attach click event� 97 }� 98 } else if (this.$trigger.hasClass('type_load')) {� 99 // we have show on page load� 100 � 101 // need to load the data-once attribute which will be either no , or yes� 102� 103 var loadOnce = this.$trigger.attr('data-once');� 104 var triggerTimer = true;� 105 if (loadOnce) { � 106 if (loadOnce === 'yes') {� 107 let modalId = this.$trigger.attr('data-id');� 108 if (!modalId) modalId= "";� 109 let modalOnce = checkForCookie ("bodModalOnce" + modalId);� 110 if (modalOnce) triggerTimer = false;� 111 } � 112 }� 113� 114 // check if we need to check for text in url to enable modal� 115 var loadurl = this.$trigger.attr('data-urltrig');� 116 if (loadurl) {� 117 if (window.location.href.indexOf(loadurl)===-1) triggerTimer = false;� 118 }� 119� 120 if (triggerTimer) {� 121 // we need to extract the delay amd set a timeout using it� 122 var loadDelay = this.$trigger.attr('data-delay');� 123 isNaN(parseInt(loadDelay)) ? loadDelay = 1000 : loadDelay = parseInt(loadDelay);� 124� 125 // if we only want to show the modal once we exact the UID provided when the modal created (optional), and the number of days we wait until we show the � 126 // modal again (this is added to the cookie)� 127 if (loadOnce) {� 128 let modalId = this.$trigger.attr('data-id');� 129 if (!modalId) modalId= "";� 130 let noShowDays = this.$trigger.attr('data-days');� 131 isNaN(parseInt(noShowDays)) ? noShowDays = 30 : noShowDays = parseInt(noShowDays);� 132 this.timer = setTimeout(this.show, loadDelay, loadOnce, modalId , noShowDays);� 133 } else {� 134 this.timer = setTimeout(this.show, loadDelay);� 135 }� 136 }� 137� 138 } else { // must be button, text, or image trigger� 139 this.$trigger.on('click', this.show); // attach click event� 140 }� 141�
142 // setup the overlay and content wrap, put them into a jquery object and � 143 // attach the hide event for the click� 144� 145 // check to see if we have disabled the close on overlay click in the frontend� 146 var disableOverlayClose = this.$overlay.attr('data-disabled-overlay-close');� 147 if (!disableOverlayClose) {� 148 this.$overlay.on('click' , this.hide);� 149 } else {� 150 if (disableOverlayClose === 'false') {� 151 this.$overlay.on('click' , this.hide); � 152 }� 153 }� 154� 155 // check to see if we have disabled the close on escape key press in the frontend� 156 var disableEscapeClose = this.$overlay.attr('data-disabled-escape-close');� 157 if (!disableEscapeClose) {� 158 this.disableEscapeClose = false;� 159 } else {� 160 if (disableEscapeClose === 'true') {� 161 this.disableEscapeClose = true; � 162 } else {� 163 this.disableEscapeClose = false;� 164 }� 165 }� 166� 167 this.$modalWrap = this.$container.find('.bod-block-popup-wrap');� 168 this.$modal = this.$container.find('.bod-block-popup');� 169 this.$modalcloser = this.$container.find('.bod-block-popup-closer')� 170 .on('click' , this.hide);� 171 this.$titlecloser = this.$container.find('.bod-block-title-closer')� 172 .on('click' , this.hide);� 173 this.$btncloser = this.$container.find('.bod-block-close-btn .bod-btn')� 174 .on('click' , this.hide);� 175 this.$modalToModal = this.$container.find('.bod-modal-to-modal')� 176 .on('click' , this.hide);� 177 this.$escCloser = $(document).on('keydown' , this.keyPress);� 178� 179 // Javascript modal wrap� 180� 181 this.modalWrap = container.querySelector('.bod-block-popup-wrap'); � 182� 183 // capture first, all and last focusable elements so we can enforce modal focus trap for ADA� 184 this.focusableContent = this.modalWrap.querySelectorAll(focusableElements);� 185 if (this.focusableContent) {� 186 this.firstFocusableElement = this.focusableContent[0]; // get first element to be focused inside modal� 187 this.lastFocusableElement = this.focusableContent[this.focusableContent.length - 1]; // get last element to be focused inside modal� 188 }� 189 this.modalOpen = false;� 190� 191 }� 192� 193 BodModal.prototype = {� 194 show: function(loadOnce , modalId, noShowDays ){� 195� 196 $(document).trigger("bod-modal-before-open",this.$modalWrap);� 197� 198 // if we try and show a modal but one is already open then return without showing the new one� 199 if (this.$trigger.hasClass('type_load') && bodModalActive === true) {� 200 return;� 201 } � 202� 203 bodModalActive = true;� 204� 205 if (loadOnce) {� 206 // check if we need to set a cookie to stop modal being shown mmore than once� 207 if (loadOnce !== 'no') {� 208 // flag set to say we only show once so set the cookie� 209 const d = new Date();� 210 d.setTime(d.getTime() + (noShowDays*24*60*60*1000));� 211 let expires = "expires="+ d.toUTCString();� 212 if (modalId) {� 213 var cookie = "bodModalOnce" + modalId;� 214 } else {� 215 var cookie = "bodModalOnce";� 216 }� 217 document.cookie = cookie + "=" + loadOnce + ";" + expires + ";path=/";� 218 }� 219 }� 220� 221 // start to clearing any timeouts� 222� 223 clearTimeout(this.timer);� 224� 225 // when we show the modal we move it to the body DOM so that� 226 // nothing else impacts it� 227 this.$overlay.appendTo(document.body).show();� 228 this.$modalWrap.appendTo(document.body).show();� 229� 230 // even though we have hit it with a show the opacticy still makes it� 231 // invisible. We wait to ensure the modal is ready then then add� 232 // an active class with triggers the opacity transition� 233 � 234 this.timer = setTimeout(this.afterShow, 25);� 235 },� 236 afterShow: function(){� 237 clearTimeout(this.timer);� 238� 239 // Lets check what transition we are going to use� 240� 241 if (this.transition = this.$modal.attr('data-transition')) {� 242 if (this.transition == 'left') {� 243 this.$modal.addClass('slide-right');� 244 } else if (this.transition == 'right') {� 245 this.$modal.addClass('slide-left');� 246 } else if (this.transition == 'bottom') {� 247 this.$modal.addClass('slide-up');� 248 } else if (this.transition == 'top') {� 249 this.$modal.addClass('slide-down');� 250 } else {� 251 this.$modal.addClass('fade');� 252 };� 253 } else {� 254 this.$modal.addClass('fade');� 255 };� 256� 257 this.$overlay.addClass('active');� 258 this.$modalWrap.addClass('active');� 259 this.$modalWrap.attr('aria-modal','true');� 260� 261 this.modalOpen = true;� 262 this.triggerElement = document.activeElement;� 263 if (this.firstFocusableElement) {� 264 this.firstFocusableElement.focus({� 265 preventScroll: true� 266 });� 267 } else {� 268 document.activeElement.blur();� 269 }� 270 $(document).trigger("bod-modal-after-open",this.$modalWrap);� 271� 272 },� 273 hide: function() {� 274 if ($(document).trigger("bod-modal-before-close",this.$modalWrap).data('cancel')){� 275 return;� 276 };� 277 � 278 this.$overlay.removeClass('active');� 279 this.$modalWrap.removeClass('active');� 280 // add the overlay and modal wrap back to the container and hide it� 281 this.$overlay.appendTo(this.$container).hide();� 282 this.$modalWrap.appendTo(this.$container).hide();� 283 this.$modalWrap.attr('aria-modal','false'); � 284 bodModalActive = false;� 285 this.modalOpen = false;� 286 $(document).trigger("bod-modal-after-close",this.$modalWrap);� 287� 288 // return focus to element that was active before modal called� 289 // but do not scroll to it� 290 if (this.triggerElement) this.triggerElement.focus(� 291 {� 292 preventScroll: true� 293 }� 294 );� 295 }, � 296 keyPress: function(e) {� 297 if ( e.keyCode === 27 && !this.disableEscapeClose) { // ESC� 298 this.hide();� 299 }� 300� 301 // here we do the ADA focus trap but only if the modal is open� 302� 303 if (this.modalOpen) {� 304� 305 // code to enforce focus trap for ADA� 306� 307 let isTabPressed = e.key === 'Tab' || e.keyCode === 9;� 308� 309 // if keypress is not tab do nothing� 310 if (!isTabPressed) {� 311 return;� 312 }� 313 � 314 // Do we have at least one element in the modal that can receive focus � 315 if (this.firstFocusableElement) {� 316 if (e.shiftKey) { // if shift key pressed for shift + tab combination� 317 if (document.activeElement === this.firstFocusableElement) {� 318 this.lastFocusableElement.focus();
318 // add focus for the last focusable element� 319 e.preventDefault();� 320 }� 321 } else { // if tab key is pressed� 322 if (document.activeElement === this.lastFocusableElement) { // if focused has reached to last focusable element then focus first focusable element after pressing tab� 323 this.firstFocusableElement.focus(); // add focus for the first focusable element� 324 e.preventDefault();� 325 }� 326 }� 327 } else {� 328 // if we are here the modal is open and the tab key has been pressed � 329 // but there are no elements in the modal that can receive focus.� 330 // Therefore we do not want to provide focus to any element outside � 331 // the modal.� 332 e.preventDefault();� 333 }� 334 }� 335 },� 336 }� 337� 338 return {� 339 initModal : initElements� 340 }� 341 � 342};� 343� 344var bodModal = bodModalBlock();� 345jQuery(document).ready(function( $ ) {� 346� 347 bodModal.initModal();� 348� 349});� 350� 351// This is an example for the custom events, this one returns cancel=true so modal will not close� 352//(function($){� 353//$(document).on("bod-modal-before-close", function(e, modalData){� 354// $(this).data('cancel', true);� 355� 356// this.$modalData = $(modalData);� 357// this.$modalData.addClass('testbeforeclose');� 358// alert("added before close");� 359//});� 360//})(jQuery);� 361� 362// This is an example of how to manually trigger initialization 10 secs after page is ready� 363//jQuery(document).ready(function( $ ) {� 364// setTimeout(bodModal.initModal,10000);� 365//});�
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.