PageSourceSearch

https://prologue-alca.fr/sites/all/themes/tssks/js/libs/modaal.min.js?tlypit

js prologue-alca.fr collected 2026-10-02 08:10:51 UTC 47,947 bytes, 1,390 lines download raw bytes

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