PageSourceSearch

https://worthingtondistribution.com/js/bundles/coreBotPlugins.js?ebde3a1344c10bbff7a9711a465cfa5ac82d9a44

js worthingtondistribution.com collected 2026-10-10 01:27:19 UTC 95,883 bytes, 2,967 lines download raw bytes

1
2
3;/* Start: js/shared.js*/
4
5// ============================================================
6// Common Scripts and Functions that are shared between templates
7// ============================================================
8
9// http://blog.stevenlevithan.com/archives/es3-regexes-broken
10// http://ianconery.com/2015/08/regexp-test-bug-in-javascript/
11RegExp.prototype.test = function(str) {
12	if(str === undefined || str === null) {
13		str = '';
14	}
15	return str.toString().match(this) !== null;
16};
17
18// Owl Carousel Options
19var owlOptions = {
20	center: true,
21	margin: 0,
22	dots: true,
23	dotsEach: 4,
24	nav: true,
25	loop: true,
26	autoplay: false,
27	autoplayTimeout: 2000,
28	autoplayHoverPause: false,
29	responsive: {
30		0: {
31			center: true,
32			items: 1,
33			slideBy: 1
34		},
35		480: {
36			center: false,
37			items: 2,
38			slideBy: 2
39		},
40		720: {
41			center: false,
42			items: 3,
43			slideBy: 3
44		},
45		920: {
46			center: false,
47			items: 4,
48			slideBy: 4
49		},
50		1140: {
51			center: false,
52			items: 4,
53			slideBy: 4
54		}
55	}
56}
57
58// Execute when DOM ready
59jQuery(function ($) {
60	
61	//Hide the mobile menu if the UL inside is empty.
62	// This is currently targeting the retail menu so it doesn't inadvertently hide the wrong elements.
63	// It can be expanded to cover other use cases as needed.
64	$($('.missing-linkset').parents('ul.topbar__left__menu.linkset')[0]).hide();
65
66	// Throw compatibility warnings for IE 11 and under
67	if (getInternetExplorerVersion() < 11 && getInternetExplorerVersion() > 0) {
68		Command: toastr["error"]("This browser is no longer supported and many features may not work correctly or will be broken entirely. Please update to a newer browser.", "Browser Compatibility Error",
69		{
70		"closeButton": true,
71		"debug": false,
72		"newestOnTop": false,
73		"progressBar": false,
74		"positionClass": "toast-top-right",
75		"preventDuplicates": false,
76		"onclick": null,
77		"showDuration": "300",
78		"hideDuration": "1000",
79		"timeOut": "0",
80		"extendedTimeOut": "0",
81		"showEasing": "swing",
82		"hideEasing": "linear",
83		"showMethod": "fadeIn",
84		"hideMethod": "fadeOut"
85		});
86	} else if (getInternetExplorerVersion() <= 11 && getInternetExplorerVersion() > 0 && $('body').hasClass('app_settings')) {
87		Command: toastr["warning"]("Design Previews are not supported by this browser. Please update to a newer browser to take full advantage of the application.", "Browser Compatibility Warning",
88		{
89		"closeButton": true,
90		"debug": false,
91		"newestOnTop": false,
92		"progressBar": false,
93		"positionClass": "toast-bottom-right",
94		"preventDuplicates": false,
95		"onclick": null,
96		"showDuration": "300",
97		"hideDuration": "1000",
98		"timeOut": "0",
99		"extendedTimeOut": "0",
100		"showEasing": "swing",
101		"hideEasing": "linear",
102		"showMethod": "fadeIn",
103		"hideMethod": "fadeOut"
104		});
105	
106		$('.c-app-preview').hide();
107		$('input[type=color]').hide();
108
109	  // Add ie class
110	} else if (getInternetExplorerVersion() <= 11 && getInternetExplorerVersion() > 0) {
111		$('body').addClass(' internet-explorer-'+getInternetExplorerVersion());
112	}
113
114	// Add autopage to link URL
115	$('.linkset a[data-autopage="1"]').each(function(){
116		var href    = $(this).attr("href");
117		var url     = window.location.href
118		if (url.indexOf('autopage=') == -1) {
119			// There is no autopage in the URL so add it to the link
120			href += (href.match(/\?/) ? '&' : '?') + 'autopage=' + encodeURIComponent(url);
121		} else {
122			// There is already an autopage in the URL so use the current URL
123			href = url
124		}
125    	$(this).attr('href', href);
126	});
127
128	// Toggle off-canvas sidebar
129	$('[data-toggle="off-canvas"]').on('click', function(e){
130		var $target = $($(this).data('target'));
131		$('body').toggleClass('side-rail-open');
132		$target.toggleClass('off-canvas-visible');
133	});
134
135	// Initialize plugins
136	// ------------------------------------------------------------
137	$('[rel="tooltip"], .tooltip-trigger, [data-toggle="tooltip"]').tooltip();
138	$('[rel="popover"], [data-toggle="popover"]').popover();
139	$('input, textarea').placeholder();
140	$('.carousel').carousel();
141
142	// Responsive lightbox
143	$('.venobox').venobox();
144
145	// Tooltips for DDT table headers
146	$('tr.headrow > th').attr('title', function(){
147		return $.trim($(this).text());
148	});
149
150	// Elements that trigger loading spinner on click
151	$('body').on('click', '[data-toggle="loading"], .loading-toggle', function(){
152		toggleLoadingWidget();
153	});
154
155	// Global toast notification config (toastr)
156	// http://codeseven.github.io/toastr/demo.html
157	try {
158		toastr.options = {
159			'closeButton'      : false,
160			'debug'            : false,
161			'newestOnTop'      : false,
162			'progressBar'      : false,
163			'positionClass'    : 'toast-top-center',
164			'preventDuplicates': false,
165			'onclick'          : null,
166			'showDuration'     : '300',
167			'hideDuration'     : '1000',
168			'timeOut'          : '5000',
169			'extendedTimeOut'  : '1000',
170			'showEasing'       : 'swing',
171			'hideEasing'       : 'linear',
172			'showMethod'       : 'fadeIn',
173			'hideMethod'       : 'fadeOut'
174		}
175	} catch(err) {
176		console.error(err.message + ' - from /js/shared.js');
177	}
178
179	// Nav base
180	// ------------------------------------------------------------
181	$('.linkset ul').parents('li:not(.noparent)').addClass('link-parent');
182	$('.hyper .active, .breadcrumb .active').parents('li').addClass('hyperactive');
183	$('.breadcrumb .hyperactive').addClass('link-parent');
184
185	//Justify
186	$('.linkset.justify').each(function(){
187		var parentWidth = $(this).parent('div').width();
188		var thisWidth = $(this).width();
189		var setLength = $(this).children('li').size();
190		var linkMargin = (((parentWidth - thisWidth) / (2 * setLength)-.05));
191		$(this).children('li').children('a').css('padding-left',linkMargin);
192		$(this).children('li').children('a').css('padding-right',linkMargin);
193	});
194
195	//Click
196		$('.linkset.click>.link-parent>a, .linkset.click-persist .link-parent>a, .linkset.click>.link-parent>span, .linkset.click-persist .link-parent>span').click(function(event){
197		// This link is open - Close this link
198		if ($(this).parent('li').hasClass('open')) {
199			$(this).parent('li').removeClass('open');
200			$(this).parent('li').find('li').removeClass('open');
201		} else {
202			// Link is child of open link - Open this link
203			if ($(this).parents('li').hasClass('open')) {
204					$(this).parents('ul').siblings('ul').children('li').removeClass('open');
205					$(this).parent('li').siblings('li').removeClass('open');
206					$(this).parent('li').siblings('li').find('li').removeClass('open');
207				$(this).parent('li').addClass('open');
208			// Link is not child of open link - Close all links and open this link.
209			} else {
210				$(this).closest('.linkset').find('li.open').removeClass('open');
211				$(this).closest('li').removeClass('open');
212				$(this).parent('li').siblings('li').removeClass('open');
213				$(this).parent('li').children('li').removeClass('open');
214				$(this).parent('li').addClass('open');
215			}
216		}
217		event.preventDefault();
218	});
219
220	$(document).on('click', function (event) {
221			if ($(event.target).closest('.linkset.click, .linkset.click-persist').length === 0) {
222				$('.linkset.click li, linkset.click-persist li').removeClass('open');
223		}
224	});
225
226
227	accordion();
228	
229
230	//Tabs
231	$('.linkset.tabs > li > a, .linkset.tabs > li > span').click(function(e){
232		if (!$(this).hasClass('open')) {
233			$(this).parent('li').siblings('li').removeClass('open');
234			$(this).parent('li').addClass('open');
235		}
236	});
237
238	// Add dropdown class
239	$('.linkset li:has(ul):not(.noparent)').each(function(){
240		$(this).addClass('drop');
241	});
242
243	// Click outside to close (for dropdowns, etc.)
244	// uses http://benalman.com/projects/jquery-outside-events-plugin/
245	$('.js-click-outside-to-close').bind('clickoutside', function(e){
246		$(this).find('.link-parent').removeClass('open');
247	});
248
249	// Owl Carousel
250	$('.owl-carousel').owlCarousel(owlOptions);
251
252	// ============================================================
253	// Responsive DDT search / filters
254	// ============================================================
255
256	// DDT filter toggle button event handler
257	$(document).on('click', '[data-toggle="DDT-filters"]', function(){
258		$(this).next('.DDT-form-search').addClass('show');
259		$(this).closest('.DDT-form-search').removeClass('show');
260	});
261
262	// Add table search filter input element
263	//injectTablesawFilter();
264
265	// Add indexing for table filter searches
266	// $('.tablesaw tbody tr:not(.tablesaw-filter):has(td)')
267	// 	.each(function(){
268	// 		var t = $(this).text().toLowerCase();
269	// 		$('<td class="indexColumn"></td>').hide().text(t).appendTo(this);
270	// 	});
271
272	// Event handlers for table filter
273	// ------------------------------------------------------------
274
275	// Do the filtering
276	$(document)
277		.on('keyup', '.tablesaw-filter-input', function(e){
278
279			// Show the clear button if there is a filter value
280			if ($(this).val()) {
281				$(this).next('.tablesaw-filter-clear').removeClass('hide');
282			} else {
283				$(this).next('.tablesaw-filter-clear').addClass('hide');
284			}
285
286			// Table to filter
287			var $filterTable = $(this).closest('table.tablesaw');
288
289			if (e.keyCode === 27 || $(this).val() === '') {
290
291				// clear search on ESC keypress when search is focused
292				if (e.keyCode === 27){
293					$(this)
294						.val('').blur()
295						// hide the clear "X"
296						.next('.tablesaw-filter-clear').addClass('hide');
297				}
298
299				// Reset previous filters
300				clearTablesawFilter($filterTable);
301
302			} else {
303
304				// Get filter values
305				var s = $(this).val().toLowerCase().split(' ');
306
307				// Reset previous filters
308				clearTablesawFilter($filterTable);
309
310				$.each(s, function(){
311					$filterTable
312						.find('.indexColumn:not(:contains("' + this + '"))')
313						.parent('tr:not(.tablesaw-filter)')
314						.addClass('hide');
315				});
316
317			} //-if (e.keyCode == 27)
318
319		});
320
321	// Clear the filter input value
322	$('.tablesaw-filter .tablesaw-filter-clear')
323		.on('click', function(e){
324			e.preventDefault();
325			var $filterTable = $(this).closest('.tablesaw');
326			clearTablesawFilter($filterTable);
327			$(this).addClass('hide').prev('.tablesaw-filter-input').val('');
328		});
329
330
331	// Bootstrap hotfixes
332	// ------------------------------------------------------------
333
334	// Prevents drop down to be closed on click into `.dropdown-menu`.
335	// github.com/mitnal/bootstrap/commit/29df6eaa230df3e1c9e5bcb4c86c75132ef32817
336	$(document).on(
337		'click.dropdown.data-api',
338		'.dropdown-menu',
339		function(e) {
340			e.stopPropagation();
341		});
342
343	// UI helpers
344	// ------------------------------------------------------------
345
346	// Remove modals from tabindex
347	// - enables close on ESC keypress for modal windows
348	// $('.modal').attr('tabindex', -1);
349
350	// Move progress bar for payment page order processing
351	$('#order_processing_modal')
352		.on('shown', function(){
353			fncMoveProgressBar('#order_processing_bar');
354		});
355
356	// Move progress bar for sign in loading msg
357	$('#login_progress_modal')
358		.on('shown', function(){
359			fncMoveProgressBar('#login_progress_bar');
360		});
361
362	// Kill the default behavior for cart builder qty update links
363	$('#cartform a[onclick^="submitCart"]')
364		.on('click', function(e){
365			e.preventDefault();
366		});
367
368	// Assign all buttons that add to cart ...
369	var addToCartButtons = '.prod_item .actions .btn.btn-small, ' +
370		'.detail_atc_standalone .btn-primary';
371
372	// Add to cart button processing indicators
373	$(addToCartButtons)
374		.on('click', function(e) {
375			// only left mousedown
376			if (e.which === 1) {
377				$(this).append('<i class="icon-spinner icon-spin hide"></i>').fadeIn('fast');
378			}
379		});
380
381	function removeSpinners(e) {
382		$(addToCartButtons).children('i.icon-spinner').remove();
383	}
384
385	// Kill the button processing indicators once items have been
386	// successfully added to the cart (by watching the modal)
387	// $('#atc_msg.modal').add(modal.$modal).on('shown', removeSpinners);
388
389	// Don't allow qty less than 1 for product detail standalone,
390	// and search results grid view, and quick order form, and cart
391	$('.detail_atc_standalone input.qtyinput, \
392		#gallery_layout input.qtyinput, \
393		#order_matrix input.qtyinput, \
394		.cart-table input.cart-input-qty')
395		.on('focusout', function(){
396			$(this).val() <= 0 ? $(this).val(1) : false
397		});
398
399	// Smooth scroll to
400	$('.scroll, .scroll-to')
401		.on('click', function(e) {
402			e.preventDefault();
403			scrollToTarget($(this));
404		});
405
406
407	// Fix links to named anchors when base href is used (static pages)
408	if ($('base').length) {
409			$('a[href^="#"]').each(function(){
410					var href = '';
411					if (!$(this).parents('ul.nav.nav-tabs').length) {
412							href +=  window.location;
413					}
414					href += $(this).attr('href').replace('/#.*/i','');
415					$(this).attr('href', href);
416			});
417	}
418		// Set active state static page
419		$('#topbar').find('a[href$="' + location.pathname.substring(location.pathname.lastIndexOf('/') + 1) + '"]').addClass('active');
420
421	// Clear the content of the shipping estimator modal on close
422	// to prevent miscalculation of height (which is used for positioning)
423	// when it is opened again
424	$('#modal_shipest').on('hidden', function(){
425		$(this).find('.modal-body').empty();
426	});
427
428	// Add a tooltip on hover if the category name is overflowing
429	$('.category-window__body .linkset li a').click(function() {
430		$('.category-window__body .linkset li a').each(function(){
431			if (isOverflowing($(this)[0])) {
432				$(this).tooltip({
433					animation: 'show', 
434					title: $(this).children('.cat-nm').text(),
435					placement: 'top',
436					delay: {show: 400, hide: 100}
437				});
438			}
439		});
440	});
441
442	$('.category-window__body .linkset li a').each(function() {
443		if (isOverflowing($(this)[0])) {
444			$(this).tooltip({
445				animation: 'show', 
446				title: $(this).children('.cat-nm').text(),
447				placement: 'top',
448				delay: {show: 400, hide: 100}
449			});
450		}
451	});
452
453	// Set active state static page
454	$('#topbar').find('a[href$="' + location.pathname.substring(location.pathname.lastIndexOf('/') + 1) + '"]').addClass('active');
455
456
457
458	// Check the subarState on page load
459	getSUbarState() ? revealSUBar() : hideSUBar();
460
461	// Remove the subar display: none; after page load to prevent animations from playing on load
462	$('#appSuperUserNotify').removeAttr('style');
463	$('.su-action-btn').removeAttr('style');
464
465	//Fix overflow on DDT dropdown links
466	$('.ddt-table-wrapper .ddt-dropdown').on('click', function(){
467		//do we have a dropdown or just a single impersonate link?
468		var hasDropdown = $(this).hasClass('dropdown-toggle');
469		if(hasDropdown){
470			//determine if the drop is open or close.
471			var isOpen = $(this).parents('.btn-group').hasClass('open');
472			if(isOpen){
473				//Removing the min height on close.
474				$(this).parents('.ddt-table-wrapper').css('min-height', '' );
475			}else{
476				//get length of UL so we can calc the minheight
477				var numberOfSites = $(this).next().children().length;
478				var adjustHeight = 35;
479				var baseHeight = $('.ddt-table-wrapper').height();
480				var minHeight = baseHeight + (adjustHeight * numberOfSites);
481				
482				//Add a min height on open
483				$(this).parents('.ddt-table-wrapper').css('min-height', minHeight +'px' );
484			}
485		}
486	});
487
488}); // $(function(){})
489
490
491// On Window Resize
492// $(window).resize(function(){
493	
494// });
495
496
497// ============================================================
498// Functions
499// ============================================================
500
501// Force gallery on mobile getCookie
502function getCookie(cname) {
503    var name = cname + "=";
504    var ca = document.cookie.split(';');
505    for (var i = 0; i < ca.length; i++) {
506        var c = ca[i];
507        while (c.charAt(0) == ' ') {
508            c = c.substring(1);
509        }
510        if (c.indexOf(name) == 0) {
511            return c.substring(name.length, c.length);
512        }
513    }
514    return "";
515}
516
517function injectTablesawFilter() {
518	// Inject the HTML
519	$('.tablesaw:not(.cart-table):not(.tablesaw-no-filter)').each(function () {
520		var $table = $(this);
521		var placeholder = $table.attr('data-tablesaw-filter-placeholder');
522
523		if (placeholder === undefined) {
524			placeholder = 'Type here to filter this page of results';
525		}
526
527		// Build HTML for table filter input element
528		var html = '<caption class="tablesaw-filter">' +
529								 '<input type="text" class="tablesaw-filter-input" name="tablesaw_filter_text" placeholder="' + placeholder + '" autocomplete="off" autocapitalize="off" autocorrect="off">' +
530								 '<button type="button" class="close tablesaw-filter-clear hide">&times;</button>' +
531							 '</caption>';
532
533		$table.prepend(html);
534	});
535}
536
537function clearTablesawFilter($table) {
538	// Simply remove the hide class from all table rows
539	$table.find('tr').removeClass('hide');
540}
541
542
543function toggleLoadingWidget(bShow) {
544	var src = 'templates/gfx/loading/loading.gif';
545	var widget = $('#appLoadingWidget');
546
547	if (bShow !== undefined) {
548		widget.toggleClass('hide', !bShow);
549	} else {
550		widget.toggleClass('hide');
551	}
552
553	// Test browser support for SVG via Modernizr
554	// Fall back to animated gif if no support
555	if (!Modernizr.svg && !Modernizr.cssanimations) {
556		widget.find('.app-loading-spinner-img').attr('src', src);
557	}
558}
559
560
561/**
562 * Use this function to test for JS dependencies and notify if they are not found
563 * http://i2admintest.webstorepackage.com/johnmarkdev/virtualweb/index.php?title=Javascript_Dependency_Checking
564 * Example:
565 * checkJavascriptDependency('jQuery', 'jQuery()', 'You need jQuery yo!', 'http://jquery.com');
566 */
567function checkJavascriptDependency(name, cmd, msg, url) {
568	try {
569		eval(cmd);
570	} catch(err) {
571		alert(name + ' is required! Check console for info');
572		console.error(err.message);
573		console.info(msg + ' ' + url);
574	}
575}
576
577
578// Use this as a generic way to simulate progressbar progress
579var fncMoveProgressBar = function(target) {
580	var progress = setInterval(function() {
581		var $bar = $(target);
582		if ($bar.width()==400) {
583			clearInterval(progress);
584			//$('.progress').removeClass('active');
585		} else {
586			$bar.width($bar.width()+30);
587		}
588	}, 100);
589}
590
591// Test to see if current page is secure
592function isSecure() {
593	return window.location.protocol == 'https:';
594}
595
596/**
597 * Check user agent for common mobile/tablet devices
598 *
599 * @returns boolean
600 */
601function isMobileDevice() {
602	var userAgent = navigator.userAgent || navigator.vendor || window.opera;
603	// iPhone is implied by testing for "Phone"
604	return /iPad|iPod|Android|BlackBerry|Mobile|Phone|Tablet/i.test(userAgent);
605}
606
607// SVG Fallback v1.0
608// https://wiki.webstorepackage.com/index.php?title=SVG_Fallback
609$('img[data-svg-fallback-ext]').on('error', function () {
610	var $this = $(this);
611
612	// The SVG check is necessary to avoid infinitely looping if the fallback image also errors.
613	if ($this.attr('src').slice($this.attr('src').length - 3) === 'svg') {
614		$this.attr('src', $this.attr('src').slice(0, -3) + $this.attr('data-svg-fallback-ext'));
615	}
616});
617
618
619/**
620 * These functions are used around the site to allow the value from one lightbox question apply a filter to another lightbox
621 * @author johns
622 * @since	 02/16/2018
623 */
624function fncChangeSearchString(field, searchstring, key) {
625	var oldHref = $('#' + field + '_disp_find_link').attr('href');
626	oldHref = removeOldFilter(oldHref);
627	var newHref = key ? setParam(oldHref, 'filter', searchstring + $('#' + key).val()) : setParam(oldHref, 'filter', '');
628	$('#' + field + '_disp_find_link').attr('href', newHref);
629} //- function fncChangeSearchString()
630
631function removeOldFilter(href) {
632	var parts = href.split('&');
633	parts.splice(parts.findIndex(function(parts) {
634		return parts.split('=')[0] == 'filter';
635	}), 1);
636	return parts.join('&')
637} //- function removeOldFilter (href)
638
639function setParam(uri, key, val) {
640	if (uri) {
641		return uri
642			.replace(new RegExp("([?&]" + key + "(?=[=&#]|$)[^#&]*|(?=#|$))"), "&" + key + "=" + encodeURIComponent(val))
643			.replace(/^([^?&]+)&/, "$1?");
644	} else {
645		return '';
646	}
647} //- function setParam()
648
649
650// Scrolls the page to the target specified in the href
651function scrollToTarget(el) {
652	var   target = el.hash,
653					 pos = $(target).offset(),
654			scrollto = pos.top - 160;
655	$('body, html').animate(
656		{scrollTop: scrollto},
657		300,
658		function(){
659			$('body, html').clearQueue();
660			$(target).trigger('focus');
661		});
662	return false;
663}
664
665// Mark active category menu items and expand parents
666function markActiveCategory() {
667	// fall back to querystring if not a static page
668	var c_key = (jsConfig.static_pages.content_key.length > 0)
669		? jsConfig.static_pages.content_key
670		: getUrlParameter('pc_id');
671	$('#category-window')
672		.find('a[data-key=' + c_key + ']')
673		.closest('li').addClass('active')
674		.parents('li.link-parent').addClass('open');
675
676	// Add Menu Tooltips
677	$('.toolbar__btn').tooltip({
678		placement: 'right',
679	});
680}
681
682// Return a specified querystring parameter value
683function getUrlParameter(param) {
684	var value;
685	var parameters = window.location.search.replace('?', '');
686	if (parameters) {
687		var pattern = new RegExp('\\b' + param + '=([^;&]+)', 'gi');
688		value = parameters.split(pattern)[1];
689	}
690	return value || '';
691};
692
693function isOverflowing(element) {
694	return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
695}
696
697/**
698 * This accordion function accounts for a number of submenus 
699 * and utilizes the accordion's height for animated opening
700 * and closing of menus
701 * @author dnelsen
702 * @since 03/22/2019
703 */
704function accordion() {
705	
706	// set accordion total height
707	var accTotalHeight = 0;
708	var accAllLinkGroups = document.querySelectorAll('.accordion > .link-parent ul');
709
710	// firefox makes us set an initial inline height
711	Array.prototype.slice.call(accAllLinkGroups, 0).forEach(function(group) {
712		if (!group.style.height) {
713			group.style.height = '0px';
714		}
715	});
716
717	$('.accordion li.link-parent > a').on('click', function(e){
718		processAccordionClick(e);
719	}); 
720}
721
722function processAccordionClick(e){
723	// initialize variables
724	var accLink = e.target;
725	var accLinkParent = accLink.closest('.link-parent');
726	if(!accLinkParent){
727		return true;
728	}
729
730	e.preventDefault();
731	var accLinkGroup = accLinkParent.querySelector('ul');
732	var accLinkChildren = accLinkGroup.children;
733	var accTopLinkGroup = accLink.closest('.accordion > .link-parent').querySelector('ul');
734
735	// check if this is opened already
736	if (!accLinkParent.classList.contains('open')) {
737
738		var accLinkChildrenHeight = 0;
739
740		// add class 'open'
741		accLinkParent.classList.add('open');
742
743		// get immediate children heights
744		for (var i = 0; i < accLinkChildren.length; i++) {
745			accLinkChildrenHeight += accLinkChildren[i].offsetHeight;
746		};
747
748		accLinkGroup.style.height = accLinkChildrenHeight+'px';
749
750		if (!accLinkGroup.isEqualNode(accTopLinkGroup)) {
751			var accTopLinkGroupHeight = parseInt(accTopLinkGroup.style.height.replace('px', ''));
752			accTopLinkGroup.style.height = (accTopLinkGroupHeight + accLinkChildrenHeight) + 'px';
753		}
754
755	} else {
756
757		// remove class 'open' from immediate link-parent
758		accLinkParent.classList.remove('open');
759		var accLinkChildrenHeight = 0;
760
761		// get immediate children heights
762		for (var i = 0; i < accLinkChildren.length; i++) {
763			accLinkChildrenHeight += accLinkChildren[i].offsetHeight;
764		};
765
766		if (!accLinkGroup.isEqualNode(accTopLinkGroup)) {
767			var accTopLinkGroupHeight = parseInt(accTopLinkGroup.style.height.replace('px', ''));
768			accTopLinkGroup.style.height = (accTopLinkGroupHeight - accLinkChildrenHeight) + 'px';
769		}
770
771		accLinkGroup.style.height = 0;
772
773	}
774}
775
776/**
777* Detect scrolling direction and append a body class
778* 
779* @author dnelsen
780* @since	 01/31/2020
781*/
782setTimeout(function() {
783	var lastScrollTop = 0;
784	window.addEventListener("scroll", function() {
785		var st = window.pageYOffset || document.documentElement.scrollTop;
786		if (st > lastScrollTop){
787			$('body').addClass('-scrolling-down');
788			$('body').removeClass('-scrolling-up');
789		} else {
790		$('body').addClass('-scrolling-up');
791		$('body').removeClass('-scrolling-down');
792		}
793		lastScrollTop = st <= 0 ? 0 : st; // For Mobile or negative scrolling
794	}, false);
795}, 300);
796
797
798/**
799* Set show/hide states for the super user bar in impersonation mode
800* 
801* @author dnelsen
802* @since  04/17/2020
803*/
804function revealSUBar(event) {
805	setSUbarState('show');
806	event ? event.preventDefault() : null;
807	jQuery('.su-action-bar').addClass('-visible');
808	jQuery('.su-action-btn').removeClass('-visible');
809}
810
811function hideSUBar(event) {
812	setSUbarState('hide');
813	event ? event.preventDefault() : null;
814	jQuery('.su-action-bar').removeClass('-visible');
815	jQuery('.su-action-btn').addClass('-visible');
816}
817
818function showSUbarInfo(event) {
819	event ? event.preventDefault() : null;
820	jQuery('.su-action-bar').toggleClass('-show-info');
821}
822
823function setSUbarState(state) {
824	$.cookie('subarState', state, { expires: 7 });
825}
826
827function getSUbarState() {
828	var state;
829	var curState = $.cookie('subarState');
830
831	if (curState) {
832		if (curState === 'show') {
833			state = true;
834		} else {
835			state = false;
836		}
837	} else {
838		state = true;
839	}
840	return state;
841}
842
843var GLOBAL_JS_EMAIL_REGEX = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/gi;
844
845$( function(){
846	markActiveCategory();
847});
848
849function isEmpty(obj){
850	if(!obj) return false;
851
852	for(var prop in obj) {
853		if(obj.hasOwnProperty(prop))
854			return false;
855	}
856
857	return JSON.stringify(obj) === JSON.stringify({});	
858}
859
860
861
862/* End: js/shared.js*/
863
864
865
866;/* Start: js/vendor/ResizeSensor.js*/
867
868'use strict';
869
870/**
871 * Copyright Marc J. Schmidt. See the LICENSE file at the top-level
872 * directory of this distribution and at
873 * https://github.com/marcj/css-element-queries/blob/master/LICENSE.
874 */
875(function (root, factory) {
876    if (typeof define === "function" && define.amd) {
877        define(factory);
878    } else if (typeof exports === "object") {
879        module.exports = factory();
880    } else {
881        root.ResizeSensor = factory();
882    }
883}(typeof window !== 'undefined' ? window : this, function () {
884
885    // Make sure it does not throw in a SSR (Server Side Rendering) situation
886    if (typeof window === "undefined") {
887        return null;
888    }
889    // https://github.com/Semantic-Org/Semantic-UI/issues/3855
890    // https://github.com/marcj/css-element-queries/issues/257
891    var globalWindow = typeof window != 'undefined' && window.Math == Math
892        ? window
893        : typeof self != 'undefined' && self.Math == Math
894            ? self
895            : Function('return this')();
896    // Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor.
897    // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and
898    // would generate too many unnecessary events.
899    var requestAnimationFrame = globalWindow.requestAnimationFrame ||
900        globalWindow.mozRequestAnimationFrame ||
901        globalWindow.webkitRequestAnimationFrame ||
902        function (fn) {
903            return globalWindow.setTimeout(fn, 20);
904        };
905
906    var cancelAnimationFrame = globalWindow.cancelAnimationFrame ||
907        globalWindow.mozCancelAnimationFrame ||
908        globalWindow.webkitCancelAnimationFrame ||
909        function (timer) {
910            globalWindow.clearTimeout(timer);
911        };
912
913    /**
914     * Iterate over each of the provided element(s).
915     *
916     * @param {HTMLElement|HTMLElement[]} elements
917     * @param {Function}                  callback
918     */
919    function forEachElement(elements, callback) {
920        var elementsType = Object.prototype.toString.call(elements);
921        var isCollectionTyped = ('[object Array]' === elementsType
922            || ('[object NodeList]' === elementsType)
923            || ('[object HTMLCollection]' === elementsType)
924            || ('[object Object]' === elementsType)
925            || ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery
926            || ('undefined' !== typeof Elements && elements instanceof Elements) //mootools
927        );
928        var i = 0, j = elements.length;
929        if (isCollectionTyped) {
930            for (; i < j; i++) {
931                callback(elements[i]);
932            }
933        } else {
934            callback(elements);
935        }
936    }
937
938    /**
939    * Get element size
940    * @param {HTMLElement} element
941    * @returns {Object} {width, height}
942    */
943    function getElementSize(element) {
944        if (!element.getBoundingClientRect) {
945            return {
946                width: element.offsetWidth,
947                height: element.offsetHeight
948            }
949        }
950
951        var rect = element.getBoundingClientRect();
952        return {
953            width: Math.round(rect.width),
954            height: Math.round(rect.height)
955        }
956    }
957
958    /**
959     * Apply CSS styles to element.
960     *
961     * @param {HTMLElement} element
962     * @param {Object} style
963     */
964    function setStyle(element, style) {
965        Object.keys(style).forEach(function (key) {
966            element.style[key] = style[key];
967        });
968    }
969
970    /**
971     * Class for dimension change detection.
972     *
973     * @param {Element|Element[]|Elements|jQuery} element
974     * @param {Function} callback
975     *
976     * @constructor
977     */
978    var ResizeSensor = function (element, callback) {
979        //Is used when checking in reset() only for invisible elements
980        var lastAnimationFrameForInvisibleCheck = 0;
981
982        /**
983         *
984         * @constructor
985         */
986        function EventQueue() {
987            var q = [];
988            this.add = function (ev) {
989                q.push(ev);
990            };
991
992            var i, j;
993            this.call = function (sizeInfo) {
994                for (i = 0, j = q.length; i < j; i++) {
995                    q[i].call(this, sizeInfo);
996                }
997            };
998
999            this.remove = function (ev) {
1000                var newQueue = [];
1001                for (i = 0, j = q.length; i < j; i++) {
1002                    if (q[i] !== ev) newQueue.push(q[i]);
1003                }
1004                q = newQueue;
1005            };
1006
1007            this.length = function () {
1008                return q.length;
1009            }
1010        }
1011
1012        /**
1013         *
1014         * @param {HTMLElement} element
1015         * @param {Function}    resized
1016         */
1017        function attachResizeEvent(element, resized) {
1018            if (!element) return;
1019            if (element.resizedAttached) {
1020                element.resizedAttached.add(resized);
1021                return;
1022            }
1023
1024            element.resizedAttached = new EventQueue();
1025            element.resizedAttached.add(resized);
1026
1027            element.resizeSensor = document.createElement('div');
1028            element.resizeSensor.dir = 'ltr';
1029            element.resizeSensor.className = 'resize-sensor';
1030
1031            var style = {
1032                pointerEvents: 'none',
1033                position: 'absolute',
1034                left: '0px',
1035                top: '0px',
1036                right: '0px',
1037                bottom: '0px',
1038                overflow: 'hidden',
1039                zIndex: '-1',
1040                visibility: 'hidden',
1041                maxWidth: '100%'
1042            };
1043            var styleChild = {
1044                position: 'absolute',
1045                left: '0px',
1046                top: '0px',
1047                transition: '0s',
1048            };
1049
1050            setStyle(element.resizeSensor, style);
1051
1052            var expand = document.createElement('div');
1053            expand.className = 'resize-sensor-expand';
1054            setStyle(expand, style);
1055
1056            var expandChild = document.createElement('div');
1057            setStyle(expandChild, styleChild);
1058            expand.appendChild(expandChild);
1059
1060            var shrink = document.createElement('div');
1061            shrink.className = 'resize-sensor-shrink';
1062            setStyle(shrink, style);
1063
1064            var shrinkChild = document.createElement('div');
1065            setStyle(shrinkChild, styleChild);
1066            setStyle(shrinkChild, { width: '200%', height: '200%' });
1067            shrink.appendChild(shrinkChild);
1068
1069            element.resizeSensor.appendChild(expand);
1070            element.resizeSensor.appendChild(shrink);
1071            element.appendChild(element.resizeSensor);
1072
1073            var computedStyle = window.getComputedStyle(element);
1074            var position = computedStyle ? computedStyle.getPropertyValue('position') : null;
1075            if ('absolute' !== position && 'relative' !== position && 'fixed' !== position && 'sticky' !== position) {
1076                element.style.position = 'relative';
1077            }
1078
1079            var dirty = false;
1080
1081            //last request animation frame id used in onscroll event
1082            var rafId = 0;
1083            var size = getElementSize(element);
1084            var lastWidth = 0;
1085            var lastHeight = 0;
1086            var initialHiddenCheck = true;
1087            lastAnimationFrameForInvisibleCheck = 0;
1088
1089            var resetExpandShrink = function () {
1090                var width = element.offsetWidth;
1091                var height = element.offsetHeight;
1092
1093                expandChild.style.width = (width + 10) + 'px';
1094                expandChild.style.height = (height + 10) + 'px';
1095
1096                expand.scrollLeft = width + 10;
1097                expand.scrollTop = height + 10;
1098
1099                shrink.scrollLeft = width + 10;
1100                shrink.scrollTop = height + 10;
1101            };
1102
1103            var reset = function () {
1104                // Check if element is hidden
1105                if (initialHiddenCheck) {
1106                    var invisible = element.offsetWidth === 0 && element.offsetHeight === 0;
1107                    if (invisible) {
1108                        // Check in next frame
1109                        if (!lastAnimationFrameForInvisibleCheck) {
1110                            lastAnimationFrameForInvisibleCheck = requestAnimationFrame(function () {
1111                                lastAnimationFrameForInvisibleCheck = 0;
1112                                reset();
1113                            });
1114                        }
1115
1116                        return;
1117                    } else {
1118                        // Stop checking
1119                        initialHiddenCheck = false;
1120                    }
1121                }
1122
1123                resetExpandShrink();
1124            };
1125            element.resizeSensor.resetSensor = reset;
1126
1127            var onResized = function () {
1128                rafId = 0;
1129
1130                if (!dirty) return;
1131
1132                lastWidth = size.width;
1133                lastHeight = size.height;
1134
1135                if (element.resizedAttached) {
1136                    element.resizedAttached.call(size);
1137                }
1138            };
1139
1140            var onScroll = function () {
1141                size = getElementSize(element);
1142                dirty = size.width !== lastWidth || size.height !== lastHeight;
1143
1144                if (dirty && !rafId) {
1145                    rafId = requestAnimationFrame(onResized);
1146                }
1147
1148                reset();
1149            };
1150
1151            var addEvent = function (el, name, cb) {
1152                if (el.attachEvent) {
1153                    el.attachEvent('on' + name, cb);
1154                } else {
1155                    el.addEventListener(name, cb);
1156                }
1157            };
1158
1159            addEvent(expand, 'scroll', onScroll);
1160            addEvent(shrink, 'scroll', onScroll);
1161
1162            // Fix for custom Elements and invisible elements
1163            lastAnimationFrameForInvisibleCheck = requestAnimationFrame(function () {
1164                lastAnimationFrameForInvisibleCheck = 0;
1165                reset();
1166            });
1167        }
1168
1169        forEachElement(element, function (elem) {
1170            attachResizeEvent(elem, callback);
1171        });
1172
1173        this.detach = function (ev) {
1174            // clean up the unfinished animation frame to prevent a potential endless requestAnimationFrame of reset
1175            if (lastAnimationFrameForInvisibleCheck) {
1176                cancelAnimationFrame(lastAnimationFrameForInvisibleCheck);
1177                lastAnimationFrameForInvisibleCheck = 0;
1178            }
1179            ResizeSensor.detach(element, ev);
1180        };
1181
1182        this.reset = function () {
1183            //To prevent invoking element.resizeSensor.resetSensor if it's undefined
1184            if (element.resizeSensor.resetSensor) {
1185                element.resizeSensor.resetSensor();
1186            }
1187        };
1188    };
1189
1190    ResizeSensor.reset = function (element) {
1191        forEachElement(element, function (elem) {
1192            //To prevent invoking element.resizeSensor.resetSensor if it's undefined
1193            if (element.resizeSensor.resetSensor) {
1194                elem.resizeSensor.resetSensor();
1195            }
1196        });
1197    };
1198
1199    ResizeSensor.detach = function (element, ev) {
1200        forEachElement(element, function (elem) {
1201            if (!elem) return;
1202            if (elem.resizedAttached && typeof ev === "function") {
1203                elem.resizedAttached.remove(ev);
1204                if (elem.resizedAttached.length()) return;
1205            }
1206            if (elem.resizeSensor) {
1207                if (elem.contains(elem.resizeSensor)) {
1208                    elem.removeChild(elem.resizeSensor);
1209                }
1210                delete elem.resizeSensor;
1211                delete elem.resizedAttached;
1212            }
1213        });
1214    };
1215
1216    if (typeof MutationObserver !== "undefined") {
1217        var observer = new MutationObserver(function (mutations) {
1218            for (var i in mutations) {
1219                if (mutations.hasOwnProperty(i)) {
1220                    var items = mutations[i].addedNodes;
1221                    for (var j = 0; j < items.length; j++) {
1222                        if (items[j].resizeSensor) {
1223                            ResizeSensor.reset(items[j]);
1224                        }
1225                    }
1226                }
1227            }
1228        });
1229
1230        document.addEventListener("DOMContentLoaded", function (event) {
1231            observer.observe(document.body, {
1232                childList: true,
1233                subtree: true,
1234            });
1235        });
1236    }
1237
1238    return ResizeSensor;
1239
1240}));
1241
1242
1243
1244/* End: js/vendor/ResizeSensor.js*/
1245
1246
1247
1248;/* Start: js/form builder/help_tip.js*/
1249
1250	/* This notice must be untouched at all times.
1251
1252	wz_tooltip.js	 v. 4.12
1253
1254	The latest version is available at
1255	http://www.walterzorn.com
1256	or http://www.devira.com
1257	or http://www.walterzorn.de
1258
1259	Copyright (c) 2002-2007 Walter Zorn. All rights reserved.
1260	Created 1.12.2002 by Walter Zorn (Web: http://www.walterzorn.com )
1261	Last modified: 13.7.2007
1262
1263	Easy-to-use cross-browser tooltips.
1264	Just include the script at the beginning of the <body> section, and invoke
1265	Tip('Tooltip text') from within the desired HTML onmouseover eventhandlers.
1266	No container DIV, no onmouseouts required.
1267	By default, width of tooltips is automatically adapted to content.
1268	Is even capable of dynamically converting arbitrary HTML elements to tooltips
1269	by calling TagToTip('ID_of_HTML_element_to_be_converted') instead of Tip(),
1270	which means you can put important, search-engine-relevant stuff into tooltips.
1271	Appearance of tooltips can be individually configured
1272	via commands passed to Tip() or TagToTip().
1273
1274	Tab Width: 4
1275	LICENSE: LGPL
1276
1277	This library is free software; you can redistribute it and/or
1278	modify it under the terms of the GNU Lesser General Public
1279	License (LGPL) as published by the Free Software Foundation; either
1280	version 2.1 of the License, or (at your option) any later version.
1281
1282	This library is distributed in the hope that it will be useful,
1283	but WITHOUT ANY WARRANTY; without even the implied warranty of
1284	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1285
1286	For more details on the GNU Lesser General Public License,
1287	see http://www.gnu.org/copyleft/lesser.html
1288	*/
1289
1290	var config = new Object();
1291
1292
1293	//===================  GLOBAL TOOPTIP CONFIGURATION  =========================//
1294	var  tt_Debug	= true		// false or true - recommended: false once you release your page to the public
1295	var  tt_Enabled	= true		// Allows to (temporarily) suppress tooltips, e.g. by providing the user with a button that sets this global variable to false
1296	var  TagsToTip	= true		// false or true - if true, the script is capable of converting HTML elements to tooltips
1297	var  tt_Current = ''
1298
1299	// For each of the following config variables there exists a command, which is
1300	// just the variablename in uppercase, to be passed to Tip() or TagToTip() to
1301	// configure tooltips individually. Individual commands override global
1302	// configuration. Order of commands is arbitrary.
1303	// Example: onmouseover="Tip('Tooltip text', LEFT, true, BGCOLOR, '#FF9900', FADEIN, 400)"
1304
1305	config. Above			= false 	// false or true - tooltip above mousepointer?
1306	config. BgColor 		= '#E4E7FF' // Background color
1307	config. BgImg			= ''		// Path to background image, none if empty string ''
1308	config. BorderColor 	= '#002299'
1309	config. BorderStyle 	= 'solid'	// Any permitted CSS value, but I recommend 'solid', 'dotted' or 'dashed'
1310	config. BorderWidth 	= 1
1311	config. CenterMouse 	= false 	// false or true - center the tip horizontally below (or above) the mousepointer
1312	config. ClickClose		= false 	// false or true - close tooltip if the user clicks somewhere
1313	config. CloseBtn		= false 	// false or true - closebutton in titlebar
1314	config. CloseBtnColors	= ['#990000', '#FFFFFF', '#DD3333', '#FFFFFF']	  // [Background, text, hovered background, hovered text] - use empty strings '' to inherit title colors
1315	config. CloseBtnText	= '&nbsp;X&nbsp;'	// Close button text (may also be an image tag)
1316	config. CopyContent		= true		// When converting a HTML element to a tooltip, copy only the element's content, rather than converting the element by its own
1317	config. Delay			= 200		// Time span in ms until tooltip shows up
1318	config. Duration		= 0 		// Time span in ms after which the tooltip disappears; 0 for infinite duration
1319	config. FadeIn			= 0 		// Fade-in duration in ms, e.g. 400; 0 for no animation
1320	config. FadeOut 		= 0
1321	config. FadeInterval	= 30		// Duration of each fade step in ms (recommended: 30) - shorter is smoother but causes more CPU-load
1322	config. Fix 			= null		// Fixated position - x- an y-oordinates in brackets, e.g. [210, 480], or null for no fixation
1323	config. FollowMouse		= false		// false or true - tooltip follows the mouse
1324	config. FontColor		= '#000044'
1325	config. FontFace		= 'Verdana,Geneva,sans-serif'
1326	config. FontSize		= '8pt' 	// E.g. '9pt' or '12px' - unit is mandatory
1327	config. FontWeight		= 'normal'	// 'normal' or 'bold';
1328	config. Left			= false 	// false or true - tooltip on the left of the mouse
1329	config. OffsetX 		= 14		// Horizontal offset of left-top corner from mousepointer
1330	config. OffsetY 		= 8 		// Vertical offset
1331	config. Opacity 		= 100		// Integer between 0 and 100 - opacity of tooltip in percent
1332	config. Padding 		= 3 		// Spacing between border and content
1333	config. Shadow			= false 	// false or true
1334	config. ShadowColor 	= '#C0C0C0'
1335	config. ShadowWidth 	= 5
1336	config. Sticky			= false 	// Do NOT hide tooltip on mouseout? false or true
1337	config. TextAlign		= 'left'	// 'left', 'right' or 'justify'
1338	config. Title			= ''		// Default title text applied to all tips (no default title: empty string '')
1339	config. TitleAlign		= 'left'	// 'left' or 'right' - text alignment inside the title bar
1340	config. TitleBgColor	= ''		// If empty string '', BorderColor will be used
1341	config. TitleFontColor	= '#ffffff'	// Color of title text - if '', BgColor (of tooltip body) will be used
1342	config. TitleFontFace	= ''		// If '' use FontFace (boldified)
1343	config. TitleFontSize	= ''		// If '' use FontSize
1344	config. Width			= 0 		// Tooltip width; 0 for automatic adaption to tooltip content
1345	config. CssClass		= ''
1346	config. TitleCssClass	= ''
1347
1348	config. Balloon = false				// true or false - set to true if you want this to be the default behaviour
1349	config. BalloonImgPath = "common_images/" // Path to images (border, corners, stem), in quotes. Path must be relative to your HTML file.
1350	// Sizes of balloon images
1351	config. BalloonEdgeSize = 5			// Integer - sidelength of quadratic corner images
1352	config. BalloonStemWidth = 15		// Integer
1353	config. BalloonStemHeight = 19		// Integer
1354	
1355	//=======  END OF TOOLTIP CONFIG, DO NOT CHANGE ANYTHING BELOW  ==============//
1356
1357
1358
1359
1360	//======================  PUBLIC  ============================================//
1361	function Tip()
1362	{
1363		tt_Tip(arguments, null);
1364	}
1365	function TagToTip()
1366	{
1367		if(TagsToTip)
1368		{
1369			var t2t = tt_GetElt(arguments[0]);
1370			if(t2t)
1371				tt_Tip(arguments, t2t);
1372		}
1373	}
1374
1375	//==================  PUBLIC EXTENSION API	==================================//
1376	// Extension eventhandlers currently supported:
1377	// OnLoadConfig, OnCreateContentString, OnSubDivsCreated, OnShow, OnMoveBefore,
1378	// OnMoveAfter, OnHideInit, OnHide, OnKill
1379
1380	var tt_aElt = new Array(10), // Container DIV, outer title & body DIVs, inner title & body TDs, closebutton SPAN, shadow DIVs, and IFRAME to cover windowed elements in IE
1381	tt_aV = new Array(),	// Caches and enumerates config data for currently active tooltip
1382	tt_sContent,			// Inner tooltip text or HTML
1383	tt_scrlX = 0, tt_scrlY = 0,
1384	tt_musX, tt_musY,
1385	tt_over,
1386	tt_x, tt_y, tt_w, tt_h; // Position, width and height of currently displayed tooltip
1387
1388	function tt_Extension()
1389	{
1390		tt_ExtCmdEnum();
1391		tt_aExt[tt_aExt.length] = this;
1392		return this;
1393	}
1394	function tt_SetTipPos(x, y)
1395	{
1396		var css = tt_aElt[0].style;
1397
1398		tt_x = x;
1399		tt_y = y;
1400		css.left = x + "px";
1401		css.top = y + "px";
1402		if(tt_ie56)
1403		{
1404			var ifrm = tt_aElt[tt_aElt.length - 1];
1405			if(ifrm)
1406			{
1407				ifrm.style.left = css.left;
1408				ifrm.style.top = css.top;
1409			}
1410		}
1411	}
1412	function tt_Hide()
1413	{
1414		tt_Current = '';
1415		if(tt_db && tt_iState)
1416		{
1417			if(tt_iState & 0x2)
1418			{
1419				tt_aElt[0].style.visibility = "hidden";
1420				tt_ExtCallFncs(0, "Hide");
1421			}
1422			tt_tShow.EndTimer();
1423			tt_tHide.EndTimer();
1424			tt_tDurt.EndTimer();
1425			tt_tFade.EndTimer();
1426			if(!tt_op && !tt_ie)
1427			{
1428				tt_tWaitMov.EndTimer();
1429				tt_bWait = false;
1430			}
1431			if(tt_aV[CLICKCLOSE])
1432				tt_RemEvtFnc(document, "mouseup", tt_HideInit);
1433			tt_AddRemOutFnc(false);
1434			tt_ExtCallFncs(0, "Kill");
1435			// In case of a TagToTip tooltip, hide converted DOM node and
1436			// re-insert it into document
1437			if(tt_t2t && !tt_aV[COPYCONTENT])
1438			{
1439				tt_t2t.style.display = "none";
1440				tt_MovDomNode(tt_t2t, tt_aElt[6], tt_t2tDad);
1441			}
1442			tt_iState = 0;
1443			tt_over = null;
1444			tt_ResetMainDiv();
1445			if(tt_aElt[tt_aElt.length - 1])
1446				tt_aElt[tt_aElt.length - 1].style.display = "none";
1447		}
1448	}
1449	function tt_GetElt(id)
1450	{
1451		return(document.getElementById ? document.getElementById(id)
1452				: document.all ? document.all[id]
1453				: null);
1454	}
1455	function tt_GetDivW(el)
1456	{
1457		return(el ? (el.offsetWidth || el.style.pixelWidth || 0) : 0);
1458	}
1459	function tt_GetDivH(el)
1460	{
1461		return(el ? (el.offsetHeight || el.style.pixelHeight || 0) : 0);
1462	}
1463	function tt_GetScrollX()
1464	{
1465		return(window.pageXOffset || (tt_db ? (tt_db.scrollLeft || 0) : 0));
1466	}
1467	function tt_GetScrollY()
1468	{
1469		return(window.pageYOffset || (tt_db ? (tt_db.scrollTop || 0) : 0));
1470	}
1471	function tt_GetClientW()
1472	{
1473		return(document.body && (typeof(document.body.clientWidth) != tt_u) ? document.body.clientWidth
1474				: (typeof(window.innerWidth) != tt_u) ? window.innerWidth
1475				: tt_db ? (tt_db.clientWidth || 0)
1476				: 0);
1477	}
1478	function tt_GetClientH()
1479	{
1480		// Exactly this order seems to yield correct values in all major browsers
1481		return(document.body && (typeof(document.body.clientHeight) != tt_u) ? document.body.clientHeight
1482				: (typeof(window.innerHeight) != tt_u) ? window.innerHeight
1483				: tt_db ? (tt_db.clientHeight || 0)
1484				: 0);
1485	}
1486	function tt_GetEvtX(e)
1487	{
1488		return (e ? ((typeof(e.pageX) != tt_u) ? e.pageX : (e.clientX + tt_scrlX)) : 0);
1489	}
1490	function tt_GetEvtY(e)
1491	{
1492		return (e ? ((typeof(e.pageY) != tt_u) ? e.pageY : (e.clientY + tt_scrlY)) : 0);
1493	}
1494	function tt_AddEvtFnc(el, sEvt, PFnc)
1495	{
1496		if(el)
1497		{
1498			if(el.addEventListener)
1499				el.addEventListener(sEvt, PFnc, false);
1500			else
1501				el.attachEvent("on" + sEvt, PFnc);
1502		}
1503	}
1504	function tt_RemEvtFnc(el, sEvt, PFnc)
1505	{
1506		if(el)
1507		{
1508			if(el.removeEventListener)
1509				el.removeEventListener(sEvt, PFnc, false);
1510			else
1511				el.detachEvent("on" + sEvt, PFnc);
1512		}
1513	}
1514
1515	//======================  PRIVATE  ===========================================//
1516	var tt_aExt = new Array(),	// Array of extension objects
1517
1518	tt_db, tt_op, tt_ie, tt_ie56, tt_bBoxOld,	// Browser flags
1519	tt_body,
1520	tt_flagOpa, 			// Opacity support: 1=IE, 2=Khtml, 3=KHTML, 4=Moz, 5=W3C
1521	tt_maxPosX, tt_maxPosY,
1522	tt_iState = 0,			// Tooltip active |= 1, shown |= 2, move with mouse |= 4
1523	tt_opa, 				// Currently applied opacity
1524	tt_bJmpVert,			// Tip above mouse (or ABOVE tip below mouse)
1525	tt_t2t, tt_t2tDad,		// Tag converted to tip, and its parent element in the document
1526	tt_elDeHref,			// The tag from which Opera has removed the href attribute
1527	// Timer
1528	tt_tShow = new Number(0), tt_tHide = new Number(0), tt_tDurt = new Number(0),
1529	tt_tFade = new Number(0), tt_tWaitMov = new Number(0),
1530	tt_bWait = false,
1531	tt_u = "undefined";
1532
1533
1534	function tt_Init()
1535	{
1536		tt_MkCmdEnum();
1537		// Send old browsers instantly to hell
1538		if(!tt_Browser() || !tt_MkMainDiv())
1539			return;
1540		tt_IsW3cBox();
1541		tt_OpaSupport();
1542		tt_AddEvtFnc(document, "mousemove", tt_Move);
1543		// In Debug mode we search for TagToTip() calls in order to notify
1544		// the user if they've forgotten to set the TagsToTip config flag
1545		if(TagsToTip || tt_Debug)
1546			tt_SetOnloadFnc();
1547		tt_AddEvtFnc(window, "scroll",
1548			function()
1549			{
1550				tt_scrlX = tt_GetScrollX();
1551				tt_scrlY = tt_GetScrollY();
1552				if(tt_iState && !(tt_aV[STICKY] && (tt_iState & 2)))
1553					tt_HideInit();
1554			} );
1555		// Ensure the tip be hidden when the page unloads
1556		tt_AddEvtFnc(window, "beforeunload", tt_Hide);
1557		tt_Hide();
1558	}
1559	// Creates command names by translating config variable names to upper case
1560	function tt_MkCmdEnum()
1561	{
1562		var n = 0;
1563		for(var i in config)
1564			eval("window." + i.toString().toUpperCase() + " = " + n++);
1565		tt_aV.length = n;
1566	}
1567	function tt_Browser()
1568	{
1569		var n, nv, n6, w3c;
1570
1571		n = navigator.userAgent.toLowerCase(),
1572		nv = navigator.appVersion;
1573		tt_op = (document.defaultView && typeof(eval("w" + "indow" + "." + "o" + "p" + "er" + "a")) != tt_u);
1574		tt_ie = n.indexOf("msie") != -1 && document.all && !tt_op;
1575		if(tt_ie)
1576		{
1577			var ieOld = (!document.compatMode || document.compatMode == "BackCompat");
1578			tt_db = !ieOld ? document.documentElement : (document.body || null);
1579			if(tt_db)
1580				tt_ie56 = parseFloat(nv.substring(nv.indexOf("MSIE") + 5)) >= 5.5
1581						&& typeof document.body.style.maxHeight == tt_u;
1582		}
1583		else
1584		{
1585			tt_db = document.documentElement || document.body ||
1586					(document.getElementsByTagName ? document.getElementsByTagName("body")[0]
1587					: null);
1588			if(!tt_op)
1589			{
1590				n6 = document.defaultView && typeof document.defaultView.getComputedStyle != tt_u;
1591				w3c = !n6 && document.getElementById;
1592			}
1593		}
1594		tt_body = (document.getElementsByTagName ? document.getElementsByTagName("body")[0]
1595					: (document.body || null));
1596		if(tt_ie || n6 || tt_op || w3c){
1597			if(tt_body && tt_db) {
1598				if(document.attachEvent || document.addEventListener)
1599					return true;
1600			} else {
1601				//tt_Err("wz_tooltip.js must be included INSIDE the body section,"
1602				//		+ " immediately after the opening <body> tag.");
1603			}
1604		}
1605		tt_db = null;
1606		return false;
1607	}
1608	function tt_MkMainDiv()
1609	{
1610		// Create the tooltip DIV
1611		if(tt_body.insertAdjacentHTML)
1612			tt_body.insertAdjacentHTML("afterBegin", tt_MkMainDivHtm());
1613		else if(typeof tt_body.innerHTML != tt_u && document.createElement && tt_body.appendChild)
1614			tt_body.appendChild(tt_MkMainDivDom());
1615		// FireFox Alzheimer bug
1616		if(window.tt_GetMainDivRefs && tt_GetMainDivRefs())
1617			return true;
1618		tt_db = null;
1619		return false;
1620	}
1621	function tt_MkMainDivHtm()
1622	{
1623		return('<div id="WzTtDiV" class="tooltip-wrapper"></div>' +
1624				(tt_ie56 ? ('<iframe id="WzTtIfRm" src="javascript:false" scrolling="no" frameborder="0" style="filter:Alpha(opacity=0);position:absolute;top:0px;left:0px;display:none;"></iframe>')
1625				: ''));
1626	}
1627	function tt_MkMainDivDom()
1628	{
1629		var el = document.createElement("div");
1630		if(el)
1631			el.id = "WzTtDiV";
1632		return el;
1633	}
1634	function tt_GetMainDivRefs()
1635	{
1636		tt_aElt[0] = tt_GetElt("WzTtDiV");
1637		if(tt_ie56 && tt_aElt[0])
1638		{
1639			tt_aElt[tt_aElt.length - 1] = tt_GetElt("WzTtIfRm");
1640			if(!tt_aElt[tt_aElt.length - 1])
1641				tt_aElt[0] = null;
1642		}
1643		if(tt_aElt[0])
1644		{
1645			var css = tt_aElt[0].style;
1646
1647			css.visibility = "hidden";
1648			css.position = "absolute";
1649			css.overflow = "hidden";
1650			return true;
1651		}
1652		return false;
1653	}
1654	function tt_ResetMainDiv()
1655	{
1656		var w = (window.screen && screen.width) ? screen.width : 10000;
1657
1658		tt_SetTipPos(-w, 0);
1659		tt_aElt[0].innerHTML = "";
1660		tt_aElt[0].style.width = (w - 1) + "px";
1661	}
1662	function tt_IsW3cBox()
1663	{
1664		var css = tt_aElt[0].style;
1665
1666		css.padding = "10px";
1667		css.width = "40px";
1668		tt_bBoxOld = (tt_GetDivW(tt_aElt[0]) == 40);
1669		css.padding = "0px";
1670		tt_ResetMainDiv();
1671	}
1672	function tt_OpaSupport()
1673	{
1674		var css = tt_body.style;
1675
1676		tt_flagOpa = (typeof(css.filter) != tt_u) ? 1
1677					: (typeof(css.KhtmlOpacity) != tt_u) ? 2
1678					: (typeof(css.KHTMLOpacity) != tt_u) ? 3
1679					: (typeof(css.MozOpacity) != tt_u) ? 4
1680					: (typeof(css.opacity) != tt_u) ? 5
1681					: 0;
1682	}
1683	// Ported from http://dean.edwards.name/weblog/2006/06/again/
1684	// (Dean Edwards et al.)
1685	function tt_SetOnloadFnc()
1686	{
1687		tt_AddEvtFnc(document, "DOMContentLoaded", tt_HideSrcTags);
1688		tt_AddEvtFnc(window, "load", tt_HideSrcTags);
1689		if(tt_body.attachEvent)
1690			tt_body.attachEvent("onreadystatechange",
1691				function() {
1692					if(tt_body.readyState == "complete")
1693						tt_HideSrcTags();
1694				} );
1695		if(/WebKit|KHTML/i.test(navigator.userAgent))
1696		{
1697			var t = setInterval(function() {
1698						if(/loaded|complete/.test(document.readyState))
1699						{
1700							clearInterval(t);
1701							tt_HideSrcTags();
1702						}
1703					}, 10);
1704		}
1705	}
1706	function tt_HideSrcTags()
1707	{
1708		if(!window.tt_HideSrcTags || window.tt_HideSrcTags.done)
1709			return;
1710		window.tt_HideSrcTags.done = true;
1711		if(!tt_HideSrcTagsRecurs(tt_body))
1712			tt_Err("To enable the capability to convert HTML elements to tooltips,"
1713					+ " you must set TagsToTip in the global tooltip configuration"
1714					+ " to true.");
1715	}
1716	function tt_HideSrcTagsRecurs(dad)
1717	{
1718		var a, ovr, asT2t;
1719
1720		// Walk the DOM tree for tags that have an onmouseover attribute
1721		// containing a TagToTip('...') call.
1722		// (.childNodes first since .children is bugous in Safari)
1723		a = dad.childNodes || dad.children || null;
1724		for(var i = a ? a.length : 0; i;)
1725		{--i;
1726			if(!tt_HideSrcTagsRecurs(a[i]))
1727				return false;
1728			ovr = a[i].getAttribute ? a[i].getAttribute("onmouseover")
1729					: (typeof a[i].onmouseover == "function") ? a[i].onmouseover
1730					: null;
1731			if(ovr)
1732			{
1733				asT2t = ovr.toString().match(/TagToTip\s*\(\s*'[^'.]+'\s*[\),]/);
1734				if(asT2t && asT2t.length)
1735				{
1736					if(!tt_HideSrcTag(asT2t[0]))
1737						return false;
1738				}
1739			}
1740		}
1741		return true;
1742	}
1743	function tt_HideSrcTag(sT2t)
1744	{
1745		var id, el;
1746
1747		// The ID passed to the found TagToTip() call identifies an HTML element
1748		// to be converted to a tooltip, so hide that element
1749		id = sT2t.replace(/.+'([^'.]+)'.+/, "$1");
1750		el = tt_GetElt(id);
1751		if(el)
1752		{
1753			if(tt_Debug && !TagsToTip)
1754				return false;
1755			else
1756				el.style.display = "none";
1757		}
1758		else
1759			tt_Err("Invalid ID\n'" + id + "'\npassed to TagToTip()."
1760					+ " There exists no HTML element with that ID.");
1761		return true;
1762	}
1763	function tt_Tip(arg, t2t)
1764	{
1765		if (arg[0] == tt_Current) {
1766			tt_HideInit();
1767		} else {
1768			tt_Current = arg[0];
1769			if(!tt_db)
1770				return;
1771			if(tt_iState)
1772				tt_Hide();
1773			if(!tt_Enabled)
1774				return;
1775			tt_t2t = t2t;
1776			if(!tt_ReadCmds(arg))
1777				return;
1778			tt_iState = 0x1 | 0x4;
1779			tt_AdaptConfig1();
1780			tt_MkTipContent(arg);
1781			tt_MkTipSubDivs();
1782			tt_FormatTip();
1783			tt_bJmpVert = false;
1784			tt_maxPosX = tt_GetClientW() + tt_scrlX - tt_w - 1;
1785			tt_maxPosY = tt_GetClientH() + tt_scrlY - tt_h - 1;
1786			tt_AdaptConfig2();
1787			// We must fake the first mousemove in order to ensure the tip
1788			// be immediately shown and positioned
1789			tt_Move();
1790			tt_ShowInit();
1791		}
1792	}
1793	function tt_ReadCmds(a)
1794	{
1795		var i;
1796
1797		// First load the global config values, to initialize also values
1798		// for which no command has been passed
1799		i = 0;
1800		for(var j in config)
1801			tt_aV[i++] = config[j];
1802		// Then replace each cached config value for which a command has been
1803		// passed (ensure the # of command args plus value args be even)
1804		
1805		if(!(a.length & 1))
1806		{
1807			for(i = a.length - 1; i > 0; i -= 2)
1808				tt_aV[a[i - 1]] = a[i];
1809			return true;
1810		}
1811		tt_Err("Incorrect call of Tip() or TagToTip().\n"
1812				+ "Each command must be followed by a value.");
1813		return false;
1814	}
1815	function tt_AdaptConfig1()
1816	{
1817		tt_ExtCallFncs(0, "LoadConfig");
1818		// Inherit unspecified title formattings from body
1819		if(!tt_aV[TITLEBGCOLOR].length)
1820			tt_aV[TITLEBGCOLOR] = tt_aV[BORDERCOLOR];
1821		if(!tt_aV[TITLEFONTCOLOR].length)
1822			tt_aV[TITLEFONTCOLOR] = tt_aV[BGCOLOR];
1823		if(!tt_aV[TITLEFONTFACE].length)
1824			tt_aV[TITLEFONTFACE] = tt_aV[FONTFACE];
1825		if(!tt_aV[TITLEFONTSIZE].length)
1826			tt_aV[TITLEFONTSIZE] = tt_aV[FONTSIZE];
1827		if(tt_aV[CLOSEBTN])
1828		{
1829			// Use title colors for non-specified closebutton colors
1830			if(!tt_aV[CLOSEBTNCOLORS])
1831				tt_aV[CLOSEBTNCOLORS] = new Array("", "", "", "");
1832			for(var i = 4; i;)
1833			{--i;
1834				if(!tt_aV[CLOSEBTNCOLORS][i].length)
1835					tt_aV[CLOSEBTNCOLORS][i] = (i & 1) ? tt_aV[TITLEFONTCOLOR] : tt_aV[TITLEBGCOLOR];
1836			}
1837			// Enforce titlebar be shown
1838			if(!tt_aV[TITLE].length)
1839				tt_aV[TITLE] = " ";
1840		}
1841		// Circumvents broken display of images and fade-in flicker in Geckos < 1.8
1842		if(tt_aV[OPACITY] == 100 && typeof tt_aElt[0].style.MozOpacity != tt_u && !Array.every)
1843			tt_aV[OPACITY] = 99;
1844		// Smartly shorten the delay for fade-in tooltips
1845		if(tt_aV[FADEIN] && tt_flagOpa && tt_aV[DELAY] > 100)
1846			tt_aV[DELAY] = Math.max(tt_aV[DELAY] - tt_aV[FADEIN], 100);
1847	}
1848	function tt_AdaptConfig2()
1849	{
1850		if(tt_aV[CENTERMOUSE])
1851			tt_aV[OFFSETX] -= ((tt_w - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0)) >> 1);
1852	}
1853	// Expose content globally so extensions can modify it
1854	function tt_MkTipContent(a)
1855	{
1856		if(tt_t2t)
1857		{
1858			if(tt_aV[COPYCONTENT])
1859				tt_sContent = tt_t2t.innerHTML;
1860			else
1861				tt_sContent = "";
1862		}
1863		else
1864			tt_sContent = a[1];
1865		tt_ExtCallFncs(0, "CreateContentString");
1866	}
1867	function tt_MkTipSubDivs()
1868	{
1869		var sCss = 'position: relative; margin: 0px; padding: 0px; border-width: 0px; left: 0px; top: 0px; line-height: normal; width: auto;',
1870		sTbTrTd = ' cellspacing=0 cellpadding=0 border=0 style="' + sCss + '"><tbody style="' + sCss + '"><tr><td ';
1871
1872		tt_aElt[0].innerHTML =
1873			(''
1874			+ (tt_aV[TITLE].length ?
1875				('<div id="WzTiTl" style="position:relative;z-index:1;">'
1876				+ '<table id="WzTiTlTb"' + sTbTrTd + 'id="WzTiTlI" style="' + sCss + '">'
1877				+ tt_aV[TITLE]
1878				+ '</td>'
1879				+ (tt_aV[CLOSEBTN] ?
1880					('<td align="right" style="' + sCss
1881					+ 'text-align:right;">'
1882					+ '<span id="WzClOsE" style="padding-left:2px;padding-right:2px;'
1883					+ 'cursor:' + (tt_ie ? 'hand' : 'pointer')
1884					+ ';" onmouseover="tt_OnCloseBtnOver(1)" onmouseout="tt_OnCloseBtnOver(0)" onclick="tt_HideInit()">'
1885					+ tt_aV[CLOSEBTNTEXT]
1886					+ '</span></td>')
1887					: '')
1888				+ '</tr></tbody></table></div>')
1889				: '')
1890			+ '<div id="WzBoDy" style="position:relative;z-index:0;">'
1891			+ '<table' + sTbTrTd + 'id="WzBoDyI" style="' + sCss + '">'
1892			+ tt_sContent
1893			+ '</td></tr></tbody></table></div>'
1894			+ (tt_aV[SHADOW]
1895				? ('<div id="WzTtShDwR" style="position:absolute;overflow:hidden;"></div>'
1896					+ '<div id="WzTtShDwB" style="position:relative;overflow:hidden;"></div>')
1897				: '')
1898			);
1899		tt_GetSubDivRefs();
1900		// Convert DOM node to tip
1901		if(tt_t2t && !tt_aV[COPYCONTENT])
1902		{
1903			// Store the tag's parent element so we can restore that DOM branch
1904			// once the tooltip is hidden
1905			tt_t2tDad = tt_t2t.parentNode || tt_t2t.parentElement || tt_t2t.offsetParent || null;
1906			if(tt_t2tDad)
1907			{
1908				tt_MovDomNode(tt_t2t, tt_t2tDad, tt_aElt[6]);
1909				tt_t2t.style.display = "block";
1910			}
1911		}
1912		tt_ExtCallFncs(0, "SubDivsCreated");
1913	}
1914	function tt_GetSubDivRefs()
1915	{
1916		var aId = new Array("WzTiTl", "WzTiTlTb", "WzTiTlI", "WzClOsE", "WzBoDy", "WzBoDyI", "WzTtShDwB", "WzTtShDwR");
1917
1918		for(var i = aId.length; i; --i)
1919			tt_aElt[i] = tt_GetElt(aId[i - 1]);
1920	}
1921	function tt_FormatTip()
1922	{
1923		var css, w, iOffY, iOffSh;
1924
1925		//--------- Title DIV ----------
1926		if(tt_aV[TITLE].length)
1927		{
1928			css = tt_aElt[1].style;
1929
1930			if (tt_aV[TITLECSSCLASS]) {
1931				tt_aElt[1].className = tt_aV[TITLECSSCLASS]
1932			} else {
1933				css.background = tt_aV[TITLEBGCOLOR];
1934				css.paddingTop = (tt_aV[CLOSEBTN] ? 2 : 0) + "px";
1935				css.paddingBottom = "1px";
1936				css.paddingLeft = css.paddingRight = tt_aV[PADDING] + "px";
1937				css = tt_aElt[3].style;
1938				css.color = tt_aV[TITLEFONTCOLOR];
1939				css.fontFamily = tt_aV[TITLEFONTFACE];
1940				css.fontSize = tt_aV[TITLEFONTSIZE];
1941				css.fontWeight = "bold";
1942				css.textAlign = tt_aV[TITLEALIGN];
1943			}
1944			// Close button DIV
1945			if(tt_aElt[4])
1946			{
1947				css.paddingRight = (tt_aV[PADDING] << 1) + "px";
1948				css = tt_aElt[4].style;
1949				css.background = tt_aV[CLOSEBTNCOLORS][0];
1950				css.color = tt_aV[CLOSEBTNCOLORS][1];
1951				css.fontFamily = tt_aV[TITLEFONTFACE];
1952				css.fontSize = tt_aV[TITLEFONTSIZE];
1953				css.fontWeight = "bold";
1954			}
1955			if(tt_aV[WIDTH] > 0)
1956				tt_w = tt_aV[WIDTH] + ((tt_aV[PADDING] + tt_aV[BORDERWIDTH]) << 1);
1957			else
1958			{
1959				tt_w = tt_GetDivW(tt_aElt[3]) + tt_GetDivW(tt_aElt[4]);
1960				// Some spacing between title DIV and closebutton
1961				if(tt_aElt[4])
1962					tt_w += tt_aV[PADDING];
1963			}
1964			// Ensure the top border of the body DIV be covered by the title DIV
1965			iOffY = -tt_aV[BORDERWIDTH];
1966		}
1967		else
1968		{
1969			tt_w = 0;
1970			iOffY = 0;
1971		}
1972
1973		//-------- Body DIV ------------
1974		css = tt_aElt[5].style;
1975		css.top = "0px";
1976		if(tt_aV[CSSCLASS]) {
1977			tt_aElt[5].className = tt_aV[CSSCLASS]
1978		} else {
1979			if(tt_aV[BORDERWIDTH])
1980			{
1981				css.borderColor = tt_aV[BORDERCOLOR];
1982				css.borderStyle = tt_aV[BORDERSTYLE];
1983				css.borderWidth = tt_aV[BORDERWIDTH] + "px";
1984			}
1985			if(tt_aV[BGCOLOR].length)
1986				css.background = tt_aV[BGCOLOR];
1987			if(tt_aV[BGIMG].length)
1988				css.backgroundImage = "url(" + tt_aV[BGIMG] + ")";
1989			css.padding = tt_aV[PADDING] + "px";
1990			css.textAlign = tt_aV[TEXTALIGN];
1991			// TD inside body DIV
1992			css = tt_aElt[6].style;
1993			css.color = tt_aV[FONTCOLOR];
1994			css.fontFamily = tt_aV[FONTFACE];
1995			css.fontSize = tt_aV[FONTSIZE];
1996			css.fontWeight = tt_aV[FONTWEIGHT];
1997			css.background = "";
1998			css.textAlign = tt_aV[TEXTALIGN];
1999		}
2000
2001		if(tt_aV[WIDTH] > 0)
2002			w = tt_aV[WIDTH] + ((tt_aV[PADDING] + tt_aV[BORDERWIDTH]) << 1);
2003		else
2004			// We measure the width of the body's inner TD, because some browsers
2005			// expand the width of the container and outer body DIV to 100%
2006			w = tt_GetDivW(tt_aElt[6]) + ((tt_aV[PADDING] + tt_aV[BORDERWIDTH]) << 1);
2007		if(w > tt_w)
2008			tt_w = w;
2009
2010		//--------- Shadow DIVs ------------
2011		if(tt_aV[SHADOW])
2012		{
2013			tt_w += tt_aV[SHADOWWIDTH];
2014			iOffSh = Math.floor((tt_aV[SHADOWWIDTH] * 4) / 3);
2015			// Bottom shadow
2016			css = tt_aElt[7].style;
2017			css.top = iOffY + "px";
2018			css.left = iOffSh + "px";
2019			css.width = (tt_w - iOffSh - tt_aV[SHADOWWIDTH]) + "px";
2020			css.height = tt_aV[SHADOWWIDTH] + "px";
2021			css.background = tt_aV[SHADOWCOLOR];
2022			// Right shadow
2023			css = tt_aElt[8].style;
2024			css.top = iOffSh + "px";
2025			css.left = (tt_w - tt_aV[SHADOWWIDTH]) + "px";
2026			css.width = tt_aV[SHADOWWIDTH] + "px";
2027			css.background = tt_aV[SHADOWCOLOR];
2028		}
2029		else
2030			iOffSh = 0;
2031
2032		//-------- Container DIV -------
2033		tt_SetTipOpa(tt_aV[FADEIN] ? 0 : tt_aV[OPACITY]);
2034		tt_FixSize(iOffY, iOffSh);
2035	}
2036	// Fixate the size so it can't dynamically change while the tooltip is moving.
2037	function tt_FixSize(iOffY, iOffSh)
2038	{
2039		var wIn, wOut, i;
2040
2041		tt_aElt[0].style.width = tt_w + "px";
2042		tt_aElt[0].style.pixelWidth = tt_w;
2043		wOut = tt_w - ((tt_aV[SHADOW]) ? tt_aV[SHADOWWIDTH] : 0);
2044		// Body
2045		wIn = wOut;
2046		if(!tt_bBoxOld)
2047		wIn = wOut - (tt_aV[PADDING] << 1);
2048		// Title
2049		if(tt_aElt[1])
2050		{
2051			wIn = wOut - (tt_aV[PADDING] << 1);
2052			if(!tt_bBoxOld)
2053				wOut = wIn;
2054		}
2055		tt_h = tt_GetDivH(tt_aElt[0]) + iOffY;
2056		// Right shadow
2057		if(tt_aElt[8])
2058		i = tt_aElt.length - 1;
2059		if(tt_aElt[i])
2060		{
2061			tt_aElt[i].style.width = tt_w + "px";
2062			tt_aElt[i].style.height = tt_h + "px";
2063		}
2064	}
2065	function tt_DeAlt(el)
2066	{
2067		var aKid;
2068
2069		if(el.alt)
2070			el.alt = "";
2071		if(el.title)
2072			el.title = "";
2073		aKid = el.childNodes || el.children || null;
2074		if(aKid)
2075		{
2076			for(var i = aKid.length; i;)
2077				tt_DeAlt(aKid[--i]);
2078		}
2079	}
2080	// This hack removes the annoying native tooltips over links in Opera
2081	function tt_OpDeHref(el)
2082	{
2083		if(!tt_op)
2084			return;
2085		if(tt_elDeHref)
2086			tt_OpReHref();
2087		while(el)
2088		{
2089			if(el.hasAttribute("href"))
2090			{
2091				el.t_href = el.getAttribute("href");
2092				el.t_stats = window.status;
2093				el.removeAttribute("href");
2094				el.style.cursor = "hand";
2095				tt_AddEvtFnc(el, "mousedown", tt_OpReHref);
2096				window.status = el.t_href;
2097				tt_elDeHref = el;
2098				break;
2099			}
2100			el = el.parentElement;
2101		}
2102	}
2103	function tt_ShowInit()
2104	{
2105		tt_tShow.Timer("tt_Show()", tt_aV[DELAY], true);
2106		if(tt_aV[CLICKCLOSE])
2107			tt_AddEvtFnc(document, "mouseup", tt_HideInit);
2108	}
2109	function tt_OverInit(e)
2110	{
2111		tt_over = e.target || e.srcElement;
2112		tt_DeAlt(tt_over);
2113		tt_OpDeHref(tt_over);
2114		tt_AddRemOutFnc(true);
2115	}
2116	function tt_Show()
2117	{
2118		var css = tt_aElt[0].style;
2119
2120		// Override the z-index of the topmost wz_dragdrop.js D&D item
2121		css.zIndex = Math.max((window.dd && dd.z) ? (dd.z + 2) : 0, 1010);
2122		if(tt_aV[STICKY] || !tt_aV[FOLLOWMOUSE])
2123			tt_iState &= ~0x4;
2124		if(tt_aV[DURATION] > 0)
2125			tt_tDurt.Timer("tt_HideInit()", tt_aV[DURATION], true);
2126		tt_ExtCallFncs(0, "Show")
2127		css.visibility = "visible";
2128		tt_iState |= 0x2;
2129		if(tt_aV[FADEIN])
2130			tt_Fade(0, 0, tt_aV[OPACITY], Math.round(tt_aV[FADEIN] / tt_aV[FADEINTERVAL]));
2131		tt_ShowIfrm();
2132	}
2133	function tt_ShowIfrm()
2134	{
2135		if(tt_ie56)
2136		{
2137			var ifrm = tt_aElt[tt_aElt.length - 1];
2138			if(ifrm)
2139			{
2140				var css = ifrm.style;
2141				css.zIndex = tt_aElt[0].style.zIndex - 1;
2142				css.display = "block";
2143			}
2144		}
2145	}
2146	function tt_Move(e)
2147	{
2148		e = window.event || e;
2149		if(e)
2150		{
2151			tt_musX = tt_GetEvtX(e);
2152			tt_musY = tt_GetEvtY(e);
2153		}
2154		if(tt_iState)
2155		{
2156			if(!tt_over && e)
2157				tt_OverInit(e);
2158			if(tt_iState & 0x4)
2159			{
2160				// Protect some browsers against jam of mousemove events
2161				if(!tt_op && !tt_ie)
2162				{
2163					if(tt_bWait)
2164						return;
2165					tt_bWait = true;
2166					tt_tWaitMov.Timer("tt_bWait = false;", 1, true);
2167				}
2168				if(tt_aV[FIX])
2169				{
2170					tt_iState &= ~0x4;
2171					tt_SetTipPos(tt_aV[FIX][0], tt_aV[FIX][1]);
2172				}
2173				else if(!tt_ExtCallFncs(e, "MoveBefore"))
2174					tt_SetTipPos(tt_PosX(), tt_PosY());
2175				tt_ExtCallFncs([tt_musX, tt_musY], "MoveAfter")
2176			}
2177		}
2178	}
2179	function tt_PosX()
2180	{
2181		var x;
2182
2183		x = tt_musX;
2184		if(tt_aV[LEFT])
2185			x -= tt_w + tt_aV[OFFSETX] - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0);
2186		else
2187			x += tt_aV[OFFSETX];
2188		// Prevent tip from extending past right/left clientarea boundary
2189		if(x > tt_maxPosX)
2190			x = tt_maxPosX;
2191		return((x < tt_scrlX) ? tt_scrlX : x);
2192	}
2193	function tt_PosY()
2194	{
2195		var y;
2196
2197		// Apply some hysteresis after the tip has snapped to the other side of the
2198		// mouse. In case of insufficient space above and below the mouse, we place
2199		// the tip below.
2200		if(tt_aV[ABOVE] && (!tt_bJmpVert || tt_CalcPosYAbove() >= tt_scrlY + 16))
2201			y = tt_DoPosYAbove();
2202		else if(!tt_aV[ABOVE] && tt_bJmpVert && tt_CalcPosYBelow() > tt_maxPosY - 16)
2203			y = tt_DoPosYAbove();
2204		else
2205			y = tt_DoPosYBelow();
2206		// Snap to other side of mouse if tip would extend past window boundary
2207		if(y > tt_maxPosY)
2208			y = tt_DoPosYAbove();
2209		if(y < tt_scrlY)
2210			y = tt_DoPosYBelow();
2211		return y;
2212	}
2213	function tt_DoPosYBelow()
2214	{
2215		tt_bJmpVert = tt_aV[ABOVE];
2216		return tt_CalcPosYBelow();
2217	}
2218	function tt_DoPosYAbove()
2219	{
2220		tt_bJmpVert = !tt_aV[ABOVE];
2221		return tt_CalcPosYAbove();
2222	}
2223	function tt_CalcPosYBelow()
2224	{
2225		return(tt_musY + tt_aV[OFFSETY]);
2226	}
2227	function tt_CalcPosYAbove()
2228	{
2229		var dy = tt_aV[OFFSETY] - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0);
2230		if(tt_aV[OFFSETY] > 0 && dy <= 0)
2231			dy = 1;
2232		return(tt_musY - tt_h - dy);
2233	}
2234	function tt_OnOut()
2235	{
2236		tt_AddRemOutFnc(false);
2237		if(!(tt_aV[STICKY] && (tt_iState & 0x2)))
2238			tt_HideInit();
2239	}
2240	function tt_HideInit()
2241	{
2242		tt_ExtCallFncs(0, "HideInit");
2243		tt_iState &= ~0x4;
2244		if(tt_flagOpa && tt_aV[FADEOUT])
2245		{
2246			tt_tFade.EndTimer();
2247			if(tt_opa)
2248			{
2249				var n = Math.round(tt_aV[FADEOUT] / (tt_aV[FADEINTERVAL] * (tt_aV[OPACITY] / tt_opa)));
2250				tt_Fade(tt_opa, tt_opa, 0, n);
2251				return;
2252			}
2253		}
2254		tt_tHide.Timer("tt_Hide();", 1, false);
2255	}
2256	function tt_OpReHref()
2257	{
2258		if(tt_elDeHref)
2259		{
2260			tt_elDeHref.setAttribute("href", tt_elDeHref.t_href);
2261			tt_RemEvtFnc(tt_elDeHref, "mousedown", tt_OpReHref);
2262			window.status = tt_elDeHref.t_stats;
2263			tt_elDeHref = null;
2264		}
2265	}
2266	function tt_Fade(a, now, z, n)
2267	{
2268		if(n)
2269		{
2270			now += Math.round((z - now) / n);
2271			if((z > a) ? (now >= z) : (now <= z))
2272				now = z;
2273			else
2274				tt_tFade.Timer("tt_Fade("
2275								+ a + "," + now + "," + z + "," + (n - 1)
2276								+ ")",
2277								tt_aV[FADEINTERVAL],
2278								true);
2279		}
2280		now ? tt_SetTipOpa(now) : tt_Hide();
2281	}
2282	// To circumvent the opacity nesting flaws of IE, we set the opacity
2283	// for each sub-DIV separately, rather than for the container DIV.
2284	function tt_SetTipOpa(opa)
2285	{
2286		tt_SetOpa(tt_aElt[5].style, opa);
2287		if(tt_aElt[1])
2288			tt_SetOpa(tt_aElt[1].style, opa);
2289		if(tt_aV[SHADOW])
2290		{
2291			opa = Math.round(opa * 0.8);
2292			tt_SetOpa(tt_aElt[7].style, opa);
2293			tt_SetOpa(tt_aElt[8].style, opa);
2294		}
2295	}
2296	function tt_OnCloseBtnOver(iOver)
2297	{
2298		var css = tt_aElt[4].style;
2299
2300		iOver <<= 1;
2301		css.background = tt_aV[CLOSEBTNCOLORS][iOver];
2302		css.color = tt_aV[CLOSEBTNCOLORS][iOver + 1];
2303	}
2304	function tt_Int(x)
2305	{
2306		var y;
2307
2308		return(isNaN(y = parseInt(x)) ? 0 : y);
2309	}
2310	// Adds or removes the document.mousemove or HoveredElem.mouseout handler
2311	// conveniently. Keeps track of those handlers to prevent them from being
2312	// set or removed redundantly.
2313	function tt_AddRemOutFnc(bAdd)
2314	{
2315		var PSet = bAdd ? tt_AddEvtFnc : tt_RemEvtFnc;
2316
2317		if(bAdd != tt_AddRemOutFnc.bOn)
2318		{
2319			PSet(tt_over, "mouseout", tt_OnOut);
2320			tt_AddRemOutFnc.bOn = bAdd;
2321			if(!bAdd)
2322				tt_OpReHref();
2323		}
2324	}
2325	tt_AddRemOutFnc.bOn = false;
2326	Number.prototype.Timer = function(s, iT, bUrge)
2327	{
2328		if(!this.value || bUrge)
2329			this.value = window.setTimeout(s, iT);
2330	}
2331	Number.prototype.EndTimer = function()
2332	{
2333		if(this.value)
2334		{
2335			window.clearTimeout(this.value);
2336			this.value = 0;
2337		}
2338	}
2339	function tt_SetOpa(css, opa)
2340	{
2341		tt_opa = opa;
2342		if(tt_flagOpa == 1)
2343		{
2344			// Hack for bugs of IE:
2345			// A DIV cannot be made visible in a single step if an opacity < 100
2346			// has been applied while the DIV was hidden.
2347			// Moreover, in IE6, applying an opacity < 100 has no effect if the
2348			// concerned element has no layout (position, size, zoom, ...).
2349			if(opa < 100)
2350			{
2351				var bVis = css.visibility != "hidden";
2352				css.zoom = "100%";
2353				if(!bVis)
2354					css.visibility = "visible";
2355				css.filter = "alpha(opacity=" + opa + ")";
2356				if(!bVis)
2357					css.visibility = "hidden";
2358			}
2359			else
2360				css.filter = "";
2361		}
2362		else
2363		{
2364			opa /= 100.0;
2365			switch(tt_flagOpa)
2366			{
2367			case 2:
2368				css.KhtmlOpacity = opa; break;
2369			case 3:
2370				css.KHTMLOpacity = opa; break;
2371			case 4:
2372				css.MozOpacity = opa; break;
2373			case 5:
2374				css.opacity = opa; break;
2375			}
2376		}
2377	}
2378	function tt_MovDomNode(el, dadFrom, dadTo)
2379	{
2380		if(dadFrom)
2381			dadFrom.removeChild(el);
2382		if(dadTo)
2383			dadTo.appendChild(el);
2384	}
2385	function tt_Err(sErr)
2386	{
2387		if(tt_Debug)
2388			alert("Tooltip Script Error Message:\n\n" + sErr);
2389	}
2390
2391	//===========  DEALING WITH EXTENSIONS	==============//
2392	function tt_ExtCmdEnum()
2393	{
2394		var s;
2395
2396		// Add new command(s) to the commands enum
2397		for(var i in config)
2398		{
2399			s = "window." + i.toString().toUpperCase();
2400			if(eval("typeof(" + s + ") == tt_u"))
2401			{
2402				eval(s + " = " + tt_aV.length);
2403				tt_aV[tt_aV.length] = null;
2404			}
2405		}
2406	}
2407	function tt_ExtCallFncs(arg, sFnc)
2408	{
2409		var b = false;
2410		for(var i = tt_aExt.length; i;)
2411		{--i;
2412			var fnc = tt_aExt[i]["On" + sFnc];
2413			// Call the method the extension has defined for this event
2414			if(fnc && fnc(arg))
2415				b = true;
2416		}
2417		return b;
2418	}
2419
2420	tt_Init();
2421
2422
2423
2424
2425
2426
2427/* End: js/form builder/help_tip.js*/
2428
2429
2430
2431;/* Start: js/vendor/ElementQueries.js*/
2432
2433'use strict';
2434
2435/**
2436 * Copyright Marc J. Schmidt. See the LICENSE file at the top-level
2437 * directory of this distribution and at
2438 * https://github.com/marcj/css-element-queries/blob/master/LICENSE.
2439 */
2440(function (root, factory) {
2441    if (typeof define === "function" && define.amd) {
2442        define(['./ResizeSensor.js'], factory);
2443    } else if (typeof exports === "object") {
2444        module.exports = factory(require('./ResizeSensor.js'));
2445    } else {
2446        root.ElementQueries = factory(root.ResizeSensor);
2447        root.ElementQueries.listen();
2448    }
2449}(typeof window !== 'undefined' ? window : this, function (ResizeSensor) {
2450
2451    /**
2452     *
2453     * @type {Function}
2454     * @constructor
2455     */
2456    var ElementQueries = function () {
2457        //<style> element with our dynamically created styles
2458        var cssStyleElement;
2459
2460        //all rules found for element queries
2461        var allQueries = {};
2462
2463        //association map to identify which selector belongs to a element from the animationstart event.
2464        var idToSelectorMapping = [];
2465
2466        /**
2467         *
2468         * @param element
2469         * @returns {Number}
2470         */
2471        function getEmSize(element) {
2472            if (!element) {
2473                element = document.documentElement;
2474            }
2475            var fontSize = window.getComputedStyle(element, null).fontSize;
2476            return parseFloat(fontSize) || 16;
2477        }
2478
2479        /**
2480         * Get element size
2481         * @param {HTMLElement} element
2482         * @returns {Object} {width, height}
2483         */
2484        function getElementSize(element) {
2485            if (!element.getBoundingClientRect) {
2486                return {
2487                    width: element.offsetWidth,
2488                    height: element.offsetHeight
2489                }
2490            }
2491
2492            var rect = element.getBoundingClientRect();
2493            return {
2494                width: Math.round(rect.width),
2495                height: Math.round(rect.height)
2496            }
2497        }
2498
2499        /**
2500         *
2501         * @copyright https://github.com/Mr0grog/element-query/blob/master/LICENSE
2502         *
2503         * @param {HTMLElement} element
2504         * @param {*} value
2505         * @returns {*}
2506         */
2507        function convertToPx(element, value) {
2508            var numbers = value.split(/\d/);
2509            var units = numbers[numbers.length - 1];
2510            value = parseFloat(value);
2511            switch (units) {
2512                case "px":
2513                    return value;
2514                case "em":
2515                    return value * getEmSize(element);
2516                case "rem":
2517                    return value * getEmSize();
2518                // Viewport units!
2519                // According to http://quirksmode.org/mobile/tableViewport.html
2520                // documentElement.clientWidth/Height gets us the most reliable info
2521                case "vw":
2522                    return value * document.documentElement.clientWidth / 100;
2523                case "vh":
2524                    return value * document.documentElement.clientHeight / 100;
2525                case "vmin":
2526                case "vmax":
2527                    var vw = document.documentElement.clientWidth / 100;
2528                    var vh = document.documentElement.clientHeight / 100;
2529                    var chooser = Math[units === "vmin" ? "min" : "max"];
2530                    return value * chooser(vw, vh);
2531                default:
2532                    return value;
2533                // for now, not supporting physical units (since they are just a set number of px)
2534                // or ex/ch (getting accurate measurements is hard)
2535            }
2536        }
2537
2538        /**
2539         *
2540         * @param {HTMLElement} element
2541         * @param {String} id
2542         * @constructor
2543         */
2544        function SetupInformation(element, id) {
2545            this.element = element;
2546            var key, option, elementSize, value, actualValue, attrValues, attrValue, attrName;
2547
2548            var attributes = ['min-width', 'min-height', 'max-width', 'max-height'];
2549
2550            /**
2551             * Extracts the computed width/height and sets to min/max- attribute.
2552             */
2553            this.call = function () {
2554                // extract current dimensions
2555                elementSize = getElementSize(this.element);
2556
2557                attrValues = {};
2558
2559                for (key in allQueries[id]) {
2560                    if (!allQueries[id].hasOwnProperty(key)) {
2561                        continue;
2562                    }
2563                    option = allQueries[id][key];
2564
2565                    value = convertToPx(this.element, option.value);
2566
2567                    actualValue = option.property === 'width' ? elementSize.width : elementSize.height;
2568                    attrName = option.mode + '-' + option.property;
2569                    attrValue = '';
2570
2571                    if (option.mode === 'min' && actualValue >= value) {
2572                        attrValue += option.value;
2573                    }
2574
2575                    if (option.mode === 'max' && actualValue <= value) {
2576                        attrValue += option.value;
2577                    }
2578
2579                    if (!attrValues[attrName]) attrValues[attrName] = '';
2580                    if (attrValue && -1 === (' ' + attrValues[attrName] + ' ').indexOf(' ' + attrValue + ' ')) {
2581                        attrValues[attrName] += ' ' + attrValue;
2582                    }
2583                }
2584
2585                for (var k in attributes) {
2586                    if (!attributes.hasOwnProperty(k)) continue;
2587
2588                    if (attrValues[attributes[k]]) {
2589                        this.element.setAttribute(attributes[k], attrValues[attributes[k]].substr(1));
2590                    } else {
2591                        this.element.removeAttribute(attributes[k]);
2592                    }
2593                }
2594            };
2595        }
2596
2597        /**
2598         * @param {HTMLElement} element
2599         * @param {Object}      id
2600         */
2601        function setupElement(element, id) {
2602            if (!element.elementQueriesSetupInformation) {
2603                element.elementQueriesSetupInformation = new SetupInformation(element, id);
2604            }
2605
2606            if (!element.elementQueriesSensor) {
2607                element.elementQueriesSensor = new ResizeSensor(element, function () {
2608                    element.elementQueriesSetupInformation.call();
2609                });
2610            }
2611        }
2612
2613        /**
2614         * Stores rules to the selector that should be applied once resized.
2615         *
2616         * @param {String} selector
2617         * @param {String} mode min|max
2618         * @param {String} property width|height
2619         * @param {String} value
2620         */
2621        function queueQuery(selector, mode, property, value) {
2622            if (typeof (allQueries[selector]) === 'undefined') {
2623                allQueries[selector] = [];
2624                // add animation to trigger animationstart event, so we know exactly when a element appears in the DOM
2625
2626                var id = idToSelectorMapping.length;
2627                cssStyleElement.innerHTML += '\n' + selector + ' {animation: 0.1s element-queries;}';
2628                cssStyleElement.innerHTML += '\n' + selector + ' > .resize-sensor {min-width: ' + id + 'px;}';
2629                idToSelectorMapping.push(selector);
2630            }
2631
2632            allQueries[selector].push({
2633                mode: mode,
2634                property: property,
2635                value: value
2636            });
2637        }
2638
2639        function getQuery(container) {
2640            var query;
2641            if (document.querySelectorAll) query = (container) ? container.querySelectorAll.bind(container) : document.querySelectorAll.bind(document);
2642            if (!query && 'undefined' !== typeof $$) query = $$;
2643            if (!query && 'undefined' !== typeof jQuery) query = jQuery;
2644
2645            if (!query) {
2646                throw 'No document.querySelectorAll, jQuery or Mootools\'s $$ found.';
2647            }
2648
2649            return query;
2650        }
2651
2652        /**
2653         * If animationStart didn't catch a new element in the DOM, we can manually search for it
2654         */
2655        function findElementQueriesElements(container) {
2656            var query = getQuery(container);
2657
2658            for (var selector in allQueries) if (allQueries.hasOwnProperty(selector)) {
2659                // find all elements based on the extract query selector from the element query rule
2660                var elements = query(selector, container);
2661
2662                for (var i = 0, j = elements.length; i < j; i++) {
2663                    setupElement(elements[i], selector);
2664                }
2665            }
2666        }
2667
2668        /**
2669         *
2670         * @param {HTMLElement} element
2671         */
2672        function attachResponsiveImage(element) {
2673            var children = [];
2674            var rules = [];
2675            var sources = [];
2676            var defaultImageId = 0;
2677            var lastActiveImage = -1;
2678            var loadedImages = [];
2679
2680            for (var i in element.children) {
2681                if (!element.children.hasOwnProperty(i)) continue;
2682
2683                if (element.children[i].tagName && element.children[i].tagName.toLowerCase() === 'img') {
2684                    children.push(element.children[i]);
2685
2686                    var minWidth = element.children[i].getAttribute('min-width') || element.children[i].getAttribute('data-min-width');
2687                    //var minHeight = element.children[i].getAttribute('min-height') || element.children[i].getAttribute('data-min-height');
2688                    var src = element.children[i].getAttribute('data-src') || element.children[i].getAttribute('url');
2689
2690                    sources.push(src);
2691
2692                    var rule = {
2693                        minWidth: minWidth
2694                    };
2695
2696                    rules.push(rule);
2697
2698                    if (!minWidth) {
2699                        defaultImageId = children.length - 1;
2700                        element.children[i].style.display = 'block';
2701                    } else {
2702                        element.children[i].style.display = 'none';
2703                    }
2704                }
2705            }
2706
2707            lastActiveImage = defaultImageId;
2708
2709            function check() {
2710                var imageToDisplay = false, i;
2711
2712                for (i in children) {
2713                    if (!children.hasOwnProperty(i)) continue;
2714
2715                    if (rules[i].minWidth) {
2716                        if (element.offsetWidth > rules[i].minWidth) {
2717                            imageToDisplay = i;
2718                        }
2719                    }
2720                }
2721
2722                if (!imageToDisplay) {
2723                    //no rule matched, show default
2724                    imageToDisplay = defaultImageId;
2725                }
2726
2727                if (lastActiveImage !== imageToDisplay) {
2728                    //image change
2729
2730                    if (!loadedImages[imageToDisplay]) {
2731                        //image has not been loaded yet, we need to load the image first in memory to prevent flash of
2732                        //no content
2733
2734                        var image = new Image();
2735                        image.onload = function () {
2736                            children[imageToDisplay].src = sources[imageToDisplay];
2737
2738                            children[lastActiveImage].style.display = 'none';
2739                            children[imageToDisplay].style.display = 'block';
2740
2741                            loadedImages[imageToDisplay] = true;
2742
2743                            lastActiveImage = imageToDisplay;
2744                        };
2745
2746                        image.src = sources[imageToDisplay];
2747                    } else {
2748                        children[lastActiveImage].style.
2748display = 'none';
2749                        children[imageToDisplay].style.display = 'block';
2750                        lastActiveImage = imageToDisplay;
2751                    }
2752                } else {
2753                    //make sure for initial check call the .src is set correctly
2754                    children[imageToDisplay].src = sources[imageToDisplay];
2755                }
2756            }
2757
2758            element.resizeSensorInstance = new ResizeSensor(element, check);
2759            check();
2760        }
2761
2762        function findResponsiveImages() {
2763            var query = getQuery();
2764
2765            var elements = query('[data-responsive-image],[responsive-image]');
2766            for (var i = 0, j = elements.length; i < j; i++) {
2767                attachResponsiveImage(elements[i]);
2768            }
2769        }
2770
2771        var regex = /,?[\s\t]*([^,\n]*?)((?:\[[\s\t]*?(?:min|max)-(?:width|height)[\s\t]*?[~$\^]?=[\s\t]*?"[^"]*?"[\s\t]*?])+)([^,\n\s\{]*)/mgi;
2772        var attrRegex = /\[[\s\t]*?(min|max)-(width|height)[\s\t]*?[~$\^]?=[\s\t]*?"([^"]*?)"[\s\t]*?]/mgi;
2773
2774        /**
2775         * @param {String} css
2776         */
2777        function extractQuery(css) {
2778            var match, smatch, attrs, attrMatch;
2779
2780            css = css.replace(/'/g, '"');
2781            while (null !== (match = regex.exec(css))) {
2782                smatch = match[1] + match[3];
2783                attrs = match[2];
2784
2785                while (null !== (attrMatch = attrRegex.exec(attrs))) {
2786                    queueQuery(smatch, attrMatch[1], attrMatch[2], attrMatch[3]);
2787                }
2788            }
2789        }
2790
2791        /**
2792         * @param {CssRule[]|String} rules
2793         */
2794        function readRules(rules) {
2795            var selector = '';
2796
2797            if (!rules) {
2798                return;
2799            }
2800
2801            if ('string' === typeof rules) {
2802                rules = rules.toLowerCase();
2803                if (-1 !== rules.indexOf('min-width') || -1 !== rules.indexOf('max-width')) {
2804                    extractQuery(rules);
2805                }
2806            } else {
2807                for (var i = 0, j = rules.length; i < j; i++) {
2808                    if (1 === rules[i].type) {
2809                        selector = rules[i].selectorText || rules[i].cssText;
2810                        if (-1 !== selector.indexOf('min-height') || -1 !== selector.indexOf('max-height')) {
2811                            extractQuery(selector);
2812                        } else if (-1 !== selector.indexOf('min-width') || -1 !== selector.indexOf('max-width')) {
2813                            extractQuery(selector);
2814                        }
2815                    } else if (4 === rules[i].type) {
2816                        readRules(rules[i].cssRules || rules[i].rules);
2817                    } else if (3 === rules[i].type) {
2818                        if (rules[i].styleSheet.hasOwnProperty("cssRules")) {
2819                            readRules(rules[i].styleSheet.cssRules);
2820                        }
2821                    }
2822                }
2823            }
2824        }
2825
2826        var defaultCssInjected = false;
2827
2828        /**
2829         * Searches all css rules and setups the event listener to all elements with element query rules..
2830         */
2831        this.init = function () {
2832            var animationStart = 'animationstart';
2833            if (typeof document.documentElement.style['webkitAnimationName'] !== 'undefined') {
2834                animationStart = 'webkitAnimationStart';
2835            } else if (typeof document.documentElement.style['MozAnimationName'] !== 'undefined') {
2836                animationStart = 'mozanimationstart';
2837            } else if (typeof document.documentElement.style['OAnimationName'] !== 'undefined') {
2838                animationStart = 'oanimationstart';
2839            }
2840
2841            document.body.addEventListener(animationStart, function (e) {
2842                var element = e.target;
2843                var styles = element && window.getComputedStyle(element, null);
2844                var animationName = styles && styles.getPropertyValue('animation-name');
2845                var requiresSetup = animationName && (-1 !== animationName.indexOf('element-queries'));
2846
2847                if (requiresSetup) {
2848                    element.elementQueriesSensor = new ResizeSensor(element, function () {
2849                        if (element.elementQueriesSetupInformation) {
2850                            element.elementQueriesSetupInformation.call();
2851                        }
2852                    });
2853
2854                    var sensorStyles = window.getComputedStyle(element.resizeSensor, null);
2855                    var id = sensorStyles.getPropertyValue('min-width');
2856                    id = parseInt(id.replace('px', ''));
2857                    setupElement(e.target, idToSelectorMapping[id]);
2858                }
2859            });
2860
2861            if (!defaultCssInjected) {
2862                cssStyleElement = document.createElement('style');
2863                cssStyleElement.type = 'text/css';
2864                cssStyleElement.innerHTML = '[responsive-image] > img, [data-responsive-image] {overflow: hidden; padding: 0; } [responsive-image] > img, [data-responsive-image] > img {width: 100%;}';
2865
2866                //safari wants at least one rule in keyframes to start working
2867                cssStyleElement.innerHTML += '\n@keyframes element-queries { 0% { visibility: inherit; } }';
2868                document.getElementsByTagName('head')[0].appendChild(cssStyleElement);
2869                defaultCssInjected = true;
2870            }
2871
2872            for (var i = 0, j = document.styleSheets.length; i < j; i++) {
2873                try {
2874                    if (document.styleSheets[i].href && 0 === document.styleSheets[i].href.indexOf('file://')) {
2875                        console.warn("CssElementQueries: unable to parse local css files, " + document.styleSheets[i].href);
2876                    }
2877
2878                    readRules(document.styleSheets[i].cssRules || document.styleSheets[i].rules || document.styleSheets[i].cssText);
2879                } catch (e) {
2880                }
2881            }
2882
2883            findResponsiveImages();
2884        };
2885
2886        /**
2887         * Go through all collected rules (readRules()) and attach the resize-listener.
2888         * Not necessary to call it manually, since we detect automatically when new elements
2889         * are available in the DOM. However, sometimes handy for dirty DOM modifications.
2890         *
2891         * @param {HTMLElement} container only elements of the container are considered (document.body if not set)
2892         */
2893        this.findElementQueriesElements = function (container) {
2894            findElementQueriesElements(container);
2895        };
2896
2897        this.update = function () {
2898            this.init();
2899        };
2900    };
2901
2902    ElementQueries.update = function () {
2903        ElementQueries.instance.update();
2904    };
2905
2906    /**
2907     * Removes all sensor and elementquery information from the element.
2908     *
2909     * @param {HTMLElement} element
2910     */
2911    ElementQueries.detach = function (element) {
2912        if (element.elementQueriesSetupInformation) {
2913            //element queries
2914            element.elementQueriesSensor.detach();
2915            delete element.elementQueriesSetupInformation;
2916            delete element.elementQueriesSensor;
2917
2918        } else if (element.resizeSensorInstance) {
2919            //responsive image
2920
2921            element.resizeSensorInstance.detach();
2922            delete element.resizeSensorInstance;
2923        }
2924    };
2925
2926    ElementQueries.init = function () {
2927        if (!ElementQueries.instance) {
2928            ElementQueries.instance = new ElementQueries();
2929        }
2930
2931        ElementQueries.instance.init();
2932    };
2933
2934    var domLoaded = function (callback) {
2935        /* Mozilla, Chrome, Opera */
2936        if (document.addEventListener) {
2937            document.addEventListener('DOMContentLoaded', callback, false);
2938        }
2939        /* Safari, iCab, Konqueror */
2940        else if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
2941            var DOMLoadTimer = setInterval(function () {
2942                if (/loaded|complete/i.test(document.readyState)) {
2943                    callback();
2944                    clearInterval(DOMLoadTimer);
2945                }
2946            }, 10);
2947        }
2948        /* Other web browsers */
2949        else window.onload = callback;
2950    };
2951
2952    ElementQueries.findElementQueriesElements = function (container) {
2953        ElementQueries.instance.findElementQueriesElements(container);
2954    };
2955
2956    ElementQueries.listen = function () {
2957        domLoaded(ElementQueries.init);
2958    };
2959
2960    return ElementQueries;
2961
2962}));
2963
2964
2965
2966/* End: js/vendor/ElementQueries.js*/
2967

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.