PageSourceSearch

https://adluckdesign.com/cms/wp-content/themes/renew_adluckdesign/js/modaal.js

js adluckdesign.com collected 2026-10-06 07:41:36 UTC 43,809 bytes, 1,241 lines download raw bytes

1/*!
2	Modaal - accessible modals - v0.3.1
3	by Humaan, for all humans.
4	http://humaan.com
5 */
6/**
7	Modaal jQuery Plugin : Accessible Modals
8
9	==== General Options ===
10	type (string) 					: ajax, inline, image, iframe, confirm. Defaults to 'inline'
11	animation (string) 				: Fade, expand, down, up. Defaults to 'fade'
12	after_callback_delay (integer)	: Specify a delay value for the after open callbacks. This is necessary because with the bundled animations
13										have a set duration in the bundled CSS. Specify a delay of the same amount as the animation duration in so
14										more accurately fire the after open/close callbacks. Defaults 350, does not apply if animation is 'none',
15										after open callbacks are dispatched immediately
16
17	is_locked (boolean)				: Set this to true to disable closing the modal via keypress or clicking the background. Beware that if
18										type != 'confirm' there will be no interface to dismiss the modal if is_locked = true, you'd have to
19										programmatically arrange to dismiss the modal. Confirm modals are always locked regardless of this option
20										Defaults to false
21
22	hide_close (boolean)			: Set this to true to hide the close modal button. Key press and overlay click will still close the modal.
23										This method is best used when you want to put a custom close button inside the modal container space.
24
25	background (string)				: Background overlay style. Defaults to '#000'
26	overlay_opacity (float) 		: Background overlay transparency. Defaults to 0.8
27	overlay_close (boolean)			: Set this to false if you want to disable click to close on overlay background.
28
29	accessible_title (string)		: Accessible title. Default 'Dialog Window'
30	start_open (boolean)			: Set this to true to launch the Modaal window immediately on page open
31	fullscreen (boolean)			: Set this to true to make the modaal fill the entire screen, false will default to own width/height attributes.
32	custom_class (string)			: Fill in this string with a custom class that will be applied to the outer most modal wrapper.
33
34	width (integer)					: Desired width of the modal. Required for iframe type. Defaults to undefined //TODO
35	height (integer)				: Desired height of the modal. Required for iframe type. Defaults to undefined //TODO
36
37	background_scroll (boolean)		: Set this to true to enable the page to scroll behind the open modal.
38
39    should_open (boolean|function)  : Boolean or closure that returns a boolean to determine whether to open the modal or not.
40
41	close_text						: String for close button text. Available for localisation and alternative languages to be used.
42	close_aria_label				: String for close button aria-label attribute (value that screen readers will read out). Available for localisation and alternative languages to be used.
43
44	=== Events ===
45	before_open (function) 			: Callback function executed before modal is opened
46	after_open (function)			: Callback function executed after modal is opened
47	before_close (function)			: Callback function executed before modal is closed
48	after_close (function)			: Callback function executed after modal is closed
49	source (function(element, src))	: Callback function executed on the default source, it is intended to transform the
50										source (href in an AJAX modal or iframe). The function passes in the triggering element
51										as well as the default source depending of the modal type. The default output of the
52										function is an untransformed default source.
53
54
55	=== Confirm Options & Events ===
56	confirm_button_text (string)	: Text on the confirm button. Defaults to 'Confirm'
57	confirm_cancel_button_text (string) : Text on the confirm modal cancel button. Defaults to 'Cancel'
58	confirm_title (string)			: Title for confirm modal. Default 'Confirm Title'
59	confirm_content (string)		: HTML content for confirm message
60	confirm_callback (function)		: Callback function for when the confirm button is pressed as opposed to cancel
61	confirm_cancel_callback (function) : Callback function for when the cancel button is pressed
62
63
64	=== Gallery Options & Events ===
65	gallery_active_class (string)	: Active class applied to the currently active image or image slide in a gallery 'gallery_active_item'
66	before_image_change (function)	: Callback function executed before the image slide changes in a gallery modal. Default function( current_item, incoming_item )
67	after_image_change (function)	: Callback function executed after the image slide changes in a gallery modal. Default function ( current_item )
68
69
70	=== AJAX Options & Events ===
71	loading_content (string)		: HTML content for loading message. Default 'Loading …'
72	loading_class (string)			: Class name to be applied while content is loaded via AJAX. Default 'is_loading'
73	ajax_error_class (string)		: Class name to be applied when content has failed to load. Default is 'modaal-error'
74	ajax_success (function)		 	: Callback for when AJAX content is loaded in
75
76
77	=== SOCIAL CONTENT ===
78	instagram_id (string)			: Unique photo ID for an Instagram photo.
79
80*/
81( function( $ ) {
82
83	var modaal_loading_spinner = '<div class="modaal-loading-spinner"><div><div></div></div><div><div></div></div><div><div></div></div><div><div></div></div><div><div></div></div><div><div></div></div><div><div></div></div><div><div></div></div></div>'
84
85	var Modaal = {
86		init : function(options, elem) {
87			var self = this;
88
89			self.dom = $('body');
90
91			self.$elem = $(elem);
92			self.options = $.extend({}, $.fn.modaal.options, self.$elem.data(), options);
93			self.xhr = null;
94
95			// set up the scope
96			self.scope = {
97				is_open: false,
98				id: 'modaal_' + ( new Date().getTime() ) + ( Math.random().toString(16).substring(2) )
99			};
100
101			// add scope attribute to trigger element
102			self.$elem.attr('data-modaal-scope', self.scope.id);
103
104			// private options
105			self.private_options = {
106				active_class: 'is_active'
107			};
108
109			self.lastFocus = null;
110
111			// if is_locked
112			if ( self.options.is_locked || self.options.type == 'confirm' || self.options.hide_close ) {
113				self.scope.close_btn = '';
114			} else {
115				self.scope.close_btn = '<button type="button" class="modaal-close" id="modaal-close" aria-label="' + self.options.close_aria_label + '"><span>' + self.options.close_text + '</span></button>';
116			}
117
118			// reset animation_speed
119			if (self.options.animation === 'none' ){
120				self.options.animation_speed = 0;
121				self.options.after_callback_delay = 0;
122			}
123
124			// On click to open modal
125			$(elem).on('click.Modaal', function(e) {
126				e.preventDefault();
127
128				var source;
129
130				// Save last active state before modal
131				self.lastFocus = document.activeElement;
132
133				if ( self.options.should_open === false || ( typeof self.options.should_open === 'function' && self.options.should_open() === false ) ) {
134					return;
135				}
136
137				// CB: before_open
138				self.options.before_open.call(self, e);
139
140				switch (self.options.type) {
141					case 'inline':
142						self.create_basic();
143						break;
144
145					case 'ajax':
146						source = self.options.source( self.$elem, self.$elem.attr('href') );
147						self.fetch_ajax( source );
148						break;
149
150					case 'confirm':
151						self.options.is_locked = true;
152						self.create_confirm();
153						break;
154
155					case 'image':
156						self.create_image();
157						break;
158
159					case 'iframe':
160						source = self.options.source( self.$elem, self.$elem.attr('href') );
161						self.create_iframe( source );
162						break;
163
164					case 'video':
165						self.create_video(self.$elem.attr('href'));
166						break;
167
168					case 'instagram':
169						self.create_instagram();
170						break;
171				}
172
173				// call events to be watched (click, tab, keyup, keydown etc.)
174				self.watch_events();
175
176			});
177
178
179			// Check for start_open
180			if (self.options.start_open === true ){
181				$(elem).click();
182			}
183		},
184
185		// Watching Modal
186		// ----------------------------------------------------------------
187		watch_events : function() {
188			var self = this;
189
190			self.dom.off('click.Modaal keyup.Modaal keydown.Modaal');
191
192			// Body keydown
193			self.dom.on('keydown.Modaal', function(e) {
194				var key = e.keyCode;
195				var target = e.target;
196
197				// look for tab change and reset focus to modal window
198				// done in keydown so the check fires repeatedly when you hold the tab key down
199				if (key == 9 && self.scope.is_open) {
200					if (!$.contains(document.getElementById(self.scope.id), target) ) {
201						$('#' + self.scope.id).find('*[tabindex="0"]').focus();
202					}
203				}
204			});
205
206			// Body keyup
207			self.dom.on('keyup.Modaal', function(e) {
208				var key = e.keyCode;
209				var target = e.target;
210
211				if ( (e.shiftKey && e.keyCode == 9) && self.scope.is_open) {
212					// Watch for shift + tab key press. if open shift focus to close button.
213					if (!$.contains(document.getElementById(self.scope.id), target) ) {
214						$('#' + self.scope.id).find('.modaal-close').focus();
215					}
216				}
217
218				if ( !self.options.is_locked ){
219					// On escape key press close modal
220					if (key == 27 && self.scope.is_open ) {
221						if ( $(document.activeElement).is('input:not(:checkbox):not(:radio)') ) {
222							return false;
223						}
224
225						self.modaal_close();
226						return;
227					}
228				}
229
230				// is gallery open and images length is > 1
231				if ( self.options.type == 'image' ) {
232					// arrow left for back
233					if (key == 37 && self.scope.is_open && (!$('#' + self.scope.id + ' .modaal-gallery-prev').hasClass('is_hidden')) ) {
234						self.gallery_update('prev');
235					}
236					// arrow right for next
237					if (key == 39 && self.scope.is_open && (!$('#' + self.scope.id + ' .modaal-gallery-next').hasClass('is_hidden')) ) {
238						self.gallery_update('next');
239					}
240					return;
241				}
242			});
243
244			// Body click
vendor: 8,238 bytes, lines 245-483
245			self.dom.on('click.Modaal', function(e) {
246				var trigger = $(e.target);
247
248				// General Controls: If it's not locked allow greedy close
249				if ( !self.options.is_locked ){
250					if ( (self.options.overlay_close && trigger.is('.modaal-inner-wrapper')) || trigger.is('.modaal-close') || trigger.closest('.modaal-close').length ) {
251						self.modaal_close();
252						return;
253					}
254				}
255
256				//Confirm Controls
257				if ( trigger.is('.modaal-confirm-btn' ) ){
258					// if 'OK' button is clicked, run confirm_callback()
259					if ( trigger.is('.modaal-ok') ) {
260						self.options.confirm_callback.call(self, self.lastFocus);
261					}
262
263					if ( trigger.is('.modaal-cancel') ) {
264						self.options.confirm_cancel_callback.call(self, self.lastFocus);
265					}
266					self.modaal_close();
267					return;
268				}
269
270				// Gallery Controls
271				if ( trigger.is( '.modaal-gallery-control' ) ){
272					// it not active, don't do nuthin!
273					if ( trigger.hasClass('is_hidden') ) {
274						return;
275					}
276
277					// trigger previous
278					if ( trigger.is('.modaal-gallery-prev') ) {
279						self.gallery_update('prev');
280					}
281					// trigger next
282					if ( trigger.is('.modaal-gallery-next') ) {
283						self.gallery_update('next');
284					}
285					return;
286				}
287			});
288		},
289
290		// Append markup into DOM
291		build_modal : function(content) {
292			var self = this;
293
294			// if is instagram
295			var igClass = '';
296			if ( self.options.type == 'instagram' ) {
297				igClass = ' modaal-instagram';
298			}
299
300			var wrap_class = (self.options.type == 'video') ? 'modaal-video-wrap' : 'modaal-content';
301
302			/*
303				modaal-start_none : fully hidden via display:none;
304				modaal-start_fade : hidden via opacity:0
305				modaal-start_slidedown : ...
306
307			*/
308			var animation_class;
309			switch ( self.options.animation ) {
310				case 'fade' :
311					animation_class = ' modaal-start_fade';
312					break;
313				case 'slide-down' :
314					animation_class = ' modaal-start_slidedown';
315					break;
316				default :
317					animation_class = ' modaal-start_none'
318			}
319
320			// fullscreen check
321			var fullscreen_class = '';
322			if ( self.options.fullscreen ) {
323				fullscreen_class = ' modaal-fullscreen';
324			}
325
326			// custom class check
327			if ( self.options.custom_class !== '' || typeof(self.options.custom_class) !== 'undefined' ) {
328				self.options.custom_class = ' ' + self.options.custom_class;
329			}
330
331			// if width and heights exists and is typeof number
332			var dimensionsStyle = '';
333			if ( self.options.width && self.options.height && typeof self.options.width == 'number' && typeof self.options.height == 'number' ) {
334				// if width and height exist, and they are both numbers
335				dimensionsStyle = ' style="max-width:' + self.options.width + 'px;height:' + self.options.height + 'px;overflow:auto;"';
336			} else if ( self.options.width && typeof self.options.width == 'number' ) {
337				// if only width
338				dimensionsStyle = ' style="max-width:' + self.options.width + 'px;"';
339			} else if ( self.options.height && typeof self.options.height == 'number' ) {
340				// if only height
341				dimensionsStyle = ' style="height:' + self.options.height + 'px;overflow:auto;"';
342			}
343
344			// Reset dimensions style (width and height) for certain types
345			if ( self.options.type == 'image' || self.options.type == 'video' || self.options.type == 'instagram' || self.options.fullscreen ) {
346				dimensionsStyle = '';
347			}
348
349			//var build_markup = '<div class="modaal-wrapper modaal-start_fade' + igClass + '" id="' + self.scope.id + '"><div class="modaal-outer-wrapper"><div class="modaal-inner-wrapper">';
350			var build_markup = '<div class="modaal-wrapper modaal-' + self.options.type + animation_class + igClass + fullscreen_class + self.options.custom_class + '" id="' + self.scope.id + '"><div class="modaal-outer-wrapper"><div class="modaal-inner-wrapper">';
351
352					// hide if video
353					if (self.options.type != 'video') {
354						build_markup += '<div class="modaal-container"' + dimensionsStyle + '>';
355					}
356
357					// add the guts of the content
358					build_markup +=	'<div class="' + wrap_class + ' modaal-focus" aria-hidden="false" aria-label="' + self.options.accessible_title + ' (Press escape to close)" role="dialog">';
359
360							// If it's inline type, we want to clone content instead of dropping it straight in
361							if (self.options.type == 'inline') {
362								build_markup += '<div class="modaal-content-container"></div>';
363							} else {
364								// Drop in the content if it's not inline
365								build_markup +=	content;
366							}
367
368					// close wrap_class
369					build_markup += '</div>' + self.scope.close_btn;
370
371					// hide if video
372					if (self.options.type != 'video') {
373						build_markup += '</div>';
374					}
375
376			// close off modaal-wrapper
377			build_markup +=	'</div></div></div>';
378
379			// append ajax modal markup to dom
380			self.dom.append(build_markup);
381
382			// if inline, clone content into space
383			if (self.options.type == 'inline') {
384				content.appendTo('#' + self.scope.id + ' .modaal-content-container');
385			}
386
387			// Trigger overlay show (which triggers modal show)
388			self.modaal_overlay('show');
389		},
390
391		// Create Basic Inline Modal
392		// ----------------------------------------------------------------
393		create_basic : function() {
394			var self = this;
395			// if $elem is a link, then href points to the target, otherwise assume target was passed in initially
396			var target = (self.$elem.is('[href]')) ? $(self.$elem.attr('href')) : self.$elem;
397			var content = '';
398
399			if (target.length) {
400				content = target.contents().clone(true,true);
401				target.empty();
402			} else {
403				content = 'Content could not be loaded. Please check the source and try again.';
404			}
405
406			// now push content into markup
407			self.build_modal(content);
408		},
409
410		// Create Instagram Modal
411		// ----------------------------------------------------------------
412		create_instagram : function() {
413			var self = this;
414			var id = self.options.instagram_id;
415			var content = '';
416
417			var error_msg = 'Instagram photo couldn\'t be loaded, please check the embed code and try again.';
418
419			self.build_modal('<div class="modaal-content-container' + ( self.options.loading_class != '' ? ' ' + self.options.loading_class : '' ) + '">' + self.options.loading_content + '</div>' );
420
421			// ID exists, is not empty null or undefined.
422			if ( id != '' && id !== null && id !== undefined ) {
423				// set up oembed url
424				var ig_url = 'https://api.instagram.com/oembed?url=http://instagr.am/p/' + id + '/';
425
426				$.ajax({
427					url: ig_url,
428					dataType: "jsonp",
429					cache: false,
430					success: function (data) {
431						// set up the new content
432						content = data.html;
433
434						// now set location for new content
435						var target = $('#' + self.scope.id + ' .modaal-content-container');
436						if ( target.length > 0) {
437							// add HTML into target region
438							target.removeClass( self.options.loading_class );
439							target.html(content);
440
441							// now trigger an instagram refresh
442							window.instgrm.Embeds.process();
443						}
444					},
445					error: function() {
446						content = error_msg;
447
448						// now set location for new content
449						var target = $('#' + self.scope.id + ' .modaal-content-container');
450						if ( target.length > 0) {
451							target.removeClass( self.options.loading_class ).addClass( self.options.ajax_error_class );
452							target.html(content);
453						}
454					}
455				});
456
457			} else {
458				content = error_msg;
459			}
460
461			return false;
462		},
463
464		// Fetch Ajax Data
465		// ----------------------------------------------------------------
466		fetch_ajax : function(url) {
467			var self = this;
468			var content = '';
469
470			// If no accessible title, set it to 'Dialog Window'
471			if ( self.options.accessible_title == null ) {
472				self.options.accessible_title = 'Dialog Window'
473			}
474
475			if ( self.xhr !== null ){
476				self.xhr.abort();
477				self.xhr = null;
478			}
479
480			self.build_modal('<div class="modaal-content-container' + ( self.options.loading_class != '' ? ' ' + self.options.loading_class : '' ) + '">' + self.options.loading_content + '</div>' );
481
482			self.xhr = $.ajax(url, {
483				success: function(data) {
484					// content fetch is successful so push it into markup
485					var target = $('#' + self.scope.id).find('.modaal-content-container');
486					if ( target.length > 0){
487						target.removeClass( self.options.loading_class );
488						target.html( data );
489
490						self.options.ajax_success.call(self, target);
491					}
492				},
493				error: function( xhr ) {
494					// There were some errors so return an error message
495					if ( xhr.statusText == 'abort' ){
496						return;
497					}
498
499					var target = $('#' + self.scope.id + ' .modaal-content-container');
500					if ( target.length > 0){
501						target.removeClass( self.options.loading_class ).addClass( self.options.ajax_error_class );
502						target.html( 'Content could not be loaded. Please check the source and try again.' );
503					}
504				}
505			});
506		},
507
508		// Create Confirm Modal
509		// ----------------------------------------------------------------
510		create_confirm : function() {
511			var self = this;
512			var content;
513
514			content = '<div class="modaal-content-container">' +
515					'<h1 id="modaal-title">' + self.options.confirm_title + '</h1>' +
516					'<div class="modaal-confirm-content">' + self.options.confirm_content + '</div>' +
517						'<div class="modaal-confirm-wrap">' +
518							'<button type="button" class="modaal-confirm-btn modaal-ok" aria-label="Confirm">' + self.options.confirm_button_text + '</button>' +
519							'<button type="button" class="modaal-confirm-btn modaal-cancel" aria-label="Cancel">' + self.options.confirm_cancel_button_text + '</button>' +
520						'</div>' +
521					'</div>' +
522				'</div>';
523
524			// now push content into markup
525			self.build_modal(content);
526		},
527
528		// Create Image/Gallery Modal
529		// ----------------------------------------------------------------
530		create_image : function() {
531			var self = this;
532			var content;
533
534			var modaal_image_markup = '';
535			var gallery_total;
536			var prev_btn = '<button type="button" class="modaal-gallery-control modaal-gallery-prev" id="modaal-gallery-prev" aria-label="Previous image (use left arrow to change)"><span>Previous Image</span></button>';
537			var next_btn = '<button type="button" class="modaal-gallery-control modaal-gallery-next" id="modaal-gallery-next" aria-label="Next image (use right arrow to change)"><span>Next Image</span></button>';
538
539			// If has rel attribute
540			if ( self.$elem.is('[rel]') ) {
541				// find gallery rel
542				var gallery_group = self.$elem.attr('rel');
543				var gallery_group_items = $('[rel="' + gallery_group + '"]');
544
545				// remove any previous active attribute to any in the group
546				gallery_group_items.removeAttr('data-gallery-active', 'is_active');
547				// add active attribute to the item clicked
548				self.$elem.attr('data-gallery-active', 'is_active');
549
550				// how many in the rel grouping are there (-1 to connect with each function starting with 0)
551				gallery_total = gallery_group_items.length - 1;
552
553				// prepare array for gallery data
554				var gallery = [];
555
556				// start preparing markup
557				modaal_image_markup = '<div class="modaal-gallery-item-wrap">';
558
559				// loop each grouping item and push it into our gallery array
560				gallery_group_items.each(function(i, item) {
561					// setup default content
562					var img_src = '';
563					var img_alt = '';
564					var img_description = '';
565					var img_active = false;
566
567					var data_modaal_desc = item.getAttribute('data-modaal-desc');
568					var data_item_active = item.getAttribute('data-gallery-active');
569
570					// is it an img SRC or link HREF value
571					if ( item.href !== '' || item.href !== undefined ) {
572						img_src = item.href;
573					} else if ( item.src !== '' || item.src !== undefined ) {
574						img_src = item.src;
575					}
576
577					// Does it have a modaal description
578					if ( data_modaal_desc != '' && data_modaal_desc !== null && data_modaal_desc !== undefined ) {
579						img_alt = data_modaal_desc;
580						img_description = '<div class="modaal-gallery-label"><span class="modaal-accessible-hide">Image ' + (i+1) + ' - </span>' + data_modaal_desc + '</div>'
581					} else {
582						img_description = '<div class="modaal-gallery-label"><span class="modaal-accessible-hide">Image ' + (i+1) + '</span></div>';
583					}
584
585					// is it the active item
586					if ( data_item_active ) {
587						img_active = true
588					}
589
590					// set new object for values we want
591					var gallery_item = {
592						'url': img_src,
593						'alt': img_alt,
594						'rawdesc': data_modaal_desc,
595						'desc': img_description,
596						'active': img_active
597					};
598
599					// push object into gallery array
600					gallery.push( gallery_item );
601				});
602
603				// now loop through all items in the gallery and build up the markup
604				for (var i = 0; i < gallery.length; i++) {
605					// Set default active class, then check if array item active is true and update string for class
606					var is_active = '';
607					var aria_label = gallery[i].rawdesc ? 'Image: ' + gallery[i].rawdesc : 'Image ' + i + ' no description';
608
609					if ( gallery[i].active ) {
610						is_active = ' ' + self.private_options.active_class;
611					}
612
613					// for each item build up the markup
614					modaal_image_markup += '<div class="modaal-gallery-item gallery-item-' + i + is_active + '" aria-label="' + aria_label + '">' +
615						'<img src="../../re_adluck/js/' + gallery[i].url + '" alt=" " style="width:100%">' +
616						gallery[i].desc +
617					'</div>';
618				}
619
620				// close off the markup for the gallery and add next/previous buttons
621				modaal_image_markup += '</div>' + prev_btn + next_btn;
622			} else {
623				// This is only a single gallery item so let's grab the necessary values
624
625				// Setup selected image
626				var this_img_src = self.$elem.attr('href');
627				var this_img_alt_txt = '';
628				var this_img_alt = '';
629				var aria_label = '';
630
631				if ( self.$elem.attr('data-modaal-desc') ) {
632					aria_label = self.$elem.attr('data-modaal-desc');
633					this_img_alt_txt = self.$elem.attr('data-modaal-desc');
634					this_img_alt = '<div class="modaal-gallery-label"><span class="modaal-accessible-hide">Image - </span>' + this_img_alt_txt + '</div>';
635				} else {
636					aria_label = "Image with no description";
637				}
638
639				// build up the html
640				modaal_image_markup = '<div class="modaal-gallery-item is_active" aria-label="' + aria_label + '">' +
641					'<img src="../../re_adluck/js/' + this_img_src + '" alt=" " style="width:100%">' +
642					this_img_alt +
643				'</div>';
644			}
645
646			// Update content variable
647			content = modaal_image_markup;
648
649			// now push content into markup
650			self.build_modal(content);
651
652			// setup next & prev buttons
653			if ( $('.modaal-gallery-item.is_active').is('.gallery-item-0') ) {
654				$('.modaal-gallery-prev').hide();
655			}
656			if ( $('.modaal-gallery-item.is_active').is('.gallery-item-' + gallery_total) ) {
657				$('.modaal-gallery-next').hide();
658			}
659		},
660
661		// Gallery Change Image
662		// ----------------------------------------------------------------
663		gallery_update : function(direction) {
664			var self = this;
665			var this_gallery = $('#' + self.scope.id);
666			var this_gallery_item = this_gallery.find('.modaal-gallery-item');
667			var this_gallery_total = this_gallery_item.length - 1;
668
669			// if single item, don't proceed
670			if ( this_gallery_total == 0 ) {
671				return false;
672			}
673
674			var prev_btn = this_gallery.find('.modaal-gallery-prev'),
675				next_btn = this_gallery.find('.modaal-gallery-next');
676
677			var duration = 250;
678
679			var new_img_w = 0,
680				new_img_h = 0;
681
vendor: 9,023 bytes, lines 682-944
682			// CB: Before image change
683			var current_item = this_gallery.find( '.modaal-gallery-item.' + self.private_options.active_class ),
684				incoming_item = ( direction == 'next' ? current_item.next( '.modaal-gallery-item' ) : current_item.prev( '.modaal-gallery-item' ) );
685			self.options.before_image_change.call(self, current_item, incoming_item);
686
687			// stop change if at start of end
688			if ( direction == 'prev' && this_gallery.find('.gallery-item-0').hasClass('is_active') ) {
689				return false;
690			} else if ( direction == 'next' && this_gallery.find('.gallery-item-' + this_gallery_total).hasClass('is_active') ) {
691				return false;
692			}
693
694
695			// lock dimensions
696			current_item.stop().animate({
697				opacity: 0
698			}, duration, function(){
699				// Move to appropriate image
700				incoming_item.addClass('is_next').css({
701					'position': 'absolute',
702					'display': 'block',
703					'opacity': 0
704				});
705
706				// Collect doc width
707				var doc_width = $(document).width();
708				var width_threshold = doc_width > 1140 ? 280 : 50;
709
710				// start toggle to 'is_next'
711				new_img_w = this_gallery.find('.modaal-gallery-item.is_next').width();
712				new_img_h = this_gallery.find('.modaal-gallery-item.is_next').height();
713
714				var new_natural_w = this_gallery.find('.modaal-gallery-item.is_next img').prop('naturalWidth');
715				var new_natural_h = this_gallery.find('.modaal-gallery-item.is_next img').prop('naturalHeight');
716
717				// if new image is wider than doc width
718				if ( new_natural_w > (doc_width - width_threshold) ) {
719					// set new width just below doc width
720					new_img_w = doc_width - width_threshold;
721
722					// Set temp widths so we can calulate the correct height;
723					this_gallery.find('.modaal-gallery-item.is_next').css({ 'width': new_img_w });
724					this_gallery.find('.modaal-gallery-item.is_next img').css({ 'width': new_img_w });
725
726					// Set new height variable
727					new_img_h = this_gallery.find('.modaal-gallery-item.is_next').find('img').height();
728				} else {
729					// new img is not wider than screen, so let's set the new dimensions
730					new_img_w = new_natural_w;
731					new_img_h = new_natural_h;
732				}
733
734				// resize gallery region
735				this_gallery.find('.modaal-gallery-item-wrap').stop().animate({
736					'width': new_img_w,
737					'height': new_img_h
738				}, duration, function() {
739					// hide old active image
740					current_item.removeClass(self.private_options.active_class + ' ' + self.options.gallery_active_class).removeAttr('style');
741					current_item.find('img').removeAttr('style');
742
743					// show new image
744					incoming_item.addClass(self.private_options.active_class + ' ' + self.options.gallery_active_class).removeClass('is_next').css('position','');
745
746					// animate in new image (now has the normal is_active class
747					incoming_item.stop().animate({
748						opacity: 1
749					}, duration, function(){
750						$(this).removeAttr('style').css({
751							'width': '100%'
752						});
753						$(this).find('img').css('width', '100%');
754
755						// remove dimension lock
756						this_gallery.find('.modaal-gallery-item-wrap').removeAttr('style');
757
758						// CB: After image change
759						self.options.after_image_change.call( self, incoming_item );
760					});
761
762					// Focus on the new gallery item
763					this_gallery.find('.modaal-gallery-item').removeAttr('tabindex');
764					this_gallery.find('.modaal-gallery-item.' + self.private_options.active_class + '').attr('tabindex', '0').focus();
765
766					// hide/show next/prev
767					if ( this_gallery.find('.modaal-gallery-item.' + self.private_options.active_class).is('.gallery-item-0') ) {
768						prev_btn.stop().animate({
769							opacity: 0
770						}, 150, function(){
771							$(this).hide();
772						});
773					} else {
774						prev_btn.stop().css({
775							'display': 'block',
776							'opacity': prev_btn.css('opacity')
777						}).animate({
778							opacity: 1
779						}, 150);
780					}
781					if ( this_gallery.find('.modaal-gallery-item.' + self.private_options.active_class).is('.gallery-item-' + this_gallery_total) ) {
782						next_btn.stop().animate({
783							opacity: 0
784						}, 150, function(){
785							$(this).hide();
786						});
787					} else {
788						next_btn.stop().css({
789							'display': 'block',
790							'opacity': prev_btn.css('opacity')
791						}).animate({
792							opacity: 1
793						}, 150);
794					}
795				});
796			});
797		},
798
799		// Create Video Modal
800		// ----------------------------------------------------------------
801		create_video : function(url) {
802			var self = this;
803			var content;
804
805			// video markup
806			content = '<iframe src="../../re_adluck/js/' + url + '" class="modaal-video-frame" frameborder="0" allowfullscreen></iframe>';
807
808			// now push content into markup
809			self.build_modal('<div class="modaal-video-container">' + content + '</div>');
810		},
811
812		// Create iFrame Modal
813		// ----------------------------------------------------------------
814		create_iframe : function(url) {
815			var self = this;
816			var content;
817
818			if ( self.options.width !== null || self.options.width !== undefined || self.options.height !== null || self.options.height !== undefined ) {
819				// video markup
820				content = '<iframe src="../../re_adluck/js/' + url + '" class="modaal-iframe-elem" frameborder="0" allowfullscreen></iframe>';
821			} else {
822				content = '<div class="modaal-content-container">Please specify a width and height for your iframe</div>';
823			}
824
825			// now push content into markup
826			self.build_modal(content);
827		},
828
829		// Open Modaal
830		// ----------------------------------------------------------------
831		modaal_open : function() {
832			var self = this;
833			var modal_wrapper = $( '#' + self.scope.id );
834			var animation_type = self.options.animation;
835
836			if (animation_type === 'none' ){
837				modal_wrapper.removeClass('modaal-start_none');
838				self.options.after_open.call(self, modal_wrapper);
839			}
840
841			// Open with fade
842			if (animation_type === 'fade') {
843				modal_wrapper.removeClass('modaal-start_fade');
844			}
845
846			// Open with slide down
847			if (animation_type === 'slide-down') {
848				modal_wrapper.removeClass('modaal-start_slide_down');
849			}
850
851			var focusTarget = modal_wrapper;
852
853			// Switch focusTarget tabindex (switch from other modal if exists)
854			$('.modaal-wrapper *[tabindex=0]').removeAttr('tabindex');
855
856			if ( self.options.type == 'image' ) {
857				focusTarget = $('#' + self.scope.id).find('.modaal-gallery-item.' + self.private_options.active_class);
858
859			} else if ( modal_wrapper.find('.modaal-iframe-elem').length ) {
860				focusTarget = modal_wrapper.find('.modaal-iframe-elem');
861
862			} else if ( modal_wrapper.find('.modaal-video-wrap').length ) {
863				focusTarget = modal_wrapper.find('.modaal-video-wrap');
864
865			} else {
866				focusTarget = modal_wrapper.find('.modaal-focus');
867
868			}
869
870			// now set the focus
871			focusTarget.attr('tabindex', '0').focus();
872
873			// Run after_open
874			if (animation_type !== 'none') {
875				// CB: after_open
876				setTimeout(function() {
877					self.options.after_open.call(self, modal_wrapper)
878				}, self.options.after_callback_delay);
879			}
880		},
881
882		// Close Modal
883		// ----------------------------------------------------------------
884		modaal_close : function() {
885			var self = this;
886			var modal_wrapper = $( '#' + self.scope.id );
887
888			// CB: before_close
889			self.options.before_close.call(self, modal_wrapper);
890
891			if (self.xhr !== null){
892				self.xhr.abort();
893				self.xhr = null;
894			}
895
896			// Now we close the modal
897			if (self.options.animation === 'none' ){
898				modal_wrapper.addClass('modaal-start_none');
899			}
900
901			// Close with fade
902			if (self.options.animation === 'fade') {
903				modal_wrapper.addClass('modaal-start_fade');
904			}
905
906			// Close with slide up (using initial slide down)
907			if (self.options.animation === 'slide-down') {
908				modal_wrapper.addClass('modaal-start_slide_down');
909			}
910
911			// CB: after_close and remove
912			setTimeout(function() {
913				// clone inline content back to origin place
914				if (self.options.type == 'inline') {
915					$('#' + self.scope.id + ' .modaal-content-container').contents().clone(true,true).appendTo( self.$elem.attr('href') )
916				}
917				// remove markup from dom
918				modal_wrapper.remove();
919				// CB: after_close
920				self.options.after_close.call(self);
921				// scope is now closed
922				self.scope.is_open = false;
923
924			}, self.options.after_callback_delay);
925
926			// Call overlay hide
927			self.modaal_overlay('hide');
928
929			// Roll back to last focus state before modal open. If was closed programmatically, this might not be set
930			if (self.lastFocus != null) {
931				self.lastFocus.focus();
932			}
933		},
934
935		// Overlay control (accepts action for show or hide)
936		// ----------------------------------------------------------------
937		modaal_overlay : function(action) {
938			var self = this;
939
940			if (action == 'show') {
941				// Modal is open so update scope
942				self.scope.is_open = true;
943
944				// set body to overflow hidden if background_scroll is false
945				if (! self.options.background_scroll) {
946					self.dom.addClass('modaal-noscroll');
947				}
948
949				// append modaal overlay
950				self.dom.append('<div class="modaal-overlay" id="' + self.scope.id + '_overlay"></div>');
951
952				// now show
953				$('#' + self.scope.id + '_overlay').css('background', self.options.background).stop().animate({
954					opacity: self.options.overlay_opacity
955				}, self.options.animation_speed, function(){
956					// now open the modal
957					self.modaal_open();
958				});
959
960			} else if (action == 'hide') {
961				// remove body overflow lock
962				self.dom.removeClass('modaal-noscroll');
963
964				// now hide the overlay
965				$('#' + self.scope.id + '_overlay').stop().animate({
966					opacity: 0
967				}, self.options.animation_speed, function(){
968					// remove overlay from dom
969					$(this).remove();
970				});
971			}
972		}
973	};
974
975	// Declare the modaal jQuery method
976	// ------------------------------------------------------------
977	$.fn.modaal = function(options) {
978		return this.each(function () {
979			var existing_modaal = $(this).data('modaal');
980
981			if ( existing_modaal ){
982				// Checking for string value, used for methods
983				if (typeof(options) == 'string'){
984					switch (options) {
985						case 'close':
986							existing_modaal.modaal_close();
987							break;
988					}
989				}
990			} else {
991				// Not a string, so let's setup the modal ready to use
992				var modaal = Object.create(Modaal);
993				modaal.init(options, this);
994				$.data(this, "modaal", modaal);
995			}
996		});
997	};
998
999	// Default options
1000	// ------------------------------------------------------------
1001	$.fn.modaal.options = {
1002
1003		//General
1004		type : 'inline',
1005		animation : 'fade',
1006		animation_speed : 300,
1007		after_callback_delay : 350,
1008		is_locked : false,
1009		hide_close: false,
1010		background: '#000',
1011		overlay_opacity: '0.8',
1012		overlay_close: true,
1013		accessible_title: 'Dialog Window',
1014		start_open: false,
1015		fullscreen: false,
1016		custom_class: '',
1017		background_scroll: false,
1018		should_open: true,
1019		close_text: 'Close',
1020		close_aria_label: 'Close (Press escape to close)',
1021		width: null,
1022		height: null,
1023
1024		//Events
1025		before_open : function(){},
1026		after_open : function(){},
1027		before_close : function(){},
1028		after_close : function(){},
1029		source : function( element, src ){
1030			return src;
1031		},
1032
1033		//Confirm Modal
1034		confirm_button_text: 'Confirm', // text on confirm button
1035		confirm_cancel_button_text: 'Cancel',
1036		confirm_title: 'Confirm Title', // title for confirm modal
1037		confirm_content: '<p>This is the default confirm dialog content. Replace me through the options</p>', // html for confirm message
1038		confirm_callback: function() {},
1039		confirm_cancel_callback: function() {},
1040
1041
1042		//Gallery Modal
1043		gallery_active_class: 'gallery_active_item',
1044		before_image_change: function( current_item, incoming_item ) {},
1045		after_image_change: function( current_item ) {},
1046
1047		//Ajax Modal
1048		loading_content : modaal_loading_spinner,
1049		loading_class : 'is_loading',
1050		ajax_error_class : 'modaal-error',
1051		ajax_success : function(){},
1052
1053		//Instagram
1054		instagram_id : null
1055	};
1056
1057	// On body load (or now, if already loaded), init any modaals defined inline
1058	// Ensure this is done after $.fn.modaal and default options are declared
1059	// ----------------------------------------------------------------
1060	$(function(){
1061		var single_modaal = $('.modaal');
1062
1063		if ( single_modaal.length ) {
1064			single_modaal.each(function() {
1065				var self = $(this);
1066
1067				// new empty options
1068				var options = {};
1069				var inline_options = false;
1070
1071				// option: type
1072				if ( self.attr('data-modaal-type') ) {
1073					inline_options = true;
1074					options.type = self.attr('data-modaal-type');
1075				}
1076
1077				// option: animation
1078				if ( self.attr('data-modaal-animation') ) {
1079					inline_options = true;
1080					options.animation = self.attr('data-modaal-animation');
1081				}
1082
1083				// option: animation_speed
1084				if ( self.attr('data-modaal-animation-speed') ) {
1085					inline_options = true;
1086					options.animation_speed = self.attr('data-modaal-animation-speed');
1087				}
1088
1089				// option: after_callback_delay
1090				if ( self.attr('data-modaal-after-callback-delay') ) {
1091					inline_options = true;
1092					options.after_callback_delay = self.attr('data-modaal-after-callback-delay');
1093				}
1094
1095				// option: after_callback_delay
1096				if ( self.attr('data-modaal-is-locked') ) {
1097					inline_options = true;
1098					options.is_locked = (self.attr('data-modaal-is-locked') === 'true' ? true : false);
1099				}
1100
1101				// option: hide_close
1102				if ( self.attr('data-modaal-hide-close') ) {
1103					inline_options = true;
1104					options.hide_close = (self.attr('data-modaal-hide-close') === 'true' ? true : false);
1105				}
1106
1107				// option: background
1108				if ( self.attr('data-modaal-background') ) {
1109					inline_options = true;
1110					options.background = self.attr('data-modaal-background');
1111				}
1112
1113				// option: overlay_opacity
1114				if ( self.attr('data-modaal-overlay-opacity') ) {
1115					inline_options = true;
1116					options.overlay_opacity = self.attr('data-modaal-overlay-opacity');
1117				}
1118
1119				// option: overlay_close
1120				if ( self.attr('data-modaal-overlay-close') ) {
1121					inline_options = true;
1122					options.overlay_close = (self.attr('data-modaal-overlay-close') === 'false' ? false : true);
1123				}
1124
1125				// option: accessible_title
1126				if ( self.attr('data-modaal-accessible-title') ) {
1127					inline_options = true;
1128					options.accessible_title = self.attr('data-modaal-accessible-title');
1129				}
1130
1131				// option: start_open
1132				if ( self.attr('data-modaal-start-open') ) {
1133					inline_options = true;
1134					options.start_open = (self.attr('data-modaal-start-open') === 'true' ? true : false);
1135				}
1136
1137				// option: fullscreen
1138				if ( self.attr('data-modaal-fullscreen') ) {
1139					inline_options = true;
1140					options.fullscreen = (self.attr('data-modaal-fullscreen') === 'true' ? true : false);
1141				}
1142
1143				// option: custom_class
1144				if ( self.attr('data-modaal-custom-class') ) {
1145					inline_options = true;
1146					options.custom_class = self.attr('data-modaal-custom-class');
1147				}
1148
1149				// option: close_text
1150				if ( self.attr('data-modaal-close-text') ) {
1151					inline_options = true;
1152					options.close_text = self.attr('data-modaal-close-text');
1153				}
1154
1155				// option: close_aria_label
1156				if ( self.attr('data-modaal-close-aria-label') ) {
1157					inline_options = true;
1158					options.close_aria_label = self.attr('data-modaal-close-aria-label');
1159				}
1160
1161				// option: background_scroll
1162				if ( self.attr('data-modaal-background-scroll') ) {
1163					inline_options = true;
1164					options.background_scroll = (self.attr('data-modaal-background-scroll') === 'true' ? true : false);
1165				}
1166
1167				// option: width
1168				if ( self.attr('data-modaal-width') ) {
1169					inline_options = true;
1170					options.width = parseInt( self.attr('data-modaal-width') );
1171				}
1172
1173				// option: height
1174				if ( self.attr('data-modaal-height') ) {
1175					inline_options = true;
1176					options.height = parseInt( self.attr('data-modaal-height') );
1177				}
1178
1179				// option: confirm_button_text
1180				if ( self.attr('data-modaal-confirm-button-text') ) {
1181					inline_options = true;
1182					options.confirm_button_text = self.attr('data-modaal-confirm-button-text');
1183				}
1184
1185				// option: confirm_cancel_button_text
1186				if ( self.attr('data-modaal-confirm-cancel-button-text') ) {
1187					inline_options = true;
1188					options.confirm_cancel_button_text = self.attr('data-modaal-confirm-cancel-button-text');
1189				}
1190
1191				// option: confirm_title
1192				if ( self.attr('data-modaal-confirm-title') ) {
1193					inline_options = true;
1194					options.confirm_title = self.attr('data-modaal-confirm-title');
1195				}
1196
1197				// option: confirm_content
1198				if ( self.attr('data-modaal-confirm-content') ) {
1199					inline_options = true;
1200					options.confirm_content = self.attr('data-modaal-confirm-content');
1201				}
1202
1203				// option: gallery_active_class
1204				if ( self.attr('data-modaal-gallery-active-class') ) {
1205					inline_options = true;
1206					options.gallery_active_class = self.attr('data-modaal-gallery-active-class');
1207				}
1208
1209				// option: loading_content
1210				if ( self.attr('data-modaal-loading-content') ) {
1211					inline_options = true;
1212					options.loading_content = self.attr('data-modaal-loading-content');
1213				}
1214
1215				// option: loading_class
1216				if ( self.attr('data-modaal-loading-class') ) {
1217					inline_options = true;
1218					options.loading_class = self.attr('data-modaal-loading-class');
1219				}
1220
1221				// option: ajax_error_class
1222				if ( self.attr('data-modaal-ajax-error-class') ) {
1223					inline_options = true;
1224					options.ajax_error_class = self.attr('data-modaal-ajax-error-class');
1225				}
1226
1227				// option: start_open
1228				if ( self.attr('data-modaal-instagram-id') ) {
1229					inline_options = true;
1230					options.instagram_id = self.attr('data-modaal-instagram-id');
1231				}
1232
1233				// now set it up for the trigger, but only if inline_options is true
1234				if ( inline_options ) {
1235					self.modaal(options);
1236				}
1237			});
1238		}
1239	});
1240
1241} ( jQuery, window, document ) );

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.