PageSourceSearch

https://www.hempmate.com/js/core.js?t=666-2020

js hempmate.com collected 2026-09-28 12:10:31 UTC 693,125 bytes, 26,391 lines download raw bytes

vendor: 9,524 bytes, lines 1-388
1/*!
2 * jQuery JavaScript Library v3.4.1
3 * https://jquery.com/
4 *
5 * Includes Sizzle.js
6 * https://sizzlejs.com/
7 *
8 * Copyright JS Foundation and other contributors
9 * Released under the MIT license
10 * https://jquery.org/license
11 *
12 * Date: 2019-05-01T21:04Z
13 */
14( function( global, factory ) {
15
16	"use strict";
17
18	if ( typeof module === "object" && typeof module.exports === "object" ) {
19
20		// For CommonJS and CommonJS-like environments where a proper `window`
21		// is present, execute the factory and get jQuery.
22		// For environments that do not have a `window` with a `document`
23		// (such as Node.js), expose a factory as module.exports.
24		// This accentuates the need for the creation of a real `window`.
25		// e.g. var jQuery = require("jquery")(window);
26		// See ticket #14549 for more info.
27		module.exports = global.document ?
28			factory( global, true ) :
29			function( w ) {
30				if ( !w.document ) {
31					throw new Error( "jQuery requires a window with a document" );
32				}
33				return factory( w );
34			};
35	} else {
36		factory( global );
37	}
38
39// Pass this if window is not defined yet
40} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
41
42// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
43// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
44// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
45// enough that all such attempts are guarded in a try block.
46"use strict";
47
48var arr = [];
49
50var document = window.document;
51
52var getProto = Object.getPrototypeOf;
53
54var slice = arr.slice;
55
56var concat = arr.concat;
57
58var push = arr.push;
59
60var indexOf = arr.indexOf;
61
62var class2type = {};
63
64var toString = class2type.toString;
65
66var hasOwn = class2type.hasOwnProperty;
67
68var fnToString = hasOwn.toString;
69
70var ObjectFunctionString = fnToString.call( Object );
71
72var support = {};
73
74var thisSiteTitle = '';
75
76var isFunction = function isFunction( obj ) {
77
78      // Support: Chrome <=57, Firefox <=52
79      // In some browsers, typeof returns "function" for HTML <object> elements
80      // (i.e., `typeof document.createElement( "object" ) === "function"`).
81      // We don't want to classify *any* DOM node as a function.
82      return typeof obj === "function" && typeof obj.nodeType !== "number";
83  };
84
85
86var isWindow = function isWindow( obj ) {
87		return obj != null && obj === obj.window;
88	};
89
90
91
92
93	var preservedScriptAttributes = {
94		type: true,
95		src: true,
96		nonce: true,
97		noModule: true
98	};
99
100	function DOMEval( code, node, doc ) {
101		doc = doc || document;
102
103		var i, val,
104			script = doc.createElement( "script" );
105
106		script.text = code;
107		if ( node ) {
108			for ( i in preservedScriptAttributes ) {
109
110				// Support: Firefox 64+, Edge 18+
111				// Some browsers don't support the "nonce" property on scripts.
112				// On the other hand, just using `getAttribute` is not enough as
113				// the `nonce` attribute is reset to an empty string whenever it
114				// becomes browsing-context connected.
115				// See https://github.com/whatwg/html/issues/2369
116				// See https://html.spec.whatwg.org/#nonce-attributes
117				// The `node.getAttribute` check was added for the sake of
118				// `jQuery.globalEval` so that it can fake a nonce-containing node
119				// via an object.
120				val = node[ i ] || node.getAttribute && node.getAttribute( i );
121				if ( val ) {
122					script.setAttribute( i, val );
123				}
124			}
125		}
126		doc.head.appendChild( script ).parentNode.removeChild( script );
127	}
128
129
130function toType( obj ) {
131	if ( obj == null ) {
132		return obj + "";
133	}
134
135	// Support: Android <=2.3 only (functionish RegExp)
136	return typeof obj === "object" || typeof obj === "function" ?
137		class2type[ toString.call( obj ) ] || "object" :
138		typeof obj;
139}
140/* global Symbol */
141// Defining this global in .eslintrc.json would create a danger of using the global
142// unguarded in another place, it seems safer to define global only for this module
143
144
145
146var
147	version = "3.4.1",
148
149	// Define a local copy of jQuery
150	/*
151	jQuery = function( selector, context ) {
152
153		// The jQuery object is actually just the init constructor 'enhanced'
154		// Need init if jQuery is called (just allow error to be thrown if not included)
155		return new jQuery.fn.init( selector, context );
156	},
157	*/
158	// Support: Android <=4.0 only
159	// Make sure we trim BOM and NBSP
160	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
161
162jQuery.fn = jQuery.prototype = {
163
164	// The current version of jQuery being used
165	jquery: version,
166
167	constructor: jQuery,
168
169	// The default length of a jQuery object is 0
170	length: 0,
171
172	toArray: function() {
173		return slice.call( this );
174	},
175
176	// Get the Nth element in the matched element set OR
177	// Get the whole matched element set as a clean array
178	get: function( num ) {
179
180		// Return all the elements in a clean array
181		if ( num == null ) {
182			return slice.call( this );
183		}
184
185		// Return just the one element from the set
186		return num < 0 ? this[ num + this.length ] : this[ num ];
187	},
188
189	// Take an array of elements and push it onto the stack
190	// (returning the new matched element set)
191	pushStack: function( elems ) {
192
193		// Build a new jQuery matched element set
194		var ret = jQuery.merge( this.constructor(), elems );
195
196		// Add the old object onto the stack (as a reference)
197		ret.prevObject = this;
198
199		// Return the newly-formed element set
200		return ret;
201	},
202
203	// Execute a callback for every element in the matched set.
204	each: function( callback ) {
205		return jQuery.each( this, callback );
206	},
207
208	map: function( callback ) {
209		return this.pushStack( jQuery.map( this, function( elem, i ) {
210			return callback.call( elem, i, elem );
211		} ) );
212	},
213
214	slice: function() {
215		return this.pushStack( slice.apply( this, arguments ) );
216	},
217
218	first: function() {
219		return this.eq( 0 );
220	},
221
222	last: function() {
223		return this.eq( -1 );
224	},
225
226	eq: function( i ) {
227		var len = this.length,
228			j = +i + ( i < 0 ? len : 0 );
229		return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
230	},
231
232	end: function() {
233		return this.prevObject || this.constructor();
234	},
235
236	// For internal use only.
237	// Behaves like an Array's method, not like a jQuery method.
238	push: push,
239	sort: arr.sort,
240	splice: arr.splice
241};
242
243jQuery.extend = jQuery.fn.extend = function() {
244	var options, name, src, copy, copyIsArray, clone,
245		target = arguments[ 0 ] || {},
246		i = 1,
247		length = arguments.length,
248		deep = false;
249
250	// Handle a deep copy situation
251	if ( typeof target === "boolean" ) {
252		deep = target;
253
254		// Skip the boolean and the target
255		target = arguments[ i ] || {};
256		i++;
257	}
258
259	// Handle case when target is a string or something (possible in deep copy)
260	if ( typeof target !== "object" && !isFunction( target ) ) {
261		target = {};
262	}
263
264	// Extend jQuery itself if only one argument is passed
265	if ( i === length ) {
266		target = this;
267		i--;
268	}
269
270	for ( ; i < length; i++ ) {
271
272		// Only deal with non-null/undefined values
273		if ( ( options = arguments[ i ] ) != null ) {
274
275			// Extend the base object
276			for ( name in options ) {
277				copy = options[ name ];
278
279				// Prevent Object.prototype pollution
280				// Prevent never-ending loop
281				if ( name === "__proto__" || target === copy ) {
282					continue;
283				}
284
285				// Recurse if we're merging plain objects or arrays
286				if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
287					( copyIsArray = Array.isArray( copy ) ) ) ) {
288					src = target[ name ];
289
290					// Ensure proper type for the source value
291					if ( copyIsArray && !Array.isArray( src ) ) {
292						clone = [];
293					} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
294						clone = {};
295					} else {
296						clone = src;
297					}
298					copyIsArray = false;
299
300					// Never move original objects, clone them
301					target[ name ] = jQuery.extend( deep, clone, copy );
302
303				// Don't bring in undefined values
304				} else if ( copy !== undefined ) {
305					target[ name ] = copy;
306				}
307			}
308		}
309	}
310
311	// Return the modified object
312	return target;
313};
314
315jQuery.extend( {
316
317	// Unique for each copy of jQuery on the page
318	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
319
320	// Assume jQuery is ready without the ready module
321	isReady: true,
322
323	error: function( msg ) {
324		throw new Error( msg );
325	},
326
327	noop: function() {},
328
329	isPlainObject: function( obj ) {
330		var proto, Ctor;
331
332		// Detect obvious negatives
333		// Use toString instead of jQuery.type to catch host objects
334		if ( !obj || toString.call( obj ) !== "[object Object]" ) {
335			return false;
336		}
337
338		proto = getProto( obj );
339
340		// Objects with no prototype (e.g., `Object.create( null )`) are plain
341		if ( !proto ) {
342			return true;
343		}
344
345		// Objects with prototype are plain iff they were constructed by a global Object function
346		Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
347		return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
348	},
349
350	isEmptyObject: function( obj ) {
351		var name;
352
353		for ( name in obj ) {
354			return false;
355		}
356		return true;
357	},
358
359	// Evaluates a script in a global context
360	globalEval: function( code, options ) {
361		DOMEval( code, { nonce: options && options.nonce } );
362	},
363
364	each: function( obj, callback ) {
365		var length, i = 0;
366
367		if ( isArrayLike( obj ) ) {
368			length = obj.length;
369			for ( ; i < length; i++ ) {
370				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
371					break;
372				}
373			}
374		} else {
375			for ( i in obj ) {
376				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
377					break;
378				}
379			}
380		}
381
382		return obj;
383	},
384
385	// Support: Android <=4.0 only
386	trim: function( text ) {
387		return text == null ?
388			"" :
vendor: 5,066 bytes, lines 389-606
389			( text + "" ).replace( rtrim, "" );
390	},
391
392	// results is for internal usage only
393	makeArray: function( arr, results ) {
394		var ret = results || [];
395
396		if ( arr != null ) {
397			if ( isArrayLike( Object( arr ) ) ) {
398				jQuery.merge( ret,
399					typeof arr === "string" ?
400					[ arr ] : arr
401				);
402			} else {
403				push.call( ret, arr );
404			}
405		}
406
407		return ret;
408	},
409
410	inArray: function( elem, arr, i ) {
411		return arr == null ? -1 : indexOf.call( arr, elem, i );
412	},
413
414	// Support: Android <=4.0 only, PhantomJS 1 only
415	// push.apply(_, arraylike) throws on ancient WebKit
416	merge: function( first, second ) {
417		var len = +second.length,
418			j = 0,
419			i = first.length;
420
421		for ( ; j < len; j++ ) {
422			first[ i++ ] = second[ j ];
423		}
424
425		first.length = i;
426
427		return first;
428	},
429
430	grep: function( elems, callback, invert ) {
431		var callbackInverse,
432			matches = [],
433			i = 0,
434			length = elems.length,
435			callbackExpect = !invert;
436
437		// Go through the array, only saving the items
438		// that pass the validator function
439		for ( ; i < length; i++ ) {
440			callbackInverse = !callback( elems[ i ], i );
441			if ( callbackInverse !== callbackExpect ) {
442				matches.push( elems[ i ] );
443			}
444		}
445
446		return matches;
447	},
448
449	// arg is for internal usage only
450	map: function( elems, callback, arg ) {
451		var length, value,
452			i = 0,
453			ret = [];
454
455		// Go through the array, translating each of the items to their new values
456		if ( isArrayLike( elems ) ) {
457			length = elems.length;
458			for ( ; i < length; i++ ) {
459				value = callback( elems[ i ], i, arg );
460
461				if ( value != null ) {
462					ret.push( value );
463				}
464			}
465
466		// Go through every key on the object,
467		} else {
468			for ( i in elems ) {
469				value = callback( elems[ i ], i, arg );
470
471				if ( value != null ) {
472					ret.push( value );
473				}
474			}
475		}
476
477		// Flatten any nested arrays
478		return concat.apply( [], ret );
479	},
480
481	// A global GUID counter for objects
482	guid: 1,
483
484	// jQuery.support is not used in Core but other projects attach their
485	// properties to it so it needs to exist.
486	support: support
487} );
488
489if ( typeof Symbol === "function" ) {
490	jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
491}
492
493// Populate the class2type map
494jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
495function( i, name ) {
496	class2type[ "[object " + name + "]" ] = name.toLowerCase();
497} );
498
499function isArrayLike( obj ) {
500
501	// Support: real iOS 8.2 only (not reproducible in simulator)
502	// `in` check used to prevent JIT error (gh-2145)
503	// hasOwn isn't used here due to false negatives
504	// regarding Nodelist length in IE
505	var length = !!obj && "length" in obj && obj.length,
506		type = toType( obj );
507
508	if ( isFunction( obj ) || isWindow( obj ) ) {
509		return false;
510	}
511
512	return type === "array" || length === 0 ||
513		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
514}
515var Sizzle =
516/*!
517 * Sizzle CSS Selector Engine v2.3.4
518 * https://sizzlejs.com/
519 *
520 * Copyright JS Foundation and other contributors
521 * Released under the MIT license
522 * https://js.foundation/
523 *
524 * Date: 2019-04-08
525 */
526(function( window ) {
527
528var i,
529	support,
530	Expr,
531	getText,
532	isXML,
533	tokenize,
534	compile,
535	select,
536	outermostContext,
537	sortInput,
538	hasDuplicate,
539
540	// Local document vars
541	setDocument,
542	document,
543	docElem,
544	documentIsHTML,
545	rbuggyQSA,
546	rbuggyMatches,
547	matches,
548	contains,
549
550	// Instance-specific data
551	expando = "sizzle" + 1 * new Date(),
552	preferredDoc = window.document,
553	dirruns = 0,
554	done = 0,
555	classCache = createCache(),
556	tokenCache = createCache(),
557	compilerCache = createCache(),
558	nonnativeSelectorCache = createCache(),
559	sortOrder = function( a, b ) {
560		if ( a === b ) {
561			hasDuplicate = true;
562		}
563		return 0;
564	},
565
566	// Instance methods
567	hasOwn = ({}).hasOwnProperty,
568	arr = [],
569	pop = arr.pop,
570	push_native = arr.push,
571	push = arr.push,
572	slice = arr.slice,
573	// Use a stripped-down indexOf as it's faster than native
574	// https://jsperf.com/thor-indexof-vs-for/5
575	indexOf = function( list, elem ) {
576		var i = 0,
577			len = list.length;
578		for ( ; i < len; i++ ) {
579			if ( list[i] === elem ) {
580				return i;
581			}
582		}
583		return -1;
584	},
585
586	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
587
588	// Regular expressions
589
590	// http://www.w3.org/TR/css3-selectors/#whitespace
591	whitespace = "[\\x20\\t\\r\\n\\f]",
592
593	// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
594	identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
595
596	// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
597	attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
598		// Operator (capture 2)
599		"*([*^$|!~]?=)" + whitespace +
600		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
601		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
602		"*\\]",
603
604	pseudos = ":(" + identifier + ")(?:\\((" +
605		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
606		// 1. quoted (capture 3; capture 4 or capture 5)
vendor: 4,396 bytes, lines 607-740
607		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
608		// 2. simple (capture 6)
609		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
610		// 3. anything else (capture 2)
611		".*" +
612		")\\)|)",
613
614	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
615	rwhitespace = new RegExp( whitespace + "+", "g" ),
616	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
617
618	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
619	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
620	rdescend = new RegExp( whitespace + "|>" ),
621
622	rpseudo = new RegExp( pseudos ),
623	ridentifier = new RegExp( "^" + identifier + "$" ),
624
625	matchExpr = {
626		"ID": new RegExp( "^#(" + identifier + ")" ),
627		"CLASS": new RegExp( "^\\.(" + identifier + ")" ),
628		"TAG": new RegExp( "^(" + identifier + "|[*])" ),
629		"ATTR": new RegExp( "^" + attributes ),
630		"PSEUDO": new RegExp( "^" + pseudos ),
631		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
632			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
633			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
634		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
635		// For use in libraries implementing .is()
636		// We use this for POS matching in `select`
637		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
638			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
639	},
640
641	rhtml = /HTML$/i,
642	rinputs = /^(?:input|select|textarea|button)$/i,
643	rheader = /^h\d$/i,
644
645	rnative = /^[^{]+\{\s*\[native \w/,
646
647	// Easily-parseable/retrievable ID or TAG or CLASS selectors
648	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
649
650	rsibling = /[+~]/,
651
652	// CSS escapes
653	// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
654	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
655	funescape = function( _, escaped, escapedWhitespace ) {
656		var high = "0x" + escaped - 0x10000;
657		// NaN means non-codepoint
658		// Support: Firefox<24
659		// Workaround erroneous numeric interpretation of +"0x"
660		return high !== high || escapedWhitespace ?
661			escaped :
662			high < 0 ?
663				// BMP codepoint
664				String.fromCharCode( high + 0x10000 ) :
665				// Supplemental Plane codepoint (surrogate pair)
666				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
667	},
668
669	// CSS string/identifier serialization
670	// https://drafts.csswg.org/cssom/#common-serializing-idioms
671	rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
672	fcssescape = function( ch, asCodePoint ) {
673		if ( asCodePoint ) {
674
675			// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
676			if ( ch === "\0" ) {
677				return "\uFFFD";
678			}
679
680			// Control characters and (dependent upon position) numbers get escaped as code points
681			return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
682		}
683
684		// Other potentially-special ASCII characters get backslash-escaped
685		return "\\" + ch;
686	},
687
688	// Used for iframes
689	// See setDocument()
690	// Removing the function wrapper causes a "Permission Denied"
691	// error in IE
692	unloadHandler = function() {
693		setDocument();
694	},
695
696	inDisabledFieldset = addCombinator(
697		function( elem ) {
698			return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
699		},
700		{ dir: "parentNode", next: "legend" }
701	);
702
703// Optimize for push.apply( _, NodeList )
704try {
705	push.apply(
706		(arr = slice.call( preferredDoc.childNodes )),
707		preferredDoc.childNodes
708	);
709	// Support: Android<4.0
710	// Detect silently failing push.apply
711	arr[ preferredDoc.childNodes.length ].nodeType;
712} catch ( e ) {
713	push = { apply: arr.length ?
714
715		// Leverage slice if possible
716		function( target, els ) {
717			push_native.apply( target, slice.call(els) );
718		} :
719
720		// Support: IE<9
721		// Otherwise append directly
722		function( target, els ) {
723			var j = target.length,
724				i = 0;
725			// Can't trust NodeList.length
726			while ( (target[j++] = els[i++]) ) {}
727			target.length = j - 1;
728		}
729	};
730}
731
732function Sizzle( selector, context, results, seed ) {
733	var m, i, elem, nid, match, groups, newSelector,
734		newContext = context && context.ownerDocument,
735
736		// nodeType defaults to 9, since context defaults to document
737		nodeType = context ? context.nodeType : 9;
738
739	results = results || [];
740
vendor: 4,664 bytes, lines 741-907
741	// Return early from calls with invalid selector or context
742	if ( typeof selector !== "string" || !selector ||
743		nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
744
745		return results;
746	}
747
748	// Try to shortcut find operations (as opposed to filters) in HTML documents
749	if ( !seed ) {
750
751		if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
752			setDocument( context );
753		}
754		context = context || document;
755
756		if ( documentIsHTML ) {
757
758			// If the selector is sufficiently simple, try using a "get*By*" DOM method
759			// (excepting DocumentFragment context, where the methods don't exist)
760			if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
761
762				// ID selector
763				if ( (m = match[1]) ) {
764
765					// Document context
766					if ( nodeType === 9 ) {
767						if ( (elem = context.getElementById( m )) ) {
768
769							// Support: IE, Opera, Webkit
770							// TODO: identify versions
771							// getElementById can match elements by name instead of ID
772							if ( elem.id === m ) {
773								results.push( elem );
774								return results;
775							}
776						} else {
777							return results;
778						}
779
780					// Element context
781					} else {
782
783						// Support: IE, Opera, Webkit
784						// TODO: identify versions
785						// getElementById can match elements by name instead of ID
786						if ( newContext && (elem = newContext.getElementById( m )) &&
787							contains( context, elem ) &&
788							elem.id === m ) {
789
790							results.push( elem );
791							return results;
792						}
793					}
794
795				// Type selector
796				} else if ( match[2] ) {
797					push.apply( results, context.getElementsByTagName( selector ) );
798					return results;
799
800				// Class selector
801				} else if ( (m = match[3]) && support.getElementsByClassName &&
802					context.getElementsByClassName ) {
803
804					push.apply( results, context.getElementsByClassName( m ) );
805					return results;
806				}
807			}
808
809			// Take advantage of querySelectorAll
810			if ( support.qsa &&
811				!nonnativeSelectorCache[ selector + " " ] &&
812				(!rbuggyQSA || !rbuggyQSA.test( selector )) &&
813
814				// Support: IE 8 only
815				// Exclude object elements
816				(nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) {
817
818				newSelector = selector;
819				newContext = context;
820
821				// qSA considers elements outside a scoping root when evaluating child or
822				// descendant combinators, which is not what we want.
823				// In such cases, we work around the behavior by prefixing every selector in the
824				// list with an ID selector referencing the scope context.
825				// Thanks to Andrew Dupont for this technique.
826				if ( nodeType === 1 && rdescend.test( selector ) ) {
827
828					// Capture the context ID, setting it first if necessary
829					if ( (nid = context.getAttribute( "id" )) ) {
830						nid = nid.replace( rcssescape, fcssescape );
831					} else {
832						context.setAttribute( "id", (nid = expando) );
833					}
834
835					// Prefix every selector in the list
836					groups = tokenize( selector );
837					i = groups.length;
838					while ( i-- ) {
839						groups[i] = "#" + nid + " " + toSelector( groups[i] );
840					}
841					newSelector = groups.join( "," );
842
843					// Expand context for sibling selectors
844					newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
845						context;
846				}
847
848				try {
849					push.apply( results,
850						newContext.querySelectorAll( newSelector )
851					);
852					return results;
853				} catch ( qsaError ) {
854					nonnativeSelectorCache( selector, true );
855				} finally {
856					if ( nid === expando ) {
857						context.removeAttribute( "id" );
858					}
859				}
860			}
861		}
862	}
863
864	// All others
865	return select( selector.replace( rtrim, "$1" ), context, results, seed );
866}
867
868/**
869 * Create key-value caches of limited size
870 * @returns {function(string, object)} Returns the Object data after storing it on itself with
871 *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
872 *	deleting the oldest entry
873 */
874function createCache() {
875	var keys = [];
876
877	function cache( key, value ) {
878		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
879		if ( keys.push( key + " " ) > Expr.cacheLength ) {
880			// Only keep the most recent entries
881			delete cache[ keys.shift() ];
882		}
883		return (cache[ key + " " ] = value);
884	}
885	return cache;
886}
887
888/**
889 * Mark a function for special use by Sizzle
890 * @param {Function} fn The function to mark
891 */
892function markFunction( fn ) {
893	fn[ expando ] = true;
894	return fn;
895}
896
897/**
898 * Support testing using an element
899 * @param {Function} fn Passed the created element and returns a boolean result
900 */
901function assert( fn ) {
902	var el = document.createElement("fieldset");
903
904	try {
905		return !!fn( el );
906	} catch (e) {
907		return false;
vendor: 10,862 bytes, lines 908-1274
908	} finally {
909		// Remove from its parent by default
910		if ( el.parentNode ) {
911			el.parentNode.removeChild( el );
912		}
913		// release memory in IE
914		el = null;
915	}
916}
917
918/**
919 * Adds the same handler for all of the specified attrs
920 * @param {String} attrs Pipe-separated list of attributes
921 * @param {Function} handler The method that will be applied
922 */
923function addHandle( attrs, handler ) {
924	var arr = attrs.split("|"),
925		i = arr.length;
926
927	while ( i-- ) {
928		Expr.attrHandle[ arr[i] ] = handler;
929	}
930}
931
932/**
933 * Checks document order of two siblings
934 * @param {Element} a
935 * @param {Element} b
936 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
937 */
938function siblingCheck( a, b ) {
939	var cur = b && a,
940		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
941			a.sourceIndex - b.sourceIndex;
942
943	// Use IE sourceIndex if available on both nodes
944	if ( diff ) {
945		return diff;
946	}
947
948	// Check if b follows a
949	if ( cur ) {
950		while ( (cur = cur.nextSibling) ) {
951			if ( cur === b ) {
952				return -1;
953			}
954		}
955	}
956
957	return a ? 1 : -1;
958}
959
960/**
961 * Returns a function to use in pseudos for input types
962 * @param {String} type
963 */
964function createInputPseudo( type ) {
965	return function( elem ) {
966		var name = elem.nodeName.toLowerCase();
967		return name === "input" && elem.type === type;
968	};
969}
970
971/**
972 * Returns a function to use in pseudos for buttons
973 * @param {String} type
974 */
975function createButtonPseudo( type ) {
976	return function( elem ) {
977		var name = elem.nodeName.toLowerCase();
978		return (name === "input" || name === "button") && elem.type === type;
979	};
980}
981
982/**
983 * Returns a function to use in pseudos for :enabled/:disabled
984 * @param {Boolean} disabled true for :disabled; false for :enabled
985 */
986function createDisabledPseudo( disabled ) {
987
988	// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
989	return function( elem ) {
990
991		// Only certain elements can match :enabled or :disabled
992		// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
993		// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
994		if ( "form" in elem ) {
995
996			// Check for inherited disabledness on relevant non-disabled elements:
997			// * listed form-associated elements in a disabled fieldset
998			//   https://html.spec.whatwg.org/multipage/forms.html#category-listed
999			//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
1000			// * option elements in a disabled optgroup
1001			//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
1002			// All such elements have a "form" property.
1003			if ( elem.parentNode && elem.disabled === false ) {
1004
1005				// Option elements defer to a parent optgroup if present
1006				if ( "label" in elem ) {
1007					if ( "label" in elem.parentNode ) {
1008						return elem.parentNode.disabled === disabled;
1009					} else {
1010						return elem.disabled === disabled;
1011					}
1012				}
1013
1014				// Support: IE 6 - 11
1015				// Use the isDisabled shortcut property to check for disabled fieldset ancestors
1016				return elem.isDisabled === disabled ||
1017
1018					// Where there is no isDisabled, check manually
1019					/* jshint -W018 */
1020					elem.isDisabled !== !disabled &&
1021						inDisabledFieldset( elem ) === disabled;
1022			}
1023
1024			return elem.disabled === disabled;
1025
1026		// Try to winnow out elements that can't be disabled before trusting the disabled property.
1027		// Some victims get caught in our net (label, legend, menu, track), but it shouldn't
1028		// even exist on them, let alone have a boolean value.
1029		} else if ( "label" in elem ) {
1030			return elem.disabled === disabled;
1031		}
1032
1033		// Remaining elements are neither :enabled nor :disabled
1034		return false;
1035	};
1036}
1037
1038/**
1039 * Returns a function to use in pseudos for positionals
1040 * @param {Function} fn
1041 */
1042function createPositionalPseudo( fn ) {
1043	return markFunction(function( argument ) {
1044		argument = +argument;
1045		return markFunction(function( seed, matches ) {
1046			var j,
1047				matchIndexes = fn( [], seed.length, argument ),
1048				i = matchIndexes.length;
1049
1050			// Match elements found at the specified indexes
1051			while ( i-- ) {
1052				if ( seed[ (j = matchIndexes[i]) ] ) {
1053					seed[j] = !(matches[j] = seed[j]);
1054				}
1055			}
1056		});
1057	});
1058}
1059
1060/**
1061 * Checks a node for validity as a Sizzle context
1062 * @param {Element|Object=} context
1063 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
1064 */
1065function testContext( context ) {
1066	return context && typeof context.getElementsByTagName !== "undefined" && context;
1067}
1068
1069// Expose support vars for convenience
1070support = Sizzle.support = {};
1071
1072/**
1073 * Detects XML nodes
1074 * @param {Element|Object} elem An element or a document
1075 * @returns {Boolean} True iff elem is a non-HTML XML node
1076 */
1077isXML = Sizzle.isXML = function( elem ) {
1078	var namespace = elem.namespaceURI,
1079		docElem = (elem.ownerDocument || elem).documentElement;
1080
1081	// Support: IE <=8
1082	// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
1083	// https://bugs.jquery.com/ticket/4833
1084	return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
1085};
1086
1087/**
1088 * Sets document-related variables once based on the current document
1089 * @param {Element|Object} [doc] An element or document object to use to set the document
1090 * @returns {Object} Returns the current document
1091 */
1092setDocument = Sizzle.setDocument = function( node ) {
1093	var hasCompare, subWindow,
1094		doc = node ? node.ownerDocument || node : preferredDoc;
1095
1096	// Return early if doc is invalid or already selected
1097	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1098		return document;
1099	}
1100
1101	// Update global variables
1102	document = doc;
1103	docElem = document.documentElement;
1104	documentIsHTML = !isXML( document );
1105
1106	// Support: IE 9-11, Edge
1107	// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
1108	if ( preferredDoc !== document &&
1109		(subWindow = document.defaultView) && subWindow.top !== subWindow ) {
1110
1111		// Support: IE 11, Edge
1112		if ( subWindow.addEventListener ) {
1113			subWindow.addEventListener( "unload", unloadHandler, false );
1114
1115		// Support: IE 9 - 10 only
1116		} else if ( subWindow.attachEvent ) {
1117			subWindow.attachEvent( "onunload", unloadHandler );
1118		}
1119	}
1120
1121	/* Attributes
1122	---------------------------------------------------------------------- */
1123
1124	// Support: IE<8
1125	// Verify that getAttribute really returns attributes and not properties
1126	// (excepting IE8 booleans)
1127	support.attributes = assert(function( el ) {
1128		el.className = "i";
1129		return !el.getAttribute("className");
1130	});
1131
1132	/* getElement(s)By*
1133	---------------------------------------------------------------------- */
1134
1135	// Check if getElementsByTagName("*") returns only elements
1136	support.getElementsByTagName = assert(function( el ) {
1137		el.appendChild( document.createComment("") );
1138		return !el.getElementsByTagName("*").length;
1139	});
1140
1141	// Support: IE<9
1142	support.getElementsByClassName = rnative.test( document.getElementsByClassName );
1143
1144	// Support: IE<10
1145	// Check if getElementById returns elements by name
1146	// The broken getElementById methods don't pick up programmatically-set names,
1147	// so use a roundabout getElementsByName test
1148	support.getById = assert(function( el ) {
1149		docElem.appendChild( el ).id = expando;
1150		return !document.getElementsByName || !document.getElementsByName( expando ).length;
1151	});
1152
1153	// ID filter and find
1154	if ( support.getById ) {
1155		Expr.filter["ID"] = function( id ) {
1156			var attrId = id.replace( runescape, funescape );
1157			return function( elem ) {
1158				return elem.getAttribute("id") === attrId;
1159			};
1160		};
1161		Expr.find["ID"] = function( id, context ) {
1162			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
1163				var elem = context.getElementById( id );
1164				return elem ? [ elem ] : [];
1165			}
1166		};
1167	} else {
1168		Expr.filter["ID"] =  function( id ) {
1169			var attrId = id.replace( runescape, funescape );
1170			return function( elem ) {
1171				var node = typeof elem.getAttributeNode !== "undefined" &&
1172					elem.getAttributeNode("id");
1173				return node && node.value === attrId;
1174			};
1175		};
1176
1177		// Support: IE 6 - 7 only
1178		// getElementById is not reliable as a find shortcut
1179		Expr.find["ID"] = function( id, context ) {
1180			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
1181				var node, i, elems,
1182					elem = context.getElementById( id );
1183
1184				if ( elem ) {
1185
1186					// Verify the id attribute
1187					node = elem.getAttributeNode("id");
1188					if ( node && node.value === id ) {
1189						return [ elem ];
1190					}
1191
1192					// Fall back on getElementsByName
1193					elems = context.getElementsByName( id );
1194					i = 0;
1195					while ( (elem = elems[i++]) ) {
1196						node = elem.getAttributeNode("id");
1197						if ( node && node.value === id ) {
1198							return [ elem ];
1199						}
1200					}
1201				}
1202
1203				return [];
1204			}
1205		};
1206	}
1207
1208	// Tag
1209	Expr.find["TAG"] = support.getElementsByTagName ?
1210		function( tag, context ) {
1211			if ( typeof context.getElementsByTagName !== "undefined" ) {
1212				return context.getElementsByTagName( tag );
1213
1214			// DocumentFragment nodes don't have gEBTN
1215			} else if ( support.qsa ) {
1216				return context.querySelectorAll( tag );
1217			}
1218		} :
1219
1220		function( tag, context ) {
1221			var elem,
1222				tmp = [],
1223				i = 0,
1224				// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
1225				results = context.getElementsByTagName( tag );
1226
1227			// Filter out possible comments
1228			if ( tag === "*" ) {
1229				while ( (elem = results[i++]) ) {
1230					if ( elem.nodeType === 1 ) {
1231						tmp.push( elem );
1232					}
1233				}
1234
1235				return tmp;
1236			}
1237			return results;
1238		};
1239
1240	// Class
1241	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1242		if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
1243			return context.getElementsByClassName( className );
1244		}
1245	};
1246
1247	/* QSA/matchesSelector
1248	---------------------------------------------------------------------- */
1249
1250	// QSA and matchesSelector support
1251
1252	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1253	rbuggyMatches = [];
1254
1255	// qSa(:focus) reports false when true (Chrome 21)
1256	// We allow this because of a bug in IE8/9 that throws an error
1257	// whenever `document.activeElement` is accessed on an iframe
1258	// So, we allow :focus to pass through QSA all the time to avoid the IE error
1259	// See https://bugs.jquery.com/ticket/13378
1260	rbuggyQSA = [];
1261
1262	if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
1263		// Build QSA regex
1264		// Regex strategy adopted from Diego Perini
1265		assert(function( el ) {
1266			// Select is set to empty string on purpose
1267			// This is to test IE's treatment of not explicitly
1268			// setting a boolean content attribute,
1269			// since its presence should be enough
1270			// https://bugs.jquery.com/ticket/12359
1271			docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
1272				"<select id='" + expando + "-\r\\' msallowcapture=''>" +
1273				"<option selected=''></option></select>";
1274
vendor: 8,268 bytes, lines 1275-1559
1275			// Support: IE8, Opera 11-12.16
1276			// Nothing should be selected when empty strings follow ^= or $= or *=
1277			// The test attribute must be unknown in Opera but "safe" for WinRT
1278			// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
1279			if ( el.querySelectorAll("[msallowcapture^='']").length ) {
1280				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1281			}
1282
1283			// Support: IE8
1284			// Boolean attributes and "value" are not treated correctly
1285			if ( !el.querySelectorAll("[selected]").length ) {
1286				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1287			}
1288
1289			// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
1290			if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
1291				rbuggyQSA.push("~=");
1292			}
1293
1294			// Webkit/Opera - :checked should return selected option elements
1295			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1296			// IE8 throws error here and will not see later tests
1297			if ( !el.querySelectorAll(":checked").length ) {
1298				rbuggyQSA.push(":checked");
1299			}
1300
1301			// Support: Safari 8+, iOS 8+
1302			// https://bugs.webkit.org/show_bug.cgi?id=136851
1303			// In-page `selector#id sibling-combinator selector` fails
1304			if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
1305				rbuggyQSA.push(".#.+[+~]");
1306			}
1307		});
1308
1309		assert(function( el ) {
1310			el.innerHTML = "<a href='' disabled='disabled'></a>" +
1311				"<select disabled='disabled'><option/></select>";
1312
1313			// Support: Windows 8 Native Apps
1314			// The type and name attributes are restricted during .innerHTML assignment
1315			var input = document.createElement("input");
1316			input.setAttribute( "type", "hidden" );
1317			el.appendChild( input ).setAttribute( "name", "D" );
1318
1319			// Support: IE8
1320			// Enforce case-sensitivity of name attribute
1321			if ( el.querySelectorAll("[name=d]").length ) {
1322				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
1323			}
1324
1325			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1326			// IE8 throws error here and will not see later tests
1327			if ( el.querySelectorAll(":enabled").length !== 2 ) {
1328				rbuggyQSA.push( ":enabled", ":disabled" );
1329			}
1330
1331			// Support: IE9-11+
1332			// IE's :disabled selector does not pick up the children of disabled fieldsets
1333			docElem.appendChild( el ).disabled = true;
1334			if ( el.querySelectorAll(":disabled").length !== 2 ) {
1335				rbuggyQSA.push( ":enabled", ":disabled" );
1336			}
1337
1338			// Opera 10-11 does not throw on post-comma invalid pseudos
1339			el.querySelectorAll("*,:x");
1340			rbuggyQSA.push(",.*:");
1341		});
1342	}
1343
1344	if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
1345		docElem.webkitMatchesSelector ||
1346		docElem.mozMatchesSelector ||
1347		docElem.oMatchesSelector ||
1348		docElem.msMatchesSelector) )) ) {
1349
1350		assert(function( el ) {
1351			// Check to see if it's possible to do matchesSelector
1352			// on a disconnected node (IE 9)
1353			support.disconnectedMatch = matches.call( el, "*" );
1354
1355			// This should fail with an exception
1356			// Gecko does not error, returns false instead
1357			matches.call( el, "[s!='']:x" );
1358			rbuggyMatches.push( "!=", pseudos );
1359		});
1360	}
1361
1362	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1363	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1364
1365	/* Contains
1366	---------------------------------------------------------------------- */
1367	hasCompare = rnative.test( docElem.compareDocumentPosition );
1368
1369	// Element contains another
1370	// Purposefully self-exclusive
1371	// As in, an element does not contain itself
1372	contains = hasCompare || rnative.test( docElem.contains ) ?
1373		function( a, b ) {
1374			var adown = a.nodeType === 9 ? a.documentElement : a,
1375				bup = b && b.parentNode;
1376			return a === bup || !!( bup && bup.nodeType === 1 && (
1377				adown.contains ?
1378					adown.contains( bup ) :
1379					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1380			));
1381		} :
1382		function( a, b ) {
1383			if ( b ) {
1384				while ( (b = b.parentNode) ) {
1385					if ( b === a ) {
1386						return true;
1387					}
1388				}
1389			}
1390			return false;
1391		};
1392
1393	/* Sorting
1394	---------------------------------------------------------------------- */
1395
1396	// Document order sorting
1397	sortOrder = hasCompare ?
1398	function( a, b ) {
1399
1400		// Flag for duplicate removal
1401		if ( a === b ) {
1402			hasDuplicate = true;
1403			return 0;
1404		}
1405
1406		// Sort on method existence if only one input has compareDocumentPosition
1407		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
1408		if ( compare ) {
1409			return compare;
1410		}
1411
1412		// Calculate position if both inputs belong to the same document
1413		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
1414			a.compareDocumentPosition( b ) :
1415
1416			// Otherwise we know they are disconnected
1417			1;
1418
1419		// Disconnected nodes
1420		if ( compare & 1 ||
1421			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1422
1423			// Choose the first element that is related to our preferred document
1424			if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
1425				return -1;
1426			}
1427			if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
1428				return 1;
1429			}
1430
1431			// Maintain original order
1432			return sortInput ?
1433				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
1434				0;
1435		}
1436
1437		return compare & 4 ? -1 : 1;
1438	} :
1439	function( a, b ) {
1440		// Exit early if the nodes are identical
1441		if ( a === b ) {
1442			hasDuplicate = true;
1443			return 0;
1444		}
1445
1446		var cur,
1447			i = 0,
1448			aup = a.parentNode,
1449			bup = b.parentNode,
1450			ap = [ a ],
1451			bp = [ b ];
1452
1453		// Parentless nodes are either documents or disconnected
1454		if ( !aup || !bup ) {
1455			return a === document ? -1 :
1456				b === document ? 1 :
1457				aup ? -1 :
1458				bup ? 1 :
1459				sortInput ?
1460				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
1461				0;
1462
1463		// If the nodes are siblings, we can do a quick check
1464		} else if ( aup === bup ) {
1465			return siblingCheck( a, b );
1466		}
1467
1468		// Otherwise we need full lists of their ancestors for comparison
1469		cur = a;
1470		while ( (cur = cur.parentNode) ) {
1471			ap.unshift( cur );
1472		}
1473		cur = b;
1474		while ( (cur = cur.parentNode) ) {
1475			bp.unshift( cur );
1476		}
1477
1478		// Walk down the tree looking for a discrepancy
1479		while ( ap[i] === bp[i] ) {
1480			i++;
1481		}
1482
1483		return i ?
1484			// Do a sibling check if the nodes have a common ancestor
1485			siblingCheck( ap[i], bp[i] ) :
1486
1487			// Otherwise nodes in our document sort first
1488			ap[i] === preferredDoc ? -1 :
1489			bp[i] === preferredDoc ? 1 :
1490			0;
1491	};
1492
1493	return document;
1494};
1495
1496Sizzle.matches = function( expr, elements ) {
1497	return Sizzle( expr, null, null, elements );
1498};
1499
1500Sizzle.matchesSelector = function( elem, expr ) {
1501	// Set document vars if needed
1502	if ( ( elem.ownerDocument || elem ) !== document ) {
1503		setDocument( elem );
1504	}
1505
1506	if ( support.matchesSelector && documentIsHTML &&
1507		!nonnativeSelectorCache[ expr + " " ] &&
1508		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1509		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
1510
1511		try {
1512			var ret = matches.call( elem, expr );
1513
1514			// IE 9's matchesSelector returns false on disconnected nodes
1515			if ( ret || support.disconnectedMatch ||
1516					// As well, disconnected nodes are said to be in a document
1517					// fragment in IE 9
1518					elem.document && elem.document.nodeType !== 11 ) {
1519				return ret;
1520			}
1521		} catch (e) {
1522			nonnativeSelectorCache( expr, true );
1523		}
1524	}
1525
1526	return Sizzle( expr, document, null, [ elem ] ).length > 0;
1527};
1528
1529Sizzle.contains = function( context, elem ) {
1530	// Set document vars if needed
1531	if ( ( context.ownerDocument || context ) !== document ) {
1532		setDocument( context );
1533	}
1534	return contains( context, elem );
1535};
1536
1537Sizzle.attr = function( elem, name ) {
1538	// Set document vars if needed
1539	if ( ( elem.ownerDocument || elem ) !== document ) {
1540		setDocument( elem );
1541	}
1542
1543	var fn = Expr.attrHandle[ name.toLowerCase() ],
1544		// Don't get fooled by Object.prototype properties (jQuery #13807)
1545		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1546			fn( elem, name, !documentIsHTML ) :
1547			undefined;
1548
1549	return val !== undefined ?
1550		val :
1551		support.attributes || !documentIsHTML ?
1552			elem.getAttribute( name ) :
1553			(val = elem.getAttributeNode(name)) && val.specified ?
1554				val.value :
1555				null;
1556};
1557
1558Sizzle.escape = function( sel ) {
1559	return (sel + "").replace( rcssescape, fcssescape )
vendor: 11,991 bytes, lines 1559-1982
1559;
1560};
1561
1562Sizzle.error = function( msg ) {
1563	throw new Error( "Syntax error, unrecognized expression: " + msg );
1564};
1565
1566/**
1567 * Document sorting and removing duplicates
1568 * @param {ArrayLike} results
1569 */
1570Sizzle.uniqueSort = function( results ) {
1571	var elem,
1572		duplicates = [],
1573		j = 0,
1574		i = 0;
1575
1576	// Unless we *know* we can detect duplicates, assume their presence
1577	hasDuplicate = !support.detectDuplicates;
1578	sortInput = !support.sortStable && results.slice( 0 );
1579	results.sort( sortOrder );
1580
1581	if ( hasDuplicate ) {
1582		while ( (elem = results[i++]) ) {
1583			if ( elem === results[ i ] ) {
1584				j = duplicates.push( i );
1585			}
1586		}
1587		while ( j-- ) {
1588			results.splice( duplicates[ j ], 1 );
1589		}
1590	}
1591
1592	// Clear input after sorting to release objects
1593	// See https://github.com/jquery/sizzle/pull/225
1594	sortInput = null;
1595
1596	return results;
1597};
1598
1599/**
1600 * Utility function for retrieving the text value of an array of DOM nodes
1601 * @param {Array|Element} elem
1602 */
1603getText = Sizzle.getText = function( elem ) {
1604	var node,
1605		ret = "",
1606		i = 0,
1607		nodeType = elem.nodeType;
1608
1609	if ( !nodeType ) {
1610		// If no nodeType, this is expected to be an array
1611		while ( (node = elem[i++]) ) {
1612			// Do not traverse comment nodes
1613			ret += getText( node );
1614		}
1615	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1616		// Use textContent for elements
1617		// innerText usage removed for consistency of new lines (jQuery #11153)
1618		if ( typeof elem.textContent === "string" ) {
1619			return elem.textContent;
1620		} else {
1621			// Traverse its children
1622			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1623				ret += getText( elem );
1624			}
1625		}
1626	} else if ( nodeType === 3 || nodeType === 4 ) {
1627		return elem.nodeValue;
1628	}
1629	// Do not include comment or processing instruction nodes
1630
1631	return ret;
1632};
1633
1634Expr = Sizzle.selectors = {
1635
1636	// Can be adjusted by the user
1637	cacheLength: 50,
1638
1639	createPseudo: markFunction,
1640
1641	match: matchExpr,
1642
1643	attrHandle: {},
1644
1645	find: {},
1646
1647	relative: {
1648		">": { dir: "parentNode", first: true },
1649		" ": { dir: "parentNode" },
1650		"+": { dir: "previousSibling", first: true },
1651		"~": { dir: "previousSibling" }
1652	},
1653
1654	preFilter: {
1655		"ATTR": function( match ) {
1656			match[1] = match[1].replace( runescape, funescape );
1657
1658			// Move the given value to match[3] whether quoted or unquoted
1659			match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
1660
1661			if ( match[2] === "~=" ) {
1662				match[3] = " " + match[3] + " ";
1663			}
1664
1665			return match.slice( 0, 4 );
1666		},
1667
1668		"CHILD": function( match ) {
1669			/* matches from matchExpr["CHILD"]
1670				1 type (only|nth|...)
1671				2 what (child|of-type)
1672				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1673				4 xn-component of xn+y argument ([+-]?\d*n|)
1674				5 sign of xn-component
1675				6 x of xn-component
1676				7 sign of y-component
1677				8 y of y-component
1678			*/
1679			match[1] = match[1].toLowerCase();
1680
1681			if ( match[1].slice( 0, 3 ) === "nth" ) {
1682				// nth-* requires argument
1683				if ( !match[3] ) {
1684					Sizzle.error( match[0] );
1685				}
1686
1687				// numeric x and y parameters for Expr.filter.CHILD
1688				// remember that false/true cast respectively to 0/1
1689				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1690				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1691
1692			// other types prohibit arguments
1693			} else if ( match[3] ) {
1694				Sizzle.error( match[0] );
1695			}
1696
1697			return match;
1698		},
1699
1700		"PSEUDO": function( match ) {
1701			var excess,
1702				unquoted = !match[6] && match[2];
1703
1704			if ( matchExpr["CHILD"].test( match[0] ) ) {
1705				return null;
1706			}
1707
1708			// Accept quoted arguments as-is
1709			if ( match[3] ) {
1710				match[2] = match[4] || match[5] || "";
1711
1712			// Strip excess characters from unquoted arguments
1713			} else if ( unquoted && rpseudo.test( unquoted ) &&
1714				// Get excess from tokenize (recursively)
1715				(excess = tokenize( unquoted, true )) &&
1716				// advance to the next closing parenthesis
1717				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
1718
1719				// excess is a negative index
1720				match[0] = match[0].slice( 0, excess );
1721				match[2] = unquoted.slice( 0, excess );
1722			}
1723
1724			// Return only captures needed by the pseudo filter method (type and argument)
1725			return match.slice( 0, 3 );
1726		}
1727	},
1728
1729	filter: {
1730
1731		"TAG": function( nodeNameSelector ) {
1732			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
1733			return nodeNameSelector === "*" ?
1734				function() { return true; } :
1735				function( elem ) {
1736					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
1737				};
1738		},
1739
1740		"CLASS": function( className ) {
1741			var pattern = classCache[ className + " " ];
1742
1743			return pattern ||
1744				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
1745				classCache( className, function( elem ) {
1746					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
1747				});
1748		},
1749
1750		"ATTR": function( name, operator, check ) {
1751			return function( elem ) {
1752				var result = Sizzle.attr( elem, name );
1753
1754				if ( result == null ) {
1755					return operator === "!=";
1756				}
1757				if ( !operator ) {
1758					return true;
1759				}
1760
1761				result += "";
1762
1763				return operator === "=" ? result === check :
1764					operator === "!=" ? result !== check :
1765					operator === "^=" ? check && result.indexOf( check ) === 0 :
1766					operator === "*=" ? check && result.indexOf( check ) > -1 :
1767					operator === "$=" ? check && result.slice( -check.length ) === check :
1768					operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
1769					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
1770					false;
1771			};
1772		},
1773
1774		"CHILD": function( type, what, argument, first, last ) {
1775			var simple = type.slice( 0, 3 ) !== "nth",
1776				forward = type.slice( -4 ) !== "last",
1777				ofType = what === "of-type";
1778
1779			return first === 1 && last === 0 ?
1780
1781				// Shortcut for :nth-*(n)
1782				function( elem ) {
1783					return !!elem.parentNode;
1784				} :
1785
1786				function( elem, context, xml ) {
1787					var cache, uniqueCache, outerCache, node, nodeIndex, start,
1788						dir = simple !== forward ? "nextSibling" : "previousSibling",
1789						parent = elem.parentNode,
1790						name = ofType && elem.nodeName.toLowerCase(),
1791						useCache = !xml && !ofType,
1792						diff = false;
1793
1794					if ( parent ) {
1795
1796						// :(first|last|only)-(child|of-type)
1797						if ( simple ) {
1798							while ( dir ) {
1799								node = elem;
1800								while ( (node = node[ dir ]) ) {
1801									if ( ofType ?
1802										node.nodeName.toLowerCase() === name :
1803										node.nodeType === 1 ) {
1804
1805										return false;
1806									}
1807								}
1808								// Reverse direction for :only-* (if we haven't yet done so)
1809								start = dir = type === "only" && !start && "nextSibling";
1810							}
1811							return true;
1812						}
1813
1814						start = [ forward ? parent.firstChild : parent.lastChild ];
1815
1816						// non-xml :nth-child(...) stores cache data on `parent`
1817						if ( forward && useCache ) {
1818
1819							// Seek `elem` from a previously-cached index
1820
1821							// ...in a gzip-friendly way
1822							node = parent;
1823							outerCache = node[ expando ] || (node[ expando ] = {});
1824
1825							// Support: IE <9 only
1826							// Defend against cloned attroperties (jQuery gh-1709)
1827							uniqueCache = outerCache[ node.uniqueID ] ||
1828								(outerCache[ node.uniqueID ] = {});
1829
1830							cache = uniqueCache[ type ] || [];
1831							nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
1832							diff = nodeIndex && cache[ 2 ];
1833							node = nodeIndex && parent.childNodes[ nodeIndex ];
1834
1835							while ( (node = ++nodeIndex && node && node[ dir ] ||
1836
1837								// Fallback to seeking `elem` from the start
1838								(diff = nodeIndex = 0) || start.pop()) ) {
1839
1840								// When found, cache indexes on `parent` and break
1841								if ( node.nodeType === 1 && ++diff && node === elem ) {
1842									uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
1843									break;
1844								}
1845							}
1846
1847						} else {
1848							// Use previously-cached element index if available
1849							if ( useCache ) {
1850								// ...in a gzip-friendly way
1851								node = elem;
1852								outerCache = node[ expando ] || (node[ expando ] = {});
1853
1854								// Support: IE <9 only
1855								// Defend against cloned attroperties (jQuery gh-1709)
1856								uniqueCache = outerCache[ node.uniqueID ] ||
1857									(outerCache[ node.uniqueID ] = {});
1858
1859								cache = uniqueCache[ type ] || [];
1860								nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
1861								diff = nodeIndex;
1862							}
1863
1864							// xml :nth-child(...)
1865							// or :nth-last-child(...) or :nth(-last)?-of-type(...)
1866							if ( diff === false ) {
1867								// Use the same loop as above to seek `elem` from the start
1868								while ( (node = ++nodeIndex && node && node[ dir ] ||
1869									(diff = nodeIndex = 0) || start.pop()) ) {
1870
1871									if ( ( ofType ?
1872										node.nodeName.toLowerCase() === name :
1873										node.nodeType === 1 ) &&
1874										++diff ) {
1875
1876										// Cache the index of each encountered element
1877										if ( useCache ) {
1878											outerCache = node[ expando ] || (node[ expando ] = {});
1879
1880											// Support: IE <9 only
1881											// Defend against cloned attroperties (jQuery gh-1709)
1882											uniqueCache = outerCache[ node.uniqueID ] ||
1883												(outerCache[ node.uniqueID ] = {});
1884
1885											uniqueCache[ type ] = [ dirruns, diff ];
1886										}
1887
1888										if ( node === elem ) {
1889											break;
1890										}
1891									}
1892								}
1893							}
1894						}
1895
1896						// Incorporate the offset, then check against cycle size
1897						diff -= last;
1898						return diff === first || ( diff % first === 0 && diff / first >= 0 );
1899					}
1900				};
1901		},
1902
1903		"PSEUDO": function( pseudo, argument ) {
1904			// pseudo-class names are case-insensitive
1905			// http://www.w3.org/TR/selectors/#pseudo-classes
1906			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
1907			// Remember that setFilters inherits from pseudos
1908			var args,
1909				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
1910					Sizzle.error( "unsupported pseudo: " + pseudo );
1911
1912			// The user may use createPseudo to indicate that
1913			// arguments are needed to create the filter function
1914			// just as Sizzle does
1915			if ( fn[ expando ] ) {
1916				return fn( argument );
1917			}
1918
1919			// But maintain support for old signatures
1920			if ( fn.length > 1 ) {
1921				args = [ pseudo, pseudo, "", argument ];
1922				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
1923					markFunction(function( seed, matches ) {
1924						var idx,
1925							matched = fn( seed, argument ),
1926							i = matched.length;
1927						while ( i-- ) {
1928							idx = indexOf( seed, matched[i] );
1929							seed[ idx ] = !( matches[ idx ] = matched[i] );
1930						}
1931					}) :
1932					function( elem ) {
1933						return fn( elem, 0, args );
1934					};
1935			}
1936
1937			return fn;
1938		}
1939	},
1940
1941	pseudos: {
1942		// Potentially complex pseudos
1943		"not": markFunction(function( selector ) {
1944			// Trim the selector passed to compile
1945			// to avoid treating leading and trailing
1946			// spaces as combinators
1947			var input = [],
1948				results = [],
1949				matcher = compile( selector.replace( rtrim, "$1" ) );
1950
1951			return matcher[ expando ] ?
1952				markFunction(function( seed, matches, context, xml ) {
1953					var elem,
1954						unmatched = matcher( seed, null, xml, [] ),
1955						i = seed.length;
1956
1957					// Match elements unmatched by `matcher`
1958					while ( i-- ) {
1959						if ( (elem = unmatched[i]) ) {
1960							seed[i] = !(matches[i] = elem);
1961						}
1962					}
1963				}) :
1964				function( elem, context, xml ) {
1965					input[0] = elem;
1966					matcher( input, null, xml, results );
1967					// Don't keep the element (issue #299)
1968					input[0] = null;
1969					return !results.pop();
1970				};
1971		}),
1972
1973		"has": markFunction(function( selector ) {
1974			return function( elem ) {
1975				return Sizzle( selector, elem ).length > 0;
1976			};
1977		}),
1978
1979		"contains": markFunction(function( text ) {
1980			text = text.replace( runescape, funescape );
1981			return function( elem ) {
1982				return ( elem.textContent || 
vendor: 1,115 bytes, lines 1982-2010
1982getText( elem ) ).indexOf( text ) > -1;
1983			};
1984		}),
1985
1986		// "Whether an element is represented by a :lang() selector
1987		// is based solely on the element's language value
1988		// being equal to the identifier C,
1989		// or beginning with the identifier C immediately followed by "-".
1990		// The matching of C against the element's language value is performed case-insensitively.
1991		// The identifier C does not have to be a valid language name."
1992		// http://www.w3.org/TR/selectors/#lang-pseudo
1993		"lang": markFunction( function( lang ) {
1994			// lang value must be a valid identifier
1995			if ( !ridentifier.test(lang || "") ) {
1996				Sizzle.error( "unsupported lang: " + lang );
1997			}
1998			lang = lang.replace( runescape, funescape ).toLowerCase();
1999			return function( elem ) {
2000				var elemLang;
2001				do {
2002					if ( (elemLang = documentIsHTML ?
2003						elem.lang :
2004						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
2005
2006						elemLang = elemLang.toLowerCase();
2007						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
2008					}
2009				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
2010				return false;
vendor: 3,169 bytes, lines 2011-2125
2011			};
2012		}),
2013
2014		// Miscellaneous
2015		"target": function( elem ) {
2016			var hash = window.location && window.location.hash;
2017			return hash && hash.slice( 1 ) === elem.id;
2018		},
2019
2020		"root": function( elem ) {
2021			return elem === docElem;
2022		},
2023
2024		"focus": function( elem ) {
2025			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
2026		},
2027
2028		// Boolean properties
2029		"enabled": createDisabledPseudo( false ),
2030		"disabled": createDisabledPseudo( true ),
2031
2032		"checked": function( elem ) {
2033			// In CSS3, :checked should return both checked and selected elements
2034			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
2035			var nodeName = elem.nodeName.toLowerCase();
2036			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
2037		},
2038
2039		"selected": function( elem ) {
2040			// Accessing this property makes selected-by-default
2041			// options in Safari work properly
2042			if ( elem.parentNode ) {
2043				elem.parentNode.selectedIndex;
2044			}
2045
2046			return elem.selected === true;
2047		},
2048
2049		// Contents
2050		"empty": function( elem ) {
2051			// http://www.w3.org/TR/selectors/#empty-pseudo
2052			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
2053			//   but not by others (comment: 8; processing instruction: 7; etc.)
2054			// nodeType < 6 works because attributes (2) do not appear as children
2055			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
2056				if ( elem.nodeType < 6 ) {
2057					return false;
2058				}
2059			}
2060			return true;
2061		},
2062
2063		"parent": function( elem ) {
2064			return !Expr.pseudos["empty"]( elem );
2065		},
2066
2067		// Element/input types
2068		"header": function( elem ) {
2069			return rheader.test( elem.nodeName );
2070		},
2071
2072		"input": function( elem ) {
2073			return rinputs.test( elem.nodeName );
2074		},
2075
2076		"button": function( elem ) {
2077			var name = elem.nodeName.toLowerCase();
2078			return name === "input" && elem.type === "button" || name === "button";
2079		},
2080
2081		"text": function( elem ) {
2082			var attr;
2083			return elem.nodeName.toLowerCase() === "input" &&
2084				elem.type === "text" &&
2085
2086				// Support: IE<8
2087				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
2088				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
2089		},
2090
2091		// Position-in-collection
2092		"first": createPositionalPseudo(function() {
2093			return [ 0 ];
2094		}),
2095
2096		"last": createPositionalPseudo(function( matchIndexes, length ) {
2097			return [ length - 1 ];
2098		}),
2099
2100		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
2101			return [ argument < 0 ? argument + length : argument ];
2102		}),
2103
2104		"even": createPositionalPseudo(function( matchIndexes, length ) {
2105			var i = 0;
2106			for ( ; i < length; i += 2 ) {
2107				matchIndexes.push( i );
2108			}
2109			return matchIndexes;
2110		}),
2111
2112		"odd": createPositionalPseudo(function( matchIndexes, length ) {
2113			var i = 1;
2114			for ( ; i < length; i += 2 ) {
2115				matchIndexes.push( i );
2116			}
2117			return matchIndexes;
2118		}),
2119
2120		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2121			var i = argument < 0 ?
2122				argument + length :
2123				argument > length ?
2124					length :
2125					
vendor: 20,845 bytes, lines 2125-2886
2125argument;
2126			for ( ; --i >= 0; ) {
2127				matchIndexes.push( i );
2128			}
2129			return matchIndexes;
2130		}),
2131
2132		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2133			var i = argument < 0 ? argument + length : argument;
2134			for ( ; ++i < length; ) {
2135				matchIndexes.push( i );
2136			}
2137			return matchIndexes;
2138		})
2139	}
2140};
2141
2142Expr.pseudos["nth"] = Expr.pseudos["eq"];
2143
2144// Add button/input type pseudos
2145for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
2146	Expr.pseudos[ i ] = createInputPseudo( i );
2147}
2148for ( i in { submit: true, reset: true } ) {
2149	Expr.pseudos[ i ] = createButtonPseudo( i );
2150}
2151
2152// Easy API for creating new setFilters
2153function setFilters() {}
2154setFilters.prototype = Expr.filters = Expr.pseudos;
2155Expr.setFilters = new setFilters();
2156
2157tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
2158	var matched, match, tokens, type,
2159		soFar, groups, preFilters,
2160		cached = tokenCache[ selector + " " ];
2161
2162	if ( cached ) {
2163		return parseOnly ? 0 : cached.slice( 0 );
2164	}
2165
2166	soFar = selector;
2167	groups = [];
2168	preFilters = Expr.preFilter;
2169
2170	while ( soFar ) {
2171
2172		// Comma and first run
2173		if ( !matched || (match = rcomma.exec( soFar )) ) {
2174			if ( match ) {
2175				// Don't consume trailing commas as valid
2176				soFar = soFar.slice( match[0].length ) || soFar;
2177			}
2178			groups.push( (tokens = []) );
2179		}
2180
2181		matched = false;
2182
2183		// Combinators
2184		if ( (match = rcombinators.exec( soFar )) ) {
2185			matched = match.shift();
2186			tokens.push({
2187				value: matched,
2188				// Cast descendant combinators to space
2189				type: match[0].replace( rtrim, " " )
2190			});
2191			soFar = soFar.slice( matched.length );
2192		}
2193
2194		// Filters
2195		for ( type in Expr.filter ) {
2196			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2197				(match = preFilters[ type ]( match ))) ) {
2198				matched = match.shift();
2199				tokens.push({
2200					value: matched,
2201					type: type,
2202					matches: match
2203				});
2204				soFar = soFar.slice( matched.length );
2205			}
2206		}
2207
2208		if ( !matched ) {
2209			break;
2210		}
2211	}
2212
2213	// Return the length of the invalid excess
2214	// if we're just parsing
2215	// Otherwise, throw an error or return tokens
2216	return parseOnly ?
2217		soFar.length :
2218		soFar ?
2219			Sizzle.error( selector ) :
2220			// Cache the tokens
2221			tokenCache( selector, groups ).slice( 0 );
2222};
2223
2224function toSelector( tokens ) {
2225	var i = 0,
2226		len = tokens.length,
2227		selector = "";
2228	for ( ; i < len; i++ ) {
2229		selector += tokens[i].value;
2230	}
2231	return selector;
2232}
2233
2234function addCombinator( matcher, combinator, base ) {
2235	var dir = combinator.dir,
2236		skip = combinator.next,
2237		key = skip || dir,
2238		checkNonElements = base && key === "parentNode",
2239		doneName = done++;
2240
2241	return combinator.first ?
2242		// Check against closest ancestor/preceding element
2243		function( elem, context, xml ) {
2244			while ( (elem = elem[ dir ]) ) {
2245				if ( elem.nodeType === 1 || checkNonElements ) {
2246					return matcher( elem, context, xml );
2247				}
2248			}
2249			return false;
2250		} :
2251
2252		// Check against all ancestor/preceding elements
2253		function( elem, context, xml ) {
2254			var oldCache, uniqueCache, outerCache,
2255				newCache = [ dirruns, doneName ];
2256
2257			// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
2258			if ( xml ) {
2259				while ( (elem = elem[ dir ]) ) {
2260					if ( elem.nodeType === 1 || checkNonElements ) {
2261						if ( matcher( elem, context, xml ) ) {
2262							return true;
2263						}
2264					}
2265				}
2266			} else {
2267				while ( (elem = elem[ dir ]) ) {
2268					if ( elem.nodeType === 1 || checkNonElements ) {
2269						outerCache = elem[ expando ] || (elem[ expando ] = {});
2270
2271						// Support: IE <9 only
2272						// Defend against cloned attroperties (jQuery gh-1709)
2273						uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
2274
2275						if ( skip && skip === elem.nodeName.toLowerCase() ) {
2276							elem = elem[ dir ] || elem;
2277						} else if ( (oldCache = uniqueCache[ key ]) &&
2278							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
2279
2280							// Assign to newCache so results back-propagate to previous elements
2281							return (newCache[ 2 ] = oldCache[ 2 ]);
2282						} else {
2283							// Reuse newcache so results back-propagate to previous elements
2284							uniqueCache[ key ] = newCache;
2285
2286							// A match means we're done; a fail means we have to keep checking
2287							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
2288								return true;
2289							}
2290						}
2291					}
2292				}
2293			}
2294			return false;
2295		};
2296}
2297
2298function elementMatcher( matchers ) {
2299	return matchers.length > 1 ?
2300		function( elem, context, xml ) {
2301			var i = matchers.length;
2302			while ( i-- ) {
2303				if ( !matchers[i]( elem, context, xml ) ) {
2304					return false;
2305				}
2306			}
2307			return true;
2308		} :
2309		matchers[0];
2310}
2311
2312function multipleContexts( selector, contexts, results ) {
2313	var i = 0,
2314		len = contexts.length;
2315	for ( ; i < len; i++ ) {
2316		Sizzle( selector, contexts[i], results );
2317	}
2318	return results;
2319}
2320
2321function condense( unmatched, map, filter, context, xml ) {
2322	var elem,
2323		newUnmatched = [],
2324		i = 0,
2325		len = unmatched.length,
2326		mapped = map != null;
2327
2328	for ( ; i < len; i++ ) {
2329		if ( (elem = unmatched[i]) ) {
2330			if ( !filter || filter( elem, context, xml ) ) {
2331				newUnmatched.push( elem );
2332				if ( mapped ) {
2333					map.push( i );
2334				}
2335			}
2336		}
2337	}
2338
2339	return newUnmatched;
2340}
2341
2342function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2343	if ( postFilter && !postFilter[ expando ] ) {
2344		postFilter = setMatcher( postFilter );
2345	}
2346	if ( postFinder && !postFinder[ expando ] ) {
2347		postFinder = setMatcher( postFinder, postSelector );
2348	}
2349	return markFunction(function( seed, results, context, xml ) {
2350		var temp, i, elem,
2351			preMap = [],
2352			postMap = [],
2353			preexisting = results.length,
2354
2355			// Get initial elements from seed or context
2356			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2357
2358			// Prefilter to get matcher input, preserving a map for seed-results synchronization
2359			matcherIn = preFilter && ( seed || !selector ) ?
2360				condense( elems, preMap, preFilter, context, xml ) :
2361				elems,
2362
2363			matcherOut = matcher ?
2364				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2365				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2366
2367					// ...intermediate processing is necessary
2368					[] :
2369
2370					// ...otherwise use results directly
2371					results :
2372				matcherIn;
2373
2374		// Find primary matches
2375		if ( matcher ) {
2376			matcher( matcherIn, matcherOut, context, xml );
2377		}
2378
2379		// Apply postFilter
2380		if ( postFilter ) {
2381			temp = condense( matcherOut, postMap );
2382			postFilter( temp, [], context, xml );
2383
2384			// Un-match failing elements by moving them back to matcherIn
2385			i = temp.length;
2386			while ( i-- ) {
2387				if ( (elem = temp[i]) ) {
2388					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2389				}
2390			}
2391		}
2392
2393		if ( seed ) {
2394			if ( postFinder || preFilter ) {
2395				if ( postFinder ) {
2396					// Get the final matcherOut by condensing this intermediate into postFinder contexts
2397					temp = [];
2398					i = matcherOut.length;
2399					while ( i-- ) {
2400						if ( (elem = matcherOut[i]) ) {
2401							// Restore matcherIn since elem is not yet a final match
2402							temp.push( (matcherIn[i] = elem) );
2403						}
2404					}
2405					postFinder( null, (matcherOut = []), temp, xml );
2406				}
2407
2408				// Move matched elements from seed to results to keep them synchronized
2409				i = matcherOut.length;
2410				while ( i-- ) {
2411					if ( (elem = matcherOut[i]) &&
2412						(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
2413
2414						seed[temp] = !(results[temp] = elem);
2415					}
2416				}
2417			}
2418
2419		// Add elements to results, through postFinder if defined
2420		} else {
2421			matcherOut = condense(
2422				matcherOut === results ?
2423					matcherOut.splice( preexisting, matcherOut.length ) :
2424					matcherOut
2425			);
2426			if ( postFinder ) {
2427				postFinder( null, results, matcherOut, xml );
2428			} else {
2429				push.apply( results, matcherOut );
2430			}
2431		}
2432	});
2433}
2434
2435function matcherFromTokens( tokens ) {
2436	var checkContext, matcher, j,
2437		len = tokens.length,
2438		leadingRelative = Expr.relative[ tokens[0].type ],
2439		implicitRelative = leadingRelative || Expr.relative[" "],
2440		i = leadingRelative ? 1 : 0,
2441
2442		// The foundational matcher ensures that elements are reachable from top-level context(s)
2443		matchContext = addCombinator( function( elem ) {
2444			return elem === checkContext;
2445		}, implicitRelative, true ),
2446		matchAnyContext = addCombinator( function( elem ) {
2447			return indexOf( checkContext, elem ) > -1;
2448		}, implicitRelative, true ),
2449		matchers = [ function( elem, context, xml ) {
2450			var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2451				(checkContext = context).nodeType ?
2452					matchContext( elem, context, xml ) :
2453					matchAnyContext( elem, context, xml ) );
2454			// Avoid hanging onto element (issue #299)
2455			checkContext = null;
2456			return ret;
2457		} ];
2458
2459	for ( ; i < len; i++ ) {
2460		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2461			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2462		} else {
2463			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2464
2465			// Return special upon seeing a positional matcher
2466			if ( matcher[ expando ] ) {
2467				// Find the next relative operator (if any) for proper handling
2468				j = ++i;
2469				for ( ; j < len; j++ ) {
2470					if ( Expr.relative[ tokens[j].type ] ) {
2471						break;
2472					}
2473				}
2474				return setMatcher(
2475					i > 1 && elementMatcher( matchers ),
2476					i > 1 && toSelector(
2477						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
2478						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2479					).replace( rtrim, "$1" ),
2480					matcher,
2481					i < j && matcherFromTokens( tokens.slice( i, j ) ),
2482					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2483					j < len && toSelector( tokens )
2484				);
2485			}
2486			matchers.push( matcher );
2487		}
2488	}
2489
2490	return elementMatcher( matchers );
2491}
2492
2493function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2494	var bySet = setMatchers.length > 0,
2495		byElement = elementMatchers.length > 0,
2496		superMatcher = function( seed, context, xml, results, outermost ) {
2497			var elem, j, matcher,
2498				matchedCount = 0,
2499				i = "0",
2500				unmatched = seed && [],
2501				setMatched = [],
2502				contextBackup = outermostContext,
2503				// We must always have either seed elements or outermost context
2504				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
2505				// Use integer dirruns iff this is the outermost matcher
2506				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
2507				len = elems.length;
2508
2509			if ( outermost ) {
2510				outermostContext = context === document || context || outermost;
2511			}
2512
2513			// Add elements passing elementMatchers directly to results
2514			// Support: IE<9, Safari
2515			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
2516			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
2517				if ( byElement && elem ) {
2518					j = 0;
2519					if ( !context && elem.ownerDocument !== document ) {
2520						setDocument( elem );
2521						xml = !documentIsHTML;
2522					}
2523					while ( (matcher = elementMatchers[j++]) ) {
2524						if ( matcher( elem, context || document, xml) ) {
2525							results.push( elem );
2526							break;
2527						}
2528					}
2529					if ( outermost ) {
2530						dirruns = dirrunsUnique;
2531					}
2532				}
2533
2534				// Track unmatched elements for set filters
2535				if ( bySet ) {
2536					// They will have gone through all possible matchers
2537					if ( (elem = !matcher && elem) ) {
2538						matchedCount--;
2539					}
2540
2541					// Lengthen the array for every element, matched or not
2542					if ( seed ) {
2543						unmatched.push( elem );
2544					}
2545				}
2546			}
2547
2548			// `i` is now the count of elements visited above, and adding it to `matchedCount`
2549			// makes the latter nonnegative.
2550			matchedCount += i;
2551
2552			// Apply set filters to unmatched elements
2553			// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
2554			// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
2555			// no element matchers and no seed.
2556			// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
2557			// case, which will result in a "00" `matchedCount` that differs from `i` but is also
2558			// numerically zero.
2559			if ( bySet && i !== matchedCount ) {
2560				j = 0;
2561				while ( (matcher = setMatchers[j++]) ) {
2562					matcher( unmatched, setMatched, context, xml );
2563				}
2564
2565				if ( seed ) {
2566					// Reintegrate element matches to eliminate the need for sorting
2567					if ( matchedCount > 0 ) {
2568						while ( i-- ) {
2569							if ( !(unmatched[i] || setMatched[i]) ) {
2570								setMatched[i] = pop.call( results );
2571							}
2572						}
2573					}
2574
2575					// Discard index placeholder values to get only actual matches
2576					setMatched = condense( setMatched );
2577				}
2578
2579				// Add matches to results
2580				push.apply( results, setMatched );
2581
2582				// Seedless set matches succeeding multiple successful matchers stipulate sorting
2583				if ( outermost && !seed && setMatched.length > 0 &&
2584					( matchedCount + setMatchers.length ) > 1 ) {
2585
2586					Sizzle.uniqueSort( results );
2587				}
2588			}
2589
2590			// Override manipulation of globals by nested matchers
2591			if ( outermost ) {
2592				dirruns = dirrunsUnique;
2593				outermostContext = contextBackup;
2594			}
2595
2596			return unmatched;
2597		};
2598
2599	return bySet ?
2600		markFunction( superMatcher ) :
2601		superMatcher;
2602}
2603
2604compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
2605	var i,
2606		setMatchers = [],
2607		elementMatchers = [],
2608		cached = compilerCache[ selector + " " ];
2609
2610	if ( !cached ) {
2611		// Generate a function of recursive functions that can be used to check each element
2612		if ( !match ) {
2613			match = tokenize( selector );
2614		}
2615		i = match.length;
2616		while ( i-- ) {
2617			cached = matcherFromTokens( match[i] );
2618			if ( cached[ expando ] ) {
2619				setMatchers.push( cached );
2620			} else {
2621				elementMatchers.push( cached );
2622			}
2623		}
2624
2625		// Cache the compiled function
2626		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2627
2628		// Save selector and tokenization
2629		cached.selector = selector;
2630	}
2631	return cached;
2632};
2633
2634/**
2635 * A low-level selection function that works with Sizzle's compiled
2636 *  selector functions
2637 * @param {String|Function} selector A selector or a pre-compiled
2638 *  selector function built with Sizzle.compile
2639 * @param {Element} context
2640 * @param {Array} [results]
2641 * @param {Array} [seed] A set of elements to match against
2642 */
2643select = Sizzle.select = function( selector, context, results, seed ) {
2644	var i, tokens, token, type, find,
2645		compiled = typeof selector === "function" && selector,
2646		match = !seed && tokenize( (selector = compiled.selector || selector) );
2647
2648	results = results || [];
2649
2650	// Try to minimize operations if there is only one selector in the list and no seed
2651	// (the latter of which guarantees us context)
2652	if ( match.length === 1 ) {
2653
2654		// Reduce context if the leading compound selector is an ID
2655		tokens = match[0] = match[0].slice( 0 );
2656		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2657				context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {
2658
2659			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2660			if ( !context ) {
2661				return results;
2662
2663			// Precompiled matchers will still verify ancestry, so step up a level
2664			} else if ( compiled ) {
2665				context = context.parentNode;
2666			}
2667
2668			selector = selector.slice( tokens.shift().value.length );
2669		}
2670
2671		// Fetch a seed set for right-to-left matching
2672		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2673		while ( i-- ) {
2674			token = tokens[i];
2675
2676			// Abort if we hit a combinator
2677			if ( Expr.relative[ (type = token.type) ] ) {
2678				break;
2679			}
2680			if ( (find = Expr.find[ type ]) ) {
2681				// Search, expanding context for leading sibling combinators
2682				if ( (seed = find(
2683					token.matches[0].replace( runescape, funescape ),
2684					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
2685				)) ) {
2686
2687					// If seed is empty or no tokens remain, we can return early
2688					tokens.splice( i, 1 );
2689					selector = seed.length && toSelector( tokens );
2690					if ( !selector ) {
2691						push.apply( results, seed );
2692						return results;
2693					}
2694
2695					break;
2696				}
2697			}
2698		}
2699	}
2700
2701	// Compile and execute a filtering function if one is not provided
2702	// Provide `match` to avoid retokenization if we modified the selector above
2703	( compiled || compile( selector, match ) )(
2704		seed,
2705		context,
2706		!documentIsHTML,
2707		results,
2708		!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
2709	);
2710	return results;
2711};
2712
2713// One-time assignments
2714
2715// Sort stability
2716support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2717
2718// Support: Chrome 14-35+
2719// Always assume duplicates if they aren't passed to the comparison function
2720support.detectDuplicates = !!hasDuplicate;
2721
2722// Initialize against the default document
2723setDocument();
2724
2725// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2726// Detached nodes confoundingly follow *each other*
2727support.sortDetached = assert(function( el ) {
2728	// Should return 1, but returns 4 (following)
2729	return el.compareDocumentPosition( document.createElement("fieldset") ) & 1;
2730});
2731
2732// Support: IE<8
2733// Prevent attribute/property "interpolation"
2734// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2735if ( !assert(function( el ) {
2736	el.innerHTML = "<a href='#'></a>";
2737	return el.firstChild.getAttribute("href") === "#" ;
2738}) ) {
2739	addHandle( "type|href|height|width", function( elem, name, isXML ) {
2740		if ( !isXML ) {
2741			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
2742		}
2743	});
2744}
2745
2746// Support: IE<9
2747// Use defaultValue in place of getAttribute("value")
2748if ( !support.attributes || !assert(function( el ) {
2749	el.innerHTML = "<input/>";
2750	el.firstChild.setAttribute( "value", "" );
2751	return el.firstChild.getAttribute( "value" ) === "";
2752}) ) {
2753	addHandle( "value", function( elem, name, isXML ) {
2754		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
2755			return elem.defaultValue;
2756		}
2757	});
2758}
2759
2760// Support: IE<9
2761// Use getAttributeNode to fetch booleans when getAttribute lies
2762if ( !assert(function( el ) {
2763	return el.getAttribute("disabled") == null;
2764}) ) {
2765	addHandle( booleans, function( elem, name, isXML ) {
2766		var val;
2767		if ( !isXML ) {
2768			return elem[ name ] === true ? name.toLowerCase() :
2769					(val = elem.getAttributeNode( name )) && val.specified ?
2770					val.value :
2771				null;
2772		}
2773	});
2774}
2775
2776return Sizzle;
2777
2778})( window );
2779
2780
2781
2782jQuery.find = Sizzle;
2783jQuery.expr = Sizzle.selectors;
2784
2785// Deprecated
2786jQuery.expr[ ":" ] = jQuery.expr.pseudos;
2787jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
2788jQuery.text = Sizzle.getText;
2789jQuery.isXMLDoc = Sizzle.isXML;
2790jQuery.contains = Sizzle.contains;
2791jQuery.escapeSelector = Sizzle.escape;
2792
2793
2794
2795
2796var dir = function( elem, dir, until ) {
2797	var matched = [],
2798		truncate = until !== undefined;
2799
2800	while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
2801		if ( elem.nodeType === 1 ) {
2802			if ( truncate && jQuery( elem ).is( until ) ) {
2803				break;
2804			}
2805			matched.push( elem );
2806		}
2807	}
2808	return matched;
2809};
2810
2811
2812var siblings = function( n, elem ) {
2813	var matched = [];
2814
2815	for ( ; n; n = n.nextSibling ) {
2816		if ( n.nodeType === 1 && n !== elem ) {
2817			matched.push( n );
2818		}
2819	}
2820
2821	return matched;
2822};
2823
2824
2825var rneedsContext = jQuery.expr.match.needsContext;
2826
2827
2828
2829function nodeName( elem, name ) {
2830
2831  return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
2832
2833};
2834var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
2835
2836
2837
2838// Implement the identical functionality for filter and not
2839function winnow( elements, qualifier, not ) {
2840	if ( isFunction( qualifier ) ) {
2841		return jQuery.grep( elements, function( elem, i ) {
2842			return !!qualifier.call( elem, i, elem ) !== not;
2843		} );
2844	}
2845
2846	// Single element
2847	if ( qualifier.nodeType ) {
2848		return jQuery.grep( elements, function( elem ) {
2849			return ( elem === qualifier ) !== not;
2850		} );
2851	}
2852
2853	// Arraylike of elements (jQuery, arguments, Array)
2854	if ( typeof qualifier !== "string" ) {
2855		return jQuery.grep( elements, function( elem ) {
2856			return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
2857		} );
2858	}
2859
2860	// Filtered directly for both simple and complex selectors
2861	return jQuery.filter( qualifier, elements, not );
2862}
2863
2864jQuery.filter = function( expr, elems, not ) {
2865	var elem = elems[ 0 ];
2866
2867	if ( not ) {
2868		expr = ":not(" + expr + ")";
2869	}
2870
2871	if ( elems.length === 1 && elem.nodeType === 1 ) {
2872		return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
2873	}
2874
2875	return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
2876		return elem.nodeType === 1;
2877	} ) );
2878};
2879
2880jQuery.fn.extend( {
2881	find: function( selector ) {
2882		var i, ret,
2883			len = this.length,
2884			self = this;
2885
2886		if ( typeof selector !== "string" ) {
vendor: 6,536 bytes, lines 2887-3147
2887			return this.pushStack( jQuery( selector ).filter( function() {
2888				for ( i = 0; i < len; i++ ) {
2889					if ( jQuery.contains( self[ i ], this ) ) {
2890						return true;
2891					}
2892				}
2893			} ) );
2894		}
2895
2896		ret = this.pushStack( [] );
2897
2898		for ( i = 0; i < len; i++ ) {
2899			jQuery.find( selector, self[ i ], ret );
2900		}
2901
2902		return len > 1 ? jQuery.uniqueSort( ret ) : ret;
2903	},
2904	filter: function( selector ) {
2905		return this.pushStack( winnow( this, selector || [], false ) );
2906	},
2907	not: function( selector ) {
2908		return this.pushStack( winnow( this, selector || [], true ) );
2909	},
2910	is: function( selector ) {
2911		return !!winnow(
2912			this,
2913
2914			// If this is a positional/relative selector, check membership in the returned set
2915			// so $("p:first").is("p:last") won't return true for a doc with two "p".
2916			typeof selector === "string" && rneedsContext.test( selector ) ?
2917				jQuery( selector ) :
2918				selector || [],
2919			false
2920		).length;
2921	}
2922} );
2923
2924
2925// Initialize a jQuery object
2926
2927
2928// A central reference to the root jQuery(document)
2929var rootjQuery,
2930
2931	// A simple way to check for HTML strings
2932	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
2933	// Strict HTML recognition (#11290: must start with <)
2934	// Shortcut simple #id case for speed
2935	rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
2936
2937	init = jQuery.fn.init = function( selector, context, root ) {
2938		var match, elem;
2939
2940		// HANDLE: $(""), $(null), $(undefined), $(false)
2941		if ( !selector ) {
2942			return this;
2943		}
2944
2945		// Method init() accepts an alternate rootjQuery
2946		// so migrate can support jQuery.sub (gh-2101)
2947		root = root || rootjQuery;
2948
2949		// Handle HTML strings
2950		if ( typeof selector === "string" ) {
2951			if ( selector[ 0 ] === "<" &&
2952				selector[ selector.length - 1 ] === ">" &&
2953				selector.length >= 3 ) {
2954
2955				// Assume that strings that start and end with <> are HTML and skip the regex check
2956				match = [ null, selector, null ];
2957
2958			} else {
2959				match = rquickExpr.exec( selector );
2960			}
2961
2962			// Match html or make sure no context is specified for #id
2963			if ( match && ( match[ 1 ] || !context ) ) {
2964
2965				// HANDLE: $(html) -> $(array)
2966				if ( match[ 1 ] ) {
2967					context = context instanceof jQuery ? context[ 0 ] : context;
2968
2969					// Option to run scripts is true for back-compat
2970					// Intentionally let the error be thrown if parseHTML is not present
2971					jQuery.merge( this, jQuery.parseHTML(
2972						match[ 1 ],
2973						context && context.nodeType ? context.ownerDocument || context : document,
2974						true
2975					) );
2976
2977					// HANDLE: $(html, props)
2978					if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
2979						for ( match in context ) {
2980
2981							// Properties of context are called as methods if possible
2982							if ( isFunction( this[ match ] ) ) {
2983								this[ match ]( context[ match ] );
2984
2985							// ...and otherwise set as attributes
2986							} else {
2987								this.attr( match, context[ match ] );
2988							}
2989						}
2990					}
2991
2992					return this;
2993
2994				// HANDLE: $(#id)
2995				} else {
2996					elem = document.getElementById( match[ 2 ] );
2997
2998					if ( elem ) {
2999
3000						// Inject the element directly into the jQuery object
3001						this[ 0 ] = elem;
3002						this.length = 1;
3003					}
3004					return this;
3005				}
3006
3007			// HANDLE: $(expr, $(...))
3008			} else if ( !context || context.jquery ) {
3009				return ( context || root ).find( selector );
3010
3011			// HANDLE: $(expr, context)
3012			// (which is just equivalent to: $(context).find(expr)
3013			} else {
3014				return this.constructor( context ).find( selector );
3015			}
3016
3017		// HANDLE: $(DOMElement)
3018		} else if ( selector.nodeType ) {
3019			this[ 0 ] = selector;
3020			this.length = 1;
3021			return this;
3022
3023		// HANDLE: $(function)
3024		// Shortcut for document ready
3025		} else if ( isFunction( selector ) ) {
3026			return root.ready !== undefined ?
3027				root.ready( selector ) :
3028
3029				// Execute immediately if ready is not present
3030				selector( jQuery );
3031		}
3032
3033		return jQuery.makeArray( selector, this );
3034	};
3035
3036// Give the init function the jQuery prototype for later instantiation
3037init.prototype = jQuery.fn;
3038
3039// Initialize central reference
3040rootjQuery = jQuery( document );
3041
3042
3043var rparentsprev = /^(?:parents|prev(?:Until|All))/,
3044
3045	// Methods guaranteed to produce a unique set when starting from a unique set
3046	guaranteedUnique = {
3047		children: true,
3048		contents: true,
3049		next: true,
3050		prev: true
3051	};
3052
3053jQuery.fn.extend( {
3054	has: function( target ) {
3055		var targets = jQuery( target, this ),
3056			l = targets.length;
3057
3058		return this.filter( function() {
3059			var i = 0;
3060			for ( ; i < l; i++ ) {
3061				if ( jQuery.contains( this, targets[ i ] ) ) {
3062					return true;
3063				}
3064			}
3065		} );
3066	},
3067
3068	closest: function( selectors, context ) {
3069		var cur,
3070			i = 0,
3071			l = this.length,
3072			matched = [],
3073			targets = typeof selectors !== "string" && jQuery( selectors );
3074
3075		// Positional selectors never match, since there's no _selection_ context
3076		if ( !rneedsContext.test( selectors ) ) {
3077			for ( ; i < l; i++ ) {
3078				for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
3079
3080					// Always skip document fragments
3081					if ( cur.nodeType < 11 && ( targets ?
3082						targets.index( cur ) > -1 :
3083
3084						// Don't pass non-elements to Sizzle
3085						cur.nodeType === 1 &&
3086							jQuery.find.matchesSelector( cur, selectors ) ) ) {
3087
3088						matched.push( cur );
3089						break;
3090					}
3091				}
3092			}
3093		}
3094
3095		return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
3096	},
3097
3098	// Determine the position of an element within the set
3099	index: function( elem ) {
3100
3101		// No argument, return index in parent
3102		if ( !elem ) {
3103			return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
3104		}
3105
3106		// Index in selector
3107		if ( typeof elem === "string" ) {
3108			return indexOf.call( jQuery( elem ), this[ 0 ] );
3109		}
3110
3111		// Locate the position of the desired element
3112		return indexOf.call( this,
3113
3114			// If it receives a jQuery object, the first element is used
3115			elem.jquery ? elem[ 0 ] : elem
3116		);
3117	},
3118
3119	add: function( selector, context ) {
3120		return this.pushStack(
3121			jQuery.uniqueSort(
3122				jQuery.merge( this.get(), jQuery( selector, context ) )
3123			)
3124		);
3125	},
3126
3127	addBack: function( selector ) {
3128		return this.add( selector == null ?
3129			this.prevObject : this.prevObject.filter( selector )
3130		);
3131	}
3132} );
3133
3134function sibling( cur, dir ) {
3135	while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
3136	return cur;
3137}
3138
3139jQuery.each( {
3140	parent: function( elem ) {
3141		var parent = elem.parentNode;
3142		return parent && parent.nodeType !== 11 ? parent : null;
3143	},
3144	parents: function( elem ) {
3145		return dir( elem, "parentNode" );
3146	},
3147	parentsUntil: function( elem, 
3147i, until ) {
3148		return dir( elem, "parentNode", until );
3149	},
3150	next: function( elem ) {
3151		return sibling( elem, "nextSibling" );
3152	},
3153	prev: function( elem ) {
3154		return sibling( elem, "previousSibling" );
3155	},
3156	nextAll: function( elem ) {
3157		return dir( elem, "nextSibling" );
3158	},
3159	prevAll: function( elem ) {
3160		return dir( elem, "previousSibling" );
3161	},
3162	nextUntil: function( elem, i, until ) {
3163		return dir( elem, "nextSibling", until );
3164	},
3165	prevUntil: function( elem, i, until ) {
3166		return dir( elem, "previousSibling", until );
3167	},
3168	siblings: function( elem ) {
3169		return siblings( ( elem.parentNode || {} ).firstChild, elem );
3170	},
3171	children: function( elem ) {
3172		return siblings( elem.firstChild );
3173	},
3174	contents: function( elem ) {
3175		if ( typeof elem.contentDocument !== "undefined" ) {
vendor: 8,211 bytes, lines 3175-3509
3175
3176			return elem.contentDocument;
3177		}
3178
3179		// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
3180		// Treat the template element as a regular one in browsers that
3181		// don't support it.
3182		if ( nodeName( elem, "template" ) ) {
3183			elem = elem.content || elem;
3184		}
3185
3186		return jQuery.merge( [], elem.childNodes );
3187	}
3188}, function( name, fn ) {
3189	jQuery.fn[ name ] = function( until, selector ) {
3190		var matched = jQuery.map( this, fn, until );
3191
3192		if ( name.slice( -5 ) !== "Until" ) {
3193			selector = until;
3194		}
3195
3196		if ( selector && typeof selector === "string" ) {
3197			matched = jQuery.filter( selector, matched );
3198		}
3199
3200		if ( this.length > 1 ) {
3201
3202			// Remove duplicates
3203			if ( !guaranteedUnique[ name ] ) {
3204				jQuery.uniqueSort( matched );
3205			}
3206
3207			// Reverse order for parents* and prev-derivatives
3208			if ( rparentsprev.test( name ) ) {
3209				matched.reverse();
3210			}
3211		}
3212
3213		return this.pushStack( matched );
3214	};
3215} );
3216var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
3217
3218
3219
3220// Convert String-formatted options into Object-formatted ones
3221function createOptions( options ) {
3222	var object = {};
3223	jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
3224		object[ flag ] = true;
3225	} );
3226	return object;
3227}
3228
3229/*
3230 * Create a callback list using the following parameters:
3231 *
3232 *	options: an optional list of space-separated options that will change how
3233 *			the callback list behaves or a more traditional option object
3234 *
3235 * By default a callback list will act like an event callback list and can be
3236 * "fired" multiple times.
3237 *
3238 * Possible options:
3239 *
3240 *	once:			will ensure the callback list can only be fired once (like a Deferred)
3241 *
3242 *	memory:			will keep track of previous values and will call any callback added
3243 *					after the list has been fired right away with the latest "memorized"
3244 *					values (like a Deferred)
3245 *
3246 *	unique:			will ensure a callback can only be added once (no duplicate in the list)
3247 *
3248 *	stopOnFalse:	interrupt callings when a callback returns false
3249 *
3250 */
3251jQuery.Callbacks = function( options ) {
3252
3253	// Convert options from String-formatted to Object-formatted if needed
3254	// (we check in cache first)
3255	options = typeof options === "string" ?
3256		createOptions( options ) :
3257		jQuery.extend( {}, options );
3258
3259	var // Flag to know if list is currently firing
3260		firing,
3261
3262		// Last fire value for non-forgettable lists
3263		memory,
3264
3265		// Flag to know if list was already fired
3266		fired,
3267
3268		// Flag to prevent firing
3269		locked,
3270
3271		// Actual callback list
3272		list = [],
3273
3274		// Queue of execution data for repeatable lists
3275		queue = [],
3276
3277		// Index of currently firing callback (modified by add/remove as needed)
3278		firingIndex = -1,
3279
3280		// Fire callbacks
3281		fire = function() {
3282
3283			// Enforce single-firing
3284			locked = locked || options.once;
3285
3286			// Execute callbacks for all pending executions,
3287			// respecting firingIndex overrides and runtime changes
3288			fired = firing = true;
3289			for ( ; queue.length; firingIndex = -1 ) {
3290				memory = queue.shift();
3291				while ( ++firingIndex < list.length ) {
3292
3293					// Run callback and check for early termination
3294					if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
3295						options.stopOnFalse ) {
3296
3297						// Jump to end and forget the data so .add doesn't re-fire
3298						firingIndex = list.length;
3299						memory = false;
3300					}
3301				}
3302			}
3303
3304			// Forget the data if we're done with it
3305			if ( !options.memory ) {
3306				memory = false;
3307			}
3308
3309			firing = false;
3310
3311			// Clean up if we're done firing for good
3312			if ( locked ) {
3313
3314				// Keep an empty list if we have data for future add calls
3315				if ( memory ) {
3316					list = [];
3317
3318				// Otherwise, this object is spent
3319				} else {
3320					list = "";
3321				}
3322			}
3323		},
3324
3325		// Actual Callbacks object
3326		self = {
3327
3328			// Add a callback or a collection of callbacks to the list
3329			add: function() {
3330				if ( list ) {
3331
3332					// If we have memory from a past run, we should fire after adding
3333					if ( memory && !firing ) {
3334						firingIndex = list.length - 1;
3335						queue.push( memory );
3336					}
3337
3338					( function add( args ) {
3339						jQuery.each( args, function( _, arg ) {
3340							if ( isFunction( arg ) ) {
3341								if ( !options.unique || !self.has( arg ) ) {
3342									list.push( arg );
3343								}
3344							} else if ( arg && arg.length && toType( arg ) !== "string" ) {
3345
3346								// Inspect recursively
3347								add( arg );
3348							}
3349						} );
3350					} )( arguments );
3351
3352					if ( memory && !firing ) {
3353						fire();
3354					}
3355				}
3356				return this;
3357			},
3358
3359			// Remove a callback from the list
3360			remove: function() {
3361				jQuery.each( arguments, function( _, arg ) {
3362					var index;
3363					while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
3364						list.splice( index, 1 );
3365
3366						// Handle firing indexes
3367						if ( index <= firingIndex ) {
3368							firingIndex--;
3369						}
3370					}
3371				} );
3372				return this;
3373			},
3374
3375			// Check if a given callback is in the list.
3376			// If no argument is given, return whether or not list has callbacks attached.
3377			has: function( fn ) {
3378				return fn ?
3379					jQuery.inArray( fn, list ) > -1 :
3380					list.length > 0;
3381			},
3382
3383			// Remove all callbacks from the list
3384			empty: function() {
3385				if ( list ) {
3386					list = [];
3387				}
3388				return this;
3389			},
3390
3391			// Disable .fire and .add
3392			// Abort any current/pending executions
3393			// Clear all callbacks and values
3394			disable: function() {
3395				locked = queue = [];
3396				list = memory = "";
3397				return this;
3398			},
3399			disabled: function() {
3400				return !list;
3401			},
3402
3403			// Disable .fire
3404			// Also disable .add unless we have memory (since it would have no effect)
3405			// Abort any pending executions
3406			lock: function() {
3407				locked = queue = [];
3408				if ( !memory && !firing ) {
3409					list = memory = "";
3410				}
3411				return this;
3412			},
3413			locked: function() {
3414				return !!locked;
3415			},
3416
3417			// Call all callbacks with the given context and arguments
3418			fireWith: function( context, args ) {
3419				if ( !locked ) {
3420					args = args || [];
3421					args = [ context, args.slice ? args.slice() : args ];
3422					queue.push( args );
3423					if ( !firing ) {
3424						fire();
3425					}
3426				}
3427				return this;
3428			},
3429
3430			// Call all the callbacks with the given arguments
3431			fire: function() {
3432				self.fireWith( this, arguments );
3433				return this;
3434			},
3435
3436			// To know if the callbacks have already been called at least once
3437			fired: function() {
3438				return !!fired;
3439			}
3440		};
3441
3442	return self;
3443};
3444
3445
3446function Identity( v ) {
3447	return v;
3448}
3449function Thrower( ex ) {
3450	throw ex;
3451}
3452
3453function adoptValue( value, resolve, reject, noValue ) {
3454	var method;
3455
3456	try {
3457
3458		// Check for promise aspect first to privilege synchronous behavior
3459		if ( value && isFunction( ( method = value.promise ) ) ) {
3460			method.call( value ).done( resolve ).fail( reject );
3461
3462		// Other thenables
3463		} else if ( value && isFunction( ( method = value.then ) ) ) {
3464			method.call( value, resolve, reject );
3465
3466		// Other non-thenables
3467		} else {
3468
3469			// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
3470			// * false: [ value ].slice( 0 ) => resolve( value )
3471			// * true: [ value ].slice( 1 ) => resolve()
3472			resolve.apply( undefined, [ value ].slice( noValue ) );
3473		}
3474
3475	// For Promises/A+, convert exceptions into rejections
3476	// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
3477	// Deferred#then to conditionally suppress rejection.
3478	} catch ( value ) {
3479
3480		// Support: Android 4.0 only
3481		// Strict mode functions invoked without .call/.apply get global-object context
3482		reject.apply( undefined, [ value ] );
3483	}
3484}
3485
3486jQuery.extend( {
3487
3488	Deferred: function( func ) {
3489		var tuples = [
3490
3491				// action, add listener, callbacks,
3492				// ... .then handlers, argument index, [final state]
3493				[ "notify", "progress", jQuery.Callbacks( "memory" ),
3494					jQuery.Callbacks( "memory" ), 2 ],
3495				[ "resolve", "done", jQuery.Callbacks( "once memory" ),
3496					jQuery.Callbacks( "once memory" ), 0, "resolved" ],
3497				[ "reject", "fail", jQuery.Callbacks( "once memory" ),
3498					jQuery.Callbacks( "once memory" ), 1, "rejected" ]
3499			],
3500			state = "pending",
3501			promise = {
3502				state: function() {
3503					return state;
3504				},
3505				always: function() {
3506					deferred.done( arguments ).fail( arguments );
3507					return this;
3508				},
3509				"catch": function( fn ) {
vendor: 15,167 bytes, lines 3510-4101
3510					return promise.then( null, fn );
3511				},
3512
3513				// Keep pipe for back-compat
3514				pipe: function( /* fnDone, fnFail, fnProgress */ ) {
3515					var fns = arguments;
3516
3517					return jQuery.Deferred( function( newDefer ) {
3518						jQuery.each( tuples, function( i, tuple ) {
3519
3520							// Map tuples (progress, done, fail) to arguments (done, fail, progress)
3521							var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
3522
3523							// deferred.progress(function() { bind to newDefer or newDefer.notify })
3524							// deferred.done(function() { bind to newDefer or newDefer.resolve })
3525							// deferred.fail(function() { bind to newDefer or newDefer.reject })
3526							deferred[ tuple[ 1 ] ]( function() {
3527								var returned = fn && fn.apply( this, arguments );
3528								if ( returned && isFunction( returned.promise ) ) {
3529									returned.promise()
3530										.progress( newDefer.notify )
3531										.done( newDefer.resolve )
3532										.fail( newDefer.reject );
3533								} else {
3534									newDefer[ tuple[ 0 ] + "With" ](
3535										this,
3536										fn ? [ returned ] : arguments
3537									);
3538								}
3539							} );
3540						} );
3541						fns = null;
3542					} ).promise();
3543				},
3544				then: function( onFulfilled, onRejected, onProgress ) {
3545					var maxDepth = 0;
3546					function resolve( depth, deferred, handler, special ) {
3547						return function() {
3548							var that = this,
3549								args = arguments,
3550								mightThrow = function() {
3551									var returned, then;
3552
3553									// Support: Promises/A+ section 2.3.3.3.3
3554									// https://promisesaplus.com/#point-59
3555									// Ignore double-resolution attempts
3556									if ( depth < maxDepth ) {
3557										return;
3558									}
3559
3560									returned = handler.apply( that, args );
3561
3562									// Support: Promises/A+ section 2.3.1
3563									// https://promisesaplus.com/#point-48
3564									if ( returned === deferred.promise() ) {
3565										throw new TypeError( "Thenable self-resolution" );
3566									}
3567
3568									// Support: Promises/A+ sections 2.3.3.1, 3.5
3569									// https://promisesaplus.com/#point-54
3570									// https://promisesaplus.com/#point-75
3571									// Retrieve `then` only once
3572									then = returned &&
3573
3574										// Support: Promises/A+ section 2.3.4
3575										// https://promisesaplus.com/#point-64
3576										// Only check objects and functions for thenability
3577										( typeof returned === "object" ||
3578											typeof returned === "function" ) &&
3579										returned.then;
3580
3581									// Handle a returned thenable
3582									if ( isFunction( then ) ) {
3583
3584										// Special processors (notify) just wait for resolution
3585										if ( special ) {
3586											then.call(
3587												returned,
3588												resolve( maxDepth, deferred, Identity, special ),
3589												resolve( maxDepth, deferred, Thrower, special )
3590											);
3591
3592										// Normal processors (resolve) also hook into progress
3593										} else {
3594
3595											// ...and disregard older resolution values
3596											maxDepth++;
3597
3598											then.call(
3599												returned,
3600												resolve( maxDepth, deferred, Identity, special ),
3601												resolve( maxDepth, deferred, Thrower, special ),
3602												resolve( maxDepth, deferred, Identity,
3603													deferred.notifyWith )
3604											);
3605										}
3606
3607									// Handle all other returned values
3608									} else {
3609
3610										// Only substitute handlers pass on context
3611										// and multiple values (non-spec behavior)
3612										if ( handler !== Identity ) {
3613											that = undefined;
3614											args = [ returned ];
3615										}
3616
3617										// Process the value(s)
3618										// Default process is resolve
3619										( special || deferred.resolveWith )( that, args );
3620									}
3621								},
3622
3623								// Only normal processors (resolve) catch and reject exceptions
3624								process = special ?
3625									mightThrow :
3626									function() {
3627										try {
3628											mightThrow();
3629										} catch ( e ) {
3630
3631											if ( jQuery.Deferred.exceptionHook ) {
3632												jQuery.Deferred.exceptionHook( e,
3633													process.stackTrace );
3634											}
3635
3636											// Support: Promises/A+ section 2.3.3.3.4.1
3637											// https://promisesaplus.com/#point-61
3638											// Ignore post-resolution exceptions
3639											if ( depth + 1 >= maxDepth ) {
3640
3641												// Only substitute handlers pass on context
3642												// and multiple values (non-spec behavior)
3643												if ( handler !== Thrower ) {
3644													that = undefined;
3645													args = [ e ];
3646												}
3647
3648												deferred.rejectWith( that, args );
3649											}
3650										}
3651									};
3652
3653							// Support: Promises/A+ section 2.3.3.3.1
3654							// https://promisesaplus.com/#point-57
3655							// Re-resolve promises immediately to dodge false rejection from
3656							// subsequent errors
3657							if ( depth ) {
3658								process();
3659							} else {
3660
3661								// Call an optional hook to record the stack, in case of exception
3662								// since it's otherwise lost when execution goes async
3663								if ( jQuery.Deferred.getStackHook ) {
3664									process.stackTrace = jQuery.Deferred.getStackHook();
3665								}
3666								window.setTimeout( process );
3667							}
3668						};
3669					}
3670
3671					return jQuery.Deferred( function( newDefer ) {
3672
3673						// progress_handlers.add( ... )
3674						tuples[ 0 ][ 3 ].add(
3675							resolve(
3676								0,
3677								newDefer,
3678								isFunction( onProgress ) ?
3679									onProgress :
3680									Identity,
3681								newDefer.notifyWith
3682							)
3683						);
3684
3685						// fulfilled_handlers.add( ... )
3686						tuples[ 1 ][ 3 ].add(
3687							resolve(
3688								0,
3689								newDefer,
3690								isFunction( onFulfilled ) ?
3691									onFulfilled :
3692									Identity
3693							)
3694						);
3695
3696						// rejected_handlers.add( ... )
3697						tuples[ 2 ][ 3 ].add(
3698							resolve(
3699								0,
3700								newDefer,
3701								isFunction( onRejected ) ?
3702									onRejected :
3703									Thrower
3704							)
3705						);
3706					} ).promise();
3707				},
3708
3709				// Get a promise for this deferred
3710				// If obj is provided, the promise aspect is added to the object
3711				promise: function( obj ) {
3712					return obj != null ? jQuery.extend( obj, promise ) : promise;
3713				}
3714			},
3715			deferred = {};
3716
3717		// Add list-specific methods
3718		jQuery.each( tuples, function( i, tuple ) {
3719			var list = tuple[ 2 ],
3720				stateString = tuple[ 5 ];
3721
3722			// promise.progress = list.add
3723			// promise.done = list.add
3724			// promise.fail = list.add
3725			promise[ tuple[ 1 ] ] = list.add;
3726
3727			// Handle state
3728			if ( stateString ) {
3729				list.add(
3730					function() {
3731
3732						// state = "resolved" (i.e., fulfilled)
3733						// state = "rejected"
3734						state = stateString;
3735					},
3736
3737					// rejected_callbacks.disable
3738					// fulfilled_callbacks.disable
3739					tuples[ 3 - i ][ 2 ].disable,
3740
3741					// rejected_handlers.disable
3742					// fulfilled_handlers.disable
3743					tuples[ 3 - i ][ 3 ].disable,
3744
3745					// progress_callbacks.lock
3746					tuples[ 0 ][ 2 ].lock,
3747
3748					// progress_handlers.lock
3749					tuples[ 0 ][ 3 ].lock
3750				);
3751			}
3752
3753			// progress_handlers.fire
3754			// fulfilled_handlers.fire
3755			// rejected_handlers.fire
3756			list.add( tuple[ 3 ].fire );
3757
3758			// deferred.notify = function() { deferred.notifyWith(...) }
3759			// deferred.resolve = function() { deferred.resolveWith(...) }
3760			// deferred.reject = function() { deferred.rejectWith(...) }
3761			deferred[ tuple[ 0 ] ] = function() {
3762				deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
3763				return this;
3764			};
3765
3766			// deferred.notifyWith = list.fireWith
3767			// deferred.resolveWith = list.fireWith
3768			// deferred.rejectWith = list.fireWith
3769			deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
3770		} );
3771
3772		// Make the deferred a promise
3773		promise.promise( deferred );
3774
3775		// Call given func if any
3776		if ( func ) {
3777			func.call( deferred, deferred );
3778		}
3779
3780		// All done!
3781		return deferred;
3782	},
3783
3784	// Deferred helper
3785	when: function( singleValue ) {
3786		var
3787
3788			// count of uncompleted subordinates
3789			remaining = arguments.length,
3790
3791			// count of unprocessed arguments
3792			i = remaining,
3793
3794			// subordinate fulfillment data
3795			resolveContexts = Array( i ),
3796			resolveValues = slice.call( arguments ),
3797
3798			// the master Deferred
3799			master = jQuery.Deferred(),
3800
3801			// subordinate callback factory
3802			updateFunc = function( i ) {
3803				return function( value ) {
3804					resolveContexts[ i ] = this;
3805					resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
3806					if ( !( --remaining ) ) {
3807						master.resolveWith( resolveContexts, resolveValues );
3808					}
3809				};
3810			};
3811
3812		// Single- and empty arguments are adopted like Promise.resolve
3813		if ( remaining <= 1 ) {
3814			adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,
3815				!remaining );
3816
3817			// Use .then() to unwrap secondary thenables (cf. gh-3000)
3818			if ( master.state() === "pending" ||
3819				isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
3820
3821				return master.then();
3822			}
3823		}
3824
3825		// Multiple arguments are aggregated like Promise.all array elements
3826		while ( i-- ) {
3827			adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
3828		}
3829
3830		return master.promise();
3831	}
3832} );
3833
3834
3835// These usually indicate a programmer mistake during development,
3836// warn about them ASAP rather than swallowing them by default.
3837var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
3838
3839jQuery.Deferred.exceptionHook = function( error, stack ) {
3840
3841	// Support: IE 8 - 9 only
3842	// Console exists when dev tools are open, which can happen at any time
3843	if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
3844		window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
3845	}
3846};
3847
3848
3849
3850
3851jQuery.readyException = function( error ) {
3852	window.setTimeout( function() {
3853		throw error;
3854	} );
3855};
3856
3857
3858
3859
3860// The deferred used on DOM ready
3861var readyList = jQuery.Deferred();
3862
3863jQuery.fn.ready = function( fn ) {
3864
3865	readyList
3866		.then( fn )
3867
3868		// Wrap jQuery.readyException in a function so that the lookup
3869		// happens at the time of error handling instead of callback
3870		// registration.
3871		.catch( function( error ) {
3872			jQuery.readyException( error );
3873		} );
3874
3875	return this;
3876};
3877
3878jQuery.extend( {
3879
3880	// Is the DOM ready to be used? Set to true once it occurs.
3881	isReady: false,
3882
3883	// A counter to track how many items to wait for before
3884	// the ready event fires. See #6781
3885	readyWait: 1,
3886
3887	// Handle when the DOM is ready
3888	ready: function( wait ) {
3889
3890		// Abort if there are pending holds or we're already ready
3891		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
3892			return;
3893		}
3894
3895		// Remember that the DOM is ready
3896		jQuery.isReady = true;
3897
3898		// If a normal DOM Ready event fired, decrement, and wait if need be
3899		if ( wait !== true && --jQuery.readyWait > 0 ) {
3900			return;
3901		}
3902
3903		// If there are functions bound, to execute
3904		readyList.resolveWith( document, [ jQuery ] );
3905	}
3906} );
3907
3908jQuery.ready.then = readyList.then;
3909
3910// The ready event handler and self cleanup method
3911function completed() {
3912	document.removeEventListener( "DOMContentLoaded", completed );
3913	window.removeEventListener( "load", completed );
3914	jQuery.ready();
3915}
3916
3917// Catch cases where $(document).ready() is called
3918// after the browser event has already occurred.
3919// Support: IE <=9 - 10 only
3920// Older IE sometimes signals "interactive" too soon
3921if ( document.readyState === "complete" ||
3922	( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
3923
3924	// Handle it asynchronously to allow scripts the opportunity to delay ready
3925	window.setTimeout( jQuery.ready );
3926
3927} else {
3928
3929	// Use the handy event callback
3930	document.addEventListener( "DOMContentLoaded", completed );
3931
3932	// A fallback to window.onload, that will always work
3933	window.addEventListener( "load", completed );
3934}
3935
3936
3937
3938
3939// Multifunctional method to get and set values of a collection
3940// The value/s can optionally be executed if it's a function
3941var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
3942	var i = 0,
3943		len = elems.length,
3944		bulk = key == null;
3945
3946	// Sets many values
3947	if ( toType( key ) === "object" ) {
3948		chainable = true;
3949		for ( i in key ) {
3950			access( elems, fn, i, key[ i ], true, emptyGet, raw );
3951		}
3952
3953	// Sets one value
3954	} else if ( value !== undefined ) {
3955		chainable = true;
3956
3957		if ( !isFunction( value ) ) {
3958			raw = true;
3959		}
3960
3961		if ( bulk ) {
3962
3963			// Bulk operations run against the entire set
3964			if ( raw ) {
3965				fn.call( elems, value );
3966				fn = null;
3967
3968			// ...except when executing function values
3969			} else {
3970				bulk = fn;
3971				fn = function( elem, key, value ) {
3972					return bulk.call( jQuery( elem ), value );
3973				};
3974			}
3975		}
3976
3977		if ( fn ) {
3978			for ( ; i < len; i++ ) {
3979				fn(
3980					elems[ i ], key, raw ?
3981					value :
3982					value.call( elems[ i ], i, fn( elems[ i ], key ) )
3983				);
3984			}
3985		}
3986	}
3987
3988	if ( chainable ) {
3989		return elems;
3990	}
3991
3992	// Gets
3993	if ( bulk ) {
3994		return fn.call( elems );
3995	}
3996
3997	return len ? fn( elems[ 0 ], key ) : emptyGet;
3998};
3999
4000
4001// Matches dashed string for camelizing
4002var rmsPrefix = /^-ms-/,
4003	rdashAlpha = /-([a-z])/g;
4004
4005// Used by camelCase as callback to replace()
4006function fcamelCase( all, letter ) {
4007	return letter.toUpperCase();
4008}
4009
4010// Convert dashed to camelCase; used by the css and data modules
4011// Support: IE <=9 - 11, Edge 12 - 15
4012// Microsoft forgot to hump their vendor prefix (#9572)
4013function camelCase( string ) {
4014	return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
4015}
4016var acceptData = function( owner ) {
4017
4018	// Accepts only:
4019	//  - Node
4020	//    - Node.ELEMENT_NODE
4021	//    - Node.DOCUMENT_NODE
4022	//  - Object
4023	//    - Any
4024	return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
4025};
4026
4027
4028
4029
4030function Data() {
4031	this.expando = jQuery.expando + Data.uid++;
4032}
4033
4034Data.uid = 1;
4035
4036Data.prototype = {
4037
4038	cache: function( owner ) {
4039
4040		// Check if the owner object already has a cache
4041		var value = owner[ this.expando ];
4042
4043		// If not, create one
4044		if ( !value ) {
4045			value = {};
4046
4047			// We can accept data for non-element nodes in modern browsers,
4048			// but we should not, see #8335.
4049			// Always return an empty object.
4050			if ( acceptData( owner ) ) {
4051
4052				// If it is a node unlikely to be stringify-ed or looped over
4053				// use plain assignment
4054				if ( owner.nodeType ) {
4055					owner[ this.expando ] = value;
4056
4057				// Otherwise secure it in a non-enumerable property
4058				// configurable must be true to allow the property to be
4059				// deleted when data is removed
4060				} else {
4061					Object.defineProperty( owner, this.expando, {
4062						value: value,
4063						configurable: true
4064					} );
4065				}
4066			}
4067		}
4068
4069		return value;
4070	},
4071	set: function( owner, data, value ) {
4072		var prop,
4073			cache = this.cache( owner );
4074
4075		// Handle: [ owner, key, value ] args
4076		// Always use camelCase key (gh-2257)
4077		if ( typeof data === "string" ) {
4078			cache[ camelCase( data ) ] = value;
4079
4080		// Handle: [ owner, { properties } ] args
4081		} else {
4082
4083			// Copy the properties one-by-one to the cache object
4084			for ( prop in data ) {
4085				cache[ camelCase( prop ) ] = data[ prop ];
4086			}
4087		}
4088		return cache;
4089	},
4090	get: function( owner, key ) {
4091		return key === undefined ?
4092			this.cache( owner ) :
4093
4094			// Always use camelCase key (gh-2257)
4095			owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
4096	},
4097	access: function( owner, key, value ) {
4098
4099		// In cases where either:
4100		//
4101		//   1. No key was specified
vendor: 10,628 bytes, lines 4102-4533
4102		//   2. A string key was specified, but no value provided
4103		//
4104		// Take the "read" path and allow the get method to determine
4105		// which value to return, respectively either:
4106		//
4107		//   1. The entire cache object
4108		//   2. The data stored at the key
4109		//
4110		if ( key === undefined ||
4111				( ( key && typeof key === "string" ) && value === undefined ) ) {
4112
4113			return this.get( owner, key );
4114		}
4115
4116		// When the key is not a string, or both a key and value
4117		// are specified, set or extend (existing objects) with either:
4118		//
4119		//   1. An object of properties
4120		//   2. A key and value
4121		//
4122		this.set( owner, key, value );
4123
4124		// Since the "set" path can have two possible entry points
4125		// return the expected data based on which path was taken[*]
4126		return value !== undefined ? value : key;
4127	},
4128	remove: function( owner, key ) {
4129		var i,
4130			cache = owner[ this.expando ];
4131
4132		if ( cache === undefined ) {
4133			return;
4134		}
4135
4136		if ( key !== undefined ) {
4137
4138			// Support array or space separated string of keys
4139			if ( Array.isArray( key ) ) {
4140
4141				// If key is an array of keys...
4142				// We always set camelCase keys, so remove that.
4143				key = key.map( camelCase );
4144			} else {
4145				key = camelCase( key );
4146
4147				// If a key with the spaces exists, use it.
4148				// Otherwise, create an array by matching non-whitespace
4149				key = key in cache ?
4150					[ key ] :
4151					( key.match( rnothtmlwhite ) || [] );
4152			}
4153
4154			i = key.length;
4155
4156			while ( i-- ) {
4157				delete cache[ key[ i ] ];
4158			}
4159		}
4160
4161		// Remove the expando if there's no more data
4162		if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
4163
4164			// Support: Chrome <=35 - 45
4165			// Webkit & Blink performance suffers when deleting properties
4166			// from DOM nodes, so set to undefined instead
4167			// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
4168			if ( owner.nodeType ) {
4169				owner[ this.expando ] = undefined;
4170			} else {
4171				delete owner[ this.expando ];
4172			}
4173		}
4174	},
4175	hasData: function( owner ) {
4176		var cache = owner[ this.expando ];
4177		return cache !== undefined && !jQuery.isEmptyObject( cache );
4178	}
4179};
4180var dataPriv = new Data();
4181
4182var dataUser = new Data();
4183
4184
4185
4186//	Implementation Summary
4187//
4188//	1. Enforce API surface and semantic compatibility with 1.9.x branch
4189//	2. Improve the module's maintainability by reducing the storage
4190//		paths to a single mechanism.
4191//	3. Use the same single mechanism to support "private" and "user" data.
4192//	4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
4193//	5. Avoid exposing implementation details on user objects (eg. expando properties)
4194//	6. Provide a clear path for implementation upgrade to WeakMap in 2014
4195
4196var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
4197	rmultiDash = /[A-Z]/g;
4198
4199function getData( data ) {
4200	if ( data === "true" ) {
4201		return true;
4202	}
4203
4204	if ( data === "false" ) {
4205		return false;
4206	}
4207
4208	if ( data === "null" ) {
4209		return null;
4210	}
4211
4212	// Only convert to a number if it doesn't change the string
4213	if ( data === +data + "" ) {
4214		return +data;
4215	}
4216
4217	if ( rbrace.test( data ) ) {
4218		return JSON.parse( data );
4219	}
4220
4221	return data;
4222}
4223
4224function dataAttr( elem, key, data ) {
4225	var name;
4226
4227	// If nothing was found internally, try to fetch any
4228	// data from the HTML5 data-* attribute
4229	if ( data === undefined && elem.nodeType === 1 ) {
4230		name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
4231		data = elem.getAttribute( name );
4232
4233		if ( typeof data === "string" ) {
4234			try {
4235				data = getData( data );
4236			} catch ( e ) {}
4237
4238			// Make sure we set the data so it isn't changed later
4239			dataUser.set( elem, key, data );
4240		} else {
4241			data = undefined;
4242		}
4243	}
4244	return data;
4245}
4246
4247jQuery.extend( {
4248	hasData: function( elem ) {
4249		return dataUser.hasData( elem ) || dataPriv.hasData( elem );
4250	},
4251
4252	data: function( elem, name, data ) {
4253		return dataUser.access( elem, name, data );
4254	},
4255
4256	removeData: function( elem, name ) {
4257		dataUser.remove( elem, name );
4258	},
4259
4260	// TODO: Now that all calls to _data and _removeData have been replaced
4261	// with direct calls to dataPriv methods, these can be deprecated.
4262	_data: function( elem, name, data ) {
4263		return dataPriv.access( elem, name, data );
4264	},
4265
4266	_removeData: function( elem, name ) {
4267		dataPriv.remove( elem, name );
4268	}
4269} );
4270
4271jQuery.fn.extend( {
4272	data: function( key, value ) {
4273		var i, name, data,
4274			elem = this[ 0 ],
4275			attrs = elem && elem.attributes;
4276
4277		// Gets all values
4278		if ( key === undefined ) {
4279			if ( this.length ) {
4280				data = dataUser.get( elem );
4281
4282				if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
4283					i = attrs.length;
4284					while ( i-- ) {
4285
4286						// Support: IE 11 only
4287						// The attrs elements can be null (#14894)
4288						if ( attrs[ i ] ) {
4289							name = attrs[ i ].name;
4290							if ( name.indexOf( "data-" ) === 0 ) {
4291								name = camelCase( name.slice( 5 ) );
4292								dataAttr( elem, name, data[ name ] );
4293							}
4294						}
4295					}
4296					dataPriv.set( elem, "hasDataAttrs", true );
4297				}
4298			}
4299
4300			return data;
4301		}
4302
4303		// Sets multiple values
4304		if ( typeof key === "object" ) {
4305			return this.each( function() {
4306				dataUser.set( this, key );
4307			} );
4308		}
4309
4310		return access( this, function( value ) {
4311			var data;
4312
4313			// The calling jQuery object (element matches) is not empty
4314			// (and therefore has an element appears at this[ 0 ]) and the
4315			// `value` parameter was not undefined. An empty jQuery object
4316			// will result in `undefined` for elem = this[ 0 ] which will
4317			// throw an exception if an attempt to read a data cache is made.
4318			if ( elem && value === undefined ) {
4319
4320				// Attempt to get data from the cache
4321				// The key will always be camelCased in Data
4322				data = dataUser.get( elem, key );
4323				if ( data !== undefined ) {
4324					return data;
4325				}
4326
4327				// Attempt to "discover" the data in
4328				// HTML5 custom data-* attrs
4329				data = dataAttr( elem, key );
4330				if ( data !== undefined ) {
4331					return data;
4332				}
4333
4334				// We tried really hard, but the data doesn't exist.
4335				return;
4336			}
4337
4338			// Set the data...
4339			this.each( function() {
4340
4341				// We always store the camelCased key
4342				dataUser.set( this, key, value );
4343			} );
4344		}, null, value, arguments.length > 1, null, true );
4345	},
4346
4347	removeData: function( key ) {
4348		return this.each( function() {
4349			dataUser.remove( this, key );
4350		} );
4351	}
4352} );
4353
4354
4355jQuery.extend( {
4356	queue: function( elem, type, data ) {
4357		var queue;
4358
4359		if ( elem ) {
4360			type = ( type || "fx" ) + "queue";
4361			queue = dataPriv.get( elem, type );
4362
4363			// Speed up dequeue by getting out quickly if this is just a lookup
4364			if ( data ) {
4365				if ( !queue || Array.isArray( data ) ) {
4366					queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
4367				} else {
4368					queue.push( data );
4369				}
4370			}
4371			return queue || [];
4372		}
4373	},
4374
4375	dequeue: function( elem, type ) {
4376		type = type || "fx";
4377
4378		var queue = jQuery.queue( elem, type ),
4379			startLength = queue.length,
4380			fn = queue.shift(),
4381			hooks = jQuery._queueHooks( elem, type ),
4382			next = function() {
4383				jQuery.dequeue( elem, type );
4384			};
4385
4386		// If the fx queue is dequeued, always remove the progress sentinel
4387		if ( fn === "inprogress" ) {
4388			fn = queue.shift();
4389			startLength--;
4390		}
4391
4392		if ( fn ) {
4393
4394			// Add a progress sentinel to prevent the fx queue from being
4395			// automatically dequeued
4396			if ( type === "fx" ) {
4397				queue.unshift( "inprogress" );
4398			}
4399
4400			// Clear up the last queue stop function
4401			delete hooks.stop;
4402			fn.call( elem, next, hooks );
4403		}
4404
4405		if ( !startLength && hooks ) {
4406			hooks.empty.fire();
4407		}
4408	},
4409
4410	// Not public - generate a queueHooks object, or return the current one
4411	_queueHooks: function( elem, type ) {
4412		var key = type + "queueHooks";
4413		return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
4414			empty: jQuery.Callbacks( "once memory" ).add( function() {
4415				dataPriv.remove( elem, [ type + "queue", key ] );
4416			} )
4417		} );
4418	}
4419} );
4420
4421jQuery.fn.extend( {
4422	queue: function( type, data ) {
4423		var setter = 2;
4424
4425		if ( typeof type !== "string" ) {
4426			data = type;
4427			type = "fx";
4428			setter--;
4429		}
4430
4431		if ( arguments.length < setter ) {
4432			return jQuery.queue( this[ 0 ], type );
4433		}
4434
4435		return data === undefined ?
4436			this :
4437			this.each( function() {
4438				var queue = jQuery.queue( this, type, data );
4439
4440				// Ensure a hooks for this queue
4441				jQuery._queueHooks( this, type );
4442
4443				if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
4444					jQuery.dequeue( this, type );
4445				}
4446			} );
4447	},
4448	dequeue: function( type ) {
4449		return this.each( function() {
4450			jQuery.dequeue( this, type );
4451		} );
4452	},
4453	clearQueue: function( type ) {
4454		return this.queue( type || "fx", [] );
4455	},
4456
4457	// Get a promise resolved when queues of a certain type
4458	// are emptied (fx is the type by default)
4459	promise: function( type, obj ) {
4460		var tmp,
4461			count = 1,
4462			defer = jQuery.Deferred(),
4463			elements = this,
4464			i = this.length,
4465			resolve = function() {
4466				if ( !( --count ) ) {
4467					defer.resolveWith( elements, [ elements ] );
4468				}
4469			};
4470
4471		if ( typeof type !== "string" ) {
4472			obj = type;
4473			type = undefined;
4474		}
4475		type = type || "fx";
4476
4477		while ( i-- ) {
4478			tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
4479			if ( tmp && tmp.empty ) {
4480				count++;
4481				tmp.empty.add( resolve );
4482			}
4483		}
4484		resolve();
4485		return defer.promise( obj );
4486	}
4487} );
4488var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
4489
4490var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
4491
4492
4493var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
4494
4495var documentElement = document.documentElement;
4496
4497
4498
4499	var isAttached = function( elem ) {
4500			return jQuery.contains( elem.ownerDocument, elem );
4501		},
4502		composed = { composed: true };
4503
4504	// Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only
4505	// Check attachment across shadow DOM boundaries when possible (gh-3504)
4506	// Support: iOS 10.0-10.2 only
4507	// Early iOS 10 versions support `attachShadow` but not `getRootNode`,
4508	// leading to errors. We need to check for `getRootNode`.
4509	if ( documentElement.getRootNode ) {
4510		isAttached = function( elem ) {
4511			return jQuery.contains( elem.ownerDocument, elem ) ||
4512				elem.getRootNode( composed ) === elem.ownerDocument;
4513		};
4514	}
4515var isHiddenWithinTree = function( elem, el ) {
4516
4517		// isHiddenWithinTree might be called from jQuery#filter function;
4518		// in that case, element will be second argument
4519		elem = el || elem;
4520
4521		// Inline style trumps all
4522		return elem.style.display === "none" ||
4523			elem.style.display === "" &&
4524
4525			// Otherwise, check computed style
4526			// Support: Firefox <=43 - 45
4527			// Disconnected elements can have computed display: none, so first confirm that elem is
4528			// in the document.
4529			isAttached( elem ) &&
4530
4531			jQuery.css( elem, "display" ) === "none";
4532	};
4533
vendor: 2,487 bytes, lines 4534-4631
4534var swap = function( elem, options, callback, args ) {
4535	var ret, name,
4536		old = {};
4537
4538	// Remember the old values, and insert the new ones
4539	for ( name in options ) {
4540		old[ name ] = elem.style[ name ];
4541		elem.style[ name ] = options[ name ];
4542	}
4543
4544	ret = callback.apply( elem, args || [] );
4545
4546	// Revert the old values
4547	for ( name in options ) {
4548		elem.style[ name ] = old[ name ];
4549	}
4550
4551	return ret;
4552};
4553
4554
4555
4556
4557function adjustCSS( elem, prop, valueParts, tween ) {
4558	var adjusted, scale,
4559		maxIterations = 20,
4560		currentValue = tween ?
4561			function() {
4562				return tween.cur();
4563			} :
4564			function() {
4565				return jQuery.css( elem, prop, "" );
4566			},
4567		initial = currentValue(),
4568		unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
4569
4570		// Starting value computation is required for potential unit mismatches
4571		initialInUnit = elem.nodeType &&
4572			( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
4573			rcssNum.exec( jQuery.css( elem, prop ) );
4574
4575	if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
4576
4577		// Support: Firefox <=54
4578		// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
4579		initial = initial / 2;
4580
4581		// Trust units reported by jQuery.css
4582		unit = unit || initialInUnit[ 3 ];
4583
4584		// Iteratively approximate from a nonzero starting point
4585		initialInUnit = +initial || 1;
4586
4587		while ( maxIterations-- ) {
4588
4589			// Evaluate and update our best guess (doubling guesses that zero out).
4590			// Finish if the scale equals or crosses 1 (making the old*new product non-positive).
4591			jQuery.style( elem, prop, initialInUnit + unit );
4592			if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
4593				maxIterations = 0;
4594			}
4595			initialInUnit = initialInUnit / scale;
4596
4597		}
4598
4599		initialInUnit = initialInUnit * 2;
4600		jQuery.style( elem, prop, initialInUnit + unit );
4601
4602		// Make sure we update the tween properties later on
4603		valueParts = valueParts || [];
4604	}
4605
4606	if ( valueParts ) {
4607		initialInUnit = +initialInUnit || +initial || 0;
4608
4609		// Apply relative offset (+=/-=) if specified
4610		adjusted = valueParts[ 1 ] ?
4611			initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
4612			+valueParts[ 2 ];
4613		if ( tween ) {
4614			tween.unit = unit;
4615			tween.start = initialInUnit;
4616			tween.end = adjusted;
4617		}
4618	}
4619	return adjusted;
4620}
4621
4622
4623var defaultDisplayMap = {};
4624
4625function getDefaultDisplay( elem ) {
4626	var temp,
4627		doc = elem.ownerDocument,
4628		nodeName = elem.nodeName,
4629		display = defaultDisplayMap[ nodeName ];
4630
4631	if ( display ) {
vendor: 4,818 bytes, lines 4632-4827
4632		return display;
4633	}
4634
4635	temp = doc.body.appendChild( doc.createElement( nodeName ) );
4636	display = jQuery.css( temp, "display" );
4637
4638	temp.parentNode.removeChild( temp );
4639
4640	if ( display === "none" ) {
4641		display = "block";
4642	}
4643	defaultDisplayMap[ nodeName ] = display;
4644
4645	return display;
4646}
4647
4648function showHide( elements, show ) {
4649	var display, elem,
4650		values = [],
4651		index = 0,
4652		length = elements.length;
4653
4654	// Determine new display value for elements that need to change
4655	for ( ; index < length; index++ ) {
4656		elem = elements[ index ];
4657		if ( !elem.style ) {
4658			continue;
4659		}
4660
4661		display = elem.style.display;
4662		if ( show ) {
4663
4664			// Since we force visibility upon cascade-hidden elements, an immediate (and slow)
4665			// check is required in this first loop unless we have a nonempty display value (either
4666			// inline or about-to-be-restored)
4667			if ( display === "none" ) {
4668				values[ index ] = dataPriv.get( elem, "display" ) || null;
4669				if ( !values[ index ] ) {
4670					elem.style.display = "";
4671				}
4672			}
4673			if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
4674				values[ index ] = getDefaultDisplay( elem );
4675			}
4676		} else {
4677			if ( display !== "none" ) {
4678				values[ index ] = "none";
4679
4680				// Remember what we're overwriting
4681				dataPriv.set( elem, "display", display );
4682			}
4683		}
4684	}
4685
4686	// Set the display of the elements in a second loop to avoid constant reflow
4687	for ( index = 0; index < length; index++ ) {
4688		if ( values[ index ] != null ) {
4689			elements[ index ].style.display = values[ index ];
4690		}
4691	}
4692
4693	return elements;
4694}
4695
4696jQuery.fn.extend( {
4697	show: function() {
4698		return showHide( this, true );
4699	},
4700	hide: function() {
4701		return showHide( this );
4702	},
4703	toggle: function( state ) {
4704		if ( typeof state === "boolean" ) {
4705			return state ? this.show() : this.hide();
4706		}
4707
4708		return this.each( function() {
4709			if ( isHiddenWithinTree( this ) ) {
4710				jQuery( this ).show();
4711			} else {
4712				jQuery( this ).hide();
4713			}
4714		} );
4715	}
4716} );
4717var rcheckableType = ( /^(?:checkbox|radio)$/i );
4718
4719var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i );
4720
4721var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
4722
4723
4724
4725// We have to close these tags to support XHTML (#13200)
4726var wrapMap = {
4727
4728	// Support: IE <=9 only
4729	option: [ 1, "<select multiple='multiple'>", "</select>" ],
4730
4731	// XHTML parsers do not magically insert elements in the
4732	// same way that tag soup parsers do. So we cannot shorten
4733	// this by omitting <tbody> or other required elements.
4734	thead: [ 1, "<table>", "</table>" ],
4735	col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
4736	tr: [ 2, "<table><tbody>", "</tbody></table>" ],
4737	td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
4738
4739	_default: [ 0, "", "" ]
4740};
4741
4742// Support: IE <=9 only
4743wrapMap.optgroup = wrapMap.option;
4744
4745wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
4746wrapMap.th = wrapMap.td;
4747
4748
4749function getAll( context, tag ) {
4750
4751	// Support: IE <=9 - 11 only
4752	// Use typeof to avoid zero-argument method invocation on host objects (#15151)
4753	var ret;
4754
4755	if ( typeof context.getElementsByTagName !== "undefined" ) {
4756		ret = context.getElementsByTagName( tag || "*" );
4757
4758	} else if ( typeof context.querySelectorAll !== "undefined" ) {
4759		ret = context.querySelectorAll( tag || "*" );
4760
4761	} else {
4762		ret = [];
4763	}
4764
4765	if ( tag === undefined || tag && nodeName( context, tag ) ) {
4766		return jQuery.merge( [ context ], ret );
4767	}
4768
4769	return ret;
4770}
4771
4772
4773// Mark scripts as having already been evaluated
4774function setGlobalEval( elems, refElements ) {
4775	var i = 0,
4776		l = elems.length;
4777
4778	for ( ; i < l; i++ ) {
4779		dataPriv.set(
4780			elems[ i ],
4781			"globalEval",
4782			!refElements || dataPriv.get( refElements[ i ], "globalEval" )
4783		);
4784	}
4785}
4786
4787
4788var rhtml = /<|&#?\w+;/;
4789
4790function buildFragment( elems, context, scripts, selection, ignored ) {
4791	var elem, tmp, tag, wrap, attached, j,
4792		fragment = context.createDocumentFragment(),
4793		nodes = [],
4794		i = 0,
4795		l = elems.length;
4796
4797	for ( ; i < l; i++ ) {
4798		elem = elems[ i ];
4799
4800		if ( elem || elem === 0 ) {
4801
4802			// Add nodes directly
4803			if ( toType( elem ) === "object" ) {
4804
4805				// Support: Android <=4.0 only, PhantomJS 1 only
4806				// push.apply(_, arraylike) throws on ancient WebKit
4807				jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
4808
4809			// Convert non-html into a text node
4810			} else if ( !rhtml.test( elem ) ) {
4811				nodes.push( context.createTextNode( elem ) );
4812
4813			// Convert html into DOM nodes
4814			} else {
4815				tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
4816
4817				// Deserialize a standard representation
4818				tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
4819				wrap = wrapMap[ tag ] || wrapMap._default;
4820				tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
4821
4822				// Descend through wrappers to the right content
4823				j = wrap[ 0 ];
4824				while ( j-- ) {
4825					tmp = tmp.lastChild;
4826				}
4827
vendor: 1,252 bytes, lines 4828-4885
4828				// Support: Android <=4.0 only, PhantomJS 1 only
4829				// push.apply(_, arraylike) throws on ancient WebKit
4830				jQuery.merge( nodes, tmp.childNodes );
4831
4832				// Remember the top-level container
4833				tmp = fragment.firstChild;
4834
4835				// Ensure the created nodes are orphaned (#12392)
4836				tmp.textContent = "";
4837			}
4838		}
4839	}
4840
4841	// Remove wrapper from fragment
4842	fragment.textContent = "";
4843
4844	i = 0;
4845	while ( ( elem = nodes[ i++ ] ) ) {
4846
4847		// Skip elements already in the context collection (trac-4087)
4848		if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
4849			if ( ignored ) {
4850				ignored.push( elem );
4851			}
4852			continue;
4853		}
4854
4855		attached = isAttached( elem );
4856
4857		// Append to fragment
4858		tmp = getAll( fragment.appendChild( elem ), "script" );
4859
4860		// Preserve script evaluation history
4861		if ( attached ) {
4862			setGlobalEval( tmp );
4863		}
4864
4865		// Capture executables
4866		if ( scripts ) {
4867			j = 0;
4868			while ( ( elem = tmp[ j++ ] ) ) {
4869				if ( rscriptType.test( elem.type || "" ) ) {
4870					scripts.push( elem );
4871				}
4872			}
4873		}
4874	}
4875
4876	return fragment;
4877}
4878
4879
4880( function() {
4881	var fragment = document.createDocumentFragment(),
4882		div = fragment.appendChild( document.createElement( "div" ) ),
4883		input = document.createElement( "input" );
4884
4885	// Support: Android 4.0 - 4.3 only
vendor: 6,890 bytes, lines 4886-5132
4886	// Check state lost if the name is set (#11217)
4887	// Support: Windows Web Apps (WWA)
4888	// `name` and `type` must use .setAttribute for WWA (#14901)
4889	input.setAttribute( "type", "radio" );
4890	input.setAttribute( "checked", "checked" );
4891	input.setAttribute( "name", "t" );
4892
4893	div.appendChild( input );
4894
4895	// Support: Android <=4.1 only
4896	// Older WebKit doesn't clone checked state correctly in fragments
4897	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
4898
4899	// Support: IE <=11 only
4900	// Make sure textarea (and checkbox) defaultValue is properly cloned
4901	div.innerHTML = "<textarea>x</textarea>";
4902	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
4903} )();
4904
4905
4906var
4907	rkeyEvent = /^key/,
4908	rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
4909	rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
4910
4911function returnTrue() {
4912	return true;
4913}
4914
4915function returnFalse() {
4916	return false;
4917}
4918
4919// Support: IE <=9 - 11+
4920// focus() and blur() are asynchronous, except when they are no-op.
4921// So expect focus to be synchronous when the element is already active,
4922// and blur to be synchronous when the element is not already active.
4923// (focus and blur are always synchronous in other supported browsers,
4924// this just defines when we can count on it).
4925function expectSync( elem, type ) {
4926	return ( elem === safeActiveElement() ) === ( type === "focus" );
4927}
4928
4929// Support: IE <=9 only
4930// Accessing document.activeElement can throw unexpectedly
4931// https://bugs.jquery.com/ticket/13393
4932function safeActiveElement() {
4933	try {
4934		return document.activeElement;
4935	} catch ( err ) { }
4936}
4937
4938function on( elem, types, selector, data, fn, one ) {
4939	var origFn, type;
4940
4941	// Types can be a map of types/handlers
4942	if ( typeof types === "object" ) {
4943
4944		// ( types-Object, selector, data )
4945		if ( typeof selector !== "string" ) {
4946
4947			// ( types-Object, data )
4948			data = data || selector;
4949			selector = undefined;
4950		}
4951		for ( type in types ) {
4952			on( elem, type, selector, data, types[ type ], one );
4953		}
4954		return elem;
4955	}
4956
4957	if ( data == null && fn == null ) {
4958
4959		// ( types, fn )
4960		fn = selector;
4961		data = selector = undefined;
4962	} else if ( fn == null ) {
4963		if ( typeof selector === "string" ) {
4964
4965			// ( types, selector, fn )
4966			fn = data;
4967			data = undefined;
4968		} else {
4969
4970			// ( types, data, fn )
4971			fn = data;
4972			data = selector;
4973			selector = undefined;
4974		}
4975	}
4976	if ( fn === false ) {
4977		fn = returnFalse;
4978	} else if ( !fn ) {
4979		return elem;
4980	}
4981
4982	if ( one === 1 ) {
4983		origFn = fn;
4984		fn = function( event ) {
4985
4986			// Can use an empty set, since event contains the info
4987			jQuery().off( event );
4988			return origFn.apply( this, arguments );
4989		};
4990
4991		// Use same guid so caller can remove using origFn
4992		fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
4993	}
4994	return elem.each( function() {
4995		jQuery.event.add( this, types, fn, data, selector );
4996	} );
4997}
4998
4999/*
5000 * Helper functions for managing events -- not part of the public interface.
5001 * Props to Dean Edwards' addEvent library for many of the ideas.
5002 */
5003jQuery.event = {
5004
5005	global: {},
5006
5007	add: function( elem, types, handler, data, selector ) {
5008
5009		var handleObjIn, eventHandle, tmp,
5010			events, t, handleObj,
5011			special, handlers, type, namespaces, origType,
5012			elemData = dataPriv.get( elem );
5013
5014		// Don't attach events to noData or text/comment nodes (but allow plain objects)
5015		if ( !elemData ) {
5016			return;
5017		}
5018
5019		// Caller can pass in an object of custom data in lieu of the handler
5020		if ( handler.handler ) {
5021			handleObjIn = handler;
5022			handler = handleObjIn.handler;
5023			selector = handleObjIn.selector;
5024		}
5025
5026		// Ensure that invalid selectors throw exceptions at attach time
5027		// Evaluate against documentElement in case elem is a non-element node (e.g., document)
5028		if ( selector ) {
5029			jQuery.find.matchesSelector( documentElement, selector );
5030		}
5031
5032		// Make sure that the handler has a unique ID, used to find/remove it later
5033		if ( !handler.guid ) {
5034			handler.guid = jQuery.guid++;
5035		}
5036
5037		// Init the element's event structure and main handler, if this is the first
5038		if ( !( events = elemData.events ) ) {
5039			events = elemData.events = {};
5040		}
5041		if ( !( eventHandle = elemData.handle ) ) {
5042			eventHandle = elemData.handle = function( e ) {
5043
5044				// Discard the second event of a jQuery.event.trigger() and
5045				// when an event is called after a page has unloaded
5046				return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
5047					jQuery.event.dispatch.apply( elem, arguments ) : undefined;
5048			};
5049		}
5050
5051		// Handle multiple events separated by a space
5052		types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
5053		t = types.length;
5054		while ( t-- ) {
5055			tmp = rtypenamespace.exec( types[ t ] ) || [];
5056			type = origType = tmp[ 1 ];
5057			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
5058
5059			// There *must* be a type, no attaching namespace-only handlers
5060			if ( !type ) {
5061				continue;
5062			}
5063
5064			// If event changes its type, use the special event handlers for the changed type
5065			special = jQuery.event.special[ type ] || {};
5066
5067			// If selector defined, determine special event api type, otherwise given type
5068			type = ( selector ? special.delegateType : special.bindType ) || type;
5069
5070			// Update special based on newly reset type
5071			special = jQuery.event.special[ type ] || {};
5072
5073			// handleObj is passed to all event handlers
5074			handleObj = jQuery.extend( {
5075				type: type,
5076				origType: origType,
5077				data: data,
5078				handler: handler,
5079				guid: handler.guid,
5080				selector: selector,
5081				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
5082				namespace: namespaces.join( "." )
5083			}, handleObjIn );
5084
5085			// Init the event handler queue if we're the first
5086			if ( !( handlers = events[ type ] ) ) {
5087				handlers = events[ type ] = [];
5088				handlers.delegateCount = 0;
5089
5090				// Only use addEventListener if the special events handler returns false
5091				if ( !special.setup ||
5092					special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
5093
5094					if ( elem.addEventListener ) {
5095						elem.addEventListener( type, eventHandle );
5096					}
5097				}
5098			}
5099
5100			if ( special.add ) {
5101				special.add.call( elem, handleObj );
5102
5103				if ( !handleObj.handler.guid ) {
5104					handleObj.handler.guid = handler.guid;
5105				}
5106			}
5107
5108			// Add to the element's handler list, delegates in front
5109			if ( selector ) {
5110				handlers.splice( handlers.delegateCount++, 0, handleObj );
5111			} else {
5112				handlers.push( handleObj );
5113			}
5114
5115			// Keep track of which events have ever been used, for event optimization
5116			jQuery.event.global[ type ] = true;
5117		}
5118
5119	},
5120
5121	// Detach an event or set of events from an element
5122	remove: function( elem, types, handler, selector, mappedTypes ) {
5123
5124		var j, origCount, tmp,
5125			events, t, handleObj,
5126			special, handlers, type, namespaces, origType,
5127			elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
5128
5129		if ( !elemData || !( events = elemData.events ) ) {
5130			return;
5131		}
5132
vendor: 4,172 bytes, lines 5133-5268
5133		// Once for each type.namespace in types; type may be omitted
5134		types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
5135		t = types.length;
5136		while ( t-- ) {
5137			tmp = rtypenamespace.exec( types[ t ] ) || [];
5138			type = origType = tmp[ 1 ];
5139			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
5140
5141			// Unbind all events (on this namespace, if provided) for the element
5142			if ( !type ) {
5143				for ( type in events ) {
5144					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
5145				}
5146				continue;
5147			}
5148
5149			special = jQuery.event.special[ type ] || {};
5150			type = ( selector ? special.delegateType : special.bindType ) || type;
5151			handlers = events[ type ] || [];
5152			tmp = tmp[ 2 ] &&
5153				new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
5154
5155			// Remove matching events
5156			origCount = j = handlers.length;
5157			while ( j-- ) {
5158				handleObj = handlers[ j ];
5159
5160				if ( ( mappedTypes || origType === handleObj.origType ) &&
5161					( !handler || handler.guid === handleObj.guid ) &&
5162					( !tmp || tmp.test( handleObj.namespace ) ) &&
5163					( !selector || selector === handleObj.selector ||
5164						selector === "**" && handleObj.selector ) ) {
5165					handlers.splice( j, 1 );
5166
5167					if ( handleObj.selector ) {
5168						handlers.delegateCount--;
5169					}
5170					if ( special.remove ) {
5171						special.remove.call( elem, handleObj );
5172					}
5173				}
5174			}
5175
5176			// Remove generic event handler if we removed something and no more handlers exist
5177			// (avoids potential for endless recursion during removal of special event handlers)
5178			if ( origCount && !handlers.length ) {
5179				if ( !special.teardown ||
5180					special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
5181
5182					jQuery.removeEvent( elem, type, elemData.handle );
5183				}
5184
5185				delete events[ type ];
5186			}
5187		}
5188
5189		// Remove data and the expando if it's no longer used
5190		if ( jQuery.isEmptyObject( events ) ) {
5191			dataPriv.remove( elem, "handle events" );
5192		}
5193	},
5194
5195	dispatch: function( nativeEvent ) {
5196
5197		// Make a writable jQuery.Event from the native event object
5198		var event = jQuery.event.fix( nativeEvent );
5199
5200		var i, j, ret, matched, handleObj, handlerQueue,
5201			args = new Array( arguments.length ),
5202			handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
5203			special = jQuery.event.special[ event.type ] || {};
5204
5205		// Use the fix-ed jQuery.Event rather than the (read-only) native event
5206		args[ 0 ] = event;
5207
5208		for ( i = 1; i < arguments.length; i++ ) {
5209			args[ i ] = arguments[ i ];
5210		}
5211
5212		event.delegateTarget = this;
5213
5214		// Call the preDispatch hook for the mapped type, and let it bail if desired
5215		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
5216			return;
5217		}
5218
5219		// Determine handlers
5220		handlerQueue = jQuery.event.handlers.call( this, event, handlers );
5221
5222		// Run delegates first; they may want to stop propagation beneath us
5223		i = 0;
5224		while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
5225			event.currentTarget = matched.elem;
5226
5227			j = 0;
5228			while ( ( handleObj = matched.handlers[ j++ ] ) &&
5229				!event.isImmediatePropagationStopped() ) {
5230
5231				// If the event is namespaced, then each handler is only invoked if it is
5232				// specially universal or its namespaces are a superset of the event's.
5233				if ( !event.rnamespace || handleObj.namespace === false ||
5234					event.rnamespace.test( handleObj.namespace ) ) {
5235
5236					event.handleObj = handleObj;
5237					event.data = handleObj.data;
5238
5239					ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
5240						handleObj.handler ).apply( matched.elem, args );
5241
5242					if ( ret !== undefined ) {
5243						if ( ( event.result = ret ) === false ) {
5244							event.preventDefault();
5245							event.stopPropagation();
5246						}
5247					}
5248				}
5249			}
5250		}
5251
5252		// Call the postDispatch hook for the mapped type
5253		if ( special.postDispatch ) {
5254			special.postDispatch.call( this, event );
5255		}
5256
5257		return event.result;
5258	},
5259
5260	handlers: function( event, handlers ) {
5261		var i, handleObj, sel, matchedHandlers, matchedSelectors,
5262			handlerQueue = [],
5263			delegateCount = handlers.delegateCount,
5264			cur = event.target;
5265
5266		// Find delegate handlers
5267		if ( delegateCount &&
5268
vendor: 5,718 bytes, lines 5269-5454
5269			// Support: IE <=9
5270			// Black-hole SVG <use> instance trees (trac-13180)
5271			cur.nodeType &&
5272
5273			// Support: Firefox <=42
5274			// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
5275			// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
5276			// Support: IE 11 only
5277			// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
5278			!( event.type === "click" && event.button >= 1 ) ) {
5279
5280			for ( ; cur !== this; cur = cur.parentNode || this ) {
5281
5282				// Don't check non-elements (#13208)
5283				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
5284				if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
5285					matchedHandlers = [];
5286					matchedSelectors = {};
5287					for ( i = 0; i < delegateCount; i++ ) {
5288						handleObj = handlers[ i ];
5289
5290						// Don't conflict with Object.prototype properties (#13203)
5291						sel = handleObj.selector + " ";
5292
5293						if ( matchedSelectors[ sel ] === undefined ) {
5294							matchedSelectors[ sel ] = handleObj.needsContext ?
5295								jQuery( sel, this ).index( cur ) > -1 :
5296								jQuery.find( sel, this, null, [ cur ] ).length;
5297						}
5298						if ( matchedSelectors[ sel ] ) {
5299							matchedHandlers.push( handleObj );
5300						}
5301					}
5302					if ( matchedHandlers.length ) {
5303						handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
5304					}
5305				}
5306			}
5307		}
5308
5309		// Add the remaining (directly-bound) handlers
5310		cur = this;
5311		if ( delegateCount < handlers.length ) {
5312			handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
5313		}
5314
5315		return handlerQueue;
5316	},
5317
5318	addProp: function( name, hook ) {
5319		Object.defineProperty( jQuery.Event.prototype, name, {
5320			enumerable: true,
5321			configurable: true,
5322
5323			get: isFunction( hook ) ?
5324				function() {
5325					if ( this.originalEvent ) {
5326							return hook( this.originalEvent );
5327					}
5328				} :
5329				function() {
5330					if ( this.originalEvent ) {
5331							return this.originalEvent[ name ];
5332					}
5333				},
5334
5335			set: function( value ) {
5336				Object.defineProperty( this, name, {
5337					enumerable: true,
5338					configurable: true,
5339					writable: true,
5340					value: value
5341				} );
5342			}
5343		} );
5344	},
5345
5346	fix: function( originalEvent ) {
5347		return originalEvent[ jQuery.expando ] ?
5348			originalEvent :
5349			new jQuery.Event( originalEvent );
5350	},
5351
5352	special: {
5353		load: {
5354
5355			// Prevent triggered image.load events from bubbling to window.load
5356			noBubble: true
5357		},
5358		click: {
5359
5360			// Utilize native event to ensure correct state for checkable inputs
5361			setup: function( data ) {
5362
5363				// For mutual compressibility with _default, replace `this` access with a local var.
5364				// `|| data` is dead code meant only to preserve the variable through minification.
5365				var el = this || data;
5366
5367				// Claim the first handler
5368				if ( rcheckableType.test( el.type ) &&
5369					el.click && nodeName( el, "input" ) ) {
5370
5371					// dataPriv.set( el, "click", ... )
5372					leverageNative( el, "click", returnTrue );
5373				}
5374
5375				// Return false to allow normal processing in the caller
5376				return false;
5377			},
5378			trigger: function( data ) {
5379
5380				// For mutual compressibility with _default, replace `this` access with a local var.
5381				// `|| data` is dead code meant only to preserve the variable through minification.
5382				var el = this || data;
5383
5384				// Force setup before triggering a click
5385				if ( rcheckableType.test( el.type ) &&
5386					el.click && nodeName( el, "input" ) ) {
5387
5388					leverageNative( el, "click" );
5389				}
5390
5391				// Return non-false to allow normal event-path propagation
5392				return true;
5393			},
5394
5395			// For cross-browser consistency, suppress native .click() on links
5396			// Also prevent it if we're currently inside a leveraged native-event stack
5397			_default: function( event ) {
5398				var target = event.target;
5399				return rcheckableType.test( target.type ) &&
5400					target.click && nodeName( target, "input" ) &&
5401					dataPriv.get( target, "click" ) ||
5402					nodeName( target, "a" );
5403			}
5404		},
5405
5406		beforeunload: {
5407			postDispatch: function( event ) {
5408
5409				// Support: Firefox 20+
5410				// Firefox doesn't alert if the returnValue field is not set.
5411				if ( event.result !== undefined && event.originalEvent ) {
5412					event.originalEvent.returnValue = event.result;
5413				}
5414			}
5415		}
5416	}
5417};
5418
5419// Ensure the presence of an event listener that handles manually-triggered
5420// synthetic events by interrupting progress until reinvoked in response to
5421// *native* events that it fires directly, ensuring that state changes have
5422// already occurred before other listeners are invoked.
5423function leverageNative( el, type, expectSync ) {
5424
5425	// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
5426	if ( !expectSync ) {
5427		if ( dataPriv.get( el, type ) === undefined ) {
5428			jQuery.event.add( el, type, returnTrue );
5429		}
5430		return;
5431	}
5432
5433	// Register the controller as a special universal handler for all event namespaces
5434	dataPriv.set( el, type, false );
5435	jQuery.event.add( el, type, {
5436		namespace: false,
5437		handler: function( event ) {
5438			var notAsync, result,
5439				saved = dataPriv.get( this, type );
5440
5441			if ( ( event.isTrigger & 1 ) && this[ type ] ) {
5442
5443				// Interrupt processing of the outer synthetic .trigger()ed event
5444				// Saved data should be false in such cases, but might be a leftover capture object
5445				// from an async native handler (gh-4350)
5446				if ( !saved.length ) {
5447
5448					// Store arguments for use when handling the inner native event
5449					// There will always be at least one argument (an event object), so this array
5450					// will not be confused with a leftover capture object.
5451					saved = slice.call( arguments );
5452					dataPriv.set( this, type, saved );
5453
5454					// Trigger the native event and capture its result
5455					// Support: IE <=9 - 11+
5456					// focus() and blur() are asynchronous
5457					notAsync = expectSync( this, type );
5458					this[ type ]();
5459					result = dataPriv.get( this, type );
5460					if ( saved !== result || notAsync ) {
5461						dataPriv.set( this, type, false );
5462					} else {
5463						result = {};
5464					}
5465					if ( saved !== result ) {
5466
5467						// Cancel the outer synthetic event
5468						event.stopImmediatePropagation();
5469						event.preventDefault();
5470						return result.value;
5471					}
5472
5473				// If this is an inner synthetic event for an event with a bubbling surrogate
5474				// (focus or blur), assume that the surrogate already propagated from triggering the
5475				// native event and prevent that from happening again here.
5476				// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
5477				// bubbling surrogate propagates *after* the non-bubbling base), but that seems
5478				// less bad than duplication.
5479				} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
5480					event.stopPropagation();
5481				}
5482
5483			// If this is a native event triggered above, everything is now in order
5484			// Fire an inner synthetic event with the original arguments
5485			} else if ( saved.length ) {
5486
5487				// ...and capture the result
5488				dataPriv.set( this, type, {
5489					value: jQuery.event.trigger(
5490
5491						// Support: IE <=9 - 11+
5492						// Extend with the prototype to reset the above stopImmediatePropagation()
5493						jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
5494						saved.slice( 1 ),
5495						this
5496					)
5497				} );
5498
5499				// Abort handling of the native event
5500				event.stopImmediatePropagation();
5501			}
5502		}
5503	} );
5504}
5505
5506jQuery.removeEvent = function( elem, type, handle ) {
5507
5508	// This "if" is needed for plain objects
5509	if ( elem.removeEventListener ) {
5510		elem.removeEventListener( type, handle );
5511	}
5512};
5513
5514jQuery.Event = function( src, props ) {
5515
5516	// Allow instantiation without the 'new' keyword
5517	if ( !( this instanceof jQuery.Event ) ) {
5518		return new jQuery.Event( src, props );
5519	}
5520
5521	// Event object
5522	if ( src && src.type ) {
5523		this.originalEvent = src;
5524		this.type = src.type;
5525
5526		// Events bubbling up the document may have been marked as prevented
5527		// by a handler lower down the tree; reflect the correct value.
5528		this.isDefaultPrevented = src.defaultPrevented ||
5529				src.defaultPrevented === undefined &&
5530
5531				// Support: Android <=2.3 only
5532				src.returnValue === false ?
5533			returnTrue :
5534			returnFalse;
5535
5536		// Create target properties
5537		// Support: Safari <=6 - 7 only
5538		// Target should not be a text node (#504, #13143)
5539		this.target = ( src.target && src.target.nodeType === 3 ) ?
5540			src.target.parentNode :
5541			src.target;
5542
5543		this.currentTarget = src.currentTarget;
5544		this.relatedTarget = src.relatedTarget;
5545
5546	// Event type
5547	} else {
5548		this.type = src;
5549	}
5550
5551	// Put explicitly provided properties onto the event object
5552	if ( props ) {
5553		jQuery.extend( this, props );
5554	}
5555
5556	// Create a timestamp if incoming event doesn't have one
5557	this.timeStamp = src && src.timeStamp || Date.now();
5558
5559	// Mark it as fixed
5560	this[ jQuery.expando ] = true;
5561};
5562
5563// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
5564// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
5565jQuery.Event.prototype = {
5566	constructor: jQuery.Event,
5567	isDefaultPrevented: returnFalse,
5568	isPropagationStopped: returnFalse,
5569	isImmediatePropagationStopped: returnFalse,
5570	isSimulated: false,
5571
5572	preventDefault: function() {
5573		var e = this.originalEvent;
5574
5575		this.isDefaultPrevented = returnTrue;
5576
5577		if ( e && !this.isSimulated ) {
5578			e.preventDefault();
5579		}
5580	},
5581	stopPropagation: function() {
5582		var e = this.originalEvent;
5583
5584		this.isPropagationStopped = returnTrue;
5585
5586		if ( e && !this.isSimulated ) {
5587			e.stopPropagation();
5588		}
5589	},
5590	stopImmediatePropagation: function() {
5591		var e = this.originalEvent;
5592
5593		this.isImmediatePropagationStopped = returnTrue;
5594
5595		if ( e && !this.isSimulated ) {
5596			e.stopImmediatePropagation();
5597		}
5598
5599		this.stopPropagation();
5600	}
5601};
5602
5603// Includes all common event props including KeyEvent and MouseEvent specific props
5604jQuery.each( {
5605	altKey: true,
5606	bubbles: true,
5607	cancelable: true,
5608	changedTouches: true,
5609	ctrlKey: true,
5610	detail: true,
5611	eventPhase: true,
5612	metaKey: true,
5613	pageX: true,
5614	pageY: true,
5615	shiftKey: true,
5616	view: true,
5617	"char": true,
5618	code: true,
5619	charCode: true,
5620	key: true,
5621	keyCode: true,
5622	button: true,
5623	buttons: true,
5624	clientX: true,
5625	clientY: true,
5626	offsetX: true,
5627	offsetY: true,
5628	pointerId: true,
5629	pointerType: true,
5630	screenX: true,
5631	screenY: true,
5632	targetTouches: true,
5633	toElement: true,
5634	touches: true,
5635
5636	which: function( event ) {
5637		var button = event.button;
5638
5639		// Add which for key events
5640		if ( event.which == null && rkeyEvent.test( event.type ) ) {
5641			return event.charCode != null ? event.charCode : event.keyCode;
5642		}
5643
5644		// Add which for click: 1 === left; 2 === middle; 3 === right
5645		if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
5646			if ( button & 1 ) {
5647				return 1;
5648			}
5649
5650			if ( button & 2 ) {
5651				return 3;
5652			}
5653
5654			if ( button & 4 ) {
5655				return 2;
5656			}
5657
5658			return 0;
5659		}
5660
5661		return event.which;
5662	}
5663}, jQuery.event.addProp );
5664
5665jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
5666	jQuery.event.special[ type ] = {
5667
5668		// Utilize native event if possible so blur/focus sequence is correct
5669		setup: function() {
5670
5671			// Claim the first handler
5672			// dataPriv.set( this, "focus", ... )
5673			// dataPriv.set( this, "blur", ... )
5674			leverageNative( this, type, expectSync );
5675
5676			// Return false to allow normal processing in the caller
5677			return false;
vendor: 4,563 bytes, lines 5678-5854
5678		},
5679		trigger: function() {
5680
5681			// Force setup before trigger
5682			leverageNative( this, type );
5683
5684			// Return non-false to allow normal event-path propagation
5685			return true;
5686		},
5687
5688		delegateType: delegateType
5689	};
5690} );
5691
5692// Create mouseenter/leave events using mouseover/out and event-time checks
5693// so that event delegation works in jQuery.
5694// Do the same for pointerenter/pointerleave and pointerover/pointerout
5695//
5696// Support: Safari 7 only
5697// Safari sends mouseenter too often; see:
5698// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
5699// for the description of the bug (it existed in older Chrome versions as well).
5700jQuery.each( {
5701	mouseenter: "mouseover",
5702	mouseleave: "mouseout",
5703	pointerenter: "pointerover",
5704	pointerleave: "pointerout"
5705}, function( orig, fix ) {
5706	jQuery.event.special[ orig ] = {
5707		delegateType: fix,
5708		bindType: fix,
5709
5710		handle: function( event ) {
5711			var ret,
5712				target = this,
5713				related = event.relatedTarget,
5714				handleObj = event.handleObj;
5715
5716			// For mouseenter/leave call the handler if related is outside the target.
5717			// NB: No relatedTarget if the mouse left/entered the browser window
5718			if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
5719				event.type = handleObj.origType;
5720				ret = handleObj.handler.apply( this, arguments );
5721				event.type = fix;
5722			}
5723			return ret;
5724		}
5725	};
5726} );
5727
5728jQuery.fn.extend( {
5729
5730	on: function( types, selector, data, fn ) {
5731		return on( this, types, selector, data, fn );
5732	},
5733	one: function( types, selector, data, fn ) {
5734		return on( this, types, selector, data, fn, 1 );
5735	},
5736	off: function( types, selector, fn ) {
5737		var handleObj, type;
5738		if ( types && types.preventDefault && types.handleObj ) {
5739
5740			// ( event )  dispatched jQuery.Event
5741			handleObj = types.handleObj;
5742			jQuery( types.delegateTarget ).off(
5743				handleObj.namespace ?
5744					handleObj.origType + "." + handleObj.namespace :
5745					handleObj.origType,
5746				handleObj.selector,
5747				handleObj.handler
5748			);
5749			return this;
5750		}
5751		if ( typeof types === "object" ) {
5752
5753			// ( types-object [, selector] )
5754			for ( type in types ) {
5755				this.off( type, selector, types[ type ] );
5756			}
5757			return this;
5758		}
5759		if ( selector === false || typeof selector === "function" ) {
5760
5761			// ( types [, fn] )
5762			fn = selector;
5763			selector = undefined;
5764		}
5765		if ( fn === false ) {
5766			fn = returnFalse;
5767		}
5768		return this.each( function() {
5769			jQuery.event.remove( this, types, fn, selector );
5770		} );
5771	}
5772} );
5773
5774
5775var
5776
5777	/* eslint-disable max-len */
5778
5779	// See https://github.com/eslint/eslint/issues/3229
5780	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
5781
5782	/* eslint-enable */
5783
5784	// Support: IE <=10 - 11, Edge 12 - 13 only
5785	// In IE/Edge using regex groups here causes severe slowdowns.
5786	// See https://connect.microsoft.com/IE/feedback/details/1736512/
5787	rnoInnerhtml = /<script|<style|<link/i,
5788
5789	// checked="checked" or checked
5790	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
5791	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
5792
5793// Prefer a tbody over its parent table for containing new rows
5794function manipulationTarget( elem, content ) {
5795	if ( nodeName( elem, "table" ) &&
5796		nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
5797
5798		return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
5799	}
5800
5801	return elem;
5802}
5803
5804// Replace/restore the type attribute of script elements for safe DOM manipulation
5805function disableScript( elem ) {
5806	elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
5807	return elem;
5808}
5809function restoreScript( elem ) {
5810	if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
5811		elem.type = elem.type.slice( 5 );
5812	} else {
5813		elem.removeAttribute( "type" );
5814	}
5815
5816	return elem;
5817}
5818
5819function cloneCopyEvent( src, dest ) {
5820	var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
5821
5822	if ( dest.nodeType !== 1 ) {
5823		return;
5824	}
5825
5826	// 1. Copy private data: events, handlers, etc.
5827	if ( dataPriv.hasData( src ) ) {
5828		pdataOld = dataPriv.access( src );
5829		pdataCur = dataPriv.set( dest, pdataOld );
5830		events = pdataOld.events;
5831
5832		if ( events ) {
5833			delete pdataCur.handle;
5834			pdataCur.events = {};
5835
5836			for ( type in events ) {
5837				for ( i = 0, l = events[ type ].length; i < l; i++ ) {
5838					jQuery.event.add( dest, type, events[ type ][ i ] );
5839				}
5840			}
5841		}
5842	}
5843
5844	// 2. Copy user data
5845	if ( dataUser.hasData( src ) ) {
5846		udataOld = dataUser.access( src );
5847		udataCur = jQuery.extend( {}, udataOld );
5848
5849		dataUser.set( dest, udataCur );
5850	}
5851}
5852
5853// Fix IE bugs, see support tests
5854function fixInput( src, dest ) {
vendor: 3,609 bytes, lines 5855-5982
5855	var nodeName = dest.nodeName.toLowerCase();
5856
5857	// Fails to persist the checked state of a cloned checkbox or radio button.
5858	if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
5859		dest.checked = src.checked;
5860
5861	// Fails to return the selected option to the default selected state when cloning options
5862	} else if ( nodeName === "input" || nodeName === "textarea" ) {
5863		dest.defaultValue = src.defaultValue;
5864	}
5865}
5866
5867function domManip( collection, args, callback, ignored ) {
5868
5869	// Flatten any nested arrays
5870	args = concat.apply( [], args );
5871
5872	var fragment, first, scripts, hasScripts, node, doc,
5873		i = 0,
5874		l = collection.length,
5875		iNoClone = l - 1,
5876		value = args[ 0 ],
5877		valueIsFunction = isFunction( value );
5878
5879	// We can't cloneNode fragments that contain checked, in WebKit
5880	if ( valueIsFunction ||
5881			( l > 1 && typeof value === "string" &&
5882				!support.checkClone && rchecked.test( value ) ) ) {
5883		return collection.each( function( index ) {
5884			var self = collection.eq( index );
5885			if ( valueIsFunction ) {
5886				args[ 0 ] = value.call( this, index, self.html() );
5887			}
5888			domManip( self, args, callback, ignored );
5889		} );
5890	}
5891
5892	if ( l ) {
5893		fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
5894		first = fragment.firstChild;
5895
5896		if ( fragment.childNodes.length === 1 ) {
5897			fragment = first;
5898		}
5899
5900		// Require either new content or an interest in ignored elements to invoke the callback
5901		if ( first || ignored ) {
5902			scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
5903			hasScripts = scripts.length;
5904
5905			// Use the original fragment for the last item
5906			// instead of the first because it can end up
5907			// being emptied incorrectly in certain situations (#8070).
5908			for ( ; i < l; i++ ) {
5909				node = fragment;
5910
5911				if ( i !== iNoClone ) {
5912					node = jQuery.clone( node, true, true );
5913
5914					// Keep references to cloned scripts for later restoration
5915					if ( hasScripts ) {
5916
5917						// Support: Android <=4.0 only, PhantomJS 1 only
5918						// push.apply(_, arraylike) throws on ancient WebKit
5919						jQuery.merge( scripts, getAll( node, "script" ) );
5920					}
5921				}
5922
5923				callback.call( collection[ i ], node, i );
5924			}
5925
5926			if ( hasScripts ) {
5927				doc = scripts[ scripts.length - 1 ].ownerDocument;
5928
5929				// Reenable scripts
5930				jQuery.map( scripts, restoreScript );
5931
5932				// Evaluate executable scripts on first document insertion
5933				for ( i = 0; i < hasScripts; i++ ) {
5934					node = scripts[ i ];
5935					if ( rscriptType.test( node.type || "" ) &&
5936						!dataPriv.access( node, "globalEval" ) &&
5937						jQuery.contains( doc, node ) ) {
5938
5939						if ( node.src && ( node.type || "" ).toLowerCase()  !== "module" ) {
5940
5941							// Optional AJAX dependency, but won't run scripts if not present
5942							if ( jQuery._evalUrl && !node.noModule ) {
5943								jQuery._evalUrl( node.src, {
5944									nonce: node.nonce || node.getAttribute( "nonce" )
5945								} );
5946							}
5947						} else {
5948							DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
5949						}
5950					}
5951				}
5952			}
5953		}
5954	}
5955
5956	return collection;
5957}
5958
5959function remove( elem, selector, keepData ) {
5960	var node,
5961		nodes = selector ? jQuery.filter( selector, elem ) : elem,
5962		i = 0;
5963
5964	for ( ; ( node = nodes[ i ] ) != null; i++ ) {
5965		if ( !keepData && node.nodeType === 1 ) {
5966			jQuery.cleanData( getAll( node ) );
5967		}
5968
5969		if ( node.parentNode ) {
5970			if ( keepData && isAttached( node ) ) {
5971				setGlobalEval( getAll( node, "script" ) );
5972			}
5973			node.parentNode.removeChild( node );
5974		}
5975	}
5976
5977	return elem;
5978}
5979
5980jQuery.extend( {
5981	htmlPrefilter: function( html ) {
5982		return html.replace( rxhtmlTag, "<$1></$2>" )
vendor: 2,889 bytes, lines 5982-6091
5982;
5983	},
5984
5985	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
5986		var i, l, srcElements, destElements,
5987			clone = elem.cloneNode( true ),
5988			inPage = isAttached( elem );
5989
5990		// Fix IE cloning issues
5991		if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
5992				!jQuery.isXMLDoc( elem ) ) {
5993
5994			// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
5995			destElements = getAll( clone );
5996			srcElements = getAll( elem );
5997
5998			for ( i = 0, l = srcElements.length; i < l; i++ ) {
5999				fixInput( srcElements[ i ], destElements[ i ] );
6000			}
6001		}
6002
6003		// Copy the events from the original to the clone
6004		if ( dataAndEvents ) {
6005			if ( deepDataAndEvents ) {
6006				srcElements = srcElements || getAll( elem );
6007				destElements = destElements || getAll( clone );
6008
6009				for ( i = 0, l = srcElements.length; i < l; i++ ) {
6010					cloneCopyEvent( srcElements[ i ], destElements[ i ] );
6011				}
6012			} else {
6013				cloneCopyEvent( elem, clone );
6014			}
6015		}
6016
6017		// Preserve script evaluation history
6018		destElements = getAll( clone, "script" );
6019		if ( destElements.length > 0 ) {
6020			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
6021		}
6022
6023		// Return the cloned set
6024		return clone;
6025	},
6026
6027	cleanData: function( elems ) {
6028		var data, elem, type,
6029			special = jQuery.event.special,
6030			i = 0;
6031
6032		for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
6033			if ( acceptData( elem ) ) {
6034				if ( ( data = elem[ dataPriv.expando ] ) ) {
6035					if ( data.events ) {
6036						for ( type in data.events ) {
6037							if ( special[ type ] ) {
6038								jQuery.event.remove( elem, type );
6039
6040							// This is a shortcut to avoid jQuery.event.remove's overhead
6041							} else {
6042								jQuery.removeEvent( elem, type, data.handle );
6043							}
6044						}
6045					}
6046
6047					// Support: Chrome <=35 - 45+
6048					// Assign undefined instead of using delete, see Data#remove
6049					elem[ dataPriv.expando ] = undefined;
6050				}
6051				if ( elem[ dataUser.expando ] ) {
6052
6053					// Support: Chrome <=35 - 45+
6054					// Assign undefined instead of using delete, see Data#remove
6055					elem[ dataUser.expando ] = undefined;
6056				}
6057			}
6058		}
6059	}
6060} );
6061
6062jQuery.fn.extend( {
6063	detach: function( selector ) {
6064		return remove( this, selector, true );
6065	},
6066
6067	remove: function( selector ) {
6068		return remove( this, selector );
6069	},
6070
6071	text: function( value ) {
6072		return access( this, function( value ) {
6073			return value === undefined ?
6074				jQuery.text( this ) :
6075				this.empty().each( function() {
6076					if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6077						this.textContent = value;
6078					}
6079				} );
6080		}, null, value, arguments.length );
6081	},
6082
6083	append: function() {
6084		return domManip( this, arguments, function( elem ) {
6085			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6086				var target = manipulationTarget( this, elem );
6087				target.appendChild( elem );
6088			}
6089		} );
6090	},
6091
vendor: 5,129 bytes, lines 6092-6284
6092	prepend: function() {
6093		return domManip( this, arguments, function( elem ) {
6094			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6095				var target = manipulationTarget( this, elem );
6096				target.insertBefore( elem, target.firstChild );
6097			}
6098		} );
6099	},
6100
6101	before: function() {
6102		return domManip( this, arguments, function( elem ) {
6103			if ( this.parentNode ) {
6104				this.parentNode.insertBefore( elem, this );
6105			}
6106		} );
6107	},
6108
6109	after: function() {
6110		return domManip( this, arguments, function( elem ) {
6111			if ( this.parentNode ) {
6112				this.parentNode.insertBefore( elem, this.nextSibling );
6113			}
6114		} );
6115	},
6116
6117	empty: function() {
6118		var elem,
6119			i = 0;
6120
6121		for ( ; ( elem = this[ i ] ) != null; i++ ) {
6122			if ( elem.nodeType === 1 ) {
6123
6124				// Prevent memory leaks
6125				jQuery.cleanData( getAll( elem, false ) );
6126
6127				// Remove any remaining nodes
6128				elem.textContent = "";
6129			}
6130		}
6131
6132		return this;
6133	},
6134
6135	clone: function( dataAndEvents, deepDataAndEvents ) {
6136		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
6137		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
6138
6139		return this.map( function() {
6140			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
6141		} );
6142	},
6143
6144	html: function( value ) {
6145		return access( this, function( value ) {
6146			var elem = this[ 0 ] || {},
6147				i = 0,
6148				l = this.length;
6149
6150			if ( value === undefined && elem.nodeType === 1 ) {
6151				return elem.innerHTML;
6152			}
6153
6154			// See if we can take a shortcut and just use innerHTML
6155			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
6156				!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
6157
6158				value = jQuery.htmlPrefilter( value );
6159
6160				try {
6161					for ( ; i < l; i++ ) {
6162						elem = this[ i ] || {};
6163
6164						// Remove element nodes and prevent memory leaks
6165						if ( elem.nodeType === 1 ) {
6166							jQuery.cleanData( getAll( elem, false ) );
6167							elem.innerHTML = value;
6168						}
6169					}
6170
6171					elem = 0;
6172
6173				// If using innerHTML throws an exception, use the fallback method
6174				} catch ( e ) {}
6175			}
6176
6177			if ( elem ) {
6178				this.empty().append( value );
6179			}
6180		}, null, value, arguments.length );
6181	},
6182
6183	replaceWith: function() {
6184		var ignored = [];
6185
6186		// Make the changes, replacing each non-ignored context element with the new content
6187		return domManip( this, arguments, function( elem ) {
6188			var parent = this.parentNode;
6189
6190			if ( jQuery.inArray( this, ignored ) < 0 ) {
6191				jQuery.cleanData( getAll( this ) );
6192				if ( parent ) {
6193					parent.replaceChild( elem, this );
6194				}
6195			}
6196
6197		// Force callback invocation
6198		}, ignored );
6199	}
6200} );
6201
6202jQuery.each( {
6203	appendTo: "append",
6204	prependTo: "prepend",
6205	insertBefore: "before",
6206	insertAfter: "after",
6207	replaceAll: "replaceWith"
6208}, function( name, original ) {
6209	jQuery.fn[ name ] = function( selector ) {
6210		var elems,
6211			ret = [],
6212			insert = jQuery( selector ),
6213			last = insert.length - 1,
6214			i = 0;
6215
6216		for ( ; i <= last; i++ ) {
6217			elems = i === last ? this : this.clone( true );
6218			jQuery( insert[ i ] )[ original ]( elems );
6219
6220			// Support: Android <=4.0 only, PhantomJS 1 only
6221			// .get() because push.apply(_, arraylike) throws on ancient WebKit
6222			push.apply( ret, elems.get() );
6223		}
6224
6225		return this.pushStack( ret );
6226	};
6227} );
6228var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
6229
6230var getStyles = function( elem ) {
6231
6232		// Support: IE <=11 only, Firefox <=30 (#15098, #14150)
6233		// IE throws on elements created in popups
6234		// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
6235		var view = elem.ownerDocument.defaultView;
6236
6237		if ( !view || !view.opener ) {
6238			view = window;
6239		}
6240
6241		return view.getComputedStyle( elem );
6242	};
6243
6244var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
6245
6246
6247
6248( function() {
6249
6250	// Executing both pixelPosition & boxSizingReliable tests require only one layout
6251	// so they're executed at the same time to save the second computation.
6252	function computeStyleTests() {
6253
6254		// This is a singleton, we need to execute it only once
6255		if ( !div ) {
6256			return;
6257		}
6258
6259		container.style.cssText = "position:absolute;left:-11111px;width:60px;" +
6260			"margin-top:1px;padding:0;border:0";
6261		div.style.cssText =
6262			"position:relative;display:block;box-sizing:border-box;overflow:scroll;" +
6263			"margin:auto;border:1px;padding:1px;" +
6264			"width:60%;top:1%";
6265		documentElement.appendChild( container ).appendChild( div );
6266
6267		var divStyle = window.getComputedStyle( div );
6268		pixelPositionVal = divStyle.top !== "1%";
6269
6270		// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
6271		reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;
6272
6273		// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
6274		// Some styles come back with percentage values, even though they shouldn't
6275		div.style.right = "60%";
6276		pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;
6277
6278		// Support: IE 9 - 11 only
6279		// Detect misreporting of content dimensions for box-sizing:border-box elements
6280		boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;
6281
6282		// Support: IE 9 only
6283		// Detect overflow:scroll screwiness (gh-3699)
6284		
vendor: 8,298 bytes, lines 6284-6574
6284// Support: Chrome <=64
6285		// Don't get tricked when zoom affects offsetWidth (gh-4029)
6286		div.style.position = "absolute";
6287		scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;
6288
6289		documentElement.removeChild( container );
6290
6291		// Nullify the div so it wouldn't be stored in the memory and
6292		// it will also be a sign that checks already performed
6293		div = null;
6294	}
6295
6296	function roundPixelMeasures( measure ) {
6297		return Math.round( parseFloat( measure ) );
6298	}
6299
6300	var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
6301		reliableMarginLeftVal,
6302		container = document.createElement( "div" ),
6303		div = document.createElement( "div" );
6304
6305	// Finish early in limited (non-browser) environments
6306	if ( !div.style ) {
6307		return;
6308	}
6309
6310	// Support: IE <=9 - 11 only
6311	// Style of cloned element affects source element cloned (#8908)
6312	div.style.backgroundClip = "content-box";
6313	div.cloneNode( true ).style.backgroundClip = "";
6314	support.clearCloneStyle = div.style.backgroundClip === "content-box";
6315
6316	jQuery.extend( support, {
6317		boxSizingReliable: function() {
6318			computeStyleTests();
6319			return boxSizingReliableVal;
6320		},
6321		pixelBoxStyles: function() {
6322			computeStyleTests();
6323			return pixelBoxStylesVal;
6324		},
6325		pixelPosition: function() {
6326			computeStyleTests();
6327			return pixelPositionVal;
6328		},
6329		reliableMarginLeft: function() {
6330			computeStyleTests();
6331			return reliableMarginLeftVal;
6332		},
6333		scrollboxSize: function() {
6334			computeStyleTests();
6335			return scrollboxSizeVal;
6336		}
6337	} );
6338} )();
6339
6340
6341function curCSS( elem, name, computed ) {
6342	var width, minWidth, maxWidth, ret,
6343
6344		// Support: Firefox 51+
6345		// Retrieving style before computed somehow
6346		// fixes an issue with getting wrong values
6347		// on detached elements
6348		style = elem.style;
6349
6350	computed = computed || getStyles( elem );
6351
6352	// getPropertyValue is needed for:
6353	//   .css('filter') (IE 9 only, #12537)
6354	//   .css('--customProperty) (#3144)
6355	if ( computed ) {
6356		ret = computed.getPropertyValue( name ) || computed[ name ];
6357
6358		if ( ret === "" && !isAttached( elem ) ) {
6359			ret = jQuery.style( elem, name );
6360		}
6361
6362		// A tribute to the "awesome hack by Dean Edwards"
6363		// Android Browser returns percentage for some values,
6364		// but width seems to be reliably pixels.
6365		// This is against the CSSOM draft spec:
6366		// https://drafts.csswg.org/cssom/#resolved-values
6367		if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {
6368
6369			// Remember the original values
6370			width = style.width;
6371			minWidth = style.minWidth;
6372			maxWidth = style.maxWidth;
6373
6374			// Put in the new values to get a computed value out
6375			style.minWidth = style.maxWidth = style.width = ret;
6376			ret = computed.width;
6377
6378			// Revert the changed values
6379			style.width = width;
6380			style.minWidth = minWidth;
6381			style.maxWidth = maxWidth;
6382		}
6383	}
6384
6385	return ret !== undefined ?
6386
6387		// Support: IE <=9 - 11 only
6388		// IE returns zIndex value as an integer.
6389		ret + "" :
6390		ret;
6391}
6392
6393
6394function addGetHookIf( conditionFn, hookFn ) {
6395
6396	// Define the hook, we'll check on the first run if it's really needed.
6397	return {
6398		get: function() {
6399			if ( conditionFn() ) {
6400
6401				// Hook not needed (or it's not possible to use it due
6402				// to missing dependency), remove it.
6403				delete this.get;
6404				return;
6405			}
6406
6407			// Hook needed; redefine it so that the support test is not executed again.
6408			return ( this.get = hookFn ).apply( this, arguments );
6409		}
6410	};
6411}
6412
6413
6414var cssPrefixes = [ "Webkit", "Moz", "ms" ],
6415	emptyStyle = document.createElement( "div" ).style,
6416	vendorProps = {};
6417
6418// Return a vendor-prefixed property or undefined
6419function vendorPropName( name ) {
6420
6421	// Check for vendor prefixed names
6422	var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
6423		i = cssPrefixes.length;
6424
6425	while ( i-- ) {
6426		name = cssPrefixes[ i ] + capName;
6427		if ( name in emptyStyle ) {
6428			return name;
6429		}
6430	}
6431}
6432
6433// Return a potentially-mapped jQuery.cssProps or vendor prefixed property
6434function finalPropName( name ) {
6435	var final = jQuery.cssProps[ name ] || vendorProps[ name ];
6436
6437	if ( final ) {
6438		return final;
6439	}
6440	if ( name in emptyStyle ) {
6441		return name;
6442	}
6443	return vendorProps[ name ] = vendorPropName( name ) || name;
6444}
6445
6446
6447var
6448
6449	// Swappable if display is none or starts with table
6450	// except "table", "table-cell", or "table-caption"
6451	// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
6452	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
6453	rcustomProp = /^--/,
6454	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
6455	cssNormalTransform = {
6456		letterSpacing: "0",
6457		fontWeight: "400"
6458	};
6459
6460function setPositiveNumber( elem, value, subtract ) {
6461
6462	// Any relative (+/-) values have already been
6463	// normalized at this point
6464	var matches = rcssNum.exec( value );
6465	return matches ?
6466
6467		// Guard against undefined "subtract", e.g., when used as in cssHooks
6468		Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
6469		value;
6470}
6471
6472function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
6473	var i = dimension === "width" ? 1 : 0,
6474		extra = 0,
6475		delta = 0;
6476
6477	// Adjustment may not be necessary
6478	if ( box === ( isBorderBox ? "border" : "content" ) ) {
6479		return 0;
6480	}
6481
6482	for ( ; i < 4; i += 2 ) {
6483
6484		// Both box models exclude margin
6485		if ( box === "margin" ) {
6486			delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
6487		}
6488
6489		// If we get here with a content-box, we're seeking "padding" or "border" or "margin"
6490		if ( !isBorderBox ) {
6491
6492			// Add padding
6493			delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
6494
6495			// For "border" or "margin", add border
6496			if ( box !== "padding" ) {
6497				delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6498
6499			// But still keep track of it otherwise
6500			} else {
6501				extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6502			}
6503
6504		// If we get here with a border-box (content + padding + border), we're seeking "content" or
6505		// "padding" or "margin"
6506		} else {
6507
6508			// For "content", subtract padding
6509			if ( box === "content" ) {
6510				delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
6511			}
6512
6513			// For "content" or "padding", subtract border
6514			if ( box !== "margin" ) {
6515				delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6516			}
6517		}
6518	}
6519
6520	// Account for positive content-box scroll gutter when requested by providing computedVal
6521	if ( !isBorderBox && computedVal >= 0 ) {
6522
6523		// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
6524		// Assuming integer scroll gutter, subtract the rest and round down
6525		delta += Math.max( 0, Math.ceil(
6526			elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
6527			computedVal -
6528			delta -
6529			extra -
6530			0.5
6531
6532		// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
6533		// Use an explicit zero to avoid NaN (gh-3964)
6534		) ) || 0;
6535	}
6536
6537	return delta;
6538}
6539
6540function getWidthOrHeight( elem, dimension, extra ) {
6541
6542	// Start with computed style
6543	var styles = getStyles( elem ),
6544
6545		// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).
6546		// Fake content-box until we know it's needed to know the true value.
6547		boxSizingNeeded = !support.boxSizingReliable() || extra,
6548		isBorderBox = boxSizingNeeded &&
6549			jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
6550		valueIsBorderBox = isBorderBox,
6551
6552		val = curCSS( elem, dimension, styles ),
6553		offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );
6554
6555	// Support: Firefox <=54
6556	// Return a confounding non-pixel value or feign ignorance, as appropriate.
6557	if ( rnumnonpx.test( val ) ) {
6558		if ( !extra ) {
6559			return val;
6560		}
6561		val = "auto";
6562	}
6563
6564
6565	// Fall back to offsetWidth/offsetHeight when value is "auto"
6566	// This happens for inline elements with no explicit setting (gh-3571)
6567	// Support: Android <=4.1 - 4.3 only
6568	// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
6569	// Support: IE 9-11 only
6570	// Also use offsetWidth/offsetHeight for when box sizing is unreliable
6571	// We use getClientRects() to check for hidden/disconnected.
6572	// In those cases, the computed value can be trusted to be border-box
6573	if ( ( !support.boxSizingReliable() && isBorderBox ||
6574		val === "auto" ||
vendor: 3,698 bytes, lines 6575-6705
6575		!parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&
6576		elem.getClientRects().length ) {
6577
6578		isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
6579
6580		// Where available, offsetWidth/offsetHeight approximate border box dimensions.
6581		// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the
6582		// retrieved value as a content box dimension.
6583		valueIsBorderBox = offsetProp in elem;
6584		if ( valueIsBorderBox ) {
6585			val = elem[ offsetProp ];
6586		}
6587	}
6588
6589	// Normalize "" and auto
6590	val = parseFloat( val ) || 0;
6591
6592	// Adjust for the element's box model
6593	return ( val +
6594		boxModelAdjustment(
6595			elem,
6596			dimension,
6597			extra || ( isBorderBox ? "border" : "content" ),
6598			valueIsBorderBox,
6599			styles,
6600
6601			// Provide the current computed size to request scroll gutter calculation (gh-3589)
6602			val
6603		)
6604	) + "px";
6605}
6606
6607jQuery.extend( {
6608
6609	// Add in style property hooks for overriding the default
6610	// behavior of getting and setting a style property
6611	cssHooks: {
6612		opacity: {
6613			get: function( elem, computed ) {
6614				if ( computed ) {
6615
6616					// We should always get a number back from opacity
6617					var ret = curCSS( elem, "opacity" );
6618					return ret === "" ? "1" : ret;
6619				}
6620			}
6621		}
6622	},
6623
6624	// Don't automatically add "px" to these possibly-unitless properties
6625	cssNumber: {
6626		"animationIterationCount": true,
6627		"columnCount": true,
6628		"fillOpacity": true,
6629		"flexGrow": true,
6630		"flexShrink": true,
6631		"fontWeight": true,
6632		"gridArea": true,
6633		"gridColumn": true,
6634		"gridColumnEnd": true,
6635		"gridColumnStart": true,
6636		"gridRow": true,
6637		"gridRowEnd": true,
6638		"gridRowStart": true,
6639		"lineHeight": true,
6640		"opacity": true,
6641		"order": true,
6642		"orphans": true,
6643		"widows": true,
6644		"zIndex": true,
6645		"zoom": true
6646	},
6647
6648	// Add in properties whose names you wish to fix before
6649	// setting or getting the value
6650	cssProps: {},
6651
6652	// Get and set the style property on a DOM Node
6653	style: function( elem, name, value, extra ) {
6654
6655		// Don't set styles on text and comment nodes
6656		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
6657			return;
6658		}
6659
6660		// Make sure that we're working with the right name
6661		var ret, type, hooks,
6662			origName = camelCase( name ),
6663			isCustomProp = rcustomProp.test( name ),
6664			style = elem.style;
6665
6666		// Make sure that we're working with the right name. We don't
6667		// want to query the value if it is a CSS custom property
6668		// since they are user-defined.
6669		if ( !isCustomProp ) {
6670			name = finalPropName( origName );
6671		}
6672
6673		// Gets hook for the prefixed version, then unprefixed version
6674		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6675
6676		// Check if we're setting a value
6677		if ( value !== undefined ) {
6678			type = typeof value;
6679
6680			// Convert "+=" or "-=" to relative numbers (#7345)
6681			if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
6682				value = adjustCSS( elem, name, ret );
6683
6684				// Fixes bug #9237
6685				type = "number";
6686			}
6687
6688			// Make sure that null and NaN values aren't set (#7116)
6689			if ( value == null || value !== value ) {
6690				return;
6691			}
6692
6693			// If a number was passed in, add the unit (except for certain CSS properties)
6694			// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append
6695			// "px" to a few hardcoded values.
6696			if ( type === "number" && !isCustomProp ) {
6697				value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
6698			}
6699
6700			// background-* props affect original clone's values
6701			if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
6702				style[ name ] = "inherit";
6703			}
6704
6705			// If a hook was provided, use that value, otherwise just set the specified value
vendor: 7,976 bytes, lines 6706-6988
6706			if ( !hooks || !( "set" in hooks ) ||
6707				( value = hooks.set( elem, value, extra ) ) !== undefined ) {
6708
6709				if ( isCustomProp ) {
6710					style.setProperty( name, value );
6711				} else {
6712					style[ name ] = value;
6713				}
6714			}
6715
6716		} else {
6717
6718			// If a hook was provided get the non-computed value from there
6719			if ( hooks && "get" in hooks &&
6720				( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
6721
6722				return ret;
6723			}
6724
6725			// Otherwise just get the value from the style object
6726			return style[ name ];
6727		}
6728	},
6729
6730	css: function( elem, name, extra, styles ) {
6731		var val, num, hooks,
6732			origName = camelCase( name ),
6733			isCustomProp = rcustomProp.test( name );
6734
6735		// Make sure that we're working with the right name. We don't
6736		// want to modify the value if it is a CSS custom property
6737		// since they are user-defined.
6738		if ( !isCustomProp ) {
6739			name = finalPropName( origName );
6740		}
6741
6742		// Try prefixed name followed by the unprefixed name
6743		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6744
6745		// If a hook was provided get the computed value from there
6746		if ( hooks && "get" in hooks ) {
6747			val = hooks.get( elem, true, extra );
6748		}
6749
6750		// Otherwise, if a way to get the computed value exists, use that
6751		if ( val === undefined ) {
6752			val = curCSS( elem, name, styles );
6753		}
6754
6755		// Convert "normal" to computed value
6756		if ( val === "normal" && name in cssNormalTransform ) {
6757			val = cssNormalTransform[ name ];
6758		}
6759
6760		// Make numeric if forced or a qualifier was provided and val looks numeric
6761		if ( extra === "" || extra ) {
6762			num = parseFloat( val );
6763			return extra === true || isFinite( num ) ? num || 0 : val;
6764		}
6765
6766		return val;
6767	}
6768} );
6769
6770jQuery.each( [ "height", "width" ], function( i, dimension ) {
6771	jQuery.cssHooks[ dimension ] = {
6772		get: function( elem, computed, extra ) {
6773			if ( computed ) {
6774
6775				// Certain elements can have dimension info if we invisibly show them
6776				// but it must have a current display style that would benefit
6777				return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
6778
6779					// Support: Safari 8+
6780					// Table columns in Safari have non-zero offsetWidth & zero
6781					// getBoundingClientRect().width unless display is changed.
6782					// Support: IE <=11 only
6783					// Running getBoundingClientRect on a disconnected node
6784					// in IE throws an error.
6785					( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
6786						swap( elem, cssShow, function() {
6787							return getWidthOrHeight( elem, dimension, extra );
6788						} ) :
6789						getWidthOrHeight( elem, dimension, extra );
6790			}
6791		},
6792
6793		set: function( elem, value, extra ) {
6794			var matches,
6795				styles = getStyles( elem ),
6796
6797				// Only read styles.position if the test has a chance to fail
6798				// to avoid forcing a reflow.
6799				scrollboxSizeBuggy = !support.scrollboxSize() &&
6800					styles.position === "absolute",
6801
6802				// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)
6803				boxSizingNeeded = scrollboxSizeBuggy || extra,
6804				isBorderBox = boxSizingNeeded &&
6805					jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
6806				subtract = extra ?
6807					boxModelAdjustment(
6808						elem,
6809						dimension,
6810						extra,
6811						isBorderBox,
6812						styles
6813					) :
6814					0;
6815
6816			// Account for unreliable border-box dimensions by comparing offset* to computed and
6817			// faking a content-box to get border and padding (gh-3699)
6818			if ( isBorderBox && scrollboxSizeBuggy ) {
6819				subtract -= Math.ceil(
6820					elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
6821					parseFloat( styles[ dimension ] ) -
6822					boxModelAdjustment( elem, dimension, "border", false, styles ) -
6823					0.5
6824				);
6825			}
6826
6827			// Convert to pixels if value adjustment is needed
6828			if ( subtract && ( matches = rcssNum.exec( value ) ) &&
6829				( matches[ 3 ] || "px" ) !== "px" ) {
6830
6831				elem.style[ dimension ] = value;
6832				value = jQuery.css( elem, dimension );
6833			}
6834
6835			return setPositiveNumber( elem, value, subtract );
6836		}
6837	};
6838} );
6839
6840jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
6841	function( elem, computed ) {
6842		if ( computed ) {
6843			return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
6844				elem.getBoundingClientRect().left -
6845					swap( elem, { marginLeft: 0 }, function() {
6846						return elem.getBoundingClientRect().left;
6847					} )
6848				) + "px";
6849		}
6850	}
6851);
6852
6853// These hooks are used by animate to expand properties
6854jQuery.each( {
6855	margin: "",
6856	padding: "",
6857	border: "Width"
6858}, function( prefix, suffix ) {
6859	jQuery.cssHooks[ prefix + suffix ] = {
6860		expand: function( value ) {
6861			var i = 0,
6862				expanded = {},
6863
6864				// Assumes a single number if not a string
6865				parts = typeof value === "string" ? value.split( " " ) : [ value ];
6866
6867			for ( ; i < 4; i++ ) {
6868				expanded[ prefix + cssExpand[ i ] + suffix ] =
6869					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
6870			}
6871
6872			return expanded;
6873		}
6874	};
6875
6876	if ( prefix !== "margin" ) {
6877		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
6878	}
6879} );
6880
6881jQuery.fn.extend( {
6882	css: function( name, value ) {
6883		return access( this, function( elem, name, value ) {
6884			var styles, len,
6885				map = {},
6886				i = 0;
6887
6888			if ( Array.isArray( name ) ) {
6889				styles = getStyles( elem );
6890				len = name.length;
6891
6892				for ( ; i < len; i++ ) {
6893					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6894				}
6895
6896				return map;
6897			}
6898
6899			return value !== undefined ?
6900				jQuery.style( elem, name, value ) :
6901				jQuery.css( elem, name );
6902		}, name, value, arguments.length > 1 );
6903	}
6904} );
6905
6906
6907function Tween( elem, options, prop, end, easing ) {
6908	return new Tween.prototype.init( elem, options, prop, end, easing );
6909}
6910jQuery.Tween = Tween;
6911
6912Tween.prototype = {
6913	constructor: Tween,
6914	init: function( elem, options, prop, end, easing, unit ) {
6915		this.elem = elem;
6916		this.prop = prop;
6917		this.easing = easing || jQuery.easing._default;
6918		this.options = options;
6919		this.start = this.now = this.cur();
6920		this.end = end;
6921		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
6922	},
6923	cur: function() {
6924		var hooks = Tween.propHooks[ this.prop ];
6925
6926		return hooks && hooks.get ?
6927			hooks.get( this ) :
6928			Tween.propHooks._default.get( this );
6929	},
6930	run: function( percent ) {
6931		var eased,
6932			hooks = Tween.propHooks[ this.prop ];
6933
6934		if ( this.options.duration ) {
6935			this.pos = eased = jQuery.easing[ this.easing ](
6936				percent, this.options.duration * percent, 0, 1, this.options.duration
6937			);
6938		} else {
6939			this.pos = eased = percent;
6940		}
6941		this.now = ( this.end - this.start ) * eased + this.start;
6942
6943		if ( this.options.step ) {
6944			this.options.step.call( this.elem, this.now, this );
6945		}
6946
6947		if ( hooks && hooks.set ) {
6948			hooks.set( this );
6949		} else {
6950			Tween.propHooks._default.set( this );
6951		}
6952		return this;
6953	}
6954};
6955
6956Tween.prototype.init.prototype = Tween.prototype;
6957
6958Tween.propHooks = {
6959	_default: {
6960		get: function( tween ) {
6961			var result;
6962
6963			// Use a property on the element directly when it is not a DOM element,
6964			// or when there is no matching style property that exists.
6965			if ( tween.elem.nodeType !== 1 ||
6966				tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
6967				return tween.elem[ tween.prop ];
6968			}
6969
6970			// Passing an empty string as a 3rd parameter to .css will automatically
6971			// attempt a parseFloat and fallback to a string if the parse fails.
6972			// Simple values such as "10px" are parsed to Float;
6973			// complex values such as "rotate(1rad)" are returned as-is.
6974			result = jQuery.css( tween.elem, tween.prop, "" );
6975
6976			// Empty strings, null, undefined and "auto" are converted to 0.
6977			return !result || result === "auto" ? 0 : result;
6978		},
6979		set: function( tween ) {
6980
6981			// Use step hook for back compat.
6982			// Use cssHook if its there.
6983			// Use .style if available and use plain properties where available.
6984			if ( jQuery.fx.step[ tween.prop ] ) {
6985				jQuery.fx.step[ tween.prop ]( tween );
6986			} else if ( tween.elem.nodeType === 1 && (
6987					jQuery.cssHooks[ tween.prop ] ||
6988					tween.elem.style[ finalPropName( tween.prop ) ] != null
vendor: 29,107 bytes, lines 6988-8185
6988 ) ) {
6989				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
6990			} else {
6991				tween.elem[ tween.prop ] = tween.now;
6992			}
6993		}
6994	}
6995};
6996
6997// Support: IE <=9 only
6998// Panic based approach to setting things on disconnected nodes
6999Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
7000	set: function( tween ) {
7001		if ( tween.elem.nodeType && tween.elem.parentNode ) {
7002			tween.elem[ tween.prop ] = tween.now;
7003		}
7004	}
7005};
7006
7007jQuery.easing = {
7008	linear: function( p ) {
7009		return p;
7010	},
7011	swing: function( p ) {
7012		return 0.5 - Math.cos( p * Math.PI ) / 2;
7013	},
7014	_default: "swing"
7015};
7016
7017jQuery.fx = Tween.prototype.init;
7018
7019// Back compat <1.8 extension point
7020jQuery.fx.step = {};
7021
7022
7023
7024
7025var
7026	fxNow, inProgress,
7027	rfxtypes = /^(?:toggle|show|hide)$/,
7028	rrun = /queueHooks$/;
7029
7030function schedule() {
7031	if ( inProgress ) {
7032		if ( document.hidden === false && window.requestAnimationFrame ) {
7033			window.requestAnimationFrame( schedule );
7034		} else {
7035			window.setTimeout( schedule, jQuery.fx.interval );
7036		}
7037
7038		jQuery.fx.tick();
7039	}
7040}
7041
7042// Animations created synchronously will run synchronously
7043function createFxNow() {
7044	window.setTimeout( function() {
7045		fxNow = undefined;
7046	} );
7047	return ( fxNow = Date.now() );
7048}
7049
7050// Generate parameters to create a standard animation
7051function genFx( type, includeWidth ) {
7052	var which,
7053		i = 0,
7054		attrs = { height: type };
7055
7056	// If we include width, step value is 1 to do all cssExpand values,
7057	// otherwise step value is 2 to skip over Left and Right
7058	includeWidth = includeWidth ? 1 : 0;
7059	for ( ; i < 4; i += 2 - includeWidth ) {
7060		which = cssExpand[ i ];
7061		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
7062	}
7063
7064	if ( includeWidth ) {
7065		attrs.opacity = attrs.width = type;
7066	}
7067
7068	return attrs;
7069}
7070
7071function createTween( value, prop, animation ) {
7072	var tween,
7073		collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
7074		index = 0,
7075		length = collection.length;
7076	for ( ; index < length; index++ ) {
7077		if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
7078
7079			// We're done with this property
7080			return tween;
7081		}
7082	}
7083}
7084
7085function defaultPrefilter( elem, props, opts ) {
7086	var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
7087		isBox = "width" in props || "height" in props,
7088		anim = this,
7089		orig = {},
7090		style = elem.style,
7091		hidden = elem.nodeType && isHiddenWithinTree( elem ),
7092		dataShow = dataPriv.get( elem, "fxshow" );
7093
7094	// Queue-skipping animations hijack the fx hooks
7095	if ( !opts.queue ) {
7096		hooks = jQuery._queueHooks( elem, "fx" );
7097		if ( hooks.unqueued == null ) {
7098			hooks.unqueued = 0;
7099			oldfire = hooks.empty.fire;
7100			hooks.empty.fire = function() {
7101				if ( !hooks.unqueued ) {
7102					oldfire();
7103				}
7104			};
7105		}
7106		hooks.unqueued++;
7107
7108		anim.always( function() {
7109
7110			// Ensure the complete handler is called before this completes
7111			anim.always( function() {
7112				hooks.unqueued--;
7113				if ( !jQuery.queue( elem, "fx" ).length ) {
7114					hooks.empty.fire();
7115				}
7116			} );
7117		} );
7118	}
7119
7120	// Detect show/hide animations
7121	for ( prop in props ) {
7122		value = props[ prop ];
7123		if ( rfxtypes.test( value ) ) {
7124			delete props[ prop ];
7125			toggle = toggle || value === "toggle";
7126			if ( value === ( hidden ? "hide" : "show" ) ) {
7127
7128				// Pretend to be hidden if this is a "show" and
7129				// there is still data from a stopped show/hide
7130				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
7131					hidden = true;
7132
7133				// Ignore all other no-op show/hide data
7134				} else {
7135					continue;
7136				}
7137			}
7138			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
7139		}
7140	}
7141
7142	// Bail out if this is a no-op like .hide().hide()
7143	propTween = !jQuery.isEmptyObject( props );
7144	if ( !propTween && jQuery.isEmptyObject( orig ) ) {
7145		return;
7146	}
7147
7148	// Restrict "overflow" and "display" styles during box animations
7149	if ( isBox && elem.nodeType === 1 ) {
7150
7151		// Support: IE <=9 - 11, Edge 12 - 15
7152		// Record all 3 overflow attributes because IE does not infer the shorthand
7153		// from identically-valued overflowX and overflowY and Edge just mirrors
7154		// the overflowX value there.
7155		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
7156
7157		// Identify a display type, preferring old show/hide data over the CSS cascade
7158		restoreDisplay = dataShow && dataShow.display;
7159		if ( restoreDisplay == null ) {
7160			restoreDisplay = dataPriv.get( elem, "display" );
7161		}
7162		display = jQuery.css( elem, "display" );
7163		if ( display === "none" ) {
7164			if ( restoreDisplay ) {
7165				display = restoreDisplay;
7166			} else {
7167
7168				// Get nonempty value(s) by temporarily forcing visibility
7169				showHide( [ elem ], true );
7170				restoreDisplay = elem.style.display || restoreDisplay;
7171				display = jQuery.css( elem, "display" );
7172				showHide( [ elem ] );
7173			}
7174		}
7175
7176		// Animate inline elements as inline-block
7177		if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
7178			if ( jQuery.css( elem, "float" ) === "none" ) {
7179
7180				// Restore the original display value at the end of pure show/hide animations
7181				if ( !propTween ) {
7182					anim.done( function() {
7183						style.display = restoreDisplay;
7184					} );
7185					if ( restoreDisplay == null ) {
7186						display = style.display;
7187						restoreDisplay = display === "none" ? "" : display;
7188					}
7189				}
7190				style.display = "inline-block";
7191			}
7192		}
7193	}
7194
7195	if ( opts.overflow ) {
7196		style.overflow = "hidden";
7197		anim.always( function() {
7198			style.overflow = opts.overflow[ 0 ];
7199			style.overflowX = opts.overflow[ 1 ];
7200			style.overflowY = opts.overflow[ 2 ];
7201		} );
7202	}
7203
7204	// Implement show/hide animations
7205	propTween = false;
7206	for ( prop in orig ) {
7207
7208		// General show/hide setup for this element animation
7209		if ( !propTween ) {
7210			if ( dataShow ) {
7211				if ( "hidden" in dataShow ) {
7212					hidden = dataShow.hidden;
7213				}
7214			} else {
7215				dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
7216			}
7217
7218			// Store hidden/visible for toggle so `.stop().toggle()` "reverses"
7219			if ( toggle ) {
7220				dataShow.hidden = !hidden;
7221			}
7222
7223			// Show elements before animating them
7224			if ( hidden ) {
7225				showHide( [ elem ], true );
7226			}
7227
7228			/* eslint-disable no-loop-func */
7229
7230			anim.done( function() {
7231
7232			/* eslint-enable no-loop-func */
7233
7234				// The final step of a "hide" animation is actually hiding the element
7235				if ( !hidden ) {
7236					showHide( [ elem ] );
7237				}
7238				dataPriv.remove( elem, "fxshow" );
7239				for ( prop in orig ) {
7240					jQuery.style( elem, prop, orig[ prop ] );
7241				}
7242			} );
7243		}
7244
7245		// Per-property setup
7246		propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
7247		if ( !( prop in dataShow ) ) {
7248			dataShow[ prop ] = propTween.start;
7249			if ( hidden ) {
7250				propTween.end = propTween.start;
7251				propTween.start = 0;
7252			}
7253		}
7254	}
7255}
7256
7257function propFilter( props, specialEasing ) {
7258	var index, name, easing, value, hooks;
7259
7260	// camelCase, specialEasing and expand cssHook pass
7261	for ( index in props ) {
7262		name = camelCase( index );
7263		easing = specialEasing[ name ];
7264		value = props[ index ];
7265		if ( Array.isArray( value ) ) {
7266			easing = value[ 1 ];
7267			value = props[ index ] = value[ 0 ];
7268		}
7269
7270		if ( index !== name ) {
7271			props[ name ] = value;
7272			delete props[ index ];
7273		}
7274
7275		hooks = jQuery.cssHooks[ name ];
7276		if ( hooks && "expand" in hooks ) {
7277			value = hooks.expand( value );
7278			delete props[ name ];
7279
7280			// Not quite $.extend, this won't overwrite existing keys.
7281			// Reusing 'index' because we have the correct "name"
7282			for ( index in value ) {
7283				if ( !( index in props ) ) {
7284					props[ index ] = value[ index ];
7285					specialEasing[ index ] = easing;
7286				}
7287			}
7288		} else {
7289			specialEasing[ name ] = easing;
7290		}
7291	}
7292}
7293
7294function Animation( elem, properties, options ) {
7295	var result,
7296		stopped,
7297		index = 0,
7298		length = Animation.prefilters.length,
7299		deferred = jQuery.Deferred().always( function() {
7300
7301			// Don't match elem in the :animated selector
7302			delete tick.elem;
7303		} ),
7304		tick = function() {
7305			if ( stopped ) {
7306				return false;
7307			}
7308			var currentTime = fxNow || createFxNow(),
7309				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
7310
7311				// Support: Android 2.3 only
7312				// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
7313				temp = remaining / animation.duration || 0,
7314				percent = 1 - temp,
7315				index = 0,
7316				length = animation.tweens.length;
7317
7318			for ( ; index < length; index++ ) {
7319				animation.tweens[ index ].run( percent );
7320			}
7321
7322			deferred.notifyWith( elem, [ animation, percent, remaining ] );
7323
7324			// If there's more to do, yield
7325			if ( percent < 1 && length ) {
7326				return remaining;
7327			}
7328
7329			// If this was an empty animation, synthesize a final progress notification
7330			if ( !length ) {
7331				deferred.notifyWith( elem, [ animation, 1, 0 ] );
7332			}
7333
7334			// Resolve the animation and report its conclusion
7335			deferred.resolveWith( elem, [ animation ] );
7336			return false;
7337		},
7338		animation = deferred.promise( {
7339			elem: elem,
7340			props: jQuery.extend( {}, properties ),
7341			opts: jQuery.extend( true, {
7342				specialEasing: {},
7343				easing: jQuery.easing._default
7344			}, options ),
7345			originalProperties: properties,
7346			originalOptions: options,
7347			startTime: fxNow || createFxNow(),
7348			duration: options.duration,
7349			tweens: [],
7350			createTween: function( prop, end ) {
7351				var tween = jQuery.Tween( elem, animation.opts, prop, end,
7352						animation.opts.specialEasing[ prop ] || animation.opts.easing );
7353				animation.tweens.push( tween );
7354				return tween;
7355			},
7356			stop: function( gotoEnd ) {
7357				var index = 0,
7358
7359					// If we are going to the end, we want to run all the tweens
7360					// otherwise we skip this part
7361					length = gotoEnd ? animation.tweens.length : 0;
7362				if ( stopped ) {
7363					return this;
7364				}
7365				stopped = true;
7366				for ( ; index < length; index++ ) {
7367					animation.tweens[ index ].run( 1 );
7368				}
7369
7370				// Resolve when we played the last frame; otherwise, reject
7371				if ( gotoEnd ) {
7372					deferred.notifyWith( elem, [ animation, 1, 0 ] );
7373					deferred.resolveWith( elem, [ animation, gotoEnd ] );
7374				} else {
7375					deferred.rejectWith( elem, [ animation, gotoEnd ] );
7376				}
7377				return this;
7378			}
7379		} ),
7380		props = animation.props;
7381
7382	propFilter( props, animation.opts.specialEasing );
7383
7384	for ( ; index < length; index++ ) {
7385		result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
7386		if ( result ) {
7387			if ( isFunction( result.stop ) ) {
7388				jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
7389					result.stop.bind( result );
7390			}
7391			return result;
7392		}
7393	}
7394
7395	jQuery.map( props, createTween, animation );
7396
7397	if ( isFunction( animation.opts.start ) ) {
7398		animation.opts.start.call( elem, animation );
7399	}
7400
7401	// Attach callbacks from options
7402	animation
7403		.progress( animation.opts.progress )
7404		.done( animation.opts.done, animation.opts.complete )
7405		.fail( animation.opts.fail )
7406		.always( animation.opts.always );
7407
7408	jQuery.fx.timer(
7409		jQuery.extend( tick, {
7410			elem: elem,
7411			anim: animation,
7412			queue: animation.opts.queue
7413		} )
7414	);
7415
7416	return animation;
7417}
7418
7419jQuery.Animation = jQuery.extend( Animation, {
7420
7421	tweeners: {
7422		"*": [ function( prop, value ) {
7423			var tween = this.createTween( prop, value );
7424			adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
7425			return tween;
7426		} ]
7427	},
7428
7429	tweener: function( props, callback ) {
7430		if ( isFunction( props ) ) {
7431			callback = props;
7432			props = [ "*" ];
7433		} else {
7434			props = props.match( rnothtmlwhite );
7435		}
7436
7437		var prop,
7438			index = 0,
7439			length = props.length;
7440
7441		for ( ; index < length; index++ ) {
7442			prop = props[ index ];
7443			Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
7444			Animation.tweeners[ prop ].unshift( callback );
7445		}
7446	},
7447
7448	prefilters: [ defaultPrefilter ],
7449
7450	prefilter: function( callback, prepend ) {
7451		if ( prepend ) {
7452			Animation.prefilters.unshift( callback );
7453		} else {
7454			Animation.prefilters.push( callback );
7455		}
7456	}
7457} );
7458
7459jQuery.speed = function( speed, easing, fn ) {
7460	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
7461		complete: fn || !fn && easing ||
7462			isFunction( speed ) && speed,
7463		duration: speed,
7464		easing: fn && easing || easing && !isFunction( easing ) && easing
7465	};
7466
7467	// Go to the end state if fx are off
7468	if ( jQuery.fx.off ) {
7469		opt.duration = 0;
7470
7471	} else {
7472		if ( typeof opt.duration !== "number" ) {
7473			if ( opt.duration in jQuery.fx.speeds ) {
7474				opt.duration = jQuery.fx.speeds[ opt.duration ];
7475
7476			} else {
7477				opt.duration = jQuery.fx.speeds._default;
7478			}
7479		}
7480	}
7481
7482	// Normalize opt.queue - true/undefined/null -> "fx"
7483	if ( opt.queue == null || opt.queue === true ) {
7484		opt.queue = "fx";
7485	}
7486
7487	// Queueing
7488	opt.old = opt.complete;
7489
7490	opt.complete = function() {
7491		if ( isFunction( opt.old ) ) {
7492			opt.old.call( this );
7493		}
7494
7495		if ( opt.queue ) {
7496			jQuery.dequeue( this, opt.queue );
7497		}
7498	};
7499
7500	return opt;
7501};
7502
7503jQuery.fn.extend( {
7504	fadeTo: function( speed, to, easing, callback ) {
7505
7506		// Show any hidden elements after setting opacity to 0
7507		return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
7508
7509			// Animate to the value specified
7510			.end().animate( { opacity: to }, speed, easing, callback );
7511	},
7512	animate: function( prop, speed, easing, callback ) {
7513		var empty = jQuery.isEmptyObject( prop ),
7514			optall = jQuery.speed( speed, easing, callback ),
7515			doAnimation = function() {
7516
7517				// Operate on a copy of prop so per-property easing won't be lost
7518				var anim = Animation( this, jQuery.extend( {}, prop ), optall );
7519
7520				// Empty animations, or finishing resolves immediately
7521				if ( empty || dataPriv.get( this, "finish" ) ) {
7522					anim.stop( true );
7523				}
7524			};
7525			doAnimation.finish = doAnimation;
7526
7527		return empty || optall.queue === false ?
7528			this.each( doAnimation ) :
7529			this.queue( optall.queue, doAnimation );
7530	},
7531	stop: function( type, clearQueue, gotoEnd ) {
7532		var stopQueue = function( hooks ) {
7533			var stop = hooks.stop;
7534			delete hooks.stop;
7535			stop( gotoEnd );
7536		};
7537
7538		if ( typeof type !== "string" ) {
7539			gotoEnd = clearQueue;
7540			clearQueue = type;
7541			type = undefined;
7542		}
7543		if ( clearQueue && type !== false ) {
7544			this.queue( type || "fx", [] );
7545		}
7546
7547		return this.each( function() {
7548			var dequeue = true,
7549				index = type != null && type + "queueHooks",
7550				timers = jQuery.timers,
7551				data = dataPriv.get( this );
7552
7553			if ( index ) {
7554				if ( data[ index ] && data[ index ].stop ) {
7555					stopQueue( data[ index ] );
7556				}
7557			} else {
7558				for ( index in data ) {
7559					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
7560						stopQueue( data[ index ] );
7561					}
7562				}
7563			}
7564
7565			for ( index = timers.length; index--; ) {
7566				if ( timers[ index ].elem === this &&
7567					( type == null || timers[ index ].queue === type ) ) {
7568
7569					timers[ index ].anim.stop( gotoEnd );
7570					dequeue = false;
7571					timers.splice( index, 1 );
7572				}
7573			}
7574
7575			// Start the next in the queue if the last step wasn't forced.
7576			// Timers currently will call their complete callbacks, which
7577			// will dequeue but only if they were gotoEnd.
7578			if ( dequeue || !gotoEnd ) {
7579				jQuery.dequeue( this, type );
7580			}
7581		} );
7582	},
7583	finish: function( type ) {
7584		if ( type !== false ) {
7585			type = type || "fx";
7586		}
7587		return this.each( function() {
7588			var index,
7589				data = dataPriv.get( this ),
7590				queue = data[ type + "queue" ],
7591				hooks = data[ type + "queueHooks" ],
7592				timers = jQuery.timers,
7593				length = queue ? queue.length : 0;
7594
7595			// Enable finishing flag on private data
7596			data.finish = true;
7597
7598			// Empty the queue first
7599			jQuery.queue( this, type, [] );
7600
7601			if ( hooks && hooks.stop ) {
7602				hooks.stop.call( this, true );
7603			}
7604
7605			// Look for any active animations, and finish them
7606			for ( index = timers.length; index--; ) {
7607				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
7608					timers[ index ].anim.stop( true );
7609					timers.splice( index, 1 );
7610				}
7611			}
7612
7613			// Look for any animations in the old queue and finish them
7614			for ( index = 0; index < length; index++ ) {
7615				if ( queue[ index ] && queue[ index ].finish ) {
7616					queue[ index ].finish.call( this );
7617				}
7618			}
7619
7620			// Turn off finishing flag
7621			delete data.finish;
7622		} );
7623	}
7624} );
7625
7626jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
7627	var cssFn = jQuery.fn[ name ];
7628	jQuery.fn[ name ] = function( speed, easing, callback ) {
7629		return speed == null || typeof speed === "boolean" ?
7630			cssFn.apply( this, arguments ) :
7631			this.animate( genFx( name, true ), speed, easing, callback );
7632	};
7633} );
7634
7635// Generate shortcuts for custom animations
7636jQuery.each( {
7637	slideDown: genFx( "show" ),
7638	slideUp: genFx( "hide" ),
7639	slideToggle: genFx( "toggle" ),
7640	fadeIn: { opacity: "show" },
7641	fadeOut: { opacity: "hide" },
7642	fadeToggle: { opacity: "toggle" }
7643}, function( name, props ) {
7644	jQuery.fn[ name ] = function( speed, easing, callback ) {
7645		return this.animate( props, speed, easing, callback );
7646	};
7647} );
7648
7649jQuery.timers = [];
7650jQuery.fx.tick = function() {
7651	var timer,
7652		i = 0,
7653		timers = jQuery.timers;
7654
7655	fxNow = Date.now();
7656
7657	for ( ; i < timers.length; i++ ) {
7658		timer = timers[ i ];
7659
7660		// Run the timer and safely remove it when done (allowing for external removal)
7661		if ( !timer() && timers[ i ] === timer ) {
7662			timers.splice( i--, 1 );
7663		}
7664	}
7665
7666	if ( !timers.length ) {
7667		jQuery.fx.stop();
7668	}
7669	fxNow = undefined;
7670};
7671
7672jQuery.fx.timer = function( timer ) {
7673	jQuery.timers.push( timer );
7674	jQuery.fx.start();
7675};
7676
7677jQuery.fx.interval = 13;
7678jQuery.fx.start = function() {
7679	if ( inProgress ) {
7680		return;
7681	}
7682
7683	inProgress = true;
7684	schedule();
7685};
7686
7687jQuery.fx.stop = function() {
7688	inProgress = null;
7689};
7690
7691jQuery.fx.speeds = {
7692	slow: 600,
7693	fast: 200,
7694
7695	// Default speed
7696	_default: 400
7697};
7698
7699
7700// Based off of the plugin by Clint Helfers, with permission.
7701// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
7702jQuery.fn.delay = function( time, type ) {
7703	time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
7704	type = type || "fx";
7705
7706	return this.queue( type, function( next, hooks ) {
7707		var timeout = window.setTimeout( next, time );
7708		hooks.stop = function() {
7709			window.clearTimeout( timeout );
7710		};
7711	} );
7712};
7713
7714
7715( function() {
7716	var input = document.createElement( "input" ),
7717		select = document.createElement( "select" ),
7718		opt = select.appendChild( document.createElement( "option" ) );
7719
7720	input.type = "checkbox";
7721
7722	// Support: Android <=4.3 only
7723	// Default value for a checkbox should be "on"
7724	support.checkOn = input.value !== "";
7725
7726	// Support: IE <=11 only
7727	// Must access selectedIndex to make default options select
7728	support.optSelected = opt.selected;
7729
7730	// Support: IE <=11 only
7731	// An input loses its value after becoming a radio
7732	input = document.createElement( "input" );
7733	input.value = "t";
7734	input.type = "radio";
7735	support.radioValue = input.value === "t";
7736} )();
7737
7738
7739var boolHook,
7740	attrHandle = jQuery.expr.attrHandle;
7741
7742jQuery.fn.extend( {
7743	attr: function( name, value ) {
7744		return access( this, jQuery.attr, name, value, arguments.length > 1 );
7745	},
7746
7747	removeAttr: function( name ) {
7748		return this.each( function() {
7749			jQuery.removeAttr( this, name );
7750		} );
7751	}
7752} );
7753
7754jQuery.extend( {
7755	attr: function( elem, name, value ) {
7756		var ret, hooks,
7757			nType = elem.nodeType;
7758
7759		// Don't get/set attributes on text, comment and attribute nodes
7760		if ( nType === 3 || nType === 8 || nType === 2 ) {
7761			return;
7762		}
7763
7764		// Fallback to prop when attributes are not supported
7765		if ( typeof elem.getAttribute === "undefined" ) {
7766			return jQuery.prop( elem, name, value );
7767		}
7768
7769		// Attribute hooks are determined by the lowercase version
7770		// Grab necessary hook if one is defined
7771		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
7772			hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
7773				( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
7774		}
7775
7776		if ( value !== undefined ) {
7777			if ( value === null ) {
7778				jQuery.removeAttr( elem, name );
7779				return;
7780			}
7781
7782			if ( hooks && "set" in hooks &&
7783				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
7784				return ret;
7785			}
7786
7787			elem.setAttribute( name, value + "" );
7788			return value;
7789		}
7790
7791		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
7792			return ret;
7793		}
7794
7795		ret = jQuery.find.attr( elem, name );
7796
7797		// Non-existent attributes return null, we normalize to undefined
7798		return ret == null ? undefined : ret;
7799	},
7800
7801	attrHooks: {
7802		type: {
7803			set: function( elem, value ) {
7804				if ( !support.radioValue && value === "radio" &&
7805					nodeName( elem, "input" ) ) {
7806					var val = elem.value;
7807					elem.setAttribute( "type", value );
7808					if ( val ) {
7809						elem.value = val;
7810					}
7811					return value;
7812				}
7813			}
7814		}
7815	},
7816
7817	removeAttr: function( elem, value ) {
7818		var name,
7819			i = 0,
7820
7821			// Attribute names can contain non-HTML whitespace characters
7822			// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
7823			attrNames = value && value.match( rnothtmlwhite );
7824
7825		if ( attrNames && elem.nodeType === 1 ) {
7826			while ( ( name = attrNames[ i++ ] ) ) {
7827				elem.removeAttribute( name );
7828			}
7829		}
7830	}
7831} );
7832
7833// Hooks for boolean attributes
7834boolHook = {
7835	set: function( elem, value, name ) {
7836		if ( value === false ) {
7837
7838			// Remove boolean attributes when set to false
7839			jQuery.removeAttr( elem, name );
7840		} else {
7841			elem.setAttribute( name, name );
7842		}
7843		return name;
7844	}
7845};
7846
7847jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
7848	var getter = attrHandle[ name ] || jQuery.find.attr;
7849
7850	attrHandle[ name ] = function( elem, name, isXML ) {
7851		var ret, handle,
7852			lowercaseName = name.toLowerCase();
7853
7854		if ( !isXML ) {
7855
7856			// Avoid an infinite loop by temporarily removing this function from the getter
7857			handle = attrHandle[ lowercaseName ];
7858			attrHandle[ lowercaseName ] = ret;
7859			ret = getter( elem, name, isXML ) != null ?
7860				lowercaseName :
7861				null;
7862			attrHandle[ lowercaseName ] = handle;
7863		}
7864		return ret;
7865	};
7866} );
7867
7868
7869
7870
7871var rfocusable = /^(?:input|select|textarea|button)$/i,
7872	rclickable = /^(?:a|area)$/i;
7873
7874jQuery.fn.extend( {
7875	prop: function( name, value ) {
7876		return access( this, jQuery.prop, name, value, arguments.length > 1 );
7877	},
7878
7879	removeProp: function( name ) {
7880		return this.each( function() {
7881			delete this[ jQuery.propFix[ name ] || name ];
7882		} );
7883	}
7884} );
7885
7886jQuery.extend( {
7887	prop: function( elem, name, value ) {
7888		var ret, hooks,
7889			nType = elem.nodeType;
7890
7891		// Don't get/set properties on text, comment and attribute nodes
7892		if ( nType === 3 || nType === 8 || nType === 2 ) {
7893			return;
7894		}
7895
7896		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
7897
7898			// Fix name and attach hooks
7899			name = jQuery.propFix[ name ] || name;
7900			hooks = jQuery.propHooks[ name ];
7901		}
7902
7903		if ( value !== undefined ) {
7904			if ( hooks && "set" in hooks &&
7905				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
7906				return ret;
7907			}
7908
7909			return ( elem[ name ] = value );
7910		}
7911
7912		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
7913			return ret;
7914		}
7915
7916		return elem[ name ];
7917	},
7918
7919	propHooks: {
7920		tabIndex: {
7921			get: function( elem ) {
7922
7923				// Support: IE <=9 - 11 only
7924				// elem.tabIndex doesn't always return the
7925				// correct value when it hasn't been explicitly set
7926				// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
7927				// Use proper attribute retrieval(#12072)
7928				var tabindex = jQuery.find.attr( elem, "tabindex" );
7929
7930				if ( tabindex ) {
7931					return parseInt( tabindex, 10 );
7932				}
7933
7934				if (
7935					rfocusable.test( elem.nodeName ) ||
7936					rclickable.test( elem.nodeName ) &&
7937					elem.href
7938				) {
7939					return 0;
7940				}
7941
7942				return -1;
7943			}
7944		}
7945	},
7946
7947	propFix: {
7948		"for": "htmlFor",
7949		"class": "className"
7950	}
7951} );
7952
7953// Support: IE <=11 only
7954// Accessing the selectedIndex property
7955// forces the browser to respect setting selected
7956// on the option
7957// The getter ensures a default option is selected
7958// when in an optgroup
7959// eslint rule "no-unused-expressions" is disabled for this code
7960// since it considers such accessions noop
7961if ( !support.optSelected ) {
7962	jQuery.propHooks.selected = {
7963		get: function( elem ) {
7964
7965			/* eslint no-unused-expressions: "off" */
7966
7967			var parent = elem.parentNode;
7968			if ( parent && parent.parentNode ) {
7969				parent.parentNode.selectedIndex;
7970			}
7971			return null;
7972		},
7973		set: function( elem ) {
7974
7975			/* eslint no-unused-expressions: "off" */
7976
7977			var parent = elem.parentNode;
7978			if ( parent ) {
7979				parent.selectedIndex;
7980
7981				if ( parent.parentNode ) {
7982					parent.parentNode.selectedIndex;
7983				}
7984			}
7985		}
7986	};
7987}
7988
7989jQuery.each( [
7990	"tabIndex",
7991	"readOnly",
7992	"maxLength",
7993	"cellSpacing",
7994	"cellPadding",
7995	"rowSpan",
7996	"colSpan",
7997	"useMap",
7998	"frameBorder",
7999	"contentEditable"
8000], function() {
8001	jQuery.propFix[ this.toLowerCase() ] = this;
8002} );
8003
8004
8005
8006
8007	// Strip and collapse whitespace according to HTML spec
8008	// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
8009	function stripAndCollapse( value ) {
8010		var tokens = value.match( rnothtmlwhite ) || [];
8011		return tokens.join( " " );
8012	}
8013
8014
8015function getClass( elem ) {
8016	return elem.getAttribute && elem.getAttribute( "class" ) || "";
8017}
8018
8019function classesToArray( value ) {
8020	if ( Array.isArray( value ) ) {
8021		return value;
8022	}
8023	if ( typeof value === "string" ) {
8024		return value.match( rnothtmlwhite ) || [];
8025	}
8026	return [];
8027}
8028
8029jQuery.fn.extend( {
8030	addClass: function( value ) {
8031		var classes, elem, cur, curValue, clazz, j, finalValue,
8032			i = 0;
8033
8034		if ( isFunction( value ) ) {
8035			return this.each( function( j ) {
8036				jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
8037			} );
8038		}
8039
8040		classes = classesToArray( value );
8041
8042		if ( classes.length ) {
8043			while ( ( elem = this[ i++ ] ) ) {
8044				curValue = getClass( elem );
8045				cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
8046
8047				if ( cur ) {
8048					j = 0;
8049					while ( ( clazz = classes[ j++ ] ) ) {
8050						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
8051							cur += clazz + " ";
8052						}
8053					}
8054
8055					// Only assign if different to avoid unneeded rendering.
8056					finalValue = stripAndCollapse( cur );
8057					if ( curValue !== finalValue ) {
8058						elem.setAttribute( "class", finalValue );
8059					}
8060				}
8061			}
8062		}
8063
8064		return this;
8065	},
8066
8067	removeClass: function( value ) {
8068		var classes, elem, cur, curValue, clazz, j, finalValue,
8069			i = 0;
8070
8071		if ( isFunction( value ) ) {
8072			return this.each( function( j ) {
8073				jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
8074			} );
8075		}
8076
8077		if ( !arguments.length ) {
8078			return this.attr( "class", "" );
8079		}
8080
8081		classes = classesToArray( value );
8082
8083		if ( classes.length ) {
8084			while ( ( elem = this[ i++ ] ) ) {
8085				curValue = getClass( elem );
8086
8087				// This expression is here for better compressibility (see addClass)
8088				cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
8089
8090				if ( cur ) {
8091					j = 0;
8092					while ( ( clazz = classes[ j++ ] ) ) {
8093
8094						// Remove *all* instances
8095						while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
8096							cur = cur.replace( " " + clazz + " ", " " );
8097						}
8098					}
8099
8100					// Only assign if different to avoid unneeded rendering.
8101					finalValue = stripAndCollapse( cur );
8102					if ( curValue !== finalValue ) {
8103						elem.setAttribute( "class", finalValue );
8104					}
8105				}
8106			}
8107		}
8108
8109		return this;
8110	},
8111
8112	toggleClass: function( value, stateVal ) {
8113		var type = typeof value,
8114			isValidValue = type === "string" || Array.isArray( value );
8115
8116		if ( typeof stateVal === "boolean" && isValidValue ) {
8117			return stateVal ? this.addClass( value ) : this.removeClass( value );
8118		}
8119
8120		if ( isFunction( value ) ) {
8121			return this.each( function( i ) {
8122				jQuery( this ).toggleClass(
8123					value.call( this, i, getClass( this ), stateVal ),
8124					stateVal
8125				);
8126			} );
8127		}
8128
8129		return this.each( function() {
8130			var className, i, self, classNames;
8131
8132			if ( isValidValue ) {
8133
8134				// Toggle individual class names
8135				i = 0;
8136				self = jQuery( this );
8137				classNames = classesToArray( value );
8138
8139				while ( ( className = classNames[ i++ ] ) ) {
8140
8141					// Check each className given, space separated list
8142					if ( self.hasClass( className ) ) {
8143						self.removeClass( className );
8144					} else {
8145						self.addClass( className );
8146					}
8147				}
8148
8149			// Toggle whole class name
8150			} else if ( value === undefined || type === "boolean" ) {
8151				className = getClass( this );
8152				if ( className ) {
8153
8154					// Store className if set
8155					dataPriv.set( this, "__className__", className );
8156				}
8157
8158				// If the element has a class name or if we're passed `false`,
8159				// then remove the whole classname (if there was one, the above saved it).
8160				// Otherwise bring back whatever was previously saved (if anything),
8161				// falling back to the empty string if nothing was stored.
8162				if ( this.setAttribute ) {
8163					this.setAttribute( "class",
8164						className || value === false ?
8165						"" :
8166						dataPriv.get( this, "__className__" ) || ""
8167					);
8168				}
8169			}
8170		} );
8171	},
8172
8173	hasClass: function( selector ) {
8174		var className, elem,
8175			i = 0;
8176
8177		className = " " + selector + " ";
8178		while ( ( elem = this[ i++ ] ) ) {
8179			if ( elem.nodeType === 1 &&
8180				( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
8181					return true;
8182			}
8183		}
8184
8185		return false;
vendor: 5,544 bytes, lines 8186-8421
8186	}
8187} );
8188
8189
8190
8191
8192var rreturn = /\r/g;
8193
8194jQuery.fn.extend( {
8195	val: function( value ) {
8196		var hooks, ret, valueIsFunction,
8197			elem = this[ 0 ];
8198
8199		if ( !arguments.length ) {
8200			if ( elem ) {
8201				hooks = jQuery.valHooks[ elem.type ] ||
8202					jQuery.valHooks[ elem.nodeName.toLowerCase() ];
8203
8204				if ( hooks &&
8205					"get" in hooks &&
8206					( ret = hooks.get( elem, "value" ) ) !== undefined
8207				) {
8208					return ret;
8209				}
8210
8211				ret = elem.value;
8212
8213				// Handle most common string cases
8214				if ( typeof ret === "string" ) {
8215					return ret.replace( rreturn, "" );
8216				}
8217
8218				// Handle cases where value is null/undef or number
8219				return ret == null ? "" : ret;
8220			}
8221
8222			return;
8223		}
8224
8225		valueIsFunction = isFunction( value );
8226
8227		return this.each( function( i ) {
8228			var val;
8229
8230			if ( this.nodeType !== 1 ) {
8231				return;
8232			}
8233
8234			if ( valueIsFunction ) {
8235				val = value.call( this, i, jQuery( this ).val() );
8236			} else {
8237				val = value;
8238			}
8239
8240			// Treat null/undefined as ""; convert numbers to string
8241			if ( val == null ) {
8242				val = "";
8243
8244			} else if ( typeof val === "number" ) {
8245				val += "";
8246
8247			} else if ( Array.isArray( val ) ) {
8248				val = jQuery.map( val, function( value ) {
8249					return value == null ? "" : value + "";
8250				} );
8251			}
8252
8253			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
8254
8255			// If set returns undefined, fall back to normal setting
8256			if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
8257				this.value = val;
8258			}
8259		} );
8260	}
8261} );
8262
8263jQuery.extend( {
8264	valHooks: {
8265		option: {
8266			get: function( elem ) {
8267
8268				var val = jQuery.find.attr( elem, "value" );
8269				return val != null ?
8270					val :
8271
8272					// Support: IE <=10 - 11 only
8273					// option.text throws exceptions (#14686, #14858)
8274					// Strip and collapse whitespace
8275					// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
8276					stripAndCollapse( jQuery.text( elem ) );
8277			}
8278		},
8279		select: {
8280			get: function( elem ) {
8281				var value, option, i,
8282					options = elem.options,
8283					index = elem.selectedIndex,
8284					one = elem.type === "select-one",
8285					values = one ? null : [],
8286					max = one ? index + 1 : options.length;
8287
8288				if ( index < 0 ) {
8289					i = max;
8290
8291				} else {
8292					i = one ? index : 0;
8293				}
8294
8295				// Loop through all the selected options
8296				for ( ; i < max; i++ ) {
8297					option = options[ i ];
8298
8299					// Support: IE <=9 only
8300					// IE8-9 doesn't update selected after form reset (#2551)
8301					if ( ( option.selected || i === index ) &&
8302
8303							// Don't return options that are disabled or in a disabled optgroup
8304							!option.disabled &&
8305							( !option.parentNode.disabled ||
8306								!nodeName( option.parentNode, "optgroup" ) ) ) {
8307
8308						// Get the specific value for the option
8309						value = jQuery( option ).val();
8310
8311						// We don't need an array for one selects
8312						if ( one ) {
8313							return value;
8314						}
8315
8316						// Multi-Selects return an array
8317						values.push( value );
8318					}
8319				}
8320
8321				return values;
8322			},
8323
8324			set: function( elem, value ) {
8325				var optionSet, option,
8326					options = elem.options,
8327					values = jQuery.makeArray( value ),
8328					i = options.length;
8329
8330				while ( i-- ) {
8331					option = options[ i ];
8332
8333					/* eslint-disable no-cond-assign */
8334
8335					if ( option.selected =
8336						jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
8337					) {
8338						optionSet = true;
8339					}
8340
8341					/* eslint-enable no-cond-assign */
8342				}
8343
8344				// Force browsers to behave consistently when non-matching value is set
8345				if ( !optionSet ) {
8346					elem.selectedIndex = -1;
8347				}
8348				return values;
8349			}
8350		}
8351	}
8352} );
8353
8354// Radios and checkboxes getter/setter
8355jQuery.each( [ "radio", "checkbox" ], function() {
8356	jQuery.valHooks[ this ] = {
8357		set: function( elem, value ) {
8358			if ( Array.isArray( value ) ) {
8359				return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
8360			}
8361		}
8362	};
8363	if ( !support.checkOn ) {
8364		jQuery.valHooks[ this ].get = function( elem ) {
8365			return elem.getAttribute( "value" ) === null ? "on" : elem.value;
8366		};
8367	}
8368} );
8369
8370
8371
8372
8373// Return jQuery for attributes-only inclusion
8374
8375
8376support.focusin = "onfocusin" in window;
8377
8378
8379var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
8380	stopPropagationCallback = function( e ) {
8381		e.stopPropagation();
8382	};
8383
8384jQuery.extend( jQuery.event, {
8385
8386	trigger: function( event, data, elem, onlyHandlers ) {
8387
8388		var i, cur, tmp, bubbleType, ontype, handle, special, lastElement,
8389			eventPath = [ elem || document ],
8390			type = hasOwn.call( event, "type" ) ? event.type : event,
8391			namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
8392
8393		cur = lastElement = tmp = elem = elem || document;
8394
8395		// Don't do events on text and comment nodes
8396		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
8397			return;
8398		}
8399
8400		// focus/blur morphs to focusin/out; ensure we're not firing them right now
8401		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
8402			return;
8403		}
8404
8405		if ( type.indexOf( "." ) > -1 ) {
8406
8407			// Namespaced trigger; create a regexp to match event type in handle()
8408			namespaces = type.split( "." );
8409			type = namespaces.shift();
8410			namespaces.sort();
8411		}
8412		ontype = type.indexOf( ":" ) < 0 && "on" + type;
8413
8414		// Caller can pass in a jQuery.Event object, Object, or just an event type string
8415		event = event[ jQuery.expando ] ?
8416			event :
8417			new jQuery.Event( type, typeof event === "object" && event );
8418
8419		// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
8420		event.isTrigger = onlyHandlers ? 2 : 3;
8421		event.namespace = namespaces.join( "." );
vendor: 7,012 bytes, lines 8422-8695
8422		event.rnamespace = event.namespace ?
8423			new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
8424			null;
8425
8426		// Clean up the event in case it is being reused
8427		event.result = undefined;
8428		if ( !event.target ) {
8429			event.target = elem;
8430		}
8431
8432		// Clone any incoming data and prepend the event, creating the handler arg list
8433		data = data == null ?
8434			[ event ] :
8435			jQuery.makeArray( data, [ event ] );
8436
8437		// Allow special events to draw outside the lines
8438		special = jQuery.event.special[ type ] || {};
8439		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
8440			return;
8441		}
8442
8443		// Determine event propagation path in advance, per W3C events spec (#9951)
8444		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
8445		if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
8446
8447			bubbleType = special.delegateType || type;
8448			if ( !rfocusMorph.test( bubbleType + type ) ) {
8449				cur = cur.parentNode;
8450			}
8451			for ( ; cur; cur = cur.parentNode ) {
8452				eventPath.push( cur );
8453				tmp = cur;
8454			}
8455
8456			// Only add window if we got to document (e.g., not plain obj or detached DOM)
8457			if ( tmp === ( elem.ownerDocument || document ) ) {
8458				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
8459			}
8460		}
8461
8462		// Fire handlers on the event path
8463		i = 0;
8464		while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
8465			lastElement = cur;
8466			event.type = i > 1 ?
8467				bubbleType :
8468				special.bindType || type;
8469
8470			// jQuery handler
8471			handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
8472				dataPriv.get( cur, "handle" );
8473			if ( handle ) {
8474				handle.apply( cur, data );
8475			}
8476
8477			// Native handler
8478			handle = ontype && cur[ ontype ];
8479			if ( handle && handle.apply && acceptData( cur ) ) {
8480				event.result = handle.apply( cur, data );
8481				if ( event.result === false ) {
8482					event.preventDefault();
8483				}
8484			}
8485		}
8486		event.type = type;
8487
8488		// If nobody prevented the default action, do it now
8489		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
8490
8491			if ( ( !special._default ||
8492				special._default.apply( eventPath.pop(), data ) === false ) &&
8493				acceptData( elem ) ) {
8494
8495				// Call a native DOM method on the target with the same name as the event.
8496				// Don't do default actions on window, that's where global variables be (#6170)
8497				if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
8498
8499					// Don't re-trigger an onFOO event when we call its FOO() method
8500					tmp = elem[ ontype ];
8501
8502					if ( tmp ) {
8503						elem[ ontype ] = null;
8504					}
8505
8506					// Prevent re-triggering of the same event, since we already bubbled it above
8507					jQuery.event.triggered = type;
8508
8509					if ( event.isPropagationStopped() ) {
8510						lastElement.addEventListener( type, stopPropagationCallback );
8511					}
8512
8513					elem[ type ]();
8514
8515					if ( event.isPropagationStopped() ) {
8516						lastElement.removeEventListener( type, stopPropagationCallback );
8517					}
8518
8519					jQuery.event.triggered = undefined;
8520
8521					if ( tmp ) {
8522						elem[ ontype ] = tmp;
8523					}
8524				}
8525			}
8526		}
8527
8528		return event.result;
8529	},
8530
8531	// Piggyback on a donor event to simulate a different one
8532	// Used only for `focus(in | out)` events
8533	simulate: function( type, elem, event ) {
8534		var e = jQuery.extend(
8535			new jQuery.Event(),
8536			event,
8537			{
8538				type: type,
8539				isSimulated: true
8540			}
8541		);
8542
8543		jQuery.event.trigger( e, null, elem );
8544	}
8545
8546} );
8547
8548jQuery.fn.extend( {
8549
8550	trigger: function( type, data ) {
8551		return this.each( function() {
8552			jQuery.event.trigger( type, data, this );
8553		} );
8554	},
8555	triggerHandler: function( type, data ) {
8556		var elem = this[ 0 ];
8557		if ( elem ) {
8558			return jQuery.event.trigger( type, data, elem, true );
8559		}
8560	}
8561} );
8562
8563
8564// Support: Firefox <=44
8565// Firefox doesn't have focus(in | out) events
8566// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
8567//
8568// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
8569// focus(in | out) events fire after focus & blur events,
8570// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
8571// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
8572if ( !support.focusin ) {
8573	jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
8574
8575		// Attach a single capturing handler on the document while someone wants focusin/focusout
8576		var handler = function( event ) {
8577			jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
8578		};
8579
8580		jQuery.event.special[ fix ] = {
8581			setup: function() {
8582				var doc = this.ownerDocument || this,
8583					attaches = dataPriv.access( doc, fix );
8584
8585				if ( !attaches ) {
8586					doc.addEventListener( orig, handler, true );
8587				}
8588				dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
8589			},
8590			teardown: function() {
8591				var doc = this.ownerDocument || this,
8592					attaches = dataPriv.access( doc, fix ) - 1;
8593
8594				if ( !attaches ) {
8595					doc.removeEventListener( orig, handler, true );
8596					dataPriv.remove( doc, fix );
8597
8598				} else {
8599					dataPriv.access( doc, fix, attaches );
8600				}
8601			}
8602		};
8603	} );
8604}
8605var location = window.location;
8606
8607var nonce = Date.now();
8608
8609var rquery = ( /\?/ );
8610
8611
8612
8613// Cross-browser xml parsing
8614jQuery.parseXML = function( data ) {
8615	var xml;
8616	if ( !data || typeof data !== "string" ) {
8617		return null;
8618	}
8619
8620	// Support: IE 9 - 11 only
8621	// IE throws on parseFromString with invalid input.
8622	try {
8623		xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
8624	} catch ( e ) {
8625		xml = undefined;
8626	}
8627
8628	if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
8629		jQuery.error( "Invalid XML: " + data );
8630	}
8631	return xml;
8632};
8633
8634
8635var
8636	rbracket = /\[\]$/,
8637	rCRLF = /\r?\n/g,
8638	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
8639	rsubmittable = /^(?:input|select|textarea|keygen)/i;
8640
8641function buildParams( prefix, obj, traditional, add ) {
8642	var name;
8643
8644	if ( Array.isArray( obj ) ) {
8645
8646		// Serialize array item.
8647		jQuery.each( obj, function( i, v ) {
8648			if ( traditional || rbracket.test( prefix ) ) {
8649
8650				// Treat each array item as a scalar.
8651				add( prefix, v );
8652
8653			} else {
8654
8655				// Item is non-scalar (array or object), encode its numeric index.
8656				buildParams(
8657					prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
8658					v,
8659					traditional,
8660					add
8661				);
8662			}
8663		} );
8664
8665	} else if ( !traditional && toType( obj ) === "object" ) {
8666
8667		// Serialize object item.
8668		for ( name in obj ) {
8669			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
8670		}
8671
8672	} else {
8673
8674		// Serialize scalar item.
8675		add( prefix, obj );
8676	}
8677}
8678
8679// Serialize an array of form elements or a set of
8680// key/values into a query string
8681jQuery.param = function( a, traditional ) {
8682	var prefix,
8683		s = [],
8684		add = function( key, valueOrFunction ) {
8685
8686			// If value is a function, invoke it and use its return value
8687			var value = isFunction( valueOrFunction ) ?
8688				valueOrFunction() :
8689				valueOrFunction;
8690
8691			s[ s.length ] = encodeURIComponent( key ) + "=" +
8692				encodeURIComponent( value == null ? "" : value );
8693		};
8694
8695	
8695if ( a == null ) {
8696		return "";
8697	}
vendor: 12,730 bytes, lines 8697-9201
8697
8698
8699	// If an array was passed in, assume that it is an array of form elements.
8700	if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
8701
8702		// Serialize the form elements
8703		jQuery.each( a, function() {
8704			add( this.name, this.value );
8705		} );
8706
8707	} else {
8708
8709		// If traditional, encode the "old" way (the way 1.3.2 or older
8710		// did it), otherwise encode params recursively.
8711		for ( prefix in a ) {
8712			buildParams( prefix, a[ prefix ], traditional, add );
8713		}
8714	}
8715
8716	// Return the resulting serialization
8717	return s.join( "&" );
8718};
8719
8720jQuery.fn.extend( {
8721	serialize: function() {
8722		return jQuery.param( this.serializeArray() );
8723	},
8724	serializeArray: function() {
8725		return this.map( function() {
8726
8727			// Can add propHook for "elements" to filter or add form elements
8728			var elements = jQuery.prop( this, "elements" );
8729			return elements ? jQuery.makeArray( elements ) : this;
8730		} )
8731		.filter( function() {
8732			var type = this.type;
8733
8734			// Use .is( ":disabled" ) so that fieldset[disabled] works
8735			return this.name && !jQuery( this ).is( ":disabled" ) &&
8736				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
8737				( this.checked || !rcheckableType.test( type ) );
8738		} )
8739		.map( function( i, elem ) {
8740			var val = jQuery( this ).val();
8741
8742			if ( val == null ) {
8743				return null;
8744			}
8745
8746			if ( Array.isArray( val ) ) {
8747				return jQuery.map( val, function( val ) {
8748					return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
8749				} );
8750			}
8751
8752			return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
8753		} ).get();
8754	}
8755} );
8756
8757
8758var
8759	r20 = /%20/g,
8760	rhash = /#.*$/,
8761	rantiCache = /([?&])_=[^&]*/,
8762	rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
8763
8764	// #7653, #8125, #8152: local protocol detection
8765	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
8766	rnoContent = /^(?:GET|HEAD)$/,
8767	rprotocol = /^\/\//,
8768
8769	/* Prefilters
8770	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
8771	 * 2) These are called:
8772	 *    - BEFORE asking for a transport
8773	 *    - AFTER param serialization (s.data is a string if s.processData is true)
8774	 * 3) key is the dataType
8775	 * 4) the catchall symbol "*" can be used
8776	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
8777	 */
8778	prefilters = {},
8779
8780	/* Transports bindings
8781	 * 1) key is the dataType
8782	 * 2) the catchall symbol "*" can be used
8783	 * 3) selection will start with transport dataType and THEN go to "*" if needed
8784	 */
8785	transports = {},
8786
8787	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
8788	allTypes = "*/".concat( "*" ),
8789
8790	// Anchor tag for parsing the document origin
8791	originAnchor = document.createElement( "a" );
8792	originAnchor.href = location.href;
8793
8794// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
8795function addToPrefiltersOrTransports( structure ) {
8796
8797	// dataTypeExpression is optional and defaults to "*"
8798	return function( dataTypeExpression, func ) {
8799
8800		if ( typeof dataTypeExpression !== "string" ) {
8801			func = dataTypeExpression;
8802			dataTypeExpression = "*";
8803		}
8804
8805		var dataType,
8806			i = 0,
8807			dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
8808
8809		if ( isFunction( func ) ) {
8810
8811			// For each dataType in the dataTypeExpression
8812			while ( ( dataType = dataTypes[ i++ ] ) ) {
8813
8814				// Prepend if requested
8815				if ( dataType[ 0 ] === "+" ) {
8816					dataType = dataType.slice( 1 ) || "*";
8817					( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
8818
8819				// Otherwise append
8820				} else {
8821					( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
8822				}
8823			}
8824		}
8825	};
8826}
8827
8828// Base inspection function for prefilters and transports
8829function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
8830
8831	var inspected = {},
8832		seekingTransport = ( structure === transports );
8833
8834	function inspect( dataType ) {
8835		var selected;
8836		inspected[ dataType ] = true;
8837		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
8838			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
8839			if ( typeof dataTypeOrTransport === "string" &&
8840				!seekingTransport && !inspected[ dataTypeOrTransport ] ) {
8841
8842				options.dataTypes.unshift( dataTypeOrTransport );
8843				inspect( dataTypeOrTransport );
8844				return false;
8845			} else if ( seekingTransport ) {
8846				return !( selected = dataTypeOrTransport );
8847			}
8848		} );
8849		return selected;
8850	}
8851
8852	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
8853}
8854
8855// A special extend for ajax options
8856// that takes "flat" options (not to be deep extended)
8857// Fixes #9887
8858function ajaxExtend( target, src ) {
8859	var key, deep,
8860		flatOptions = jQuery.ajaxSettings.flatOptions || {};
8861
8862	for ( key in src ) {
8863		if ( src[ key ] !== undefined ) {
8864			( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
8865		}
8866	}
8867	if ( deep ) {
8868		jQuery.extend( true, target, deep );
8869	}
8870
8871	return target;
8872}
8873
8874/* Handles responses to an ajax request:
8875 * - finds the right dataType (mediates between content-type and expected dataType)
8876 * - returns the corresponding response
8877 */
8878function ajaxHandleResponses( s, jqXHR, responses ) {
8879
8880	var ct, type, finalDataType, firstDataType,
8881		contents = s.contents,
8882		dataTypes = s.dataTypes;
8883
8884	// Remove auto dataType and get content-type in the process
8885	while ( dataTypes[ 0 ] === "*" ) {
8886		dataTypes.shift();
8887		if ( ct === undefined ) {
8888			ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
8889		}
8890	}
8891
8892	// Check if we're dealing with a known content-type
8893	if ( ct ) {
8894		for ( type in contents ) {
8895			if ( contents[ type ] && contents[ type ].test( ct ) ) {
8896				dataTypes.unshift( type );
8897				break;
8898			}
8899		}
8900	}
8901
8902	// Check to see if we have a response for the expected dataType
8903	if ( dataTypes[ 0 ] in responses ) {
8904		finalDataType = dataTypes[ 0 ];
8905	} else {
8906
8907		// Try convertible dataTypes
8908		for ( type in responses ) {
8909			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
8910				finalDataType = type;
8911				break;
8912			}
8913			if ( !firstDataType ) {
8914				firstDataType = type;
8915			}
8916		}
8917
8918		// Or just use first one
8919		finalDataType = finalDataType || firstDataType;
8920	}
8921
8922	// If we found a dataType
8923	// We add the dataType to the list if needed
8924	// and return the corresponding response
8925	if ( finalDataType ) {
8926		if ( finalDataType !== dataTypes[ 0 ] ) {
8927			dataTypes.unshift( finalDataType );
8928		}
8929		return responses[ finalDataType ];
8930	}
8931}
8932
8933/* Chain conversions given the request and the original response
8934 * Also sets the responseXXX fields on the jqXHR instance
8935 */
8936function ajaxConvert( s, response, jqXHR, isSuccess ) {
8937	var conv2, current, conv, tmp, prev,
8938		converters = {},
8939
8940		// Work with a copy of dataTypes in case we need to modify it for conversion
8941		dataTypes = s.dataTypes.slice();
8942
8943	// Create converters map with lowercased keys
8944	if ( dataTypes[ 1 ] ) {
8945		for ( conv in s.converters ) {
8946			converters[ conv.toLowerCase() ] = s.converters[ conv ];
8947		}
8948	}
8949
8950	current = dataTypes.shift();
8951
8952	// Convert to each sequential dataType
8953	while ( current ) {
8954
8955		if ( s.responseFields[ current ] ) {
8956			jqXHR[ s.responseFields[ current ] ] = response;
8957		}
8958
8959		// Apply the dataFilter if provided
8960		if ( !prev && isSuccess && s.dataFilter ) {
8961			response = s.dataFilter( response, s.dataType );
8962		}
8963
8964		prev = current;
8965		current = dataTypes.shift();
8966
8967		if ( current ) {
8968
8969			// There's only work to do if current dataType is non-auto
8970			if ( current === "*" ) {
8971
8972				current = prev;
8973
8974			// Convert response if prev dataType is non-auto and differs from current
8975			} else if ( prev !== "*" && prev !== current ) {
8976
8977				// Seek a direct converter
8978				conv = converters[ prev + " " + current ] || converters[ "* " + current ];
8979
8980				// If none found, seek a pair
8981				if ( !conv ) {
8982					for ( conv2 in converters ) {
8983
8984						// If conv2 outputs current
8985						tmp = conv2.split( " " );
8986						if ( tmp[ 1 ] === current ) {
8987
8988							// If prev can be converted to accepted input
8989							conv = converters[ prev + " " + tmp[ 0 ] ] ||
8990								converters[ "* " + tmp[ 0 ] ];
8991							if ( conv ) {
8992
8993								// Condense equivalence converters
8994								if ( conv === true ) {
8995									conv = converters[ conv2 ];
8996
8997								// Otherwise, insert the intermediate dataType
8998								} else if ( converters[ conv2 ] !== true ) {
8999									current = tmp[ 0 ];
9000									dataTypes.unshift( tmp[ 1 ] );
9001								}
9002								break;
9003							}
9004						}
9005					}
9006				}
9007
9008				// Apply converter (if not an equivalence)
9009				if ( conv !== true ) {
9010
9011					// Unless errors are allowed to bubble, catch and return them
9012					if ( conv && s.throws ) {
9013						response = conv( response );
9014					} else {
9015						try {
9016							response = conv( response );
9017						} catch ( e ) {
9018							return {
9019								state: "parsererror",
9020								error: conv ? e : "No conversion from " + prev + " to " + current
9021							};
9022						}
9023					}
9024				}
9025			}
9026		}
9027	}
9028
9029	return { state: "success", data: response };
9030}
9031
9032jQuery.extend( {
9033
9034	// Counter for holding the number of active queries
9035	active: 0,
9036
9037	// Last-Modified header cache for next request
9038	lastModified: {},
9039	etag: {},
9040
9041	ajaxSettings: {
9042		url: location.href,
9043		type: "GET",
9044		isLocal: rlocalProtocol.test( location.protocol ),
9045		global: true,
9046		processData: true,
9047		async: true,
9048		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
9049
9050		/*
9051		timeout: 0,
9052		data: null,
9053		dataType: null,
9054		username: null,
9055		password: null,
9056		cache: null,
9057		throws: false,
9058		traditional: false,
9059		headers: {},
9060		*/
9061
9062		accepts: {
9063			"*": allTypes,
9064			text: "text/plain",
9065			html: "text/html",
9066			xml: "application/xml, text/xml",
9067			json: "application/json, text/javascript"
9068		},
9069
9070		contents: {
9071			xml: /\bxml\b/,
9072			html: /\bhtml/,
9073			json: /\bjson\b/
9074		},
9075
9076		responseFields: {
9077			xml: "responseXML",
9078			text: "responseText",
9079			json: "responseJSON"
9080		},
9081
9082		// Data converters
9083		// Keys separate source (or catchall "*") and destination types with a single space
9084		converters: {
9085
9086			// Convert anything to text
9087			"* text": String,
9088
9089			// Text to html (true = no transformation)
9090			"text html": true,
9091
9092			// Evaluate text as a json expression
9093			"text json": JSON.parse,
9094
9095			// Parse text as xml
9096			"text xml": jQuery.parseXML
9097		},
9098
9099		// For options that shouldn't be deep extended:
9100		// you can add your own custom options here if
9101		// and when you create one that shouldn't be
9102		// deep extended (see ajaxExtend)
9103		flatOptions: {
9104			url: true,
9105			context: true
9106		}
9107	},
9108
9109	// Creates a full fledged settings object into target
9110	// with both ajaxSettings and settings fields.
9111	// If target is omitted, writes into ajaxSettings.
9112	ajaxSetup: function( target, settings ) {
9113		return settings ?
9114
9115			// Building a settings object
9116			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
9117
9118			// Extending ajaxSettings
9119			ajaxExtend( jQuery.ajaxSettings, target );
9120	},
9121
9122	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
9123	ajaxTransport: addToPrefiltersOrTransports( transports ),
9124
9125	// Main method
9126	ajax: function( url, options ) {
9127
9128		// If url is an object, simulate pre-1.5 signature
9129		if ( typeof url === "object" ) {
9130			options = url;
9131			url = undefined;
9132		}
9133
9134		// Force options to be an object
9135		options = options || {};
9136
9137		var transport,
9138
9139			// URL without anti-cache param
9140			cacheURL,
9141
9142			// Response headers
9143			responseHeadersString,
9144			responseHeaders,
9145
9146			// timeout handle
9147			timeoutTimer,
9148
9149			// Url cleanup var
9150			urlAnchor,
9151
9152			// Request state (becomes false upon send and true upon completion)
9153			completed,
9154
9155			// To know if global events are to be dispatched
9156			fireGlobals,
9157
9158			// Loop variable
9159			i,
9160
9161			// uncached part of the url
9162			uncached,
9163
9164			// Create the final options object
9165			s = jQuery.ajaxSetup( {}, options ),
9166
9167			// Callbacks context
9168			callbackContext = s.context || s,
9169
9170			// Context for global events is callbackContext if it is a DOM node or jQuery collection
9171			globalEventContext = s.context &&
9172				( callbackContext.nodeType || callbackContext.jquery ) ?
9173					jQuery( callbackContext ) :
9174					jQuery.event,
9175
9176			// Deferreds
9177			deferred = jQuery.Deferred(),
9178			completeDeferred = jQuery.Callbacks( "once memory" ),
9179
9180			// Status-dependent callbacks
9181			statusCode = s.statusCode || {},
9182
9183			// Headers (they are sent all at once)
9184			requestHeaders = {},
9185			requestHeadersNames = {},
9186
9187			// Default abort message
9188			strAbort = "canceled",
9189
9190			// Fake xhr
9191			jqXHR = {
9192				readyState: 0,
9193
9194				// Builds headers hashtable if needed
9195				getResponseHeader: function( key ) {
9196					var match;
9197					if ( completed ) {
9198						if ( !responseHeaders ) {
9199							responseHeaders = {};
9200							while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
9201								responseHeaders[ match[ 1 ].toLowerCase() 
9201+ " " ] =
9202									( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] )
9203										.concat( match[ 2 ] );
9204							}
9205						}
9206						match = responseHeaders[ key.toLowerCase() + " " ];
9207					}
9208					return match == null ? null : match.join( ", " )
vendor: 10,702 bytes, lines 9208-9597
9208;
9209				},
9210
9211				// Raw string
9212				getAllResponseHeaders: function() {
9213					return completed ? responseHeadersString : null;
9214				},
9215
9216				// Caches the header
9217				setRequestHeader: function( name, value ) {
9218					if ( completed == null ) {
9219						name = requestHeadersNames[ name.toLowerCase() ] =
9220							requestHeadersNames[ name.toLowerCase() ] || name;
9221						requestHeaders[ name ] = value;
9222					}
9223					return this;
9224				},
9225
9226				// Overrides response content-type header
9227				overrideMimeType: function( type ) {
9228					if ( completed == null ) {
9229						s.mimeType = type;
9230					}
9231					return this;
9232				},
9233
9234				// Status-dependent callbacks
9235				statusCode: function( map ) {
9236					var code;
9237					if ( map ) {
9238						if ( completed ) {
9239
9240							// Execute the appropriate callbacks
9241							jqXHR.always( map[ jqXHR.status ] );
9242						} else {
9243
9244							// Lazy-add the new callbacks in a way that preserves old ones
9245							for ( code in map ) {
9246								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
9247							}
9248						}
9249					}
9250					return this;
9251				},
9252
9253				// Cancel the request
9254				abort: function( statusText ) {
9255					var finalText = statusText || strAbort;
9256					if ( transport ) {
9257						transport.abort( finalText );
9258					}
9259					done( 0, finalText );
9260					return this;
9261				}
9262			};
9263
9264		// Attach deferreds
9265		deferred.promise( jqXHR );
9266
9267		// Add protocol if not provided (prefilters might expect it)
9268		// Handle falsy url in the settings object (#10093: consistency with old signature)
9269		// We also use the url parameter if available
9270		s.url = ( ( url || s.url || location.href ) + "" )
9271			.replace( rprotocol, location.protocol + "//" );
9272
9273		// Alias method option to type as per ticket #12004
9274		s.type = options.method || options.type || s.method || s.type;
9275
9276		// Extract dataTypes list
9277		s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];
9278
9279		// A cross-domain request is in order when the origin doesn't match the current origin.
9280		if ( s.crossDomain == null ) {
9281			urlAnchor = document.createElement( "a" );
9282
9283			// Support: IE <=8 - 11, Edge 12 - 15
9284			// IE throws exception on accessing the href property if url is malformed,
9285			// e.g. http://example.com:80x/
9286			try {
9287				urlAnchor.href = s.url;
9288
9289				// Support: IE <=8 - 11 only
9290				// Anchor's host property isn't correctly set when s.url is relative
9291				urlAnchor.href = urlAnchor.href;
9292				s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
9293					urlAnchor.protocol + "//" + urlAnchor.host;
9294			} catch ( e ) {
9295
9296				// If there is an error parsing the URL, assume it is crossDomain,
9297				// it can be rejected by the transport if it is invalid
9298				s.crossDomain = true;
9299			}
9300		}
9301
9302		// Convert data if not already a string
9303		if ( s.data && s.processData && typeof s.data !== "string" ) {
9304			s.data = jQuery.param( s.data, s.traditional );
9305		}
9306
9307		// Apply prefilters
9308		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
9309
9310		// If request was aborted inside a prefilter, stop there
9311		if ( completed ) {
9312			return jqXHR;
9313		}
9314
9315		// We can fire global events as of now if asked to
9316		// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
9317		fireGlobals = jQuery.event && s.global;
9318
9319		// Watch for a new set of requests
9320		if ( fireGlobals && jQuery.active++ === 0 ) {
9321			jQuery.event.trigger( "ajaxStart" );
9322		}
9323
9324		// Uppercase the type
9325		s.type = s.type.toUpperCase();
9326
9327		// Determine if request has content
9328		s.hasContent = !rnoContent.test( s.type );
9329
9330		// Save the URL in case we're toying with the If-Modified-Since
9331		// and/or If-None-Match header later on
9332		// Remove hash to simplify url manipulation
9333		cacheURL = s.url.replace( rhash, "" );
9334
9335		// More options handling for requests with no content
9336		if ( !s.hasContent ) {
9337
9338			// Remember the hash so we can put it back
9339			uncached = s.url.slice( cacheURL.length );
9340
9341			// If data is available and should be processed, append data to url
9342			if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
9343				cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
9344
9345				// #9682: remove data so that it's not used in an eventual retry
9346				delete s.data;
9347			}
9348
9349			// Add or update anti-cache param if needed
9350			if ( s.cache === false ) {
9351				cacheURL = cacheURL.replace( rantiCache, "$1" );
9352				uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached;
9353			}
9354
9355			// Put hash and anti-cache on the URL that will be requested (gh-1732)
9356			s.url = cacheURL + uncached;
9357
9358		// Change '%20' to '+' if this is encoded form body content (gh-2658)
9359		} else if ( s.data && s.processData &&
9360			( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
9361			s.data = s.data.replace( r20, "+" );
9362		}
9363
9364		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
9365		if ( s.ifModified ) {
9366			if ( jQuery.lastModified[ cacheURL ] ) {
9367				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
9368			}
9369			if ( jQuery.etag[ cacheURL ] ) {
9370				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
9371			}
9372		}
9373
9374		// Set the correct header, if data is being sent
9375		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
9376			jqXHR.setRequestHeader( "Content-Type", s.contentType );
9377		}
9378
9379		// Set the Accepts header for the server, depending on the dataType
9380		jqXHR.setRequestHeader(
9381			"Accept",
9382			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
9383				s.accepts[ s.dataTypes[ 0 ] ] +
9384					( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
9385				s.accepts[ "*" ]
9386		);
9387
9388		// Check for headers option
9389		for ( i in s.headers ) {
9390			jqXHR.setRequestHeader( i, s.headers[ i ] );
9391		}
9392
9393		// Allow custom headers/mimetypes and early abort
9394		if ( s.beforeSend &&
9395			( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
9396
9397			// Abort if not done already and return
9398			return jqXHR.abort();
9399		}
9400
9401		// Aborting is no longer a cancellation
9402		strAbort = "abort";
9403
9404		// Install callbacks on deferreds
9405		completeDeferred.add( s.complete );
9406		jqXHR.done( s.success );
9407		jqXHR.fail( s.error );
9408
9409		// Get transport
9410		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
9411
9412		// If no transport, we auto-abort
9413		if ( !transport ) {
9414			done( -1, "No Transport" );
9415		} else {
9416			jqXHR.readyState = 1;
9417
9418			// Send global event
9419			if ( fireGlobals ) {
9420				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
9421			}
9422
9423			// If request was aborted inside ajaxSend, stop there
9424			if ( completed ) {
9425				return jqXHR;
9426			}
9427
9428			// Timeout
9429			if ( s.async && s.timeout > 0 ) {
9430				timeoutTimer = window.setTimeout( function() {
9431					jqXHR.abort( "timeout" );
9432				}, s.timeout );
9433			}
9434
9435			try {
9436				completed = false;
9437				transport.send( requestHeaders, done );
9438			} catch ( e ) {
9439
9440				// Rethrow post-completion exceptions
9441				if ( completed ) {
9442					throw e;
9443				}
9444
9445				// Propagate others as results
9446				done( -1, e );
9447			}
9448		}
9449
9450		// Callback for when everything is done
9451		function done( status, nativeStatusText, responses, headers ) {
9452			var isSuccess, success, error, response, modified,
9453				statusText = nativeStatusText;
9454
9455			// Ignore repeat invocations
9456			if ( completed ) {
9457				return;
9458			}
9459
9460			completed = true;
9461
9462			// Clear timeout if it exists
9463			if ( timeoutTimer ) {
9464				window.clearTimeout( timeoutTimer );
9465			}
9466
9467			// Dereference transport for early garbage collection
9468			// (no matter how long the jqXHR object will be used)
9469			transport = undefined;
9470
9471			// Cache response headers
9472			responseHeadersString = headers || "";
9473
9474			// Set readyState
9475			jqXHR.readyState = status > 0 ? 4 : 0;
9476
9477			// Determine if successful
9478			isSuccess = status >= 200 && status < 300 || status === 304;
9479
9480			// Get response data
9481			if ( responses ) {
9482				response = ajaxHandleResponses( s, jqXHR, responses );
9483			}
9484
9485			// Convert no matter what (that way responseXXX fields are always set)
9486			response = ajaxConvert( s, response, jqXHR, isSuccess );
9487
9488			// If successful, handle type chaining
9489			if ( isSuccess ) {
9490
9491				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
9492				if ( s.ifModified ) {
9493					modified = jqXHR.getResponseHeader( "Last-Modified" );
9494					if ( modified ) {
9495						jQuery.lastModified[ cacheURL ] = modified;
9496					}
9497					modified = jqXHR.getResponseHeader( "etag" );
9498					if ( modified ) {
9499						jQuery.etag[ cacheURL ] = modified;
9500					}
9501				}
9502
9503				// if no content
9504				if ( status === 204 || s.type === "HEAD" ) {
9505					statusText = "nocontent";
9506
9507				// if not modified
9508				} else if ( status === 304 ) {
9509					statusText = "notmodified";
9510
9511				// If we have data, let's convert it
9512				} else {
9513					statusText = response.state;
9514					success = response.data;
9515					error = response.error;
9516					isSuccess = !error;
9517				}
9518			} else {
9519
9520				// Extract error from statusText and normalize for non-aborts
9521				error = statusText;
9522				if ( status || !statusText ) {
9523					statusText = "error";
9524					if ( status < 0 ) {
9525						status = 0;
9526					}
9527				}
9528			}
9529
9530			// Set data for the fake xhr object
9531			jqXHR.status = status;
9532			jqXHR.statusText = ( nativeStatusText || statusText ) + "";
9533
9534			// Success/Error
9535			if ( isSuccess ) {
9536				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
9537			} else {
9538				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
9539			}
9540
9541			// Status-dependent callbacks
9542			jqXHR.statusCode( statusCode );
9543			statusCode = undefined;
9544
9545			if ( fireGlobals ) {
9546				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
9547					[ jqXHR, s, isSuccess ? success : error ] );
9548			}
9549
9550			// Complete
9551			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
9552
9553			if ( fireGlobals ) {
9554				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
9555
9556				// Handle the global AJAX counter
9557				if ( !( --jQuery.active ) ) {
9558					jQuery.event.trigger( "ajaxStop" );
9559				}
9560			}
9561		}
9562
9563		return jqXHR;
9564	},
9565
9566	getJSON: function( url, data, callback ) {
9567		return jQuery.get( url, data, callback, "json" );
9568	},
9569
9570	getScript: function( url, callback ) {
9571		return jQuery.get( url, undefined, callback, "script" );
9572	}
9573} );
9574
9575jQuery.each( [ "get", "post" ], function( i, method ) {
9576	jQuery[ method ] = function( url, data, callback, type ) {
9577
9578		// Shift arguments if data argument was omitted
9579		if ( isFunction( data ) ) {
9580			type = type || callback;
9581			callback = data;
9582			data = undefined;
9583		}
9584
9585		// The url can be an options object (which then must have .url)
9586		return jQuery.ajax( jQuery.extend( {
9587			url: url,
9588			type: method,
9589			dataType: type,
9590			data: data,
9591			success: callback
9592		}, jQuery.isPlainObject( url ) && url ) );
9593	};
9594} );
9595
9596
9597jQuery._evalUrl = function( url
9597, options ) {
9598	return jQuery.ajax( {
9599		url: url,
9600
9601		// Make this explicit, since user can override this through ajaxSetup (#11264)
9602		type: "GET",
9603		dataType: "script",
9604		cache: true,
9605		async: false,
9606		global: false,
9607
9608		// Only evaluate the response if it is successful (gh-4126)
9609		// dataFilter is not invoked for failure responses, so using it instead
9610		// of the default converter is kludgy but it works.
9611		converters: {
9612			"text script": function() {}
9613		},
9614		dataFilter: function( response ) {
9615			jQuery.globalEval( response, options
vendor: 11,651 bytes, lines 9615-10080
9615 );
9616		}
9617	} );
9618};
9619
9620
9621jQuery.fn.extend( {
9622	wrapAll: function( html ) {
9623		var wrap;
9624
9625		if ( this[ 0 ] ) {
9626			if ( isFunction( html ) ) {
9627				html = html.call( this[ 0 ] );
9628			}
9629
9630			// The elements to wrap the target around
9631			wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
9632
9633			if ( this[ 0 ].parentNode ) {
9634				wrap.insertBefore( this[ 0 ] );
9635			}
9636
9637			wrap.map( function() {
9638				var elem = this;
9639
9640				while ( elem.firstElementChild ) {
9641					elem = elem.firstElementChild;
9642				}
9643
9644				return elem;
9645			} ).append( this );
9646		}
9647
9648		return this;
9649	},
9650
9651	wrapInner: function( html ) {
9652		if ( isFunction( html ) ) {
9653			return this.each( function( i ) {
9654				jQuery( this ).wrapInner( html.call( this, i ) );
9655			} );
9656		}
9657
9658		return this.each( function() {
9659			var self = jQuery( this ),
9660				contents = self.contents();
9661
9662			if ( contents.length ) {
9663				contents.wrapAll( html );
9664
9665			} else {
9666				self.append( html );
9667			}
9668		} );
9669	},
9670
9671	wrap: function( html ) {
9672		var htmlIsFunction = isFunction( html );
9673
9674		return this.each( function( i ) {
9675			jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );
9676		} );
9677	},
9678
9679	unwrap: function( selector ) {
9680		this.parent( selector ).not( "body" ).each( function() {
9681			jQuery( this ).replaceWith( this.childNodes );
9682		} );
9683		return this;
9684	}
9685} );
9686
9687
9688jQuery.expr.pseudos.hidden = function( elem ) {
9689	return !jQuery.expr.pseudos.visible( elem );
9690};
9691jQuery.expr.pseudos.visible = function( elem ) {
9692	return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
9693};
9694
9695
9696
9697
9698jQuery.ajaxSettings.xhr = function() {
9699	try {
9700		return new window.XMLHttpRequest();
9701	} catch ( e ) {}
9702};
9703
9704var xhrSuccessStatus = {
9705
9706		// File protocol always yields status code 0, assume 200
9707		0: 200,
9708
9709		// Support: IE <=9 only
9710		// #1450: sometimes IE returns 1223 when it should be 204
9711		1223: 204
9712	},
9713	xhrSupported = jQuery.ajaxSettings.xhr();
9714
9715support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
9716support.ajax = xhrSupported = !!xhrSupported;
9717
9718jQuery.ajaxTransport( function( options ) {
9719	var callback, errorCallback;
9720
9721	// Cross domain only allowed if supported through XMLHttpRequest
9722	if ( support.cors || xhrSupported && !options.crossDomain ) {
9723		return {
9724			send: function( headers, complete ) {
9725				var i,
9726					xhr = options.xhr();
9727
9728				xhr.open(
9729					options.type,
9730					options.url,
9731					options.async,
9732					options.username,
9733					options.password
9734				);
9735
9736				// Apply custom fields if provided
9737				if ( options.xhrFields ) {
9738					for ( i in options.xhrFields ) {
9739						xhr[ i ] = options.xhrFields[ i ];
9740					}
9741				}
9742
9743				// Override mime type if needed
9744				if ( options.mimeType && xhr.overrideMimeType ) {
9745					xhr.overrideMimeType( options.mimeType );
9746				}
9747
9748				// X-Requested-With header
9749				// For cross-domain requests, seeing as conditions for a preflight are
9750				// akin to a jigsaw puzzle, we simply never set it to be sure.
9751				// (it can always be set on a per-request basis or even using ajaxSetup)
9752				// For same-domain requests, won't change header if already provided.
9753				if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
9754					headers[ "X-Requested-With" ] = "XMLHttpRequest";
9755				}
9756
9757				// Set headers
9758				for ( i in headers ) {
9759					xhr.setRequestHeader( i, headers[ i ] );
9760				}
9761
9762				// Callback
9763				callback = function( type ) {
9764					return function() {
9765						if ( callback ) {
9766							callback = errorCallback = xhr.onload =
9767								xhr.onerror = xhr.onabort = xhr.ontimeout =
9768									xhr.onreadystatechange = null;
9769
9770							if ( type === "abort" ) {
9771								xhr.abort();
9772							} else if ( type === "error" ) {
9773
9774								// Support: IE <=9 only
9775								// On a manual native abort, IE9 throws
9776								// errors on any property access that is not readyState
9777								if ( typeof xhr.status !== "number" ) {
9778									complete( 0, "error" );
9779								} else {
9780									complete(
9781
9782										// File: protocol always yields status 0; see #8605, #14207
9783										xhr.status,
9784										xhr.statusText
9785									);
9786								}
9787							} else {
9788								complete(
9789									xhrSuccessStatus[ xhr.status ] || xhr.status,
9790									xhr.statusText,
9791
9792									// Support: IE <=9 only
9793									// IE9 has no XHR2 but throws on binary (trac-11426)
9794									// For XHR2 non-text, let the caller handle it (gh-2498)
9795									( xhr.responseType || "text" ) !== "text"  ||
9796									typeof xhr.responseText !== "string" ?
9797										{ binary: xhr.response } :
9798										{ text: xhr.responseText },
9799									xhr.getAllResponseHeaders()
9800								);
9801							}
9802						}
9803					};
9804				};
9805
9806				// Listen to events
9807				xhr.onload = callback();
9808				errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" );
9809
9810				// Support: IE 9 only
9811				// Use onreadystatechange to replace onabort
9812				// to handle uncaught aborts
9813				if ( xhr.onabort !== undefined ) {
9814					xhr.onabort = errorCallback;
9815				} else {
9816					xhr.onreadystatechange = function() {
9817
9818						// Check readyState before timeout as it changes
9819						if ( xhr.readyState === 4 ) {
9820
9821							// Allow onerror to be called first,
9822							// but that will not handle a native abort
9823							// Also, save errorCallback to a variable
9824							// as xhr.onerror cannot be accessed
9825							window.setTimeout( function() {
9826								if ( callback ) {
9827									errorCallback();
9828								}
9829							} );
9830						}
9831					};
9832				}
9833
9834				// Create the abort callback
9835				callback = callback( "abort" );
9836
9837				try {
9838
9839					// Do send the request (this may raise an exception)
9840					xhr.send( options.hasContent && options.data || null );
9841				} catch ( e ) {
9842
9843					// #14683: Only rethrow if this hasn't been notified as an error yet
9844					if ( callback ) {
9845						throw e;
9846					}
9847				}
9848			},
9849
9850			abort: function() {
9851				if ( callback ) {
9852					callback();
9853				}
9854			}
9855		};
9856	}
9857} );
9858
9859
9860
9861
9862// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
9863jQuery.ajaxPrefilter( function( s ) {
9864	if ( s.crossDomain ) {
9865		s.contents.script = false;
9866	}
9867} );
9868
9869// Install script dataType
9870jQuery.ajaxSetup( {
9871	accepts: {
9872		script: "text/javascript, application/javascript, " +
9873			"application/ecmascript, application/x-ecmascript"
9874	},
9875	contents: {
9876		script: /\b(?:java|ecma)script\b/
9877	},
9878	converters: {
9879		"text script": function( text ) {
9880			jQuery.globalEval( text );
9881			return text;
9882		}
9883	}
9884} );
9885
9886// Handle cache's special case and crossDomain
9887jQuery.ajaxPrefilter( "script", function( s ) {
9888	if ( s.cache === undefined ) {
9889		s.cache = false;
9890	}
9891	if ( s.crossDomain ) {
9892		s.type = "GET";
9893	}
9894} );
9895
9896// Bind script tag hack transport
9897jQuery.ajaxTransport( "script", function( s ) {
9898
9899	// This transport only deals with cross domain or forced-by-attrs requests
9900	if ( s.crossDomain || s.scriptAttrs ) {
9901		var script, callback;
9902		return {
9903			send: function( _, complete ) {
9904				script = jQuery( "<script>" )
9905					.attr( s.scriptAttrs || {} )
9906					.prop( { charset: s.scriptCharset, src: s.url } )
9907					.on( "load error", callback = function( evt ) {
9908						script.remove();
9909						callback = null;
9910						if ( evt ) {
9911							complete( evt.type === "error" ? 404 : 200, evt.type );
9912						}
9913					} );
9914
9915				// Use native DOM manipulation to avoid our domManip AJAX trickery
9916				document.head.appendChild( script[ 0 ] );
9917			},
9918			abort: function() {
9919				if ( callback ) {
9920					callback();
9921				}
9922			}
9923		};
9924	}
9925} );
9926
9927
9928
9929
9930var oldCallbacks = [],
9931	rjsonp = /(=)\?(?=&|$)|\?\?/;
9932
9933// Default jsonp settings
9934jQuery.ajaxSetup( {
9935	jsonp: "callback",
9936	jsonpCallback: function() {
9937		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
9938		this[ callback ] = true;
9939		return callback;
9940	}
9941} );
9942
9943// Detect, normalize options and install callbacks for jsonp requests
9944jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
9945
9946	var callbackName, overwritten, responseContainer,
9947		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
9948			"url" :
9949			typeof s.data === "string" &&
9950				( s.contentType || "" )
9951					.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
9952				rjsonp.test( s.data ) && "data"
9953		);
9954
9955	// Handle iff the expected data type is "jsonp" or we have a parameter to set
9956	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
9957
9958		// Get callback name, remembering preexisting value associated with it
9959		callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?
9960			s.jsonpCallback() :
9961			s.jsonpCallback;
9962
9963		// Insert callback into url or form data
9964		if ( jsonProp ) {
9965			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
9966		} else if ( s.jsonp !== false ) {
9967			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
9968		}
9969
9970		// Use data converter to retrieve json after script execution
9971		s.converters[ "script json" ] = function() {
9972			if ( !responseContainer ) {
9973				jQuery.error( callbackName + " was not called" );
9974			}
9975			return responseContainer[ 0 ];
9976		};
9977
9978		// Force json dataType
9979		s.dataTypes[ 0 ] = "json";
9980
9981		// Install callback
9982		overwritten = window[ callbackName ];
9983		window[ callbackName ] = function() {
9984			responseContainer = arguments;
9985		};
9986
9987		// Clean-up function (fires after converters)
9988		jqXHR.always( function() {
9989
9990			// If previous value didn't exist - remove it
9991			if ( overwritten === undefined ) {
9992				jQuery( window ).removeProp( callbackName );
9993
9994			// Otherwise restore preexisting value
9995			} else {
9996				window[ callbackName ] = overwritten;
9997			}
9998
9999			// Save back as free
10000			if ( s[ callbackName ] ) {
10001
10002				// Make sure that re-using the options doesn't screw things around
10003				s.jsonpCallback = originalSettings.jsonpCallback;
10004
10005				// Save the callback name for future use
10006				oldCallbacks.push( callbackName );
10007			}
10008
10009			// Call if it was a function and we have a response
10010			if ( responseContainer && isFunction( overwritten ) ) {
10011				overwritten( responseContainer[ 0 ] );
10012			}
10013
10014			responseContainer = overwritten = undefined;
10015		} );
10016
10017		// Delegate to script
10018		return "script";
10019	}
10020} );
10021
10022
10023
10024
10025// Support: Safari 8 only
10026// In Safari 8 documents created via document.implementation.createHTMLDocument
10027// collapse sibling forms: the second one becomes a child of the first one.
10028// Because of that, this security measure has to be disabled in Safari 8.
10029// https://bugs.webkit.org/show_bug.cgi?id=137337
10030support.createHTMLDocument = ( function() {
10031	var body = document.implementation.createHTMLDocument( "" ).body;
10032	body.innerHTML = "<form></form><form></form>";
10033	return body.childNodes.length === 2;
10034} )();
10035
10036
10037// Argument "data" should be string of html
10038// context (optional): If specified, the fragment will be created in this context,
10039// defaults to document
10040// keepScripts (optional): If true, will include scripts passed in the html string
10041jQuery.parseHTML = function( data, context, keepScripts ) {
10042	if ( typeof data !== "string" ) {
10043		return [];
10044	}
10045	if ( typeof context === "boolean" ) {
10046		keepScripts = context;
10047		context = false;
10048	}
10049
10050	var base, parsed, scripts;
10051
10052	if ( !context ) {
10053
10054		// Stop scripts or inline event handlers from being executed immediately
10055		// by using document.implementation
10056		if ( support.createHTMLDocument ) {
10057			context = document.implementation.createHTMLDocument( "" );
10058
10059			// Set the base href for the created document
10060			// so any parsed elements with URLs
10061			// are based on the document's URL (gh-2965)
10062			base = context.createElement( "base" );
10063			base.href = document.location.href;
10064			context.head.appendChild( base );
10065		} else {
10066			context = document;
10067		}
10068	}
10069
10070	parsed = rsingleTag.exec( data );
10071	scripts = !keepScripts && [];
10072
10073	// Single tag
10074	if ( parsed ) {
10075		return [ context.createElement( parsed[ 1 ] ) ];
10076	}
10077
10078	parsed = buildFragment( [ data ], context, scripts );
10079
10080	if ( scripts && scripts.length ) {
vendor: 14,511 bytes, lines 10081-10601
10081		jQuery( scripts ).remove();
10082	}
10083
10084	return jQuery.merge( [], parsed.childNodes );
10085};
10086
10087
10088/**
10089 * Load a url into a page
10090 */
10091jQuery.fn.load = function( url, params, callback ) {
10092	var selector, type, response,
10093		self = this,
10094		off = url.indexOf( " " );
10095
10096	if ( off > -1 ) {
10097		selector = stripAndCollapse( url.slice( off ) );
10098		url = url.slice( 0, off );
10099	}
10100
10101	// If it's a function
10102	if ( isFunction( params ) ) {
10103
10104		// We assume that it's the callback
10105		callback = params;
10106		params = undefined;
10107
10108	// Otherwise, build a param string
10109	} else if ( params && typeof params === "object" ) {
10110		type = "POST";
10111	}
10112
10113	// If we have elements to modify, make the request
10114	if ( self.length > 0 ) {
10115		jQuery.ajax( {
10116			url: url,
10117
10118			// If "type" variable is undefined, then "GET" method will be used.
10119			// Make value of this field explicit since
10120			// user can override it through ajaxSetup method
10121			type: type || "GET",
10122			dataType: "html",
10123			data: params
10124		} ).done( function( responseText ) {
10125
10126			// Save response for use in complete callback
10127			response = arguments;
10128
10129			self.html( selector ?
10130
10131				// If a selector was specified, locate the right elements in a dummy div
10132				// Exclude scripts to avoid IE 'Permission Denied' errors
10133				jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
10134
10135				// Otherwise use the full result
10136				responseText );
10137
10138		// If the request succeeds, this function gets "data", "status", "jqXHR"
10139		// but they are ignored because response was set above.
10140		// If it fails, this function gets "jqXHR", "status", "error"
10141		} ).always( callback && function( jqXHR, status ) {
10142			self.each( function() {
10143				callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
10144			} );
10145		} );
10146	}
10147
10148	return this;
10149};
10150
10151
10152
10153
10154// Attach a bunch of functions for handling common AJAX events
10155jQuery.each( [
10156	"ajaxStart",
10157	"ajaxStop",
10158	"ajaxComplete",
10159	"ajaxError",
10160	"ajaxSuccess",
10161	"ajaxSend"
10162], function( i, type ) {
10163	jQuery.fn[ type ] = function( fn ) {
10164		return this.on( type, fn );
10165	};
10166} );
10167
10168
10169
10170
10171jQuery.expr.pseudos.animated = function( elem ) {
10172	return jQuery.grep( jQuery.timers, function( fn ) {
10173		return elem === fn.elem;
10174	} ).length;
10175};
10176
10177
10178
10179
10180jQuery.offset = {
10181	setOffset: function( elem, options, i ) {
10182		var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
10183			position = jQuery.css( elem, "position" ),
10184			curElem = jQuery( elem ),
10185			props = {};
10186
10187		// Set position first, in-case top/left are set even on static elem
10188		if ( position === "static" ) {
10189			elem.style.position = "relative";
10190		}
10191
10192		curOffset = curElem.offset();
10193		curCSSTop = jQuery.css( elem, "top" );
10194		curCSSLeft = jQuery.css( elem, "left" );
10195		calculatePosition = ( position === "absolute" || position === "fixed" ) &&
10196			( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
10197
10198		// Need to be able to calculate position if either
10199		// top or left is auto and position is either absolute or fixed
10200		if ( calculatePosition ) {
10201			curPosition = curElem.position();
10202			curTop = curPosition.top;
10203			curLeft = curPosition.left;
10204
10205		} else {
10206			curTop = parseFloat( curCSSTop ) || 0;
10207			curLeft = parseFloat( curCSSLeft ) || 0;
10208		}
10209
10210		if ( isFunction( options ) ) {
10211
10212			// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
10213			options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
10214		}
10215
10216		if ( options.top != null ) {
10217			props.top = ( options.top - curOffset.top ) + curTop;
10218		}
10219		if ( options.left != null ) {
10220			props.left = ( options.left - curOffset.left ) + curLeft;
10221		}
10222
10223		if ( "using" in options ) {
10224			options.using.call( elem, props );
10225
10226		} else {
10227			curElem.css( props );
10228		}
10229	}
10230};
10231
10232jQuery.fn.extend( {
10233
10234	// offset() relates an element's border box to the document origin
10235	offset: function( options ) {
10236
10237		// Preserve chaining for setter
10238		if ( arguments.length ) {
10239			return options === undefined ?
10240				this :
10241				this.each( function( i ) {
10242					jQuery.offset.setOffset( this, options, i );
10243				} );
10244		}
10245
10246		var rect, win,
10247			elem = this[ 0 ];
10248
10249		if ( !elem ) {
10250			return;
10251		}
10252
10253		// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
10254		// Support: IE <=11 only
10255		// Running getBoundingClientRect on a
10256		// disconnected node in IE throws an error
10257		if ( !elem.getClientRects().length ) {
10258			return { top: 0, left: 0 };
10259		}
10260
10261		// Get document-relative position by adding viewport scroll to viewport-relative gBCR
10262		rect = elem.getBoundingClientRect();
10263		win = elem.ownerDocument.defaultView;
10264		return {
10265			top: rect.top + win.pageYOffset,
10266			left: rect.left + win.pageXOffset
10267		};
10268	},
10269
10270	// position() relates an element's margin box to its offset parent's padding box
10271	// This corresponds to the behavior of CSS absolute positioning
10272	position: function() {
10273		if ( !this[ 0 ] ) {
10274			return;
10275		}
10276
10277		var offsetParent, offset, doc,
10278			elem = this[ 0 ],
10279			parentOffset = { top: 0, left: 0 };
10280
10281		// position:fixed elements are offset from the viewport, which itself always has zero offset
10282		if ( jQuery.css( elem, "position" ) === "fixed" ) {
10283
10284			// Assume position:fixed implies availability of getBoundingClientRect
10285			offset = elem.getBoundingClientRect();
10286
10287		} else {
10288			offset = this.offset();
10289
10290			// Account for the *real* offset parent, which can be the document or its root element
10291			// when a statically positioned element is identified
10292			doc = elem.ownerDocument;
10293			offsetParent = elem.offsetParent || doc.documentElement;
10294			while ( offsetParent &&
10295				( offsetParent === doc.body || offsetParent === doc.documentElement ) &&
10296				jQuery.css( offsetParent, "position" ) === "static" ) {
10297
10298				offsetParent = offsetParent.parentNode;
10299			}
10300			if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {
10301
10302				// Incorporate borders into its offset, since they are outside its content origin
10303				parentOffset = jQuery( offsetParent ).offset();
10304				parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true );
10305				parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true );
10306			}
10307		}
10308
10309		// Subtract parent offsets and element margins
10310		return {
10311			top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
10312			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
10313		};
10314	},
10315
10316	// This method will return documentElement in the following cases:
10317	// 1) For the element inside the iframe without offsetParent, this method will return
10318	//    documentElement of the parent window
10319	// 2) For the hidden or detached element
10320	// 3) For body or html element, i.e. in case of the html node - it will return itself
10321	//
10322	// but those exceptions were never presented as a real life use-cases
10323	// and might be considered as more preferable results.
10324	//
10325	// This logic, however, is not guaranteed and can change at any point in the future
10326	offsetParent: function() {
10327		return this.map( function() {
10328			var offsetParent = this.offsetParent;
10329
10330			while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
10331				offsetParent = offsetParent.offsetParent;
10332			}
10333
10334			return offsetParent || documentElement;
10335		} );
10336	}
10337} );
10338
10339// Create scrollLeft and scrollTop methods
10340jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
10341	var top = "pageYOffset" === prop;
10342
10343	jQuery.fn[ method ] = function( val ) {
10344		return access( this, function( elem, method, val ) {
10345
10346			// Coalesce documents and windows
10347			var win;
10348			if ( isWindow( elem ) ) {
10349				win = elem;
10350			} else if ( elem.nodeType === 9 ) {
10351				win = elem.defaultView;
10352			}
10353
10354			if ( val === undefined ) {
10355				return win ? win[ prop ] : elem[ method ];
10356			}
10357
10358			if ( win ) {
10359				win.scrollTo(
10360					!top ? val : win.pageXOffset,
10361					top ? val : win.pageYOffset
10362				);
10363
10364			} else {
10365				elem[ method ] = val;
10366			}
10367		}, method, val, arguments.length );
10368	};
10369} );
10370
10371// Support: Safari <=7 - 9.1, Chrome <=37 - 49
10372// Add the top/left cssHooks using jQuery.fn.position
10373// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
10374// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
10375// getComputedStyle returns percent when specified for top/left/bottom/right;
10376// rather than make the css module depend on the offset module, just check for it here
10377jQuery.each( [ "top", "left" ], function( i, prop ) {
10378	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
10379		function( elem, computed ) {
10380			if ( computed ) {
10381				computed = curCSS( elem, prop );
10382
10383				// If curCSS returns percentage, fallback to offset
10384				return rnumnonpx.test( computed ) ?
10385					jQuery( elem ).position()[ prop ] + "px" :
10386					computed;
10387			}
10388		}
10389	);
10390} );
10391
10392
10393// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
10394jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
10395	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
10396		function( defaultExtra, funcName ) {
10397
10398		// Margin is only for outerHeight, outerWidth
10399		jQuery.fn[ funcName ] = function( margin, value ) {
10400			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
10401				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
10402
10403			return access( this, function( elem, type, value ) {
10404				var doc;
10405
10406				if ( isWindow( elem ) ) {
10407
10408					// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
10409					return funcName.indexOf( "outer" ) === 0 ?
10410						elem[ "inner" + name ] :
10411						elem.document.documentElement[ "client" + name ];
10412				}
10413
10414				// Get document width or height
10415				if ( elem.nodeType === 9 ) {
10416					doc = elem.documentElement;
10417
10418					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
10419					// whichever is greatest
10420					return Math.max(
10421						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
10422						elem.body[ "offset" + name ], doc[ "offset" + name ],
10423						doc[ "client" + name ]
10424					);
10425				}
10426
10427				return value === undefined ?
10428
10429					// Get width or height on the element, requesting but not forcing parseFloat
10430					jQuery.css( elem, type, extra ) :
10431
10432					// Set width or height on the element
10433					jQuery.style( elem, type, value, extra );
10434			}, type, chainable ? margin : undefined, chainable );
10435		};
10436	} );
10437} );
10438
10439
10440jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
10441	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
10442	"change select submit keydown keypress keyup contextmenu" ).split( " " ),
10443	function( i, name ) {
10444
10445	// Handle event binding
10446	jQuery.fn[ name ] = function( data, fn ) {
10447		return arguments.length > 0 ?
10448			this.on( name, null, data, fn ) :
10449			this.trigger( name );
10450	};
10451} );
10452
10453jQuery.fn.extend( {
10454	hover: function( fnOver, fnOut ) {
10455		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
10456	}
10457} );
10458
10459
10460
10461
10462jQuery.fn.extend( {
10463
10464	bind: function( types, data, fn ) {
10465		return this.on( types, null, data, fn );
10466	},
10467	unbind: function( types, fn ) {
10468		return this.off( types, null, fn );
10469	},
10470
10471	delegate: function( selector, types, data, fn ) {
10472		return this.on( types, selector, data, fn );
10473	},
10474	undelegate: function( selector, types, fn ) {
10475
10476		// ( namespace ) or ( selector, types [, fn] )
10477		return arguments.length === 1 ?
10478			this.off( selector, "**" ) :
10479			this.off( types, selector || "**", fn );
10480	}
10481} );
10482
10483// Bind a function to a context, optionally partially applying any
10484// arguments.
10485// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
10486// However, it is not slated for removal any time soon
10487jQuery.proxy = function( fn, context ) {
10488	var tmp, args, proxy;
10489
10490	if ( typeof context === "string" ) {
10491		tmp = fn[ context ];
10492		context = fn;
10493		fn = tmp;
10494	}
10495
10496	// Quick check to determine if target is callable, in the spec
10497	// this throws a TypeError, but we will just return undefined.
10498	if ( !isFunction( fn ) ) {
10499		return undefined;
10500	}
10501
10502	// Simulated bind
10503	args = slice.call( arguments, 2 );
10504	proxy = function() {
10505		return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
10506	};
10507
10508	// Set the guid of unique handler to the same of original handler, so it can be removed
10509	proxy.guid = fn.guid = fn.guid || jQuery.guid++;
10510
10511	return proxy;
10512};
10513
10514jQuery.holdReady = function( hold ) {
10515	if ( hold ) {
10516		jQuery.readyWait++;
10517	} else {
10518		jQuery.ready( true );
10519	}
10520};
10521jQuery.isArray = Array.isArray;
10522jQuery.parseJSON = JSON.parse;
10523jQuery.nodeName = nodeName;
10524jQuery.isFunction = isFunction;
10525jQuery.isWindow = isWindow;
10526jQuery.camelCase = camelCase;
10527jQuery.type = toType;
10528
10529jQuery.now = Date.now;
10530
10531jQuery.isNumeric = function( obj ) {
10532
10533	// As of jQuery 3.0, isNumeric is limited to
10534	// strings and numbers (primitives or objects)
10535	// that can be coerced to finite numbers (gh-2662)
10536	var type = jQuery.type( obj );
10537	return ( type === "number" || type === "string" ) &&
10538
10539		// parseFloat NaNs numeric-cast false positives ("")
10540		// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
10541		// subtraction forces infinities to NaN
10542		!isNaN( obj - parseFloat( obj ) );
10543};
10544
10545
10546
10547
10548// Register as a named AMD module, since jQuery can be concatenated with other
10549// files that may use define, but not via a proper concatenation script that
10550// understands anonymous AMD modules. A named AMD is safest and most robust
10551// way to register. Lowercase jquery is used because AMD module names are
10552// derived from file names, and jQuery is normally delivered in a lowercase
10553// file name. Do this after creating the global so that if an AMD module wants
10554// to call noConflict to hide this version of jQuery, it will work.
10555
10556// Note that for maximum portability, libraries that are not jQuery should
10557// declare themselves as anonymous modules, and avoid setting a global if an
10558// AMD loader is present. jQuery is a special case. For more information, see
10559// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
10560
10561if ( typeof define === "function" && define.amd ) {
10562	define( "jquery", [], function() {
10563		return jQuery;
10564	} );
10565}
10566
10567
10568
10569
10570var
10571
10572	// Map over jQuery in case of overwrite
10573	_jQuery = window.jQuery,
10574
10575	// Map over the $ in case of overwrite
10576	_$ = window.$;
10577
10578jQuery.noConflict = function( deep ) {
10579	if ( window.$ === jQuery ) {
10580		window.$ = _$;
10581	}
10582
10583	if ( deep && window.jQuery === jQuery ) {
10584		window.jQuery = _jQuery;
10585	}
10586
10587	return jQuery;
10588};
10589
10590// Expose jQuery and $ identifiers, even in AMD
10591// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
10592// and CommonJS for browser emulators (#13566)
10593if ( !noGlobal ) {
10594	window.jQuery = window.$ = jQuery;
10595}
10596
10597
10598
10599
10600return jQuery;
10601} );
vendor: 5,871 bytes, lines 10602-10840
10602
10603/*!
10604 * JavaScript Cookie v2.2.1
10605 * https://github.com/js-cookie/js-cookie
10606 *
10607 * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
10608 * Released under the MIT license
10609 */
10610;(function (factory) {
10611	var registeredInModuleLoader;
10612	if (typeof define === 'function' && define.amd) {
10613		define(factory);
10614		registeredInModuleLoader = true;
10615	}
10616	if (typeof exports === 'object') {
10617		module.exports = factory();
10618		registeredInModuleLoader = true;
10619	}
10620	if (!registeredInModuleLoader) {
10621		var OldCookies = window.Cookies;
10622		var api = window.Cookies = factory();
10623		api.noConflict = function () {
10624			window.Cookies = OldCookies;
10625			return api;
10626		};
10627	}
10628}(function () {
10629	function extend () {
10630		var i = 0;
10631		var result = {};
10632		for (; i < arguments.length; i++) {
10633			var attributes = arguments[ i ];
10634			for (var key in attributes) {
10635				result[key] = attributes[key];
10636			}
10637		}
10638		return result;
10639	}
10640
10641	function decode (s) {
10642		return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
10643	}
10644
10645	function init (converter) {
10646		function api() {}
10647
10648		function set (key, value, attributes) {
10649			if (typeof document === 'undefined') {
10650				return;
10651			}
10652
10653			attributes = extend({
10654				path: '/'
10655			}, api.defaults, attributes);
10656
10657			if (typeof attributes.expires === 'number') {
10658				attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5);
10659			}
10660
10661			// We're using "expires" because "max-age" is not supported by IE
10662			attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
10663
10664			try {
10665				var result = JSON.stringify(value);
10666				if (/^[\{\[]/.test(result)) {
10667					value = result;
10668				}
10669			} catch (e) {}
10670
10671			value = converter.write ?
10672				converter.write(value, key) :
10673				encodeURIComponent(String(value))
10674					.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
10675
10676			key = encodeURIComponent(String(key))
10677				.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)
10678				.replace(/[\(\)]/g, escape);
10679
10680			var stringifiedAttributes = '';
10681			for (var attributeName in attributes) {
10682				if (!attributes[attributeName]) {
10683					continue;
10684				}
10685				stringifiedAttributes += '; ' + attributeName;
10686				if (attributes[attributeName] === true) {
10687					continue;
10688				}
10689
10690				// Considers RFC 6265 section 5.2:
10691				// ...
10692				// 3.  If the remaining unparsed-attributes contains a %x3B (";")
10693				//     character:
10694				// Consume the characters of the unparsed-attributes up to,
10695				// not including, the first %x3B (";") character.
10696				// ...
10697				stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
10698			}
10699
10700			return (document.cookie = key + '=' + value + stringifiedAttributes);
10701		}
10702
10703		function get (key, json) {
10704			if (typeof document === 'undefined') {
10705				return;
10706			}
10707
10708			var jar = {};
10709			// To prevent the for loop in the first place assign an empty array
10710			// in case there are no cookies at all.
10711			var cookies = document.cookie ? document.cookie.split('; ') : [];
10712			var i = 0;
10713
10714			for (; i < cookies.length; i++) {
10715				var parts = cookies[i].split('=');
10716				var cookie = parts.slice(1).join('=');
10717
10718				if (!json && cookie.charAt(0) === '"') {
10719					cookie = cookie.slice(1, -1);
10720				}
10721
10722				try {
10723					var name = decode(parts[0]);
10724					cookie = (converter.read || converter)(cookie, name) ||
10725						decode(cookie);
10726
10727					if (json) {
10728						try {
10729							cookie = JSON.parse(cookie);
10730						} catch (e) {}
10731					}
10732
10733					jar[name] = cookie;
10734
10735					if (key === name) {
10736						break;
10737					}
10738				} catch (e) {}
10739			}
10740
10741			return key ? jar[key] : jar;
10742		}
10743
10744		api.set = set;
10745		api.get = function (key) {
10746			return get(key, false /* read as raw */);
10747		};
10748		api.getJSON = function (key) {
10749			return get(key, true /* read as json */);
10750		};
10751		api.remove = function (key, attributes) {
10752			set(key, '', extend(attributes, {
10753				expires: -1
10754			}));
10755		};
10756
10757		api.defaults = {};
10758
10759		api.withConverter = init;
10760
10761		return api;
10762	}
10763
10764	return init(function () {});
10765}));
10766
10767/**
10768 *
10769 *	[SOW] Stepofweb Controller
10770 *
10771 *	@author Dorin Grigoras
10772 *			www.stepofweb.com
10773 *
10774 *	@version 1.0.0
10775
10776
10777 	@globals
10778
10779 		$.SOW.globals.direction 						'ltr|rtl'
10780 		$.SOW.globals.width 							actual width 	(updated on resize)
10781 		$.SOW.globals.height 							actual height 	(updated on resize)
10782 		$.SOW.globals.is_mobile 						true|false
10783 		$.SOW.globals.is_modern_browser 				true if modern
10784 		$.SOW.globals.is_admin 							true|false 		(admin layout)
10785 		$.SOW.globals.breakpoints.[sm|ms|lg|xl] 		bootstrap default breakpoints
10786 		$.SOW.globals.elBody 							body element
10787 		$.SOW.globals.elHeader 							header element
10788 		$.SOW.globals.elAside 							main sidebar element
10789		$.SOW.globals.elSideCart						CART @sidebar
10790
10791 	@functions
10792 		$.SOW.reinit('#container') 						reinit plugins for a specific ajax container; see also:
10793
10794 *
10795 **/
10796;(function ($) {
10797	'use strict';
10798
10799	/**
10800	 *
10801	 *	@vars
10802	 *
10803	 *
10804	 **/
10805	 var _v = '1.0.0';
10806
10807
10808	$.SOW = {
10809
10810
10811		/**
10812		 *
10813		 *	@init
10814		 *
10815		 *
10816		 **/
10817		init: function () {
10818
10819			/**
10820
10821				None, Strict and Lax Parameters
10822				1. None
10823					If you use the ‘None’ value, this allows cookies to be
10824					sent to requests issued by third parties. You have to make
10825					sure to add the secure attribute alongside setting SameSite=None.
10826
10827				2. Strict
10828					If you use the ‘Strict’ value, the cookies will not be sent when
10829					a third party issues the requests. In some cases, this option might
10830					negatively impact your browsing experience. For example, if a website
10831					you visit by clicking on a link has the SameSite=Strict attribute set,
10832					the website might request you to log in again, since the cookie won’t
10833					be sent along with the request.
10834
10835				3. Lax
10836					If you use the ‘Lax’ value, this allows cookies to be sent if the third
10837					party issues a GET request that causes a Top Level Navigation, which
10838					means that the request will change the address bar. Only those requests
10839					allow the cookie to be sent with the ‘Lax’ value.
10840
10841			**/ 	document.cookie = 'cross-site-cookie=sow; ' + $.SOW.globals.cookie_secure + ';path=/';
10842			// -- --
10843
10844
10845
10846			// Debug infos
10847			// https://developers.google.com/web/fundamentals/performance/navigation-and-resource-timing/
10848			if(window.performance) {
10849
10850				var __start = new Date().getTime();
10851				window.onload = function() {
10852
10853					if($.SOW.config.sow__debug_enable === true) {
10854
10855						var __now 		= new Date().getTime();
10856						var pageNav 	= performance.getEntriesByType("navigation")[0];
10857						var pagePaint 	= performance.getEntriesByType('paint');
10858
10859						$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
10860						$.SOW.helper.consoleLog('+ PAGE DISPLAY: ' + (__now - __start) + ' milliseconds', 'color: #6dbb30; font-size: 13px;');
10861						$.SOW.helper.consoleLog('+ DOM RENDERING:', 'color: #6dbb30; font-size: 13px;');
10862
10863						if(pagePaint) {
10864							pagePaint.forEach( (performanceEntry, i, entries) => {
10865								$.SOW.helper.consoleLog('     - ' + performanceEntry.name + ' was ' + performanceEntry.startTime + ' milliseconds', 'color: #6dbb30; font-size: 13px;');
10866							});
10867						}
10868
10869						$.SOW.helper.consoleLog('+ Depends on user hardware! First load is always expensive, next loads are using the cache! ', 'color: #999999; font-size: 12px;');
10870
10871						if(pageNav) {
10872							$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
10873							$.SOW.helper.consoleLog('+ DNS Lookup time: ' + (pageNav.domainLookupEnd - pageNav.domainLookupStart) + ' seconds', 'color: #6dbb30; font-size: 13px;');
10874							$.SOW.helper.consoleLog('+ Connection time: ' + (pageNav.connectEnd - pageNav.connectStart) + ' milliseconds', 'color: #6dbb30; font-size: 13px;');
10875							$.SOW.helper.consoleLog('+ Cache Seek: ' + (pageNav.responseEnd - pageNav.fetchStart) + ' milliseconds', 'color: #6dbb30; font-size: 13px;');
10876							$.SOW.helper.consoleLog('+ Compression Ratio: ' + (pageNav.decodedBodySize / pageNav.encodedBodySize), 'color: #6dbb30; font-size: 13px;');
10877							$.SOW.helper.consoleLog('+ Download Time: ' + (pageNav.responseEnd - pageNav.requestStart) + ' milliseconds', 'color: #6dbb30; font-size: 13px;');
10878						}
10879
10880						$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
10881
10882					}
10883				}
10884
10885			}
10886
10887
10888
10889			$(document).ready(function() {
10890
10891				/*
10892
10893					Check if debug is enabled
10894					Should be disabled on production!
10895
10896				*/
10897				if($.SOW.config.sow__debug_enable === true) {
10898
10899					$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
10900					$.SOW.helper.consoleLog('+ CONSOLE DEBUG ENABLED : gulp.config.settings.js', 'color: #ff0000; font-size: 13px;');
10901					$.SOW.helper.consoleLog('+ SOW Controller : ' + _v, 'color: #ff0000; font-size: 13px;');
10902					$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
10903
10904				}
10905
10906				// on load
10907				$.SOW.globals.js_location 	= $.SOW.helper.jsLocation();
10908				$.SOW.globals.css_location 	= $.SOW.helper.cssLocation();
10909				$.SOW.onresize();
10910
10911
10912
10913				/*
10914
10915					1. 	Check for bootstrap
10916						:: 	Part of bundle file!
10917							vendor_bundle.min.js
10918
10919				*/
10920				if(typeof $().emulateTransitionEnd === 'function') {
10921					$.SOW.reinit(); /* first init ; ajax callable */
10922					return;
10923				}
10924
10925
10926
10927				/*
10928
10929					1. 	Bundle not loaded
10930						:: 	Load it! And init!
10931							vendor_bundle.min.js
10932
10933				*/
10934				// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10935				$.SOW.helper.loadScript([$.SOW.globals.js_location + 'vendor_bundle.min.js'], false, true).done(function() {
10936					$.SOW.helper.consoleLog('Vendor Bunde: Dynamically loaded!');
10937					$.SOW.reinit(); /* first init ; ajax callable */
10938				});
10939				// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10940
10941			});
10942
10943		},
10944
10945
10946
10947		/**
10948		 *
10949		 *	@globals
10950		 *	SOW Config
10951		 *
10952		 **/
10953		globals: {
10954
10955			direction 			: $('body').css('direction'), 	/* rtl | ltr */
10956			width 				: $(window).width(), 			/* window width, updated on resize */
10957			height 				: $(window).height(), 			/* window height, updated on resize */
10958			is_modern_browser 	: ('querySelector' in document && 'localStorage' in window && 'addEventListener' in window), 	/* `true` if modern */
10959			is_mobile 			: ($(window).width() < 993) 			? true : false,
10960			is_admin 			: $('body').hasClass('layout-admin') 	? true : false,
10961			ajax_container 		: 'body', 						/* DO NOT USE THIS IN YOUR SCRIPT, IS EXCLUSIVELY USED BY REINIT() FUNCTION */
10962			page_first_load 	: true, 						/* set by reinit() to false after first load - used by ajax */
10963			js_location 		: '',							/* javascripts location, used to dinamicaly load js scripts */
10964			css_location 		: '',							/* javascripts location, used to dinamicaly load css */
10965			cookie_secure 		: 'SameSite=None; secure',		/* New Google Secure Cookie */
10966
10967			/* bootstrap breakpoints */
10968			breakpoints 	: {
10969				'sm': 576,
10970				'md': 768,
10971				'lg': 992,
10972				'xl': 1200
10973			},
10974
10975			/*
10976				Most used only!
10977				Cache once : Use everywhere
10978			*/
10979			elBody			: $('body'),
10980			elHeader		: ($('#header').length > 0) 	? $('#header') 		: null,
10981			elAside			: ($('#aside-main').length > 0) ? $('#aside-main') 	: null,
10982			elSideCart		: ($('#sidecart').length > 0)	? $('#sidecart') 	: null,
10983
10984		},
10985
10986
10987
10988		/**
10989		 *
10990		 *	@core
10991		 *	SOW Core Plugins
10992		 *
10993		 **/
10994		core: {},
10995
10996
10997
10998		/**
10999		 *
11000		 *	@vendor
11001		 *	Vendor Plugins [separated by SOW]
11002		 *
11003		 **/
11004		vendor: {},
11005
11006
11007
11008		/**
11009		 *
11010		 *	@helper
11011		 *	SOW Helpers
11012		 *
11013		 **/
11014		helper: {},
11015
11016
11017
11018		/**
11019		 *
11020		 *	@custom
11021		 *	My Custom [optional]
11022		 *
11023		 **/
11024		custom: {},
11025
11026
11027
11028		/**
11029		 *
11030		 *	@resize
11031		 *	Window Resize
11032		 *
11033		 **/
11034		onresize: function() {
11035
11036			// On Resize
11037			jQuery(window).resize(function() {
11038
11039				if(window.afterResizeApp)
11040					clearTimeout(window.afterResizeApp);
11041
11042				window.afterResizeApp = setTimeout(function() {
11043
11044
11045					/** Window Width **/
11046					$.SOW.globals.width 	= jQuery(window).width();
11047
11048					/** Window Height **/
11049					$.SOW.globals.height 	= jQuery(window).height();
11050
11051					/** Is Mobile **/
11052					$.SOW.globals.is_mobile = ($(window).width() < 993) ? true : false;
11053
11054
11055				}, 150);
11056
11057			});
11058
11059		},
11060
11061
11062
11063		/**
11064		 *
11065		 *	@reinit
11066		 *	Ajax Callable
11067		 *
11068		 **/
11069		reinit: function(ajax_container) {
11070
11071			/*
11072				For each Ajax call, we temporarily set the ajax container as global
11073				After reinit, we reset back the ajax container as 'body'
11074			*/
11075			$.SOW.globals.ajax_container = $.SOW.helper.check_var(ajax_container) || 'body';
11076
11077
11078			/** Bootstrap Toasts **/
11079			$($.SOW.globals.ajax_container + ' .toast').toast('show');
11080
11081
11082			/** Bootstrap Tooltip **/
11083			$($.SOW.globals.ajax_container + " [data-toggle=tooltip]," + $.SOW.globals.ajax_container + " [data-tooltip]").tooltip('dispose').tooltip({
11084				container: ($.SOW.globals.ajax_container == 'body') ? 'html' : $.SOW.globals.ajax_container /* fixing wired positioning! */
11085			});
11086
11087
11088			/** Bootstrap Popover **/
11089			$($.SOW.globals.ajax_container + ' [data-toggle="popover"]').popover({
11090				container: ($.SOW.globals.ajax_container == 'body') ? 'html' : $.SOW.globals.ajax_container /* fixing wired positioning! */
11091			});
11092
11093
11094			/** Bootstrap Carousel **/
11095			$($.SOW.globals.ajax_container + ' .carousel').carousel('dispose').carousel({
11096				direction: 	($.SOW.globals.direction == 'ltr') ? 'right' : 'left'
11097			});
11098
11099			/** Bootstrap Scrollspy **/
11100			$('[data-spy="scroll"]').each(function () {
11101				$(this).scrollspy('refresh');
11102			});
11103
11104
11105
11106			/*
11107
11108				Autoinit plugins
11109				Specified in Config
11110
11111			*/
11112			// for (var index = 0; index < $.SOW.config.autoinit.length; ++index) {
11113			for (var index in $.SOW.config.autoinit) {
11114
11115				// Not first page load, skip if plugin do not allow reinit by ajax
11116				if($.SOW.globals.page_first_load === false && $.SOW.config.autoinit[index][3] === false)
11117					continue;
11118
11119				$.SOW.helper.executeFunctionByName(
11120						$.SOW.config.autoinit[index][0], 	// script
11121						window,
11122						$.SOW.config.autoinit[index][1], 	// selector
11123						$.SOW.config.autoinit[index][2]);	// config
11124
11125			}
11126
11127
11128			/*
11129
11130				Reserved for emergencies!
11131				Called for each ajax container!
11132
11133				global_callback = function(ajax_container) {
11134					...
11135				}
11136
11137			*/
11138			if(typeof global_callback === 'function')
11139				$.SOW.helper.executeFunctionByName('global_callback', window, $.SOW.globals.ajax_container);
11140
11141
11142			/*
11143				Page classic preloader : first load only!
11144			*/
11145			if($.SOW.globals.page_first_load === true) {
11146
11147				jQuery('#page_preload').fadeOut(1000, function() {
11148					jQuery(this).remove();
11149				});
11150
11151			}
11152
11153			// First page load finished!
11154			// Any future reinit() calls are Ajax!
11155			$.SOW.globals.page_first_load 	= false;
11156			$.SOW.globals.ajax_container 	= 'body'; // reset
11157
11158		},
11159
11160
11161	};
11162
11163
11164
11165	/**
11166	 *
11167	 *	Init this
11168	 *
11169	 *
11170	 **/
11171	$.SOW.init();
11172
11173})(jQuery);
11174/**
11175 *
11176 *	[SOW] Config
11177 *
11178 **/
11179;(function ($) {
11180	'use strict';
11181
11182	$.SOW.config = {
11183
11184		/*
11185
11186			+++++++++++++++++++++++++++++++++
11187			OVERWRITEN BY GULP : LEAVE IT FALSE!
11188			Browser console global debuger!
11189			+++++++++++++++++++++++++++++++++
11190
11191		*/
11192		sow__debug_enable								: false,
11193
11194
11195
11196		/*
11197
11198			SOW : VARIOUS
11199			-----------------------------------------------------
11200
11201		*/
11202		/* Icons */
11203		sow__icon_loading 								: 'fi fi-circle-spin fi-spin',		// ajax loading indicator
11204		sow__icon_check 								: 'fi fi-check', 					// 'success' messages or other places
11205		sow__icon_close 								: 'fi fi-close', 					// 'failed'  messages or other places
11206
11207	};
11208
11209})(jQuery);
11210/**
11211 *
11212 *	[SOW] Helper
11213 *
11214 *	@author 		Dorin Grigoras
11215 *					www.stepofweb.com
11216 *
11217 *
11218 *	@Dependency 	-
11219 *
11220
11221 	*	@check_var
11222		$.SOW.helper.check_var(variable);
11223	*
11224 		@check_var
11225 		$.SOW.helper.is_numeric(str);
11226 	*
11227		@loadScript
11228		$.SOW.helper.loadScript(script_arr, async[true|false], cache[true|false]).done(function() {
11229			// all scripts loaded... do something
11230			// * async = false by default (scripts are loaded in order)
11231			// * cache = true by default
11232		});
11233
11234
11235	 *
11236		@loadCSS
11237		$.SOW.helper.loadCSS("/path/to/file.css", "append|prepend|remove");  "append" is default, if no option passed
11238	 *
11239		@loadingSpinner
11240		$.SOW.helper.loadingSpinner('show|hide', "#mycontainer", 'overlay|icon');
11241	 *
11242		@executeFunctionByName
11243		$.SOW.helper.executeFunctionByName("FunctionName", window, arguments);
11244	 *
11245		@overlay
11246		$.SOW.helper.overlay('show|hide|toggle');
11247	 *
11248		@randomStr
11249		$.SOW.helper.randomStr(8, ''|L|N);
11250	 *
11251	 	@byte2size
11252	 	$.SOW.helper.byte2size(bytes, precision=2, int_only=false);
11253	 	$.SOW.helper.byte2kb(bytes);
11254	 *
11255		@scrollAnimate
11256		$.SOW.helper.scrollAnimate(_el, _offset, _hash_change, _speed);
11257			_el 			= element to scroll to. #top = page top
11258			_offset 		= top offset (0 default)
11259			_hash_change 	= update url hash on click
11260			_speed 			= scroll speed (400 default)
11261
11262		$.SOW.helper.scrollAnimate('#top', 0, false, 400);
11263	 *
11264		@removeUrlHash
11265		$.SOW.helper.removeUrlHash('https://domain.com/url#hash');
11266	 *
11267		@playSound
11268		$.SOW.helper.playSound('path/to/audio.mp3');
11269	 *
11270	 	@time_from_ms
11271		$.SOW.helper.time_from_ms(miliseconds, 's|m|h|d|empty for all');
11272	 *
11273		@get_browser (unfinished, need improvement, do not use)
11274		$.SOW.helper.get_browser();
11275	 *
11276		@params_parse
11277		var params = $.SOW.helper.params_parse('['param','value']['param2','value2']); // return: array
11278
11279			var ajax_params_arr = $.SOW.helper.params_parse(ajax_params);
11280			for (var i = 0; i < ajax_params_arr.length; ++i) {
11281				formDataDel.append(ajax_params_arr[i][0], ajax_params_arr[i][1]);
11282			}
11283	 *
11284		@indexedDB (local database)
11285		$.SOW.helper.indexedDB(.. see function ..);
11286	 *
11287		@currencyFormat
11288		$.SOW.helper.currencyFormat(1000000); // output: 1,234,567.89
11289
11290		// 1,234,567.89
11291		$.SOW.helper.currencyFormat(1000000, [
11292			   2, ',', '.' // en
11293			// 2, '.', ',' // de
11294			// 2, ' ', ',' // fr
11295		]);
11296	 *
11297	 	@strhash
11298	 	$.SOW.helper.strhash('string here'); // create a hash, md5 alternative
11299	 *
11300		 @videoEmbedFromUrl
11301		 $.SOW.helper.videoEmbedFromUrl('https://www.youtube.com?v=jh8Hgd466', autoplay=1);
11302	 *
11303		@consoleLog (output - only if debug is enabled!)
11304		$.SOW.helper.consoleLog('Lorem Ipsum', 'color: #ff0000;');
11305 *
11306 *
11307 **/
11308;(function ($) {
11309	'use strict';
11310
11311
11312	/**
11313	 *
11314	 *	@vars
11315	 *
11316	 *
11317	 **/
11318	var obj 			= {}; 				// used by loadScript
11319
11320
11321	$.SOW.helper = {
11322
11323
11324		/**
11325		 *
11326		 *	@config
11327		 *
11328		 *
11329		 **/
11330		config: {},
11331
11332
11333
11334		/**
11335		 *
11336		 *	@collection
11337		 *
11338		 *
11339		 **/
11340		collection: $(),
11341
11342
11343
11344		/**
11345		 *
11346		 *	@init
11347		 *
11348		 *
11349		 **/
11350		init: function (selector, config) {/** no init required **/},
11351
11352
11353
11354
11355		/**
11356		 *
11357		 *	@__selector
11358		 *	DO NOT! DO NOT CHANGE!
11359		 * 	$.SOW.helper.__selector(selector);
11360		 *
11361		 **/
11362		__selector: function(selector) {
11363
11364			var selector 		= $.SOW.helper.check_var(selector) || ''; /* '' is required if null */
11365			var selector_orig 	= selector;
11366			var element 		= (selector && $(selector).length > 0) ? $(selector) : $();
11367
11368			/* add ajax container - required for binds */
11369			if($.SOW.globals.ajax_container != 'html' && $.SOW.globals.ajax_container != 'body' && $.SOW.globals.ajax_container != '') {
11370
11371				if (selector.indexOf(',') > -1)
11372					var selector = selector.split(',').join(', ' + $.SOW.globals.ajax_container + ' ');
11373
11374				selector = $.SOW.globals.ajax_container + ' ' + selector;
11375
11376			}
11377
11378			return [selector, element, selector_orig]; // selector_orig = without ajax container, in case is needed
11379
11380		},
11381
11382
11383
11384
11385
11386
11387		/**
11388		 *
11389		 *	@check_var
11390		 *
11391			$.SOW.helper.check_var(variable);
11392		 *
11393		 **/
11394		check_var: function(_var) {
11395
11396			return 	(typeof _var !== "undefined") ? _var : null;
11397
11398		},
11399
11400
11401
11402
11403
11404
11405
11406		/**
11407		 *
11408		 *	@is_numeric
11409		 *
11410		 *	Welcome to Javascript!
11411		 *	Please, stay! Is nice in here!
11412		 *
11413			$.SOW.helper.is_numeric(_var);
11414		 * 	1.2 = true 	; 	1,2 = false
11415		 **/
11416		is_numeric: function(_var) {
11417
11418			if(typeof _var === 'number')
11419				return true;
11420
11421			// at this point, we might have bool/object/function/etc
11422			else if(typeof _var !== 'string')
11423				return false;
11424
11425			// -- --
11426
11427			var _var = ''+_var.replace(/\s/g, '');
11428			if(_var === '')
11429				return false;
11430
11431			else if(_var.slice(-1) === '.')
11432				return false; 	// something like '1.'
11433
11434			// -- --
11435
11436			return !isNaN(parseFloat(_var)) && isFinite(_var);
11437
11438		},
11439
11440
11441
11442
11443
11444
11445
11446		/**
11447		 *
11448		 *	@loadScript
11449		 *
11450
11451			async false:
11452				loads scripts one-by-one using recursion (ordered)
11453				returns jQuery.Deferred
11454
11455			async true:
11456				loads scripts asynchronized, if order is not needed!
11457				returns jQuery.when
11458
11459
11460
11461				var script_arr = [
11462					'myscript1.js',
11463					'myscript2.js',
11464					'myscript3.js'
11465				];
11466
11467				$.SOW.helper.loadScript(script_arr, async[true|false], cache[true|false]).done(function() {
11468					// all scripts loaded... do something
11469					// * async = false by default (scripts are loaded in order)
11470					// * cache = true by default
11471				});
11472
11473		 *
11474		 **/
11475		loadScript: function(script_arr, async, cache) {
11476
11477			return (async === true) ? $.SOW.helper.__loadScriptAsync(script_arr, cache) : $.SOW.helper.__loadScriptOrdered(script_arr, cache);
11478
11479		},
11480
11481			/*
11482
11483				Credits (Salman A : stackovweflow user)
11484					https://stackoverflow.com/a/33312665
11485
11486			*/
11487			__loadScriptOrdered: function(script_arr, cache) {
11488
11489				var deferred = jQuery.Deferred();
11490
11491				function __loadScript(i) {
11492
11493					if (i < script_arr.length) {
11494
11495						jQuery.ajax({
11496
11497							url: 		script_arr[i],
11498							dataType: 	"script",
11499							cache: 		(cache !== false) ? true : false,
11500
11501							success: 	function() {
11502
11503								__loadScript(i + 1);
11504
11505							}
11506
11507						});
11508
11509					} else {
11510
11511						deferred.resolve();
11512
11513					}
11514
11515				}
11516
11517				__loadScript(0);
11518				return deferred;
11519
11520			},
11521
11522			/*
11523
11524				Credits (adeneo stackovweflow user)
11525					https://stackoverflow.com/a/11803418
11526
11527			*/
11528			__loadScriptAsync: function(script_arr, cache) {
11529
11530				var _arr = $.map(script_arr, function(scr) {
11531					return (cache !== false) ? $.SOW.helper.getScriptCached( scr ) : $.getScript( scr );
11532				});
11533
11534				_arr.push($.Deferred(function( deferred ) {
11535					$( deferred.resolve );
11536				}));
11537
11538				return $.when.apply($, _arr);
11539
11540			},
11541				getScriptCached: function(url, options) {
11542
11543					// Allow user to set any option except for dataType, cache, and url
11544					options = $.extend( options || {}, {
11545						dataType: "script",
11546						cache: true,
11547						url: url
11548					});
11549
11550					// Use $.ajax() since it is more flexible than $.getScript
11551					// Return the jqXHR object so we can chain callbacks
11552					return jQuery.ajax( options );
11553
11554				},
11555
11556
11557
11558
11559		/**
11560		 *
11561		 *	@loadCSS
11562		 *
11563			$.SOW.helper.loadCSS("/path/to/file.css", "append|prepend|remove");
11564			"append" is default, if no option passed
11565		 *
11566		 **/
11567		loadCSS: function(cssFile, option) {
11568
11569			/* 1. remove */
11570			if(option === 'remove')
11571				jQuery('head link[href="'+cssFile+'"]').remove();
11572
11573
11574			/* 2. prepend */
11575			else if(option === 'prepend') {
11576				if(jQuery('head link[href="'+cssFile+'"]').length > 0)
11577					return;
11578				jQuery('head').prepend('<link rel="stylesheet" href="'+cssFile+'">');
11579			}
11580
11581
11582			/* 3. append : default */
11583			else  {
11584
11585				if(jQuery('head link[href="'+cssFile+'"]').length > 0)
11586					return;
11587
11588				jQuery('head').append('<link rel="stylesheet" href="'+cssFile+'">');
11589			}
11590
11591
11592		},
11593
11594
11595
11596
11597		/**
11598		 *
11599		 *	@loadingSpinner
11600		 *
11601			$.SOW.helper.loadingSpinner('show|hide', "#mycontainer", 'overlay|icon');
11602		 *
11603		 **/
11604		loadingSpinner: function(option, _container, _layout) { // layout: overlay|icon
11605
11606			var _container 	= (_container === null) ? jQuery('body') : jQuery(_container);
11607			var _layout 	= (typeof _layout !== 'undefined') ? _layout : 'icon';
11608
11609			if(option === 'show') {
11610
11611				// remove existing and stop
11612				if(jQuery('#js_loading_icon').length > 0) {
11613					jQuery('#js_loading_icon').remove();
11614					return;
11615				}
11616
11617				// 1. overlay, absolute positioning inside container
11618				var _tpl1 = '<div id="js_loading_icon" class="position-absolute absolute-full overlay-dark overlay-opacity-2 z-index-9999 text-center">'
11619							+ '<i class="' + $.SOW.config.sow__icon_loading + ' fs--30 text-muted valign-middle"></i>'
11620					  + '</div>';
11621
11622				// 2. fixed - bottom of the screen, no overlay
11623				var _tpl2 =
11624					'<div id="js_loading_icon" class="position-fixed fixed-bottom w-100 mb-3 z-index-9999 text-center shadow-none">'
11625						+ '<span class="bg-white d-inline-block px-4 rounded-lg shadow-lg">'
11626							+ '<i class="' + $.SOW.config.sow__icon_loading + ' fs--30 text-muted"></i>'
11627						+ '</span>'
11628				  + '</div>';
11629
11630
11631				var _tpl 		= (_layout == 'overlay') ? _tpl1 : _tpl2;
11632				var _container 	= (_layout == 'overlay') ? _container : 'body'; // it's fixed, add to body!
11633
11634
11635				// show
11636				if(typeof _container === 'object') {
11637					_container.prepend(_tpl);
11638				} else {
11639					jQuery(_container).prepend(_tpl);
11640				}
11641
11642
11643			} else {
11644
11645				jQuery('#js_loading_icon').remove();
11646
11647			}
11648
11649		},
11650
11651
11652
11653
11654		/**
11655		 *
11656		 *	@executeFunctionByName
11657		 *
11658			$.SOW.helper.executeFunctionByName("FunctionName", window);
11659			$.SOW.helper.executeFunctionByName("My.Namespace.functionName", window, arguments);
11660			$.SOW.helper.executeFunctionByName("Namespace.functionName", My, arguments);
11661
11662
11663			!WARNING! !NOTE!
11664
11665			Most js code obfuscators might wreck the code as they will change the function names, making the string invalid.
11666			Anyway, all obfuscators will double the size of your code and, of course, will be much slower!
11667
11668			This function is used in two places:
11669				1. init|reinit scripts
11670				2. ajax callbacks
11671
11672			Please do not overuse it!
11673
11674		 *
11675		 **/
11676		executeFunctionByName: function(functionName, context /*, args */) {
11677
11678			// return new Promise(resolve => {
11679
11680				if(typeof(window) !== 'undefined') {
11681
11682					// Use the window (from browser) as context if none providen.
11683					context = context || window;
11684
11685				} else {
11686
11687					// If using Node.js, the context will be an empty object
11688					context = context || global;
11689
11690				}
11691
11692
11693				var args 		= Array.prototype.slice.call(arguments, 2);
11694				var namespaces 	= functionName.split(".");
11695				var func 		= namespaces.pop();
11696
11697				for(var i = 0; i < namespaces.length; i++) {
11698					context = context[namespaces[i]];
11699				}
11700
11701
11702				return context[func].apply(context, args);
11703
11704			// });
11705
11706		},
11707
11708
11709
11710
11711		/**
11712		 *
11713		 *	@overlay
11714		 *
11715			$.SOW.helper.overlay('show|hide|toggle');
11716		 *
11717		 **/
11718		overlay: function(option) {
11719
11720			if(option === 'show') {
11721
11722				jQuery('body').append('<div id="overlay-default"></div>');
11723				jQuery('body').addClass('overflow-hidden');
11724
11725			}
11726
11727			else if(option === 'hide') {
11728
11729				jQuery('#overlay-default').unbind().remove();
11730				jQuery('body').removeClass('overflow-hidden');
11731
11732			}
11733
11734			else {
11735
11736				if(jQuery('#overlay-default').length > 0) {
11737					$.SOW.helper.__overlay_hide();
11738				} else {
11739					$.SOW.helper.__overlay_show();
11740				}
11741
11742			}
11743
11744		},
11745			__overlay_show: function() {
11746				jQuery('body').append('<div id="overlay-default"></div>');
11747				jQuery('body').addClass('overflow-hidden');
11748			},
11749			__overlay_hide: function() {
11750				jQuery('#overlay-default').unbind().remove();
11751				jQuery('body').removeClass('overflow-hidden');
11752			},
11753
11754
11755
11756
11757		/**
11758		 *
11759		 *	@randomStr
11760		 *
11761			$.SOW.helper.randomStr(8, ''|L|N);
11762		 *
11763		 **/
11764		randomStr: function(length, type) {
11765
11766			switch(type) {
11767
11768				case 'L':
11769					var characters   = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
11770					break;
11771
11772				case 'N':
11773					var characters   = '0123456789';
11774					break;
11775
11776				default:
11777					var characters   = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
11778
11779			}
11780
11781			var result           = '';
11782			var charactersLength = characters.length;
11783
11784			for ( var i = 0; i < length; i++ ) {
11785				result += characters.charAt(Math.floor(Math.random() * charactersLength));
11786			}
11787
11788			return result;
11789
11790		},
11791
11792
11793		/**
11794		 *
11795		 *	@byte2size
11796		 *
11797		 * 	$.SOW.helper.byte2size(bytes, precision=2, int_only=false);
11798		 *
11799		 **/
11800		byte2size: function(bytes, precision, int_only) {
11801			var precision 	= typeof precision 	!== 'undefined' ? precision : 2;
11802			var int_only 	= typeof int_only 	!== 'undefined' ? int_only 	: false;
11803
11804			if(bytes < 1)
11805					return 0 + (int_only === false) ? 'B' : '';
11806
11807
11808			var k 			= 1024;
11809			var precision 	= precision < 0 ? 0 : precision;
11810			var unit 		= ['B', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb'];
11811
11812			var i 			= Math.floor(Math.log(bytes) / Math.log(k));
11813			var unit_txt 	= (int_only === false) ? ' ' + unit[i] : 0;
11814			return parseFloat((bytes / Math.pow(k, i)).toFixed(precision)) + unit_txt;
11815
11816		},
11817
11818
11819
11820
11821		/**
11822		 *
11823		 *	@byte2kb
11824		 *
11825		 * 	$.SOW.helper.byte2kb(bytes);
11826		 *
11827		 **/
11828		byte2kb: function(bytes) {
11829
11830			if(bytes < 1)
11831				return bytes;
11832
11833			var bytes = bytes / 1024;
11834			return (Math.round(bytes * 100) / 100);
11835
11836		},
11837
11838
11839
11840
11841
11842		/**
11843		 *
11844		 *	@scrollAnimate
11845		 *
11846			$.SOW.helper.scrollAnimate(_el, _offset, _hash_change, _speed);
11847				_el 			= element to scroll to. #top = page top
11848				_offset 		= top offset (0 default)
11849				_hash_change 	= update url hash on click
11850				_speed 			= scroll speed (400 default)
11851
11852			$.SOW.helper.scrollAnimate('#top', 0, false, 400);
11853		 *
11854		 **/
11855		scrollAnimate: function(_el, _offset, _hash_change, _speed) {
11856			_el 				= typeof _el 			!== 'undefined' 	? _el 			: '';
11857			_hash_change 		= typeof _hash_change 	!== 'undefined' 	? _hash_change 	: 'false';
11858			_offset 			= typeof _offset 		!== 'undefined' 	? _offset 		: 0;
11859			_speed 				= typeof _speed 		!== 'undefined' 	? _speed 		: 400;
11860
11861			// Calculate offset if not given!
11862			if(_offset < 1) {
11863
11864				if($.SOW.globals.elBody.hasClass('header-hide'))
11865					_offset = 15;
11866
11867				// .header-fixed is added by js header plugin for all: .header-sticky, .header-scroll-reveal
11868				else if($.SOW.globals.elBody.hasClass('header-fixed') || $.SOW.globals.elBody.hasClass('header-sticky'))
11869					_offset = $.SOW.globals.elHeader.outerHeight() + 15;
11870
11871			}
11872
11873
11874			// Scroll
11875			if(_el != '#' && _el != '#!' && _el != 'javascript:;') {
11876
11877				if(_el == '#top') {
11878
11879					jQuery('html, body').animate({scrollTop: $.SOW.globals.elBody.offset().top}, _speed, function() {
11880
11881						if(_hash_change == 'true') {
11882							window.location.hash = _el;
11883						}
11884
11885					});
11886
11887				} else {
11888
11889					// unexpected error (should never happen - invalid element)!
11890					if(!jQuery(_el).offset()) return;
11891
11892					jQuery('html, body').animate({scrollTop: jQuery(_el).offset().top - parseInt(_offset)}, _speed, function() {
11893
11894						if(_hash_change == 'true') {
11895							window.location.hash = _el;
11896						}
11897
11898					});
11899
11900				}
11901
11902			}
11903
11904		},
11905
11906
11907
11908		/**
11909		 *
11910		 *	@removeUrlHash
11911		 *
11912			$.SOW.helper.removeUrlHash('https://domain.com/url#hash');
11913		 *
11914		 **/
11915		removeUrlHash: function(_url){
11916
11917		    if (_url.indexOf('#') > -1)
11918				return _url.replace(/#.*$/, '');
11919
11920			return _url;
11921
11922		},
11923
11924
11925
11926		/**
11927		 *
11928		 *	@playSound
11929		 *
11930			$.SOW.helper.playSound('path/to/audio.mp3');
11931		 *
11932		 **/
11933		playSound: function(_soundFile) {
11934
11935			var audioElement = document.createElement('audio');
11936
11937			audioElement.setAttribute('src', _soundFile);
11938			audioElement.setAttribute('autoplay', 'autoplay');
11939
11940			audioElement.addEventListener("load", function() {
11941				audioElement.play();
11942			}, true);
11943
11944		},
11945
11946
11947
11948
11949
11950		/**
11951		 *
11952		 *	@time_from_ms
11953		 *
11954			$.SOW.helper.time_from_ms(miliseconds, 's|m|h|d|empty for all');
11955		 *
11956		 **/
11957		time_from_ms: function(miliseconds, format) {
11958			var days, hours, minutes, seconds, total_hours, total_minutes, total_seconds;
11959
11960			total_seconds 	= parseInt(Math.floor(miliseconds / 1000));
11961			total_minutes 	= parseInt(Math.floor(total_seconds / 60));
11962			total_hours 	= parseInt(Math.floor(total_minutes / 60));
11963			days 			= parseInt(Math.floor(total_hours / 24));
11964
11965			seconds 		= parseInt(total_seconds % 60);
11966			minutes 		= parseInt(total_minutes % 60);
11967			hours 			= parseInt(total_hours % 24);
11968
11969			switch(format) {
11970				case 's':
11971					return total_seconds;
11972
11973				case 'm':
11974					return total_minutes;
11975
11976				case 'h':
11977					return total_hours;
11978
11979				case 'd':
11980					return days;
11981
11982				default:
11983					return { d: days, h: hours, m: minutes, s: seconds };
11984			}
11985
11986		},
11987
11988
11989
11990		/**
11991		 *
11992		 *	@get_browser
11993		 *
11994			$.SOW.helper.get_browser();
11995		 *
11996		 **/
11997		get_browser: function() {
11998
11999			var ua = navigator.userAgent.toLowerCase();
12000
12001			if (ua.indexOf('chrome') > -1)
12002				return 'chrome';
12003
12004			else if (ua.indexOf('safari') > -1)
12005				return 'safari';
12006
12007			else if (ua.indexOf('mozilla') > -1)
12008				return 'mozilla';
12009
12010			else if (ua.indexOf('edge') > -1)
12011				return 'edge';
12012
12013			else // ie, etc
12014				return 'n/a';
12015
12016		},
12017
12018
12019
12020
12021		/**
12022		 *
12023		 *	@params_parse
12024		 *
12025			var params = $.SOW.helper.params_parse('['param','value']['param2','value2']); // return: array
12026		 *
12027		 **/
12028		params_parse: function(string) {
12029
12030			if(string != '' && string.length > 2) {
12031
12032				// creating a valid json
12033				var string = '[' + string + ']'; 				// add [] brackets
12034				var string = string.replace(/'/g, '"'); 		// replace ' with "
12035				var string = string.replace(/ /g, ''); 			// remove spaces
12036				var string = string.replace(/]\[/g, '],['); 	// replace: '][' with '],['
12037
12038				// parse
12039				var string = JSON.parse(string);
12040
12041			}
12042
12043			return string;
12044
12045		},
12046
12047
12048
12049
12050		/**
12051		 *
12052		 *	@indexedDB
12053		 *
12054		 	https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
12055
12056			IndexedDB is a low-level API for client-side storage of significant amounts of
12057			structured data, including files/blobs. This API uses indexes to enable
12058			high-performance searches of this data. While Web Storage is useful for storing
12059			smaller amounts of data, it is less useful for storing larger amounts of structured data.
12060			IndexedDB provides a solution.
12061
12062
12063
12064			+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12065				:: EVERYTHING IS RETURNED TO A CALLBACK! ::
12066
12067				callbackFn = function(result) {
12068					console.log(result);
12069				}
12070
12071
12072				var _version 	= 1;
12073				var _database 	= "smarty_test";
12074
12075
12076				// 1. Create Database
12077				$.SOW.helper.indexedDB({ // create database (& indexes)
12078					version: 		_version,
12079					action: 		'db:create',
12080					database: 		_database,
12081
12082					// {} or null
12083					db_options: 	{ keyPath: "item_id", autoIncrement: true },
12084
12085					// define what data items the objectStore will contain
12086					// [indexName, keyPath, {objectParameters}]
12087					db_indexes: 	[
12088						['title', 'title', 		{ unique: false }],
12089						['date', 'date', 		{ unique: false }]
12090					]
12091				});
12092
12093				// Check if database exists
12094				$.SOW.helper.indexedDB({ // check if database exists
12095					version: 		_version,
12096					action: 		'db:check',
12097					database: 		_database,
12098					callback: 		callbackFn
12099				});
12100
12101
12102				// 2. Add Item
12103				$.SOW.helper.indexedDB({ // add item
12104					version: 		_version,
12105					action: 		'db:add',
12106					database: 		_database,
12107					callback: 		callbackFn,
12108					item: 			{
12109						item_id: 	1,
12110						title: 		'Lorem ipsum',
12111						date: 		new Date(),
12112					}
12113				});
12114
12115
12116				// 3. Update : or insert if not exist
12117				$.SOW.helper.indexedDB({ // update | insert if not exist
12118					version: 		_version,
12119					action: 		'db:update',
12120					database: 		_database,
12121					callback: 		callbackFn,
12122					item: 			{
12123						item_id: 	2,
12124						title: 		'This is updated!',
12125						date: 		new Date(),
12126					}
12127				});
12128
12129
12130
12131				// 4. Delete database
12132				$.SOW.helper.indexedDB({ // delete entire database
12133					version: 		_version,
12134					action: 		'db:delete:database',
12135					database: 		_database,
12136				});
12137
12138
12139				$.SOW.helper.indexedDB({ // delete item by keyPath
12140					version: 		_version,
12141					action: 		'db:delete',
12142					database: 		_database,
12143					keyPath: 		1
12144				});
12145
12146
12147				// 6. Get Items
12148				$.SOW.helper.indexedDB({ // get single item by keyPath
12149					version: 		_version,
12150					action: 		'db:get:keyPath',
12151					database: 		_database,
12152					keyPath: 		1,
12153					callback: 		callbackFn
12154				});
12155
12156				$.SOW.helper.indexedDB({ // get all items
12157					version: 		_version,
12158					action: 		'db:get:all',
12159					database: 		_database,
12160					callback: 		callbackFn
12161				});
12162
12163				$.SOW.helper.indexedDB({ // get all item keys
12164					version: 		_version,
12165					action: 		'db:get:allkeys',
12166					database: 		_database,
12167					callback: 		callbackFn
12168				});
12169
12170				$.SOW.helper.indexedDB({ // get item key
12171					version: 		_version,
12172					action: 		'db:get:key',
12173					database: 		_database,
12174					keyPath: 		2,
12175					callback: 		callbackFn
12176				});
12177
12178				$.SOW.helper.indexedDB({ // get columns (indexNames)
12179					version: 		_version,
12180					action: 		'db:get:columns',
12181					database: 		_database,
12182					callback: 		callbackFn
12183				});
12184
12185				// 7. Count Items
12186				$.SOW.helper.indexedDB({ // count items
12187					version: 		_version,
12188					action: 		'db:count',
12189					database: 		_database,
12190					callback: 		callbackFn
12191				});
12192			+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12193
12194		 *
12195		 **/
12196		indexedDB: function(_obj) {
12197
12198			if (!('indexedDB' in window))
12199			  window.indexedDB = window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
12200
12201
12202			if(!window.indexedDB) {
12203				$.SOW.helper.consoleLog("[indexedDB] Not supported on this browser!");
12204				return;
12205			}
12206
12207			// --
12208			var version 				= _obj.version 		|| 1;
12209			var action 					= _obj.action;
12210			var database 				= _obj.database;
12211			var key 					= _obj.key 			|| _obj.db_options 	|| _obj.item || _obj.keyPath;
12212			var callback 				= _obj.callback 	|| _obj.db_indexes;
12213			// --
12214			var req 					= window.indexedDB.open(database, version);
12215			var smarty 					= {};
12216			var data 					= '';
12217
12218			smarty.onerror = function(e) {
12219				console.log("[indexedDB] Database error: ", e.target.errorCode);
12220			};
12221
12222
12223			req.onupgradeneeded = function(e) {
12224				smarty.db = e.target.result || e.result || this.result;
12225
12226				if(action !== 'db:create')
12227					return;
12228
12229				if(smarty.db.objectStoreNames.contains(database))
12230					smarty.db.deleteObjectStore(database);
12231
12232				// Create an objectStore for this database
12233				// example: smarty.db.createObjectStore('database', {keyPath: "item_id", autoIncrement: true});
12234				var objectStore = smarty.db.createObjectStore(database, key || {});
12235
12236				// define what data items the objectStore will contain
12237				// callback is used as "columns"
12238				for(var i=0;i<callback.length;++i) {
12239					var column = callback[i];
12240					objectStore.createIndex(column[0], column[1], column[2]);
12241				}
12242
12243				$.SOW.helper.consoleLog('[indexedDB] Table ' + database + ' created!');
12244
12245			}; 	req.onerror = smarty.onerror;
12246
12247
12248			req.onsuccess = function(e) {
12249
12250				if(action === 'db:create')
12251					return;
12252
12253
12254				smarty.db = e.target.result || e.result || this.result;
12255
12256				var db_action = (action === 'db:add' || action === 'db:update' || action === 'db:delete' || action == 'db:delete:database') ? 'readwrite' : 'readonly';
12257
12258				var transaction 		= smarty.db.transaction([database], db_action);
12259				transaction.oncomplete 	= function(event) {};
12260				transaction.onerror 	= function(event) {};
12261				var table 				= transaction.objectStore(database);
12262
12263				if(action === 'db:add')
12264					table.add(key);
12265
12266				else if(action === 'db:update')
12267					table.put(key);
12268
12269				else if(action === 'db:delete')
12270					table.delete(key);
12271
12272				else if(action === 'db:delete:database')
12273					table.clear();
12274
12275				else if(action === 'db:get:keyPath') {
12276
12277					var get = table.get(key);
12278
12279					get.onsuccess = () => {
12280						callback(get.result);
12281					};
12282
12283				}
12284
12285				else if(action === 'db:get:all') {
12286
12287					var get = table.getAll(key || null); // key = query, count
12288
12289					get.onsuccess = () => {
12290						callback(get.result);
12291					};
12292
12293				}
12294
12295				else if(action === 'db:get:allkeys') {
12296
12297					var get = table.getAllKeys(key || null); // key = query, count
12298
12299					get.onsuccess = () => {
12300						callback(get.result);
12301					};
12302
12303				}
12304
12305				else if(action === 'db:get:key') {
12306
12307					var get = table.getKey(key);
12308
12309					get.onsuccess = () => {
12310						callback(get.result);
12311					};
12312
12313				}
12314
12315				else if(action === 'db:get:columns') {
12316
12317					var result = table.indexNames;
12318					callback(result);
12319
12320				}
12321
12322				else if(action === 'db:count') {
12323
12324					var get = table.count();
12325
12326					get.onsuccess = () => {
12327						callback(get.result);
12328					};
12329
12330
12331				}
12332
12333
12334				else if(action === 'db:check') {
12335
12336					var _exists = (smarty.db.objectStoreNames.contains(database)) ? true : false;
12337					callback(_exists);
12338
12339				}
12340
12341
12342				// smarty.db.close();
12343
12344			}; 	req.onerror = smarty.onerror;
12345
12346
12347		},
12348
12349
12350
12351
12352		/**
12353		 *
12354		 *	@currencyFormat
12355		 *
12356			$.SOW.helper.currencyFormat(1000000); // output: 1,234,567.89
12357
12358			// 1,234,567.89
12359			$.SOW.helper.currencyFormat(1000000, [
12360				   2, ',', '.' // en
12361				// 2, '.', ',' // de
12362				// 2, ' ', ',' // fr
12363			]);
12364
12365		 *
12366		 **/
12367		currencyFormat: function(amount, custom) {
12368
12369			if(typeof custom !== 'object')
12370				var custom = [
12371					// 2, ',', '.' // en
12372					   2, '.', ',' // de
12373					// 2, ' ', ',' // fr
12374				];
12375
12376			return (  amount.toFixed(custom[0])
12377							.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1:repl:')
12378							.replace('.', custom[2])
12379							.replace(/:repl:/g, custom[1])
12380					);
12381
12382		},
12383
12384
12385
12386
12387		/**
12388		 *
12389		 *	@jsLocation
12390		 *
12391			$.SOW.helper.jsLocation(); // output: javascript location
12392		 *
12393		 **/
12394		jsLocation: function() {
12395
12396			var currentScript;
12397			var scripts = document.querySelectorAll('script[src]');
12398
12399			for(var s = 0; s < scripts.length; s++) {
12400
12401				if(scripts[s].src.indexOf('core') !== -1) {
12402					var currentScript = scripts[s].src;
12403					break;
12404				}
12405
12406				else if(scripts[s].src.indexOf('bundle') !== -1) {
12407					var currentScript = scripts[s].src;
12408					break;
12409				}
12410
12411				else if(scripts[s].src.indexOf('vendor') !== -1) {
12412					var currentScript = scripts[s].src;
12413					break;
12414				}
12415
12416			}
12417
12418			// nothing we want found! get the last script!
12419			if(!currentScript)
12420				currentScript = scripts[scripts.length-1].src;
12421
12422			if(!currentScript)
12423				currentScript = 'assets/js/';
12424
12425			var currentScriptChunks = currentScript.split('/');
12426			var currentScriptFile 	= currentScriptChunks[currentScriptChunks.length - 1];
12427			var scriptPath 			= currentScript.replace(currentScriptFile, '');
12428
12429			return scriptPath;
12430
12431		},
12432
12433
12434
12435
12436		/**
12437		 *
12438		 *	@cssLocation
12439		 *
12440			$.SOW.helper.cssLocation(); // output: css location
12441		 *
12442		 **/
12443		cssLocation: function() {
12444
12445			var currentScript;
12446			var scripts = document.querySelectorAll('link[rel=stylesheet]');
12447
12448			for(var s = 0; s < scripts.length; s++) {
12449
12450				if(scripts[s].href.indexOf('core') !== -1) {
12451					var currentScript = scripts[s].href;
12452					break;
12453				}
12454
12455				else if(scripts[s].href.indexOf('bundle') !== -1) {
12456					var currentScript = scripts[s].href;
12457					break;
12458				}
12459
12460				else if(scripts[s].href.indexOf('vendor') !== -1) {
12461					var currentScript = scripts[s].href;
12462					break;
12463				}
12464
12465			}
12466
12467			// nothing we want found! get the last script!
12468			if(!currentScript)
12469				currentScript = scripts[scripts.length-1].href;
12470
12471			if(!currentScript)
12472				currentScript = 'assets/css/';
12473
12474			var currentScriptChunks = currentScript.split('/');
12475			var currentScriptFile 	= currentScriptChunks[currentScriptChunks.length - 1];
12476			var scriptPath 			= currentScript.replace(currentScriptFile, '');
12477
12478			return scriptPath;
12479
12480		},
12481
12482
12483
12484
12485		/**
12486		 *
12487		 *	@vendorLogic
12488		 *
12489			$.SOW.helper.vendorLogicPaths('fullcalendar'); // output:array
12490
12491			Get vendor logics: js & css paths
12492			FOR EXTERNAL SCRIPTS LOAD!
12493		 *
12494		 **/
12495		vendorLogicPaths: function(vendor) {
12496
12497			if(!vendor)
12498				return arr;
12499
12500			var js_location 	= ($.SOW.globals.js_location != '') ? $.SOW.globals.js_location : $.SOW.helper.jsLocation();
12501			var css_location 	= ($.SOW.globals.js_location != '') ? $.SOW.globals.css_location : $.SOW.helper.cssLocation();
12502			var arr 			= [];
12503				arr['path_js'] 	= '';
12504				arr['path_css'] = '';
12505
12506
12507
12508
12509			/* CSS FILE */
12510			if($.SOW.config["vendor:external_css"]) {
12511
12512				for (var module in $.SOW.config["vendor:external_css"]) {
12513
12514					for(var v = 0; v < $.SOW.config["vendor:external_css"][module].length; v++) {
12515
12516						if($.SOW.config["vendor:external_css"][module].includes(vendor) === true) {
12517
12518							arr['path_css'] 	= css_location+module+'.'+vendor+'.min.css';
12519
12520							// apply here, else swiper and other plugins has issues : is css loaded after js
12521							$.SOW.helper.loadCSS(arr['path_css']);
12522							break;
12523						}
12524
12525					}
12526
12527				}
12528
12529			}
12530
12531
12532
12533			/* JS FILE */
12534			if($.SOW.config["vendor:external_js"]) {
12535
12536				for (var module in $.SOW.config["vendor:external_js"]) {
12537
12538					for(var v = 0; v < $.SOW.config["vendor:external_js"][module].length; v++) {
12539
12540						if($.SOW.config["vendor:external_js"][module].includes(vendor) === true) {
12541							arr['path_js'] 	= js_location+module+'.'+vendor+'.min.js';
12542							break;
12543						}
12544
12545					}
12546
12547				}
12548
12549			}
12550
12551			return arr;
12552		},
12553
12554
12555
12556
12557
12558		/**
12559		 *
12560		 *	@videoEmbedFromUrl
12561			$.SOW.helper.videoEmbedFromUrl('https://www.youtube.com?v=jh8Hgd466', autoplay=1);
12562		 *
12563		 **/
12564		videoEmbedFromUrl: function(href, autoplay) {
12565
12566
12567			// Localvideo first!
12568			if( href.match(/(.mp4)/) || href.match(/(.webm)/) ) {
12569
12570				var mp4 	= href.replace('.webm', '.mp4');
12571				var webm 	= href.replace('.mp4', '.webm');
12572				var jpg 	= href.replace('.mp4', '.jpg').replace('.webm', '.jpg');
12573				var auto 	= (!autoplay) ? null : 'autoplay';
12574
12575				// Local Video
12576				return '<div class="embed-responsive embed-responsive-16by9">'
12577					+ '<video preload="auto" '+auto+' controls="controls" poster="'+jpg+'">'
12578						+ '<source src="'+webm+'" type="video/webm;">'
12579						+ '<source src="'+webm+'" type="video/mp4;">'
12580					+ '</video>'
12581				+ '</div>';
12582
12583			};
12584
12585			// :: default
12586			var videoEmbedLink = null;
12587
12588
12589			// :: youtube
12590			if(videoEmbedLink === null) {
12591				var youtubeMatch 	= href.match(/(youtube\.com|youtu\.be|youtube\-nocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i);
12592				var videoEmbedLink 	= (youtubeMatch) ? "https://www.youtube.com/embed/"+youtubeMatch[4]+"?autoplay=" + autoplay || 1 + '' : null;
12593			}
12594
12595			// :: vimeo
12596			if(videoEmbedLink === null) {
12597				var vimeoMatch 		= href.match(/^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/);
12598				var videoEmbedLink 	= (vimeoMatch) ? "https://player.vimeo.com/video/"+vimeoMatch[2]+"?autoplay=" + autoplay || 1 + '' : null;
12599			}
12600
12601
12602			// Err!
12603			if(!videoEmbedLink)
12604				return null;
12605
12606			// -- --
12607
12608			// Construct Embed!
12609			return '<div class="embed-responsive embed-responsive-16by9">'
12610						+ '<iframe class="embed-responsive-item" src="' + videoEmbedLink + '" allow="autoplay; encrypted-media" width="560" height="315"></iframe>'
12611					+ '</div>';
12612
12613		},
12614
12615
12616
12617
12618		/**
12619		 *
12620		 *	@strhash
12621		 *	author: Sergey.Shuchkin
12622		 *	https://stackoverflow.com/questions/6122571/simple-non-secure-hash-function-for-javascript
12623		 *
12624			$.SOW.helper.strhash('string here');
12625		 *
12626		 **/
12627		strhash: function( str ) {
12628		    if (str.length % 32 > 0) str += Array(33 - str.length % 32).join("z");
12629
12630		    var hash = '', bytes = [];
12631		    var i, j, k, a; i = j = k = a = 0;
12632		    var dict = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','1','2','3','4','5','6','7','8','9'];
12633
12634		    for (i = 0; i < str.length; i++ ) {
12635		        var ch = str.charCodeAt(i);
12636		        bytes[j++] = (ch < 127) ? ch & 0xFF : 127;
12637		    }
12638
12639		    var chunk_len = Math.ceil(bytes.length / 32);
12640
12641		    for (i=0; i<bytes.length; i++) {
12642		        j += bytes[i]; k++;
12643
12644		        if ((k == chunk_len) || (i == bytes.length-1)) {
12645		            var a = Math.floor( j / k );
12646
12647		            if (a < 32) 			hash += '0';
12648		            else if (a > 126) 		hash += 'z';
12649		            else 					hash += dict[  Math.floor( (a-32) / 2.76) ];
12650
12651		            var j = k = 0;
12652		        }
12653
12654		    }
12655
12656		    return hash;
12657		},
12658
12659
12660
12661
12662		/**
12663		 *
12664		 *	@consoleLog
12665		 *
12666			$.SOW.helper.consoleLog('%cLorem Ipsum', 'color: #ff0000;');
12667		 *
12668		 **/
12669		consoleLog: function(data, css) {
12670
12671			if($.SOW.config.sow__debug_enable !== true)
12672				return;
12673
12674
12675			// Console css
12676			if(typeof css !== "undefined" && typeof css !== 'object') {
12677				var data 	= '%c' + data;
12678
12679				console.log(data, css);
12680				return;
12681			}
12682
12683			else if(typeof css === 'object') {
12684				console.log(data, css);
12685				return;
12686			}
12687
12688			console.log(data);
12689		}
12690
12691	};
12692})(jQuery);
12693/**
12694 *
12695 *	[SOW] Header
12696 *
12697 *	@author 		Dorin Grigoras
12698 *					www.stepofweb.com
12699 *
12700 *	@Dependency 	-
12701 *	@Usage			$.SOW.core.header.init();
12702 *
12703 *
12704 **/
12705;(function ($) {
12706	'use strict';
12707
12708
12709	/**
12710	 *
12711	 *	@vars
12712	 *
12713	 *
12714	 **/
12715	var scriptInfo 			= 'SOW Header';
12716
12717	window._headerID 		= '#header';
12718	window.lastScrollTop 	= 0;
12719
12720
12721
12722	$.SOW.core.header = {
12723
12724
12725		/**
12726		 *
12727		 *	@config
12728		 *
12729		 *
12730		 **/
12731		config: {},
12732
12733
12734
12735		/**
12736		 *
12737		 *	@collection
12738		 *
12739		 *
12740		 **/
12741		collection: $(),
12742
12743
12744
12745		/**
12746		 *
12747		 *	@init
12748		 *
12749		 *
12750		 **/
12751		init: function (selector, config) {
12752
12753
12754			if(!$.SOW.globals.elHeader)
12755				return;
12756
12757
12758			/**
12759				1. HEADER : STICKY/FIXED
12760			**/
12761			if($.SOW.globals.elBody.hasClass('header-sticky'))
12762				$.SOW.core.header.header_sticky();
12763
12764
12765			/**
12766				2. HEADER : REVEAL ON SCROLL
12767			**/
12768			else if($.SOW.globals.elBody.hasClass('header-scroll-reveal'))
12769				$.SOW.core.header.header_scroll_reveal();
12770
12771
12772			/**
12773				3. HEADER & ASIDE : HORIZONTAL NAVIGATION
12774			**/	$.SOW.core.header.horizontal_nav();
12775
12776
12777			/**
12778				4. HEADER TOGGLE
12779			**/	$.SOW.core.header.header_toggle();
12780
12781
12782			/**
12783				5. HEADER SCROLLTO : NAVBAR CLOSE
12784			**/	$.SOW.core.header.header_onepagenav();
12785
12786
12787			// -- * --
12788			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
12789			// -- * --
12790
12791
12792		},
12793
12794
12795
12796
12797		/**
12798		 *
12799		 *	1. HEADER : STICKY/FIXED
12800		 *
12801		 *
12802		 **/
12803		header_sticky: function() {
12804
12805
12806			// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
12807			// Oct. 08. 2019
12808			// EVERYTHING REPLCACED WITH FLEX & CSS position: sticky;
12809			// Not fully supported (IE, etc) but is ok for admin!
12810			// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
12811			// [v3.0.0] Stop on admin!
12812			// Curently not used!
12813			// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
12814			if($.SOW.globals.elBody.hasClass('layout-admin'))
12815				return;
12816			// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
12817
12818			if($.SOW.globals.elHeader.length < 1)
12819				return;
12820
12821			var _headerEl_H 	= $.SOW.globals.elHeader.outerHeight() || 0,
12822				_diff 			= 0;
12823
12824
12825			if($.SOW.globals.elBody.hasClass('layout-boxed'))
12826				_diff = _headerEl_H / 2 || 0;
12827
12828			/*
12829
12830				1. add header spacing
12831				2. add header-fixed class
12832
12833			*/	$.SOW.globals.elBody.addClass('header-fixed');
12834
12835
12836			// admin : padding top instead of spacer
12837			if($.SOW.globals.elBody.hasClass('layout-admin aside-sticky')) {
12838
12839				jQuery('#middle').css({"padding-top":_headerEl_H + _diff + parseInt(jQuery('#middle').css('padding-top'))});
12840
12841			} else {
12842
12843				jQuery('#js_header_spacer').remove();
12844				jQuery('#wrapper>'+window._headerID+', body>'+window._headerID).after('<div id="js_header_spacer"><!-- spacer added by header js --></div>');
12845				jQuery('#js_header_spacer').css({"margin-top":_headerEl_H + _diff});
12846
12847			}
12848
12849
12850			// -- -- -- --
12851
12852
12853
12854
12855
12856			/*
12857
12858				.header-sticky + .header-over
12859				all what we do here is to apply body.user-scrolled-down if user scolled down
12860				so we can apply a CSS background-color to the header (else, will be buggy - transparent header on scroll down)
12861
12862			*/
12863			if($.SOW.globals.elBody.hasClass('header-over') && jQuery(this).scrollTop() > 0)
12864				$.SOW.globals.elBody.addClass('user-scrolled-down');
12865
12866
12867			// stop! no need for scroll assist!
12868			if(!$.SOW.globals.elBody.hasClass('header-over') && jQuery('#top_bar').length < 1)
12869				return;
12870
12871
12872
12873
12874
12875
12876
12877			/*
12878
12879				1. on scroll down - hide #top_bar to make little more space (and show on scroll up)
12880				2. add|remove .user-scrolled-down - used together with .header-over
12881
12882			*/
12883			var
12884				top_bar_present 	= jQuery('#top_bar').length,
12885				top_bar_height 		= (top_bar_present > 0) ? jQuery('#top_bar').outerHeight() : 0,
12886				top_bar_js_ignore 	= false,
12887				delta 				= 5,
12888				didScroll;
12889
12890			jQuery(window).scroll(function(event) {
12891				didScroll = true;
12892			});
12893
12894
12895			// check for js ignore (if true, do not hide #top_bar on scroll)
12896			if(top_bar_present > 0) {
12897				if(jQuery('#top_bar').hasClass('js-ignore'))
12898					var top_bar_js_ignore = true;
12899			}
12900
12901
12902			setInterval(function() {
12903				if(didScroll) {
12904					$.SOW.core.header.header_sticky__hasScrolled(_headerEl_H, delta, top_bar_present, top_bar_height, top_bar_js_ignore);
12905					didScroll = false;
12906				}
12907			}, 100);
12908
12909
12910
12911			// On first load!
12912			$.SOW.core.header.header_sticky__hasScrolled(_headerEl_H, delta, top_bar_present, top_bar_height, top_bar_js_ignore);
12913			// -- -- -- -- --
12914
12915		},
12916			header_sticky__hasScrolled: function(_headerEl_H, delta, top_bar_present, top_bar_height, top_bar_js_ignore) {
12917				var st = document.scrollingElement.scrollTop;
12918
12919				// ADD distinct class - used by transparent header
12920				if(st < 1) {
12921					$.SOW.globals.elBody.removeClass('user-scrolled-down');
12922				} else {
12923					$.SOW.globals.elBody.addClass('user-scrolled-down');
12924				}
12925
12926
12927				if(top_bar_present > 0 && top_bar_js_ignore === false) {
12928
12929					// Make sure they scroll more than delta
12930					if(Math.abs(window.lastScrollTop - st) <= delta)
12931						return;
12932
12933
12934					if(st > window.lastScrollTop && st > _headerEl_H){
12935
12936						// Scroll Down
12937						$.SOW.globals.elHeader.css({"margin-top":"-"+top_bar_height+"px"});
12938
12939					} else {
12940
12941						// Scroll Up
12942						if(st + jQuery(window).height() < jQuery(document).height()) {
12943							$.SOW.globals.elHeader.css({"margin-top":""});
12944						}
12945
12946					}
12947
12948					window.lastScrollTop = st;
12949
12950				}
12951
12952			},
12953
12954
12955
12956
12957
12958		/**
12959		 *
12960		 *	2. HEADER : REVEAL ON SCROLL
12961		 *
12962		 *
12963		 **/
12964		header_scroll_reveal: function() {
12965
12966			/** HEADER : REVEAL
12967				1. Hide Header on on scroll down
12968				2. Show Header on on scroll up
12969			** ************************************/
12970			if($.SOW.globals.elHeader.length > 0) {
12971
12972				var _headerEl_H 	= $.SOW.globals.elHeader.outerHeight() || 0,
12973					_diff 			= 0,
12974					lastScrollTop 	= 0,
12975					delta 			= 5,
12976					didScroll;
12977
12978
12979				if($.SOW.globals.elBody.hasClass('layout-boxed'))
12980					_diff = _headerEl_H / 2 || 0;
12981
12982				/*
12983
12984					1. add header spacing
12985					2. add header-fixed class
12986
12987				*/
12988
12989				jQuery('#js_header_spacer').remove();
12990				jQuery('#wrapper>'+window._headerID+', body>'+window._headerID).after('<div id="js_header_spacer"><!-- spacer added by header js --></div>');
12991				jQuery('#js_header_spacer').css({"margin-top":_headerEl_H + _diff});
12992
12993				$.SOW.globals.elBody.addClass('header-fixed');
12994				jQuery('body>'+window._headerID).addClass('header-fixed');
12995
12996				// on load : according to .header-over
12997				if($.SOW.globals.elBody.hasClass('header-over') && jQuery(this).scrollTop() > 0) {
12998					$.SOW.globals.elBody.addClass('user-scrolled-down');
12999					jQuery(window._headerID).addClass('header-down');
13000					lastScrollTop = jQuery(this).scrollTop(); // avoid jumping
13001				} else {
13002					$.SOW.globals.elBody.addClass('header-is-on-top');
13003				}
13004
13005				// -- -- -- --
13006
13007
13008				jQuery(window).scroll(function(event) {
13009					didScroll = true;
13010				});
13011
13012				setInterval(function() {
13013					if(didScroll) {
13014						$.SOW.core.header.header_scroll_reveal__hasScrolled(_headerEl_H, delta);
13015						didScroll = false;
13016					}
13017				}, 100);
13018
13019			}
13020
13021		},
13022
13023			header_scroll_reveal__hasScrolled: function(_headerEl_H, delta) {
13024				var st = document.scrollingElement.scrollTop;
13025
13026				// ADD distinct class - used by transparent header
13027				if(st < 1) {
13028					$.SOW.globals.elBody.addClass('header-is-on-top').removeClass('user-scrolled-down');
13029				} else {
13030					$.SOW.globals.elBody.addClass('user-scrolled-down');
13031				}
13032
13033				// Make sure they scroll more than delta
13034				if(Math.abs(window.lastScrollTop - st) <= delta)
13035					return;
13036
13037				if(st > window.lastScrollTop && st > _headerEl_H){
13038
13039					// Scroll Down
13040					$.SOW.globals.elHeader.removeClass('header-down').addClass('header-up');
13041					$.SOW.globals.elBody.removeClass('header-is-on-top');
13042
13043				} else {
13044
13045					// Scroll Up
13046					if(st + jQuery(window).height() < jQuery(document).height()) {
13047						$.SOW.globals.elHeader.removeClass('header-up').addClass('header-down');
13048					}
13049
13050				}
13051
13052				window.lastScrollTop = st;
13053			},
13054
13055
13056		/**
13057		 *
13058		 *	3. HEADER & ASIDE : HORIZONTAL NAVIGATION
13059		 *
13060		 *
13061		 **/
13062		horizontal_nav: function() {
13063
13064
13065			if(jQuery("nav.horizontal-nav").length < 1)
13066				return;
13067
13068
13069
13070			// CONTENT MAIN MENU
13071			if(jQuery("section nav.horizontal-nav").length > 0) {
13072
13073				var _diffWidth 	= (jQuery("section .container").width() - jQuery('section nav.horizontal-nav').width()),
13074					_navHeight 	= jQuery("section nav.horizontal-nav").height();
13075
13076				// Submenu widh & height
13077				jQuery("section nav.horizontal-nav>div>ul>li.main-nav-expanded>.main-nav-submenu").css({"width":_diffWidth+"px"});
13078				//jQuery("section nav.horizontal-nav>div>ul>li>.main-nav-submenu").css({"min-height":_navHeight+"px"});
13079
13080				// SUBMENUS
13081				jQuery("section nav.horizontal-nav>div>ul>li").on("click", function(e) {
13082					var _this = jQuery(this);
13083
13084					if(!jQuery('div', _this).hasClass('main-nav-open')) {
13085						jQuery("section nav.horizontal-nav>div>ul>li>.main-nav-submenu").removeClass('main-nav-open');
13086					}
13087
13088					jQuery('div', _this).toggleClass('main-nav-open');
13089				});
13090
13091			}
13092
13093
13094
13095
13096
13097
13098			// HEADER MAIN MENU
13099			var _hdiffWidth 	= jQuery(window._headerID+" .container").width() - 278,
13100				_hdiffHeight 	= jQuery(window._headerID+" nav.horizontal-nav").height();
13101
13102			// Submenu widh & height
13103			jQuery(window._headerID+" nav.horizontal-nav>div>ul>li>.main-nav-submenu").css({"min-height":_hdiffHeight+"px"});
13104			jQuery(window._headerID+" nav.horizontal-nav>div>ul>li.main-nav-expanded>
13104.main-nav-submenu").css({"width":_hdiffWidth+"px"});
13105
13106			// SUBMENUS
13107			jQuery(window._headerID+" nav.horizontal-nav>div>ul>li").on("click", function(e) {
13108				var _this = jQuery(this);
13109
13110				if(!jQuery('div', _this).hasClass('main-nav-open')) {
13111					jQuery(window._headerID+" nav.horizontal-nav>div>ul>li>.main-nav-submenu").removeClass('main-nav-open');
13112				}
13113
13114				jQuery('div', _this).toggleClass('main-nav-open');
13115			});
13116
13117
13118
13119			// HEADER MAIN MENU
13120			if(window.width > 960) { //  desktop|tablet
13121
13122				jQuery("button.main-nav-horizontal").mouseover(function(e) {
13123					e.preventDefault();
13124
13125					$.SOW.core.header._initMainNav();
13126
13127				});
13128
13129
13130			} else { // mobile
13131
13132				jQuery("button.main-nav-horizontal").on("click", function(e) {
13133					e.preventDefault();
13134
13135					$.SOW.core.header._initMainNav();
13136
13137				});
13138
13139			}
13140
13141	        $.SOW.globals.elBody.on('click', 'button.main-nav-horizontal, nav.horizontal-nav', function (e) {
13142	            e.stopPropagation();
13143	        });
13144
13145	        jQuery("button.main-nav-horizontal, "+window._headerID+" nav.horizontal-nav").mouseover(function(e) {
13146	        	 e.stopPropagation();
13147	        });
13148
13149
13150			jQuery(document).on("click", function() {
13151
13152				$.SOW.core.header._hideMainNav();
13153
13154			});
13155
13156
13157
13158			// Menu Click
13159			jQuery("nav.horizontal-nav>div>ul>li a").on("click", function(e) {
13160				var _href = jQuery(this).attr('href');
13161
13162				if(_href == '#') {
13163					e.preventDefault();
13164				}
13165			});
13166		},
13167
13168			_initMainNav: function() {
13169
13170				// remove overlay first, no matter what
13171				jQuery("#main-nav-overlay").remove();
13172
13173				// open menu
13174				jQuery(window._headerID+" nav.horizontal-nav").addClass('min-nav-active');
13175
13176				// add overlay
13177				$.SOW.globals.elBody.append('<div id="main-nav-overlay"></div>');
13178
13179
13180				// Mobile menu open|close on click
13181				jQuery('button.nav-toggle-close').on("click", function() {
13182					jQuery("nav.horizontal-nav").removeClass('min-nav-active');
13183				});
13184
13185				// Close menu on hover
13186		        jQuery("#main-nav-overlay, "+window._headerID).mouseover(function() {
13187
13188		        	$.SOW.core.header._hideMainNav();
13189
13190		        });
13191
13192			},
13193
13194			_hideMainNav: function() {
13195				jQuery("#main-nav-overlay").remove();
13196				jQuery("nav.horizontal-nav").removeClass('min-nav-active');
13197			},
13198
13199
13200
13201
13202
13203		/**
13204		 *
13205		 *	4. HEADER TOGGLE
13206		 *
13207		 *
13208		 **/
13209		header_toggle: function() {
13210
13211			jQuery('.btn-header-toggle').on('click', function(e) {
13212				e.preventDefault();
13213
13214				var is_hidden 		= $.SOW.globals.elBody.hasClass('header-hide') ? true : false,
13215					has_spacer 		= jQuery('#js_header_spacer').length > 0 ? true : false,
13216					_headerEl_H 	= $.SOW.globals.elHeader.outerHeight() 		|| 0,
13217					_addEl 			= '';
13218
13219				// no header present?
13220				if(_headerEl_H < 1)
13221					return;
13222
13223
13224				// Add animation class to content
13225				if(has_spacer === true) {
13226					jQuery('#wrapper_content').addClass('js-animation-enable');
13227					_addEl = ', #wrapper_content';
13228				}
13229
13230
13231				// Add animation class!
13232				jQuery('#header'+_addEl).addClass('transition-all-ease-250');
13233
13234
13235				if(is_hidden === false) {
13236
13237					jQuery('#header'+_addEl).animate({ 'margin-top': -_headerEl_H+"px" }, 50, function(e) {
13238						$.SOW.globals.elBody.addClass('header-hide');
13239
13240						/*
13241							show toggle button with a delay to avoid spacing
13242							issues (because of fixed position) + nice effect with css
13243						*/
13244						setTimeout(function() {
13245
13246							$.SOW.globals.elBody.addClass('btn-header-toggle-show');
13247
13248						}, 600);
13249
13250					});
13251
13252				} else {
13253
13254					jQuery('#header'+_addEl).animate({ 'margin-top': "0" }, 0, function(e) {
13255						$.SOW.globals.elBody.removeClass('header-hide btn-header-toggle-show');
13256
13257						// Remove animation class
13258						if(has_spacer === true) {
13259							setTimeout(function() {
13260
13261								jQuery('#wrapper_content').removeClass('js-animation-enable');
13262
13263							}, 600);
13264						}
13265
13266					});
13267				}
13268
13269
13270			});
13271
13272		},
13273
13274
13275
13276		/**
13277		 *
13278		 *	5. HEADER SCROLLTO : NAVBAR CLOSE
13279		 *
13280		 *
13281		 **/
13282		header_onepagenav: function() {
13283
13284			jQuery('.navbar-collapse').each(function() {
13285
13286				var _t = jQuery(this);
13287
13288				jQuery('.nav-item>.nav-link.scroll-to, .nav-item>.nav-link.js-ajax, .dropdown-item>.dropdown-link.js-ajax', _t).on('click',function() {
13289
13290					if($.SOW.globals.is_mobile === true)
13291						_t.collapse('hide');
13292
13293				});
13294
13295			});
13296
13297		},
13298
13299
13300
13301
13302
13303
13304		/**
13305		 *
13306		 *	DESTROY / RESET (sticky/reveal)
13307		 *
13308		 *
13309		 **/
13310		header_destroy: function() {
13311
13312			$.SOW.globals.elHeader.removeClass('header-down header-up');
13313			$.SOW.globals.elBody.removeClass('header-hide header-over header-fixed header-is-on-top user-scrolled-down');
13314			$.SOW.globals.elHeader.css({"margin-top":""});
13315			jQuery('#top_bar').removeClass('hide-by-scroll');
13316			jQuery('#js_header_spacer').remove();
13317			jQuery(window).off("scroll");
13318
13319		}
13320
13321	};
13322
13323
13324})(jQuery);
13325/**
13326 *
13327 *	[SOW] Search Suggest
13328 *
13329 *	@author 		Dorin Grigoras
13330 *					www.stepofweb.com
13331 *
13332 *	@Dependency 	-
13333 *	@Usage			$.SOW.core.search_suggest.init('form.js-ajax-search');
13334 *
13335 *
13336 **/
13337;(function ($) {
13338	'use strict';
13339
13340
13341	/**
13342	 *
13343	 *	@vars
13344	 *
13345	 *
13346	 **/
13347	var scriptInfo 				= 'SOW Search Suggest';
13348
13349	window._relatedFirstLoad 	= '';
13350
13351
13352
13353	$.SOW.core.search_suggest = {
13354
13355
13356		/**
13357		 *
13358		 *	@config
13359		 *
13360		 *
13361		 **/
13362		config: {
13363
13364			enable 						: true,
13365			method 						: '', 		// [GET|POST] WARNING! THIS IS PRIMARY! Leave empty to use the form method (usualy is GET)
13366			container 					: '#sow-search-container',
13367			input_min_length 			: 2,
13368			input_delay 				: 100, 		// ms
13369			related_kw 					: '',		// default keywords on load (leave empty to control from your backend)
13370			related_url 				: '',
13371			related_action 				: 'related_get',
13372			suggest_url 				: '',
13373			suggest_action 				: 'suggest_get',
13374			// --
13375			contentType 				: '', 		// example: 'application/json; charset=utf-8'
13376			dataType 					: '',		// example: json
13377			forceStringify 				: false,	// stringify requests - data sent as JSON;  data: JSON.stringify(...)
13378
13379		},
13380
13381
13382
13383		/**
13384		 *
13385		 *	@collection
13386		 *
13387		 *
13388		 **/
13389		collection: $(),
13390
13391
13392
13393		/**
13394		 *
13395		 *	@init
13396		 *
13397		 *
13398		 **/
13399		init: function (selector, config) {
13400
13401			var __selector 			= $.SOW.helper.__selector(selector);
13402			var __config 			= $.SOW.helper.check_var(config);
13403
13404			this.selector 			= __selector[0]; 	// '#selector'
13405			this.collection 		= __selector[1]; 	// $('#selector')
13406			this.selector_orig 		= __selector[2]; 	// $('#selector') // without ajax container prefix
13407			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
13408
13409
13410			if(jQuery(this.selector).length < 1)
13411				return;
13412
13413
13414			// -- * --
13415			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
13416			// -- * --
13417
13418
13419			// Toggler
13420			$.SOW.core.search_suggest.sow_suggest_toggler();
13421
13422			// 1. Has no selector
13423			if(!this.selector) {
13424				$.SOW.core.search_suggest.process($('form.js-ajax-search'));
13425				return this.collection;
13426			}
13427
13428			// 2. Has selector
13429			return this.collection.each(function() {
13430
13431				$.SOW.core.search_suggest.process($(this));
13432
13433			});
13434
13435		},
13436
13437
13438
13439		/**
13440		 *
13441		 *	@process
13442		 *
13443		 *
13444		 *
13445		 **/
13446		process: function(_this) {
13447
13448			_this.each(function() {
13449
13450				var _t 					= jQuery(this),
13451					_method 			= _t.attr('method')					|| '', 			// got from form [GET|POST]
13452					search_enable 		= _t.data('autosuggest')			|| '',
13453					// --
13454					search_mode 		= _t.data('mode')					|| 'html',					// html|json
13455					json_max_results	= _t.data('json-max-results')		|| 10,						// JSON ONLY
13456					json_title_realted	= _t.data('json-related-title')		|| 'Popular',				// JSON ONLY
13457					json_icon_related	= _t.data('json-related-item-icon')	|| 'fi fi-star-empty',		// JSON ONLY
13458					json_title_suggest	= _t.data('json-suggest-title')		|| 'Search Suggestion',		// JSON ONLY
13459					json_noresult_txt	= _t.data('json-suggest-noresult')	|| 'No results for',		// JSON ONLY
13460					json_icon_suggest	= _t.data('json-suggest-item-icon')	|| 'fi fi-search',			// JSON ONLY
13461					json_min_score		= _t.data('json-suggest-min-score')	|| 0,						// JSON ONLY
13462					json_highlight_term	= _t.data('json-highlight-term')	|| 'true',					// JSON ONLY
13463					// --
13464					_container 			= _t.data('container') 				|| '',
13465					related_kw 			= _t.data('related-keywords') 		|| '',
13466					related_url 		= _t.data('related-url') 			|| '',
13467					suggest_url 		= _t.data('suggest-url') 			|| '',
13468					suggest_action 		= _t.data('suggest-action')			|| '',			// action type
13469					related_action 		= _t.data('related-action')			|| '',			// action type
13470					_contentType 		= _t.data('contentType')			|| '',
13471					themeClass 			= _t.data('theme-class')			|| 'primary', 	// only the name *-primary; used by json only
13472					_dataType 			= _t.data('dataType')				|| '',
13473					min_length 			= _t.data('input-min-length')		|| 0,
13474					input_delay 		= _t.data('input-delay')	 		|| 0; // ms
13475
13476
13477				// --
13478
13479				if(search_enable == '' && $.SOW.core.search_suggest.config.enable === false)
13480					return;
13481
13482				else if(search_enable != 'on')
13483					return;
13484
13485				// --
13486
13487
13488				if(_container == '')
13489					var _container = $.SOW.core.search_suggest.config.container;
13490
13491				if(min_length < 1)
13492					var min_length = $.SOW.core.search_suggest.config.input_min_length;
13493
13494				if(input_delay < 50)
13495					var input_delay = $.SOW.core.search_suggest.config.input_delay;
13496
13497				if(related_kw == '')
13498					var related_kw = $.SOW.core.search_suggest.config.related_kw;
13499
13500				if(related_url == '')
13501					var related_url = $.SOW.core.search_suggest.config.related_url;
13502
13503				if(related_action == '')
13504					var related_action = $.SOW.core.search_suggest.config.related_action;
13505
13506				if(suggest_url == '')
13507					var suggest_url = $.SOW.core.search_suggest.config.suggest_url;
13508
13509				if(suggest_action == '')
13510					var suggest_action = $.SOW.core.search_suggest.config.suggest_action;
13511
13512				// --
13513
13514				// Override the original form method!
13515				if($.SOW.core.search_suggest.config.method != '')
13516					var _method = $.SOW.core.search_suggest.config.method;
13517
13518
13519
13520				// Needed to avoid multiple same request
13521				window._lastSearch = null;
13522
13523				// Check required
13524				if(related_url == '' && suggest_url == '') {
13525					$.SOW.helper.consoleLog('Search Suggest Error: No related and/or suggest url provided!');
13526					return;
13527				}
13528
13529
13530				// --
13531
13532
13533				// Close/hide autosuggest on backdrop click
13534				window.suggestionIsAlreadyFocused = false;
13535				jQuery('.sow-search-backdrop', _t).addClass('hide').on('click', function(e) {
13536					$.SOW.core.search_suggest.__suggest_hide(_t);
13537				});
13538
13539				// Close/hide autosuggest for `esc` key
13540				jQuery(document).keyup(function(e) {
13541
13542					if(e.keyCode === 27) { // 27 = ESC key
13543						$.SOW.core.search_suggest.__suggest_hide(_t, _container);
13544					}
13545
13546				});
13547
13548
13549
13550				// --
13551
13552
13553
13554				// :: FOCUS : RELATED
13555				jQuery('input.form-control-sow-search', _t).focus(function(e) {
13556
13557					var _autosuggestContent = jQuery(_container + ' .sow-search-content').html();
13558
13559
13560					// SUGGEST BY RELATED (home, category, product, etc)
13561					if(_autosuggestContent.length < 3) {
13562						jQuery('.sow-search-loader').removeClass('hide');
13563
13564						if(window.afterSearchKeyUp)
13565							clearTimeout(window.afterSearchKeyUp);
13566
13567						window.afterSearchKeyUp = setTimeout(function() {
13568
13569							var _formData = {ajax:"true", action:related_action, related_keywords:related_kw};
13570
13571							// console log
13572							if($.SOW.core.search_suggest.config.forceStringify === true)
13573								$.SOW.helper.consoleLog("JSON Related Sent: " + JSON.stringify(_formData));
13574							else
13575								$.SOW.helper.consoleLog("Related Sent: " + JSON.stringify(_formData));
13576
13577							$.SOW.helper.consoleLog('Url Request: ' + related_url, 'color: #cccccc;');
13578							$.SOW.helper.consoleLog('Mode: ' + search_mode, 'color: #cccccc;');
13579							$.SOW.helper.consoleLog('------------------------------------------------------------', 'color: #cccccc;');
13580
13581							jQuery.ajax({
13582
13583								url: 			related_url,
13584								data: 			($.SOW.core.search_suggest.config.forceStringify === true) ? JSON.stringify(_formData) : _formData,
13585								type: 			_method,
13586								cache: 			(search_mode == 'json') ? false : true,
13587								contentType: 	_contentType 	|| 'application/x-www-form-urlencoded; charset=UTF-8',
13588								dataType: 		_dataType 		|| null,
13589								headers: 		'',
13590								crossDomain: 	'',
13591
13592								error: 	function(XMLHttpRequest, textStatus, errorThrown) {
13593
13594									if(typeof $.SOW.core.toast === 'object') {
13595
13596										$.SOW.core.toast.show('danger', 'Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
13597
13598									} else {
13599
13600										alert("[404] Unexpected internal error!");
13601
13602									}
13603
13604									jQuery('.sow-search-loader').addClass('hide');
13605
13606								},
13607
13608								success: function(data) {
13609
13610									if(search_mode === 'json')
13611										var data = $.SOW.core.search_suggest.process_json(data, related_kw, json_max_results, json_title_realted, json_noresult_txt, json_highlight_term, json_icon_related, json_min_score, themeClass);
13612
13613									// Push data
13614									jQuery(_container + ' .sow-search-content').html(data);
13615
13616									// keep as a 'cache'
13617									window._relatedFirstLoad = data;
13618
13619									// hide loader
13620									jQuery('.sow-search-loader').addClass('hide');
13621
13622								}
13623
13624							});
13625
13626						}, 50);
13627
13628					}
13629
13630					$.SOW.core.search_suggest.__suggest_show(_t, _container);
13631
13632				});
13633
13634
13635
13636				// --
13637
13638
13639
13640				// USER KEY UP : SEARCH
13641				jQuery('input.form-control-sow-search', _t).on('keyup change',function(e) {
13642
13643					var _keyInput 	= jQuery(this).val() || '';
13644
13645					$.SOW.core.search_suggest.__suggest_show(_t, _container);
13646
13647					if(_keyInput.length >= Number(min_length) && window._lastSearch != _keyInput) {
13648
13649
13650						// START AJAX SEARCH
13651						jQuery('.sow-search-loader').removeClass('hide');
13652
13653
13654						// SUGGEST BY USER INPUT
13655						if(window.afterSearchKeyUp)
13656							clearTimeout(window.afterSearchKeyUp);
13657
13658						window.afterSearchKeyUp = setTimeout(function() {
13659
13660							window._lastSearch = _keyInput;
13661
13662							var _formData = {ajax:"true", action:suggest_action, user_keywords:_keyInput };
13663
13664							// console log
13665							if($.SOW.core.search_suggest.config.forceStringify === true)
13666								$.SOW.helper.consoleLog("JSON Suggest Sent: " + JSON.stringify(_formData));
13667							else
13668								$.SOW.helper.consoleLog("Related Suggest: " +  JSON.stringify(_formData));
13669
13670							$.SOW.helper.consoleLog('Url Request: ' + related_url, 'color: #cccccc;');
13671							$.SOW.helper.consoleLog('Mode: ' + search_mode, 'color: #cccccc;');
13672							$.SOW.helper.consoleLog('------------------------------------------------------------', 'color: #cccccc;');
13673
13674							jQuery.ajax({
13675								url: 			suggest_url,
13676								data: 			($.SOW.core.search_suggest.config.forceStringify === true) ? JSON.stringify(_formData) : _formData,
13677								type: 			_method,
13678								cache: 			(search_mode == 'json') ? false : true,
13679								contentType: 	_contentType 	|| 'application/x-www-form-urlencoded; charset=UTF-8',
13680								dataType: 		_dataType 		|| null,
13681								headers: 		'',
13682								crossDomain: 	'',
13683
13684								error: 	function(XMLHttpRequest, textStatus, errorThrown) {
13685
13686									if(typeof $.SOW.core.toast === 'object') {
13687
13688										$.SOW.core.toast.show('danger', 'Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
13689
13690									} else {
13691
13692										alert("[404] Unexpected internal error!");
13693
13694									}
13695
13696									jQuery('.sow-search-loader').addClass('hide');
13697
13698								},
13699
13700								success: function(data) {
13701
13702									if(search_mode === 'json')
13703										var data = $.SOW.core.search_suggest.process_json(data, _keyInput, json_max_results, json_title_suggest, json_noresult_txt, json_highlight_term, json_icon_suggest, json_min_score, themeClass);
13704
13705									// Push data
13706									jQuery(_container + ' .sow-search-content').html(data);
13707
13708									// hide loader
13709									jQuery('.sow-search-loader').addClass('hide');
13710
13711								}
13712
13713							});
13714
13715						}, Number(input_delay));
13716
13717
13718
13719					} else {
13720
13721						// BACK TO RELATED
13722						if(window._relatedFirstLoad != '' && _keyInput == '') {
13723							jQuery(_container + ' .sow-search-content').html(window._relatedFirstLoad);
13724						}
13725
13726					}
13727
13728				});
13729
13730
13731
13732			});
13733
13734		},
13735
13736			/**
13737			 *
13738			 *	@__suggest_show
13739			 *	:: Helper
13740			 *
13741			 *
13742			 **/
13743			__suggest_show: function(_t, _container) {
13744
13745				// Begin autosuggest
13746				if(window.suggestionIsAlreadyFocused === false) {
13747
13748					_t.removeClass('hide');
13749					jQuery('.sow-search-backdrop', _t).removeClass('hide');
13750					jQuery(_container).removeClass('hide');
13751					window.suggestionIsAlreadyFocused = true;
13752
13753				}
13754
13755			},
13756
13757			/**
13758			 *
13759			 *	@__suggest_hide
13760			 *	:: Helper
13761			 *
13762			 *
13763			 **/
13764			__suggest_hide: function(_t, _container) {
13765
13766				if(window.suggestionIsAlreadyFocused === true) {
13767
13768					$.SOW.globals.elBody.removeClass('overflow-hidden');
13769
13770					jQuery('.sow-search-backdrop', _t).addClass('hide');
13771					jQuery('.sow-search-container', _t).addClass('hide');
13772					jQuery('.sow-search-over', _t).addClass('hide');
13773
13774					jQuery('input.form-control-sow-search', _t).blur();
13775					_t.removeClass('sow-search-mobile');
13776					jQuery('.sow-search-over').addClass('hide'); // all of them, if many available
13777
13778					window.suggestionIsAlreadyFocused = false;
13779
13780				}
13781
13782			},
13783
13784
13785
13786		/**
13787		 *
13788		 *	@sow_suggest_toggler
13789		 *
13790		 *
13791		 *
13792		 **/
13793		sow_suggest_toggler: function() {
13794
13795			var _selector = this.selector_orig;
13796
13797			jQuery('.btn-sow-search-toggler:not(.btn-sow-search-togglified)').addClass('btn-sow-search-togglified').on('click', function(e) {
13798				e.preventDefault();
13799
13800				var _target = jQuery(this).data('target') || _selector;
13801
13802				jQuery(_target).toggleClass('sow-search-mobile');
13803				jQuery(_target+'.sow-search-over').toggleClass('hide');
13804
13805				if(jQuery(_target).hasClass('sow-search-mobile')) {
13806
13807					jQuery(_target+' input.form-control-sow-search').focus();
13808					$.SOW.globals.elBody.addClass('overflow-hidden');
13809					jQuery(_target+'.sow-search-over').removeClass('hide');
13810
13811				} else {
13812
13813					jQuery(_target+' input.form-control-sow-search').blur();
13814					$.SOW.globals.elBody.removeClass('overflow-hidden');
13815					jQuery(_target+'.sow-search-over').addClass('hide').removeClass('sow-search-mobile');
13816
13817				}
13818
13819			});
13820
13821		},
13822
13823
13824		/**
13825		 *
13826		 *	@process_json
13827		 *
13828		 *
13829		 *
13830		 **/
13831		process_json: function(data, keyword, json_max_results, json_title, json_noresult_txt, highlight_term, icon, json_min_score, themeClass) {
13832
13833			/*
13834				-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
13835				https://github.com/bripkens/fuzzy.js/blob/gh-pages/fuzzy.js
13836				Check for fuzzy.js vendor
13837
13838			*/
13839			if(typeof fuzzy !== 'function') {
13840
13841				// -- * --
13842				$.SOW.helper.consoleLog(' ERROR : ' + scriptInfo + ' : Require fuzzy.js Vendor for JSON search mode!', 'color: #ff0000; font-weight: bold;');
13843				// -- * --
13844
13845				return '<h3 class="fs--18 p--20 pb--10 m-0 text-danger">' + scriptInfo + ' Error</h3>'
13846						+ '<hr><p class="pl--20 pr--20">data-mode="json" <br> You enabled JSON search mode but fuzzy.js Vendor could not be found!</p>'
13847						+ '<hr><p class="pl--20 pr--20"> Add fuzzy.js Vendor or switch to data-mode="html"</p>';
13848
13849			}
13850			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
13851
13852
13853
13854
13855
13856			try {
13857
13858				var _data = JSON.parse(data);
13859
13860			} catch(err) {
13861
13862				var _data = data;
13863
13864			}	var data = null; // clear/reset
13865
13866
13867			/*
13868
13869				TEST ONLY!
13870				fuzzy.js used instead!
13871
13872				var results = _data.filter(function(result) {
13873				  return result.label.indexOf(keyword) > -1;
13874				});
13875				console.log(results);
13876
13877			*/
13878
13879
13880			// TPL START : Common for related & suggest
13881			var _tpl = '<h3 class="fs--18 p-4 m-0 text-'+ themeClass +'">' + json_title + '</h3>'
13882						+ '<ul class="list-unstyled list-suggestion">';
13883
13884
13885
13886
13887
13888			// 1. FUZZY SEARCH : BY USER INPUT
13889			if(keyword != '') {
13890
13891				var filterResult 	= [],
13892					filterIndex 	= [],
13893					_found 			= 0;
13894
13895				// fuzzy setup
13896				fuzzy.analyzeSubTerms = true;
13897
13898				// Walk through json data
13899				for (var i = 0; i < _data.length; i++) {
13900					filterResult[i] 		= fuzzy(_data[i].label, keyword); 	// label filter
13901					filterResult[i].url 	= _data[i].url; 					// url required!
13902				}
13903
13904
13905				// sorting
13906				filterResult.sort(fuzzy.matchComparator);
13907
13908
13909				// Walk through results
13910				for (var i = 0; i < filterResult.length && i < json_max_results; i++) {
13911					var option 				= filterResult[i],
13912						term 				= option.term,
13913						score 				= option.score,
13914						termHighlighted		= option.highlightedTerm,
13915						_term = (highlight_term == true)  ? termHighlighted : term;
13916
13917
13918
13919					// Append each result
13920					if(score >= json_min_score) {
13921						_found++;
13922						_tpl += '<li class="list-item" data-score="'+score+'">'
13923								+ '<a href="'+option.url+'">'
13924									//+ '<span class="text-muted fs--13 float-end p--3">0 results</span>'
13925									+ '<i class="'+icon+'"></i> ' + _term
13926								+ '</a>'
13927							+ '</li>';
13928					}
13929
13930				}
13931
13932				if(_found < 1) {
13933					_tpl += '<li class="list-item text-muted px-4 pb-4">'
13934							+ json_noresult_txt + ' <i>"' + keyword + '"</i>'
13935						+ '</li>';
13936				}
13937
13938			// RELATED!
13939			} else {
13940
13941				var filterResult 	= [];
13942
13943				// Walk through json data
13944				for (var i = 0; i < _data.length; i++) {
13945					filterResult[i] = _data[i].label;
13946				}
13947
13948
13949				for (var i = 0; i < filterResult.length && i < json_max_results; i++) {
13950
13951					// Append each result
13952					_tpl += '<li class="list-item">'
13953							+ '<a href="'+_data[i].url+'">'
13954								+ '<i class="'+icon+'"></i> ' + _data[i].label
13955							+ '</a>'
13956						+ '</li>';
13957
13958				}
13959
13960			}
13961
13962
13963
13964
13965			// TPL END : Common for related & suggest
13966			_tpl += '</ul>';
13967
13968
13969			return _tpl;
13970
13971
13972		}
13973
13974	}
13975
13976})(jQuery);
13977
13978/**
13979 *
13980 *	[SOW] Lazyload
13981 *
13982 *	@author 		Dorin Grigoras
13983 *					www.stepofweb.com
13984 *
13985 *	@Dependency 	-
13986 *	@Usage			$.SOW.core.lazyload.init('.lazy');
13987 *
13988 * 	Based on Lozad Plugin
13989 * 	https://github.com/ApoorvSaxena/lozad.js
13990 *
13991 **/
13992;(function ($) {
13993	'use strict';
13994
13995
13996
13997	/**
13998	 *
13999	 *	@vars
14000	 *
14001	 *
14002	 **/
14003	var scriptInfo 		= 'SOW Lazyload';
14004	var __observer 		= void 0;
14005
14006	$.SOW.core.lazyload = {
14007
14008
14009		/**
14010		 *
14011		 *	@config
14012		 *
14013		 *
14014		 **/
14015		config: {
14016
14017			rootMargin: 	'0px',		// syntax similar to that of CSS Margin
14018			threshold: 		0.1, 		// 0 - 1; 1 = when 100% of the target is visible
14019
14020			load: function load(element) {
14021
14022				// <video>
14023				if (element.nodeName.toLowerCase() === 'video' && !element.getAttribute('data-src')) {
14024
14025					if (element.children) {
14026
14027						var childs 		= element.children;
14028						var childSrc 	= void 0;
14029
14030						for (var i = 0; i <= childs.length - 1; i++) {
14031
14032							childSrc = childs[i].getAttribute('data-src');
14033
14034							if (childSrc)
14035								childs[i].src = childSrc;
14036
14037						}
14038
14039						element.load();
14040					}
14041
14042				}
14043
14044				if (element.getAttribute('data-src'))
14045					element.src = element.getAttribute('data-src');
14046
14047				if (element.getAttribute('data-srcset'))
14048					element.setAttribute('srcset', element.getAttribute('data-srcset'));
14049
14050				// mobile, if exists
14051				if ($.SOW.globals.is_mobile === true && element.getAttribute('data-background-image-xs'))
14052					element.style.backgroundImage = 'url(\'' + element.getAttribute('data-background-image-xs') + '\')';
14053
14054				// fallback desktop from mobile
14055				else if (element.getAttribute('data-background-image'))
14056					element.style.backgroundImage = 'url(\'' + element.getAttribute('data-background-image') + '\')';
14057
14058				/*
14059					<div class="lazy" data-toggle-class="active">
14060					The active class will be toggled on the element when it enters the browser’s viewport.
14061				*/
14062				if (element.getAttribute('data-lazy-toggle-class')) {
14063					jQuery(element).addClass(element.getAttribute('data-lazy-toggle-class'));
14064					// element.classList.toggle(element.getAttribute('data-toggle-class'));
14065				}
14066
14067				// clear
14068				jQuery(element).removeAttr('data-lazy-toggle-class data-background-image data-srcset data-src');
14069
14070			}
14071
14072		},
14073
14074
14075
14076		/**
14077		 *
14078		 *	@collection
14079		 *
14080		 *
14081		 **/
14082		collection: $(),
14083
14084
14085
14086		/**
14087		 *
14088		 *	@init
14089		 *
14090		 *
14091		 **/
14092		init: function (selector, config) {
14093
14094			var __selector 			= $.SOW.helper.__selector(selector);
14095			var __config 			= $.SOW.helper.check_var(config);
14096
14097			this.selector 			= __selector[0]; 	// '#selector'
14098			this.collection 		= __selector[1]; 	// $('#selector')
14099			this.selector_orig 		= __selector[2]; 	// $('#selector') // without ajax container prefix
14100			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
14101
14102
14103			if(jQuery(this.selector).length < 1)
14104				return;
14105
14106
14107			// -- * --
14108			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
14109			// -- * --
14110
14111
14112			// 1. Has no selector
14113			if(!this.selector) {
14114				$.SOW.core.lazyload.process('.lazy').observe();
14115				return jQuery('.lazy');
14116			}
14117
14118			// 2. Has selector
14119			$.SOW.core.lazyload.process(this.selector).observe();
14120
14121
14122			return this.collection;
14123		},
14124
14125
14126
14127		/**
14128		 *
14129		 *	@process
14130		 *
14131		 *
14132		 *
14133		 **/
14134		process: function(selector) {
14135
14136			var load 					= $.SOW.core.lazyload.config.load;
14137
14138			if(window.IntersectionObserver) {
14139
14140				__observer = new IntersectionObserver($.SOW.core.lazyload.onIntersection(load), {
14141					rootMargin: $.SOW.core.lazyload.config.rootMargin,
14142					threshold: 	$.SOW.core.lazyload.config.threshold
14143				});
14144
14145			} else {
14146
14147				// load them all instead of using polyfill!
14148				// https://www.npmjs.com/package/intersection-observer
14149				var elements = $.SOW.core.lazyload.getElements(selector);
14150				for(var i = 0; i < elements.length; i++) {
14151					load(elements[i]);
14152					$.SOW.core.lazyload.markLoaded(elements[i]);
14153				}
14154
14155				// -- * --
14156				$.SOW.helper.consoleLog('Lazyload: This browser does not support IntersectionObserver()');
14157				$.SOW.helper.consoleLog('Images loaded without lazyloading!');
14158				$.SOW.helper.consoleLog('To enable, download this polyfill and include before any other js script: https://www.npmjs.com/package/intersection-observer');
14159				// -- * --
14160
14161			}
14162
14163			return {
14164
14165				observe: function observe() {
14166
14167					var items = $.SOW.core.lazyload.getElements(selector);
14168					for(var i=0; i < items.length; ++i) {
14169
14170						if($.SOW.core.lazyload.isLoaded(items[i]))
14171							continue;
14172
14173						if(__observer) {
14174							__observer.observe(items[i]);
14175							continue;
14176						}
14177
14178						load(items[i]);
14179						$.SOW.core.lazyload.markLoaded(items[i]);
14180
14181					}
14182				},
14183
14184				__observer: __observer
14185
14186			};
14187
14188		},
14189
14190
14191
14192
14193
14194		/**
14195		 *
14196		 *	@markLoaded
14197		 *
14198		 *
14199		 *
14200		 **/
14201		markLoaded: function(element) {
14202			element.setAttribute('data-loaded', true);
14203		},
14204
14205
14206
14207
14208		/**
14209		 *
14210		 *	@isLoaded
14211		 *
14212		 *
14213		 *
14214		 **/
14215		isLoaded: function(element) {
14216			return element.getAttribute('data-loaded') === 'true';
14217		},
14218
14219
14220
14221
14222		/**
14223		 *
14224		 *	@onIntersection
14225		 *
14226		 *
14227		 *
14228		 **/
14229		onIntersection: function(load) {
14230
14231			return function(items, __observer) {
14232
14233				items.forEach(function (item) {
14234
14235					if (item.intersectionRatio > 0 || item.isIntersecting) {
14236
14237						// call __observer is exists
14238						if(__observer)
14239							__observer.unobserve(item.target);
14240
14241						if (!$.SOW.core.lazyload.isLoaded(item.target)) {
14242							$.SOW.core.lazyload.config.load(item.target);
14243							$.SOW.core.lazyload.markLoaded(item.target);
14244						}
14245					}
14246
14247				});
14248
14249			}
14250
14251		},
14252
14253
14254
14255
14256		/**
14257		 *
14258		 *	@getElements
14259		 *
14260		 *
14261		 *
14262		 **/
14263		getElements: function(selector) {
14264
14265			if (selector instanceof Element)
14266				return [selector];
14267
14268			if (selector instanceof NodeList)
14269				return selector;
14270
14271			return document.querySelectorAll(selector);
14272
14273		},
14274
14275	}
14276
14277})(jQuery);
14278/**
14279 *
14280 *	[SOW] Ajax Navigation
14281 *
14282 *	@author 		Dorin Grigoras
14283 *					www.stepofweb.com
14284 *
14285 *	@Dependency 	-
14286 *	@Usage			$.SOW.core.ajax_navigation.init('a.js-ajax');
14287 *  				-- + --
14288 * 					From another plugin, for a specific container only:
14289 * 					Only this plugin is reinitialised, -WITHOUT- $.SOW.reinit() call
14290 * 					$.SOW.core.ajax_navigation.__initFor('#container');
14291 *  				-- + --
14292 * 					$.SOW.core.ajax_navigation.__selector();
14293 * 					returns the selector only: .js-ajax
14294 *
14295 **/
14296;(function ($) {
14297	'use strict';
14298
14299
14300	/**
14301	 *
14302	 *	@vars
14303	 *
14304	 *
14305	 **/
14306	var scriptInfo 		= 'SOW Ajax Navigation';
14307
14308	window.sow_ajax_links_last_href 	= null;
14309	window.sow_ajax_links_curr_href 	= null;
14310
14311
14312	$.SOW.core.ajax_navigation = {
14313
14314
14315		/**
14316		 *
14317		 *	@config
14318		 *
14319		 *
14320		 **/
14321		config: {
14322
14323
14324		/*
14325
14326			You can overwrite by adding the needed param to the link.
14327
14328			These params can be used on any <a class="js-ajax" ...></a> to overwrite thse settings
14329				data-ajax-method="GET|POST"
14330				data-ajax-container="#middle"					container to push data from the server; admin use #middle as main content container
14331				data-ajax-update-url="true|false"				update history state.
14332				data-ajax-show-loading-icon="true" 				false to disable loading icon on ajax requests
14333				data-ajax-callback-function="" 					custom callback function
14334				data-ajax-callback-before-push="false" 			do not push data to container, send to the callback only
14335				data-ajax-reponse-extract-element="#middle"		get a specific element from returned data (not the entire result/page). Example: <div id="something"><div class="else"> <div id="middle">this content</div> </div></div>
14336				data-ajax-autoscroll-to-content="false" 		scroll to top content after loading
14337
14338				Second container, if needed to add a class: hide, show, animate, etc
14339				data-ajax-container2-element="img.js-ajax-loaded-animate" 	<img class="js-ajaxloaded-animate" ...>
14340				data-ajax-container2-class="animate-bouncein"
14341
14342			*/
14343			enable 							: true,
14344			method 							: 'GET',
14345			contentType 					: '',
14346			dataType 						: '',
14347			headers 						: '',
14348			crossDomain 					: '',
14349			data_params 					: {ajax:'true'},
14350
14351			target_container				: '#middle', // where data is pushed
14352			update_url 						: true,
14353			show_loading_icon				: true,
14354
14355			/*
14356				callback_example = function(el, data, target_container) {
14357					// el 				= link clicked 				$(this)
14358					// data 			= server response 			(html|string)
14359					// target_container = container to push data  	(string:#middle)
14360				}
14361			*/
14362			callback_function 				: '',
14363
14364			// content (server response) is sent to your callback function only.
14365			callback_before_push			: false,
14366
14367			/*
14368				#middle 		= main content to be extracted
14369				#page_js_files  = second container containing js files wrapped inside a div
14370			*/
14371			parser_extract_enable 			: true,
14372			parser_force_push2target 		: false,		// in case #middle element not found in request, entire data/page is pushed/shown
14373			parser_extract_element			: '#middle, #page_js_files',
14374
14375			autoscroll_to_content			: true, 		// scroll up to content after page loaded
14376
14377
14378			// Optional second container - add a class when page loaded
14379			container2_element				: '',
14380			container2_class				: '',
14381
14382			// 404 error page
14383			page_404						: '404.html',
14384
14385
14386			// Reload page content on back/forward history button instead of loading from history cache
14387			onpopstate_reload 				: true,
14388
14389			/*
14390				Different than callback, cannot be overwrited by params
14391				Will call a custom function after each page load
14392				Condition: callback_before_push: false (else, call the function from your callback).
14393
14394				Can be used to reinit custom scripts/plugins and/or process special data
14395
14396				custom_function_example = function(el, target_container) {
14397					// el 			= link clicked 						$(this)
14398					// container 	= container where data is pushed   	(string:#middle)
14399				}
14400			*/
14401			custom_function_call 			: '',
14402
14403
14404
14405
14406			// Ajax remainings of other plugins that are not self removed
14407			// .note-popover = summernote (bootstrap4 bug)
14408			AjaxOtherGarbage 				: '.datepicker, .daterangepicker, .modal, .modal-backdrop, .note-popover, #dropdown_toggle_overlay',
14409		},
14410
14411
14412
14413		/**
14414		 *
14415		 *	@collection
14416		 *
14417		 *
14418		 **/
14419		collection: $(),
14420
14421
14422
14423		/**
14424		 *
14425		 *	@init
14426		 *
14427		 *
14428		 **/
14429		init: function (selector, config) {
14430
14431
14432			/* disabled by config */
14433			if($.SOW.core.ajax_navigation.config.enable !== true) {
14434				$.SOW.helper.consoleLog('Disabled : ' + scriptInfo, 'color: #ff0000;');
14435				return;
14436			}
14437
14438
14439			var __selector 			= $.SOW.helper.__selector(selector);
14440			var __config 			= $.SOW.helper.check_var(config);
14441
14442			this.selector 			= __selector[0]; 	// '#selector'
14443			this.collection 		= __selector[1]; 	// $('#selector')
14444			this.selector_orig 		= __selector[2]; 	// $('#selector') // without ajax container prefix
14445			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
14446
14447			if(jQuery(this.selector).length < 1)
14448				return;
14449
14450
14451			// -- * --
14452			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
14453			// -- * --
14454
14455
14456			/*
14457
14458				History Postate
14459
14460			*/
14461			$.SOW.core.ajax_navigation.__historyPopState();
14462
14463
14464
14465			// 1. Has no selector
14466			if(!this.selector) {
14467				$.SOW.core.ajax_navigation.ajax_navigation($('a.js-ajax'));
14468				return this.collection;
14469			}
14470
14471			// 2. Has selector
14472			return this.collection.each(function() {
14473
14474				$.SOW.core.ajax_navigation.ajax_navigation($(this));
14475
14476			});
14477
14478		},
14479
14480
14481
14482		/**
14483		 *
14484		 *	@ajax_navigation
14485		 *
14486			1. LINKS
14487
14488				USAGE 1:
14489
14490					<a href="https://myurl.com/request/" class="js-ajax" data-ajax-container="#my_container">Click</a>
14491					<div id="my_container"><!-- ajax content is loaded here --></div>
14492
14493				USAGE 2: (using data-href)
14494
14495					<a href="#" data-href="https://myurl.com/request/" class="js-ajax" data-ajax-container="#my_container">Click</a>
14496					<div id="my_container"><!-- ajax content is loaded here --></div>
14497
14498
14499				OPTIONAL PARAMS:
14500					data-ajax-method="GET|POST"				default: GET
14501					data-ajax-update-url="true"		default: false - update history state
14502					data-ajax-show-loading-icon="false" 		do not show loading icon
14503					data-ajax-callback-function="" 			custom callback function
14504					data-ajax-callback-before-push="false" 	do not push data to container, send to the callback only
14505					data-ajax-reponse-extract-element="#middle"		push only an element returned from aja
14505x (not the entire result/page)
14506					data-ajax-autoscroll-to-content="false" 	scroll to top content after loading
14507					data-ajax-container="#middle"			container to push data from the server
14508
14509					Second container, if needed to add a class: hide, show, animate, etc
14510					data-ajax-container2-element="#myimg"
14511					data-ajax-container2-class="animate-bouncein"
14512
14513				&ajax=true - added but NOT to .html files
14514		 *
14515		 *
14516		 **/
14517		ajax_navigation: function(_this, ajax_navigation_reinit_skip) { // ajax_navigation_reinit_skip: used by calling from other plugins via __initFor(). DO NOT REMOVE!
14518
14519			var _selector 		= this.selector;
14520			var _selector_orig 	= this.selector_orig;
14521
14522			if($.SOW.core.ajax_navigation.config.enable !== true) {
14523				_this.off('click');
14524				return;
14525			}
14526
14527			// !!! do not use unbind()
14528			// deep navigation links conflict for ajax
14529			_this.on('click', function(e) {
14530
14531
14532				/*
14533					Because we want to be sure that we bind only once
14534					and avoid multiple times! We can't use unbind() because
14535					some other plugins might bind that link for some reason!
14536				*/
14537				// if(jQuery(this).hasClass('js-ajaxified'))
14538				// 	return;
14539				/* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
14540
14541
14542				e.preventDefault();
14543				e.stopPropagation();
14544
14545				var _t 						= jQuery(this),
14546					_href 					= _t.attr('href')								|| '#',
14547					_href_data 				= _t.attr('data-href')							|| '',
14548					_href_title 			= _t.attr('title')								|| '', 		// used by historyPushState to update the title
14549					_scrollToContent		= _t.attr('data-ajax-autoscroll-to-content')	|| '',
14550					_callback				= _t.data('ajax-callback-function')				|| '',
14551					_callbackBeforePush		= _t.attr('data-ajax-callback-before-push')		|| '', 		// pass to calback, do not push content to container
14552					_method 				= _t.data('ajax-method') 						|| '',
14553					_updateURL 				= _t.attr('data-ajax-update-url') 				|| '', 		// istory push state
14554					_showLoadingIcon		= _t.attr('data-ajax-show-loading-icon') 		|| '',
14555					_container2El 			= _t.data('ajax-container2-element') 			|| '',		// add a class to a container, or an animation... anything
14556					_container2Class 		= _t.data('ajax-container2-class') 				|| '',		// add a class to a container, or an animation... anything
14557					_contentResponseExtract = _t.data('ajax-parser-extract-element') 		|| '',		// id|class (document container to get data from)
14558					_target 				= _t.data('ajax-target-container') 				|| '';
14559
14560
14561				if(_href_data != '')
14562					_href = _href_data;
14563
14564
14565
14566				// ok, bind identifier for this function so we don't bind again!
14567				//_t.addClass('js-ajaxified');
14568
14569
14570
14571				// Check nav-deep for this link, if comes from content!
14572				// We want it highlighted!
14573				if(!_t.hasClass('nav-link') && typeof $.SOW.core.nav_deep === 'object') {
14574
14575					/**
14576
14577						We remove #hash and rewrite the _href
14578						Actually, the back button on pushState will not contain the #hash anymore
14579						But when the user click "Back Button", page position is ok
14580						It's not something critical, we can live with this intentional bug.
14581						The chance that somebody notice... is very, very, very low :)
14582
14583					**/
14584					var _href 				= $.SOW.helper.removeUrlHash(_href); // remove hash (helper)
14585					var __navHasThisLink 	= jQuery(_selector_orig+'.nav-link[href="'+_href+'"]');
14586
14587					if(__navHasThisLink.length > 0) {
14588
14589						$.SOW.core.nav_deep.nav_deep_open(__navHasThisLink);
14590						$.SOW.core.nav_deep.nav_deep_close_all(__navHasThisLink);
14591
14592					}
14593
14594					// clear/reset
14595					var __navHasThisLink 	= null;
14596
14597				}
14598				// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
14599
14600
14601
14602				/**
14603					CONFIG DEFAULTS
14604				**/
14605				if(_scrollToContent == '')
14606					var _scrollToContent = $.SOW.core.ajax_navigation.config.autoscroll_to_content;
14607
14608				if(_callback == '')
14609					var _callback = $.SOW.core.ajax_navigation.config.callback_function;
14610
14611				if(_callbackBeforePush == '')
14612					var _callbackBeforePush = $.SOW.core.ajax_navigation.config.callback_before_push;
14613
14614				if(_method == '')
14615					var _method = $.SOW.core.ajax_navigation.config.method;
14616
14617				if(_updateURL == '')
14618					var _updateURL = $.SOW.core.ajax_navigation.config.update_url;
14619
14620				if(_showLoadingIcon == '')
14621					var _showLoadingIcon = $.SOW.core.ajax_navigation.config.show_loading_icon;
14622
14623				if(_container2El == '')
14624					var _container2El = $.SOW.core.ajax_navigation.config.container2_element;
14625
14626				if(_container2Class == '')
14627					var _container2Class = $.SOW.core.ajax_navigation.config.container2_class;
14628
14629				// --
14630
14631				if(_contentResponseExtract == '' && $.SOW.core.ajax_navigation.config.parser_extract_enable === true) /* default self config (se top config) */
14632					var _contentResponseExtract = $.SOW.core.ajax_navigation.config.parser_extract_element;
14633
14634				/*
14635
14636					In case there is another ajax request,
14637					but for a different specified #destination_container
14638
14639				*/
14640				if(_target != '' && _target != _contentResponseExtract)
14641					_contentResponseExtract = '';
14642
14643				// --
14644
14645				if(_target == '')
14646					var _target = $.SOW.core.ajax_navigation.config.target_container;
14647
14648
14649
14650				if(_target == '') {
14651
14652					$.SOW.helper.consoleLog('Ajax request: data-ajax-container missing!');
14653					return;
14654
14655				}
14656
14657
14658				else if(_href == '#' || _href == '#!' || _href == '' || _href == 'javascript:;') {
14659
14660					$.SOW.helper.consoleLog('Ajax request: no valid link!');
14661					return;
14662
14663				}
14664
14665
14666
14667
14668				/*
14669
14670					Block "flooding"
14671
14672				*/
14673				if(window.sow_ajax_links_last_href == _href)
14674					return;
14675
14676				window.sow_ajax_links_last_href = _href;
14677				// --
14678
14679
14680
14681				// Remove any unwanted stuff - like: if click was from modal
14682				jQuery('.modal-backdrop').remove();
14683				jQuery('body').removeClass('modal-open overflow-hidden');
14684
14685
14686
14687
14688
14689
14690
14691				/*
14692
14693					CREATE AN OBJECT WITH ALL PARAMS TO SEND THEM TO AJAX FUNCTION!
14694
14695					The reason we do this, is because we need the exactly same
14696					ajax request for historyPushState on "back button" click.
14697					This object we save it as "html" (json) to historyPushState
14698
14699					This object will be packed as json by __ajaxLinkProcess() function
14700					 _json = JSON.stringify(_obj);
14701
14702				*/
14703				var _obj 							= new Object();
14704					_obj._t 						= _t;
14705					_obj._href 						= _href;
14706					_obj._scrollToContent 			= _scrollToContent;
14707					_obj._callback 					= _callback;
14708					_obj._callbackBeforePush 		= _callbackBeforePush;
14709					_obj._method 					= _method;
14710					_obj._updateURL 				= _updateURL;
14711					_obj._showLoadingIcon 			= _showLoadingIcon;
14712					_obj._container2El 				= _container2El;
14713					_obj._container2Class 			= _container2Class;
14714					_obj._contentResponseExtract 	= _contentResponseExtract;
14715					_obj._target 					= _target;
14716
14717
14718					/**
14719
14720						HOW IT WORKS?
14721
14722							1. __ajaxLinkProcess() send an ajax request. If _callbackBeforePush is not set tot true, the page will update.
14723							2. the object above is packed into a JSON string and passed it to __ajaxLinkProcess() as to keep it in history pushState ;)
14724							3. user is happy, drinking 10 beers but suddently navigate back using "back button" so the page is the same but the link is changing!
14725							4. the history will return the sting from cache (our jsonified object) we just created on step 2
14726							5. history function will call __ajaxLinkProcess() passing the object but disabling things like _updateURL (because is already on that page)
14727							6. __ajaxLinkProcess() will try to find the link to get the element because jQuery(this) is needed (I mean: _t)
14728							7. Because we keep the previous pages in pushHistory, we use them to catch the clicked link.
14729
14730							Looks complicated but the process is simple.
14731
14732					**/
14733					return $.SOW.core.ajax_navigation.__ajaxLinkProcess(_obj, ajax_navigation_reinit_skip);
14734
14735
14736			});
14737
14738
14739		},
14740
14741			/**
14742			 *
14743			 *	Ajax Process
14744			 *	:: Helper
14745			 *
14746			 **/
14747			__ajaxLinkProcess: function(_obj, ajax_navigation_reinit_skip) {
14748
14749				if($.SOW.core.ajax_navigation.config.enable !== true)
14750					return;
14751
14752
14753				var _t 							= _obj._t,
14754					_href 						= _obj._href,
14755					_scrollToContent 			= _obj._scrollToContent,
14756					_callback 					= _obj._callback,
14757					_callbackBeforePush 		= _obj._callbackBeforePush,
14758					_method 					= _obj._method,
14759					_updateURL 					= _obj._updateURL,
14760					_showLoadingIcon 			= _obj._showLoadingIcon,
14761					_container2El 				= _obj._container2El,
14762					_container2Class 			= _obj._container2Class,
14763					_contentResponseExtract 	= _obj._contentResponseExtract,
14764					_target 					= _obj._target,
14765					_obj 						= null;
14766
14767
14768
14769				// Yeah, the ugliest bool fix ever.
14770				var _callbackBeforePush = _callbackBeforePush+'';
14771				var _callbackBeforePush = _callbackBeforePush.toLowerCase();
14772				var _updateURL 			= _updateURL+'';
14773				var _updateURL 			= _updateURL.toLowerCase();
14774				var _showLoadingIcon 	= _showLoadingIcon+'';
14775				var _showLoadingIcon 	= _showLoadingIcon.toLowerCase();
14776				var _scrollToContent 	= _scrollToContent+'';
14777				var _scrollToContent 	= _scrollToContent.toLowerCase();
14778
14779
14780
14781				jQuery.ajax({
14782					url:			_href,
14783					data: 			$.SOW.core.ajax_navigation.config.data_params,
14784					type: 			_method,
14785					contentType: 	$.SOW.core.ajax_navigation.config.contentType,
14786					dataType: 		$.SOW.core.ajax_navigation.config.dataType,
14787					headers: 		$.SOW.core.ajax_navigation.config.headers,
14788					crossDomain: 	$.SOW.core.ajax_navigation.config.crossDomain,
14789
14790					beforeSend: function() {
14791
14792						if(_showLoadingIcon == 'true')
14793							$.SOW.helper.loadingSpinner('show', _target);
14794
14795						// disable link
14796						_t.addClass('disabled');
14797
14798
14799						/*
14800
14801							Click from admin : close mobile aside
14802
14803						*/
14804						if($.SOW.globals.is_mobile === true) {
14805
14806							if($.SOW.globals.elBody.hasClass('layout-admin') && jQuery('#aside-main').hasClass('js-aside-show'))
14807								jQuery('.btn-sidebar-toggle').trigger('click');
14808
14809						}
14810
14811					},
14812
14813					error: 	function(XMLHttpRequest, textStatus, errorThrown) {
14814
14815						// 404 error page
14816						var page_404_response = $.SOW.core.ajax_navigation.page_404(_contentResponseExtract, _target); // should return true!
14817
14818						if(!page_404_response) {
14819
14820							$.SOW.helper.loadingSpinner('hide');
14821
14822							if(typeof $.SOW.core.toast === 'object') {
14823
14824								$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
14825
14826							} else {
14827
14828								alert("[404] Unexpected internal error!");
14829
14830							}
14831
14832						}
14833
14834
14835
14836						// if debug enabled, see config
14837						if($.SOW.config.sow__debug_enable === true) {
14838
14839							$.SOW.helper.consoleLog('----------------------------');
14840							$.SOW.helper.consoleLog('--- AJAX  REQUEST ERROR ----');
14841							$.SOW.helper.consoleLog('1. XMLHttpRequest:');
14842							$.SOW.helper.consoleLog(XMLHttpRequest);
14843							$.SOW.helper.consoleLog('2. textStatus:');
14844							$.SOW.helper.consoleLog(textStatus);
14845							$.SOW.helper.consoleLog('3. errorThrown:');
14846							$.SOW.helper.consoleLog(errorThrown);
14847							$.SOW.helper.consoleLog('----------------------------');
14848
14849						}
14850
14851					},
14852
14853					success: function(data) {
14854
14855
14856						// Ajax remainings of other plugins that are not self removed
14857						$.SOW.core.ajax_navigation.__cleanAjaxOtherGarbage();
14858						// ----------------------------------------------------------
14859
14860
14861						var __dataHtml = '';
14862
14863						if(_callbackBeforePush == 'false') {
14864
14865							// Push data
14866							if(_contentResponseExtract == '' || $.SOW.core.ajax_navigation.config.parser_extract_enable === false) {
14867
14868
14869
14870								/*
14871
14872									[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated
14873									because of its detrimental effects to the end user's experience.
14874									For more help, check https://xhr.spec.whatwg.org/
14875
14876									Remove any <script> and append them using async:
14877										html_parsed__apply_scripts()
14878
14879								*/
14880								var script_src	 		= new Array,
14881									script_inline	 	= new Array,
14882									jQ_source = jQuery('<div>' + data + '</div>');
14883
14884								// get scripts with src
14885								jQuery('script[src]', jQ_source).each(function() {
14886									script_src.push($(this).attr('src'));
14887								});
14888								jQuery('script[src]', jQ_source).remove();
14889
14890								// get scripts without src
14891								jQuery('script', jQ_source).each(function() {
14892									script_inline.push($(this));
14893								});
14894								jQuery('script', jQ_source).remove();
14895								// --------------------------------------------------------------------------------
14896								var parsed_data = jQ_source.html();
14897
14898
14899								// force push content, as it is because nothing parsed
14900								if(parsed_data == '' && $.SOW.core.ajax_navigation.config.parser_force_push2target === true)
14901									var parsed_data = data;
14902
14903
14904								// Append data
14905								jQuery(_target).empty().append(parsed_data);
14906
14907
14908								// Apply JS
14909								$.SOW.core.ajax_navigation.html_parsed__apply_scripts(script_src, script_inline);
14910								var jQ_source = null;
14911
14912
14913								if(_updateURL == 'true')
14914									var __dataHtml = parsed_data;
14915
14916							// Parse content and push
14917							} else {
14918
14919								// Pase data
14920								var _objParsed = $.SOW.core.ajax_navigation.html_parse(_contentResponseExtract, data);
14921
14922								if(typeof _objParsed !== 'object') {
14923
14924									var __dataHtml 	= '';
14925
14926								} else {
14927
14928									var __dataHtml 	= _objParsed.html_content;
14929									var _href_title = _objParsed.meta_title;
14930
14931								}
14932
14933
14934								// force push content, as it is because nothing parsed
14935								if(!__dataHtml && $.SOW.core.ajax_navigation.config.parser_force_push2target === true)
14936									__dataHtml = data;
14937
14938
14939								// Push Content
14940								jQuery(_target).empty().append(__dataHtml);
14941
14942								// Push Scripts
14943								$.SOW.core.ajax_navigation.html_parsed__apply_scripts(_objParsed.scripts_src, _objParsed.scripts_inline);
14944								var _objParsed 	= null; // clear
14945
14946							}
14947							// --
14948
14949
14950							// We also avoid adding same page to history pushState on multiple clicks on the same link
14951							if(_updateURL == 'true' && window.sow_ajax_links_curr_href != _href) {
14952
14953								/*
14954
14955									We create a new object here, can't use the one passed to the function!
14956									Regular js function is working. This is not!
14957								*/
14958								var _obj 						= new Object;
14959								_obj._href 						= _href;
14960								_obj._callback 					= _callback;
14961								_obj._callbackBeforePush 		= _callbackBeforePush;
14962								_obj._contentResponseExtract 	= _contentResponseExtract;
14963								_obj._updateURL 				= _updateURL;
14964								_obj._container2El 				= _container2El;
14965								_obj._container2Class 			= _container2Class;
14966								_obj._scrollToContent 			= _scrollToContent;
14967								_obj._target 					= _target;
14968								_obj._html 						= (__dataHtml != '') ? __dataHtml : '';
14969								var _json 						= JSON.stringify(_obj);
14970
14971								$.SOW.core.ajax_navigation.__historyPushState(_href, _href_title, _json);
14972							}
14973
14974
14975							// scroll to content
14976							if(_scrollToContent == 'true') {
14977								if(typeof $.SOW.helper.scrollAnimate === "function") {
14978									var _contentEl = jQuery(_target);
14979									$.SOW.helper.scrollAnimate(_contentEl, 0, false, 200);
14980								}
14981							}
14982
14983
14984							// Second container - remove and|or add class (animation, toggle, hide, etc)
14985							if(_container2El != '') {
14986
14987								// to animate after scrolling
14988								var _container2Delay = (_scrollToContent == true) ? 200 : 60;
14989
14990
14991								// Remove first
14992								jQuery(_container2El).removeClass(_container2Class);
14993
14994								setTimeout(function() {
14995
14996									// Add back (useful for animation)
14997									if(_container2Class != '')
14998										jQuery(_container2El).addClass(_container2Class);
14999
15000								}, _container2Delay);
15001
15002							}
15003
15004
15005							// custom_function_call()
15006							// call this function after each page load
15007							if($.SOW.core.ajax_navigation.config.custom_function_call != '') {
15008
15009								if(typeof $.SOW.helper.executeFunctionByName === "function")
15010									$.SOW.helper.executeFunctionByName($.SOW.core.ajax_navigation.config.custom_function_call, window, _t, _target, this.selector);
15011
15012							}
15013
15014
15015							// ++ REINIT PLUGINS ++
15016							if(ajax_navigation_reinit_skip !== 'true')
15017								$.SOW.core.ajax_navigation.reinit_call(_target);
15018							// ++ ++ ++ ++ ++ ++ ++
15019
15020
15021						}
15022
15023
15024
15025						// notice only
15026						if(_callbackBeforePush == 'true' && _callback == '')
15027							$.SOW.helper.consoleLog('data-ajax-callback-function="" -BUT- data-ajax-callback-before-push="true"');
15028
15029
15030
15031						// callback function
15032						if(_callback != '') {
15033
15034							if(typeof $.SOW.helper.executeFunctionByName === "function")
15035								$.SOW.helper.executeFunctionByName(_callback, window, _t, __dataHtml || data, _target);
15036
15037						}
15038
15039
15040
15041						// remove loading icon
15042						$.SOW.helper.loadingSpinner('hide');
15043
15044
15045
15046						// enable link
15047						_t.removeClass('disabled');
15048
15049
15050
15051						// Add url to container, in case is "ajax content" plugin used
15052						// so we can have a real "reload btn" with new link
15053						if(jQuery(_target).hasClass('js-ajax'))
15054							jQuery(_target).attr('data-ajax-url', _href);
15055
15056
15057
15058						// clear/reset
15059						var data 			= null,
15060							_obj 			= null,
15061							_json			= null,
15062							__dataHtml 		= null,
15063							__source 		= null,
15064							__dataParsed 	= null;
15065						window.sow_ajax_links_last_href 	= null;
15066
15067						// Used to avoid adding same page to history pushState on multiple clicks on the same link
15068						if(_updateURL == 'true' && window.sow_ajax_links_curr_href != _href)
15069							window.sow_ajax_links_curr_href = _href;
15070
15071
15072						// Needed for links from fullscreen
15073						$.SOW.globals.elBody.removeClass('overflow-hidden');
15074
15075					}
15076
15077				});
15078
15079				return true;
15080
15081			},
15082
15083
15084
15085
15086
15087
15088
15089		/**
15090		 *
15091		 * 	@html_parse
15092		 *	Extract content of html. One or more selectors
15093		 *	html_parse('#selector1, #selector2, ...', html);
15094		 *
15095		 *
15096		**/
15097		html_parse: function(_selectors, _data) {
15098
15099			if(!_data)
15100				return null;
15101
15102			else if(!_selectors) {
15103				var _obj 					= new Object;
15104					_obj.meta_title 		= null;
15105					_obj.html_content 		= _data;
15106			}
15107
15108			var jQ_source 			= jQuery('<div>' + _data + '</div>'),
15109				html_content 		= '',
15110				meta_title 			= jQ_source.find('title').html() || '',
15111				data_parsed 		= jQ_source.find(_selectors),
15112				script_src	 		= new Array,
15113				script_inline	 	= new Array;
15114
15115			if(!data_parsed)
15116				return null;
15117
15118
15119			// Add each element (if more than one elements passed)
15120			data_parsed.each(function() {
15121
15122				/*
15123
15124					[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated
15125					because of its detrimental effects to the end user's experience.
15126					For more help, check https://xhr.spec.whatwg.org/
15127
15128					Remove any <script> and append them using async:
15129						html_parsed__apply_scripts()
15130
15131				*/
15132				// get scripts with src
15133				jQuery('script[src]', this).each(function() {
15134					script_src.push($(this).attr('src'));
15135				});
15136				jQuery('script[src]', this).remove();
15137
15138				// get scripts without src
15139				jQuery('script', this).each(function() {
15140					script_inline.push($(this));
15141				});
15142				jQuery('script', this).remove();
15143
15144				// at this point, we shuld be <script> free
15145				html_content += $(this).html(); // required for __historyPushState
15146
15147			});
15148
15149
15150			var _obj 					= new Object;
15151				_obj.meta_title 		= meta_title;
15152				_obj.html_content 		= html_content;
15153				_obj.scripts_src 		= script_src;
15154				_obj.scripts_inline 	= script_inline;
15155
15156			return _obj;
15157		},
15158
15159
15160
15161
15162
15163
15164		/**
15165		 *
15166		 * 	@html_parsed__apply_scripts
15167		 *	Apply parsed scripts
15168		 *
15169		 *
15170		**/
15171		html_parsed__apply_scripts: function(scripts_src, scripts_inline) {
15172
15173
15174			/**
15175
15176				Reason this function exists:
15177
15178					[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated
15179					because of its detrimental effects to the end user's experience.
15180					For more help, check https://xhr.spec.whatwg.org/
15181
15182					So we can't just append(html_content) including scripts.
15183					We cut them out on html_parse() and append them this way!
15184
15185			**/
15186			// $.SOW.helper.loadScript(script_arr, async[true|false], cache[true|false])
15187			$.SOW.helper.loadScript(scripts_src, false, true).done(function() {
15188
15189				jQuery('#js_ajax_navigation_appended_scripts').remove();
15190
15191				if(scripts_inline.length > 0) {
15192
15193					jQuery('body').append('<div id="js_ajax_navigation_appended_scripts"></div>');
15194
15195					for (var i in scripts_inline) {
15196						jQuery('#js_ajax_navigation_appended_scripts').append(scripts_inline[i]);
15197					}
15198
15199				}
15200
15201			});
15202
15203			return true;
15204
15205		},
15206
15207
15208
15209
15210
15211
15212
15213		/**
15214		 *
15215		 * 	@reinit_call
15216		 *	Call main $.SOW.reinit()
15217		 *
15218		 *
15219		**/
15220		reinit_call: function(_target) {
15221
15222			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
15223			// reinit inside ajax container
15224			if($.SOW.config.sow__debug_enable === true) { // just to avoid always calling the helper
15225				$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
15226				$.SOW.helper.consoleLog(scriptInfo, 'color: #6dbb30; font-weight: bold; font-size:14px;');
15227				$.SOW.helper.consoleLog('Ajax Reinit For: ' + _target);
15228				$.SOW.helper.consoleLog(window.location.href);
15229				$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
15230			}
15231
15232			$.SOW.reinit(_target);
15233
15234			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
15235
15236		},
15237
15238
15239
15240
15241
15242
15243
15244
15245		/**
15246		 *
15247		 * 	@page_404
15248		 *	Get Page 404
15249		 *
15250		 *
15251		**/
15252		page_404: function(_contentResponseExtract, _target) {
15253
15254			if($.SOW.core.ajax_navigation.config.page_404 == '')
15255				return null;
15256
15257			// get the page
15258			jQuery.ajax({
15259				url:			$.SOW.core.ajax_navigation.config.page_404,
15260				data: 			{ajax:"true"},
15261				type: 			'GET',
15262				contentType: 	'',
15263				dataType: 		'',
15264				headers: 		'',
15265				crossDomain: 	'',
15266
15267				beforeSend: function() {
15268
15269					$.SOW.helper.loadingSpinner('show', _target);
15270
15271				},
15272
15273				error: 	function(XMLHttpRequest, textStatus, errorThrown) {
15274
15275					$.SOW.helper.loadingSpinner('hide');
15276
15277				},
15278
15279				success: function(data) {
15280
15281					// Pase data
15282					var _objParsed 	= $.SOW.core.ajax_navigation.html_parse(_contentResponseExtract, data),
15283						data 		= null;
15284
15285					if(typeof _objParsed !== 'object') {
15286
15287						var __dataHtml = '';
15288
15289					} else {
15290
15291						var __dataHtml 	= _objParsed.html_content;
15292						document.title 	= _objParsed.meta_title;
15293
15294						// we need it in case o refresh!
15295						$.SOW.core.ajax_navigation.__historyPushState($.SOW.core.ajax_navigation.config.page_404, document.title, __dataHtml);
15296
15297					}
15298
15299
15300					// force push content, as it is because nothing parsed
15301					if(!__dataHtml && $.SOW.core.ajax_navigation.config.parser_force_push2target === true)
15302						__dataHtml = data;
15303
15304
15305					// Push Content
15306					jQuery(_target).empty().html(__dataHtml);
15307					$.SOW.helper.loadingSpinner('hide');
15308
15309					// Push Scripts
15310					$.SOW.core.ajax_navigation.html_parsed__apply_scripts(_objParsed.scripts_src, _objParsed.scripts_inline);
15311					var _objParsed 	= null; // clear
15312
15313
15314					// reinit plugins for 404 page
15315					$.SOW.core.ajax_navigation.reinit_call(_target);
15316
15317
15318
15319				}
15320
15321			});
15322
15323
15324			return true;
15325
15326		},
15327
15328
15329
15330
15331
15332
15333
15334
15335
15336		/*
15337
15338			Init for specific container
15339			Used by other plugins
15340
15341		*/
15342		__initFor: function(_container) {
15343
15344			if(!_container)
15345				return;
15346
15347			var ajax_navigation_reinit_skip = true; // true, no matter what!
15348			return $.SOW.core.ajax_navigation.ajax_navigation(jQuery(_container + ' ' + this.selector_orig), ajax_navigation_reinit_skip);
15349
15350		},
15351
15352
15353
15354
15355
15356
15357
15358		/*
15359
15360			Return the selector only
15361			Example: .js-ajax
15362
15363		*/
15364		__selector: function() {
15365
15366			return this.selector_orig;
15367
15368		},
15369
15370
15371
15372
15373
15374		/*
15375
15376			Clean `garbage`
15377			Ajax remainings that are not self removed
15378
15379		*/
15380		__cleanAjaxOtherGarbage: function() {
15381
15382			$($.SOW.core.ajax_navigation.config.AjaxOtherGarbage).remove();
15383			jQuery('body').removeClass('overflow-hidden modal-open');
15384
15385		},
15386
15387
15388
15389
15390
15391
15392
15393
15394
15395
15396
15397
15398
15399
15400
15401
15402
15403
15404		/** HISTORY PUSH STATE
15405			Change url without refresh & push data
15406		 **************************************************************** **/
15407		__historyPushState: function(_url, _pageTitle, html) {
15408
15409			if(_url == '' || _url == '#' || _url == 'javascript:;')
15410				return;
15411
15412			// Non compatible browsers
15413			if(typeof(history.pushState) == "undefined") {
15414				window.location = _url;
15415				return;
15416			}
15417
15418			window.history.pushState(
15419					{
15420						"html": 		html,
15421						"pageTitle": 	_pageTitle,
15422					},
15423					"", _url
15424			);
15425
15426			$.SOW.helper.consoleLog("SOW Ajax : history.pushState : " + _url);
15427		},
15428
15429
15430
15431
15432
15433
15434		/*
15435
15436			Popstate
15437			Back Button
15438
15439		*/
15440		__historyPopState: function() {
15441
15442			var _selector 		= this.selector;
15443			var _selector_orig 	= this.selector_orig; // without ajax container
15444
15445			if(typeof(window.onpopstate) !== "function") {
15446
15447				window.onpopstate = function(e) {
15448
15449					if(e.state) {
15450
15451						document.title = e.state.pageTitle; // update title from history
15452
15453						var _obj = JSON.parse(e.state.html);
15454
15455						// Update html (from history version)
15456						// needed to search the link - see below
15457						var _target = (_obj._target != '') ? _obj._target : '#middle';
15458						jQuery(_target).empty().html(_obj._html);
15459
15460						// No reason to continue, we can't find the element to click or get data
15461						// We keep the page from history!
15462						if(_obj._href == '') {
15463							$.SOW.helper.consoleLog("SOW Ajax : history.pushState : Err : Missing Back Link! Displayed the page from history, no real request to the server reload!");
15464							return;
15465						}
15466
15467
15468						/* --------------------------------------------------------------------------- */
15469
15470						// Let's get the element! We have only the link to work with!
15471						var _t = jQuery(_selector_orig+'[href="'+_obj._href+'"]').first();
15472
15473						if(!_t)
15474							var _t = jQuery(_selector_orig+'[href="'+_obj._href+'"]').first();
15475
15476
15477						if(!_t) {
15478							$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
15479
15480							// No link found? Reload page if also no history html version.
15481							if(_obj._html == '')
15482								location.reload(true);
15483
15484							// Ok, stop here!
15485							return;
15486
15487						}
15488
15489						/* --------------------------------------------------------------------------- */
15490						if($.SOW.core.ajax_navigation.config.onpopstate_reload === true) {
15491							/*
15492								Reload the content!
15493								Display the page from the history, which is already doing few lines above!
15494							*/
15495
15496							_obj._t  				= _t;			// most important (is actually the link clicked - dom element)
15497							_obj._updateURL 		= false;		// do not update, we already are on it
15498							_obj._scrollToContent 	= false; 		// annoyng on each back to have a scrolling page
15499
15500							$.SOW.core.ajax_navigation.__ajaxLinkProcess(_obj); 				// ajax call, refresh page|content
15501							$.SOW.helper.consoleLog("SOW Ajax : onpopstate : Content request sent to the server!");
15502
15503						}
15504						/* --------------------------------------------------------------------------- */
15505
15506						/*
15507							Deep Navigation Plugin
15508							Active Current
15509						*/
15510						if(typeof $.SOW.core.nav_deep === 'object') {
15511							$.SOW.core.nav_deep.nav_deep_open(_t);
15512							$.SOW.core.nav_deep.nav_deep_close_all(_t);
15513						}
15514
15515						/* --------------------------------------------------------------------------- */
15516
15517
15518					} else {
15519
15520						/*
15521
15522							onpopstate is handling hashed as "regular" links, refreshing the page
15523							So we have to stop this behavior!
15524
15525						*/
15526						var _href = window.location.href;
15527						if (_href.indexOf('#') > -1)
15528							return;
15529
15530						// Origin - refresh!
15531						location.reload(true);
15532
15533					}
15534
15535
15536				};
15537
15538			}
15539		}
15540
15541	}
15542
15543})(jQuery);
15544/**
15545 *
15546 *	[SOW] Ajax Content
15547 *
15548 *	@author 		Dorin Grigoras
15549 *					www.stepofweb.com
15550 *
15551 *	@Dependency 	-
15552 *	@Usage			$.SOW.core.ajax_content.init('div.js-ajax, section.js-ajax');
15553 *
15554 *
15555 **/
15556;(function ($) {
15557	'use strict';
15558
15559
15560	/**
15561	 *
15562	 *	@vars
15563	 *
15564	 *
15565	 **/
15566	var scriptInfo 	= 'SOW Ajax Content';
15567
15568
15569	$.SOW.core.ajax_content = {
15570
15571
15572		/**
15573		 *
15574		 *	@config
15575		 *
15576		 *
15577		 **/
15578		config: {
15579			method 							: 'GET',
15580			contentType 					: '',
15581			dataType 						: '',
15582			headers 						: '',
15583			crossDomain 					: '',
15584			data_params 					: {ajax:'true'},
15585
15586			/*
15587				callback_example = function(el, data, target_container) {
15588					// el 				= link clicked 				$(this)
15589					// data 			= server response 			(html|string)
15590					// target_container = container to push data  	(string:#middle)
15591				}
15592			*/
15593			callback_function 				: '',
15594
15595			// content (server response) is sent to your callback function only.
15596			callback_before_push			: false,
15597
15598		},
15599
15600
15601
15602		/**
15603		 *
15604		 *	@collection
15605		 *
15606		 *
15607		 **/
15608		collection: $(),
15609
15610
15611
15612		/**
15613		 *
15614		 *	@init
15615		 *
15616		 *
15617		 **/
15618		init: function (selector, config) {
15619
15620			var __selector 			= $.SOW.helper.__selector(selector);
15621			var __config 			= $.SOW.helper.check_var(config);
15622
15623			this.selector 			= __selector[0]; 	// '#selector'
15624			this.collection 		= __selector[1]; 	// $('#selector')
15625			this.selector_orig 		= __selector[2]; 	// $('#selector') // without ajax container prefix
15626			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
15627
15628
15629			if(jQuery(this.selector).length < 1)
15630				return;
15631
15632
15633			/*
15634
15635				Because this script is needed on body only and not inside itself,
15636				we block this script loading by another plugins reinit
15637				Easier and better than creating another rule in Controller for all plugins!
15638
15639
15640				Note: we use .last() instead of .first() because we might have
15641				one content in a static area (main navigation as an eample)
15642				and another one inside ajax (loaded by ajax navigation)
15643
15644			*/
15645			if(jQuery(this.selector_orig).last().hasClass('js-ajaxified'))
15646				return;
15647			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
15648
15649
15650			// -- * --
15651			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
15652			// -- * --
15653
15654
15655			// 1. Has no selector
15656			if(!this.selector) {
15657				$.SOW.core.ajax_content.ajax_content($('div.js-ajax, section.js-ajax'));
15658				return this.collection;
15659			}
15660
15661			// 2. Has selector
15662			return this.collection.each(function() {
15663
15664				$.SOW.core.ajax_content.ajax_content($(this));
15665
15666			});
15667
15668		},
15669
15670
15671
15672		/**
15673		 *
15674		 *	@ajax_content
15675		 *
15676			2. DIVS (and sections)
15677
15678				USAGE:
15679
15680				<section id="section_1" class="js-ajax" data-ajax-url="_ajax/dummy_text.html" data-ajax-container="#section_1 .section-body" data-ajax-method="GET">
15681
15682					<div class="section-body">
15683						Lorem Ipsum
15684					</div>
15685
15686					<a href="#" class="btn-js-ajax-reload" data-ajax-container="#section_1">Reload Content</a>
15687
15688				</section>
15689
15690				&ajax=true - added but NOT to .html files
15691		 *
15692		 *
15693		 **/
15694		ajax_content: function(_this) {
15695
15696			if(_this.hasClass('.js-ajaxified') || _this.length < 1)
15697				return;
15698
15699			_this.addClass('js-ajaxified');
15700
15701
15702			var _id 						= _this.attr('id')							|| '',
15703				_url  						= _this.data('ajax-url') 					|| '',
15704				_callback  					= _this.data('ajax-callback-function') 		|| $.SOW.core.ajax_content.config.callback_function,
15705				_callbackBeforePush  		= _this.data('ajax-callback-before-push') 	|| $.SOW.core.ajax_content.config.callback_before_push,
15706				_method  					= _this.data('ajax-method') 				|| $.SOW.core.ajax_content.config.method,
15707				_btn_reload  				= _this.data('ajax-btn-reload') 			|| '',
15708				_target  					= _this.data('ajax-target-container') 		|| '';
15709
15710
15711			/*
15712
15713				Container has no ID
15714				We generate one
15715
15716			*/
15717			if(_id == '') {
15718				_id = $.SOW.helper.randomStr(8);
15719				_this.attr('id', _id);
15720			}
15721
15722
15723			// Add a generated id to reload button, if has no id.
15724			// do not rewrite if exists
15725			if(jQuery(_btn_reload).length > 0) {
15726
15727				var _btnReloadTarget = jQuery(_btn_reload).attr('data-ajax-container') || '';
15728
15729				if(_btnReloadTarget == '')
15730					jQuery(_btn_reload).attr('data-ajax-container', '#'+_id).addClass('btn-js-ajax-content-reloader');
15731
15732			}
15733
15734
15735
15736
15737
15738			/*
15739
15740				No target specified
15741				We use self container
15742
15743			*/
15744			if(_target == '' || _target == 'self' || _target == '_self')
15745				var _target = '#' + _id;
15746
15747
15748
15749			// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
15750			// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
15751			// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
15752			// FUTURE UPDATE
15753			// PROECESS ONLY WHEN ELEMENT IS VISIBLE!
15754			// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
15755			// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
15756			// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
15757
15758
15759			// Process!
15760			$.SOW.core.ajax_content.__ajaxDivProcess(_id, _url, _target, _method, null, _callback, _callbackBeforePush);
15761			// -- -- --
15762
15763
15764
15765
15766			// Bind reload button[s]
15767			$.SOW.core.ajax_content.btn_reload_bind();
15768
15769		},
15770
15771
15772
15773
15774
15775
15776		/**
15777		 *
15778		 *	@btn_reload_bind
15779		 *
15780		 *
15781		 *
15782		 **/
15783		btn_reload_bind: function() {
15784
15785			jQuery('.btn-js-ajax-content-reloader:not(.btn-js-ajaxified)').addClass('btn-js-ajaxified').on('click', function(e) {
15786				e.preventDefault();
15787
15788				var __btnEl 		= jQuery(this),
15789				__containerID 		= jQuery(this).data('ajax-container') || '';
15790
15791				if(__containerID != '') {
15792
15793					var __t 					= jQuery(__containerID),
15794						__id 					= __t.attr('id')								|| '',
15795						__url  					= __t.attr('data-ajax-url') 					|| '', // .attr, ELSE WILL NOT UPDATE!
15796						__callback  			= __t.data('ajax-callback-function') 			|| $.SOW.core.ajax_content.config.callback_function,
15797						__callbackBeforePush 	= __t.data('ajax-callback-before-push') 		|| $.SOW.core.ajax_content.config.callback_before_push,
15798						__method  				= __t.data('ajax-method') 						|| $.SOW.core.ajax_content.config.method,
15799						__target  				= __t.data('ajax-target-container') 			|| __containerID;
15800
15801					// Process!
15802					$.SOW.core.ajax_content.__ajaxDivProcess(__id, __url, __target, __method, __btnEl, __callback, __callbackBeforePush);
15803					// -- -- --
15804
15805				}
15806
15807			});
15808
15809		},
15810
15811
15812
15813
15814
15815
15816
15817		/*
15818
15819			Function also called on reload ajax content!
15820
15821			_btnEl - is reload button element
15822			Used only on reload content to disable|enable on ajax process
15823
15824		*/
15825		__ajaxDivProcess: function(_id, _url, _target, _method, _btnEl, _callback, _callbackBeforePush) {
15826
15827			var _selector = this.selector;
15828
15829
15830			// Yeah, the ugliest bool fix ever.
15831			var _callbackBeforePush = _callbackBeforePush+'';
15832			var _callbackBeforePush = _callbackBeforePush.toLowerCase();
15833
15834
15835			jQuery.ajax({
15836				url:			_url,
15837				type: 			_method,
15838				data: 			$.SOW.core.ajax_content.config.data_params,
15839				contentType: 	$.SOW.core.ajax_content.config.contentType,
15840				dataType: 		$.SOW.core.ajax_content.config.dataType,
15841				headers: 		$.SOW.core.ajax_content.config.headers,
15842				crossDomain: 	$.SOW.core.ajax_content.config.crossDomain,
15843
15844				beforeSend: function() {
15845
15846					// We don't show loading icon on load!
15847					// Let user show it's own loading message
15848					// Show loading only for "reload button"
15849					if(_btnEl) {
15850
15851						jQuery(_target).addClass('overlay-light overlay-opacity-6 overlay-over');
15852						$.SOW.helper.loadingSpinner('show', _target);
15853						_btnEl.addClass('disabled active').prop('disabled', true);
15854
15855					}
15856
15857				},
15858
15859				error: 	function(XMLHttpRequest, textStatus, errorThrown) {
15860
15861					$.SOW.helper.loadingSpinner('hide');
15862
15863					if(typeof $.SOW.core.toast === 'object') {
15864
15865						$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
15866
15867					} else {
15868
15869						alert("[404] Unexpected internal error!");
15870
15871					}
15872
15873					// if debug enabled, see config
15874					$.SOW.helper.consoleLog('----------------------------');
15875					$.SOW.helper.consoleLog('--- AJAX  REQUEST ERROR ----');
15876					$.SOW.helper.consoleLog('DIV|SECTION ID: ' + _id);
15877					$.SOW.helper.consoleLog('1. XMLHttpRequest:');
15878					$.SOW.helper.consoleLog(XMLHttpRequest);
15879					$.SOW.helper.consoleLog('2. textStatus:');
15880					$.SOW.helper.consoleLog(textStatus);
15881					$.SOW.helper.consoleLog('3. errorThrown:');
15882					$.SOW.helper.consoleLog(errorThrown);
15883					$.SOW.helper.consoleLog('----------------------------');
15884
15885				},
15886
15887				success: function(data) {
15888
15889					// Push data
15890					if(_callbackBeforePush == 'false')
15891						jQuery(_target).empty().html(data);
15892
15893
15894					// callback function
15895					if(_callback != '' && typeof $.SOW.helper.executeFunctionByName === "function")
15896						$.SOW.helper.executeFunctionByName(_callback, window, _id, _target, data);
15897
15898
15899
15900					// notice
15901					if(_callbackBeforePush == 'true' && _callback == '')
15902						$.SOW.helper.consoleLog('data-ajax-callback-function="" -BUT- data-ajax-callback-before-push="true"');
15903
15904
15905
15906					// enable reload button
15907					// if(_btnEl) {
15908
15909						// Set a delay, so user know content loaded, if was too fast
15910						setTimeout(function() {
15911							$.SOW.helper.loadingSpinner('hide');
15912							jQuery(_target).removeClass('overlay-light overlay-opacity-6 overlay-over');
15913
15914							if(_btnEl)
15915								_btnEl.removeClass('disabled active').prop('disabled', false);
15916
15917
15918							// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
15919							// reinit inside ajax container
15920							if(_callbackBeforePush == 'false') {
15921								$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
15922								$.SOW.helper.consoleLog(scriptInfo, 'color: #6dbb30; font-weight: bold; font-size:14px;');
15923								$.SOW.helper.consoleLog('Ajax Reinit For: ' + _target);
15924								$.SOW.helper.consoleLog(window.location.href);
15925								$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
15926
15927								$.SOW.reinit(_target);
15928
15929								$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
15930							}
15931							// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
15932
15933						}, 300);
15934
15935
15936					// }
15937
15938
15939
15940				}
15941
15942			});
15943
15944			return true;
15945
15946		},
15947
15948
15949
15950	}
15951
15952})(jQuery);
15953/**
15954 *
15955 *	[SOW] Ajax Form
15956 *
15957 *	@author 		Dorin Grigoras
15958 *					www.stepofweb.com
15959 *
15960 *	@Dependency 	-
15961 *	@Usage			$.SOW.core.ajax_form.init('form.js-ajax');
15962 *
15963 *
15964 **/
15965;(function ($) {
15966	'use strict';
15967
15968
15969	/**
15970	 *
15971	 *	@vars
15972	 *
15973	 *
15974	 **/
15975	var scriptInfo 		= 'SOW Ajax Form';
15976
15977
15978
15979
15980	$.SOW.core.ajax_form = {
15981
15982
15983		/**
15984		 *
15985		 *	@config
15986		 *
15987		 *
15988		 **/
15989		config: {
15990
15991			method 							: 'GET',
15992			contentType 					: '',
15993			dataType 						: '',
15994			headers 						: '',
15995			crossDomain 					: '',
15996
15997		},
15998
15999
16000
16001		/**
16002		 *
16003		 *	@collection
16004		 *
16005		 *
16006		 **/
16007		collection: $(),
16008
16009
16010
16011		/**
16012		 *
16013		 *	@init
16014		 *
16015		 *
16016		 **/
16017		init: function (selector, config) {
16018
16019			var __selector 			= $.SOW.helper.__selector(selector);
16020			var __config 			= $.SOW.helper.check_var(config);
16021
16022			this.selector 			= __selector[0]; 	// '#selector'
16023			this.collection 		= __selector[1]; 	// $('#selector')
16024			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
16025
16026
16027
16028			if(jQuery(this.selector).length < 1)
16029				return;
16030
16031
16032			// -- * --
16033			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
16034			// -- * --
16035
16036
16037			// 1. Has no selector
16038			if(!this.selector) {
16039				$.SOW.core.ajax_form.process($('form.js-ajax'));
16040				return this.collection;
16041			}
16042
16043			// 2. Has selector
16044			return this.collection.each(function() {
16045
16046				$.SOW.core.ajax_form.process($(this));
16047
16048			});
16049
16050		},
16051
16052
16053
16054		/**
16055		 *
16056		 *	@ajax_form
16057		 *
16058			3. FORMS
16059
16060
16061				EXAMPLE USAGE.  (form.js-ajax  - REQUIRED)
16062
16063					<form class="js-ajax bs-validate" novalidate action="YOUR_URL" data-ajax-container="#ajax_container" data-ajax-update-url="true">
16064
16065						<input required type="text" name="first_name" value="" placeholder="first name" class="form-control mb-4">
16066						<input type="text" name="birthdate" value="" placeholder="birthdate" class="form-control mb-4">
16067
16068						<!--
16069							Error Notice - more visible
16070
16071							Instead of this alert, you can use a toast alert instead by adding to form:
16072								data-error-toast-text="<i class='fi fi-circle-spin fi-spin float-start'></i> Please, complete all required fields!"
16073								data-error-toast-delay="3000"
16074								data-error-toast-position="top-right"
16075
16076						-->
16077						<div class="bs-validate-info hide alert alert-danger" data-error-alert-delay="4000">
16078							<i class="fi fi-circle-spin fi-spin float-start"></i>
16079							Please, complete all required fields!
16080						</div>
16081
16082						<button type="submit" class="btn btn-primary">Submit</button>
16083					</form>
16084
16085
16086					<!-- position relative|fixed|absolute is required for loading icon -->
16087					<div id="ajax_container" class="position-relative w--500 pl--30 pr--30 pt--80 pb--80">
16088						<!-- RESPONSE ADDED HERE, IF NEEDED -->
16089					</div>
16090
16091
16092				ajax-callback-function="" 	- used to handle the response, instead of appending the response to a container
16093		 *
16094		 *
16095		 **/
16096		process: function(_this) {
16097
16098			var _selector 		= this.selector;
16099			var _selector_orig 	= this.selector_orig;
16100
16101			_this.submit(function(e) {
16102
16103				var _t 					= _this,
16104					_formID				= _t.attr('id')								|| '',
16105					_action 			= _t.attr('action')							|| '',
16106					_callback			= _t.attr('data-ajax-callback-function')	|| '',
16107					_method 			= _t.attr('method') 						|| $.SOW.core.ajax_form.config.method,
16108					_updateURL 			= _t.attr('data-ajax-update-url') 			|| 'false',
16109					_scrollErrUp 		= _t.attr('data-error-scroll-up') 			|| 'false',
16110					_showLoadingIcon 	= _t.attr('data-ajax-show-loading-icon') 	|| 'true',
16111					_contentType 		= _t.data('ajax-contentType') 				|| '',
16112					_dataType 			= _t.data('ajax-dataType') 					|| '',
16113					_target 			= _t.data('ajax-container') 				|| '',
16114					_toast_text 		= _t.data('error-toast-text')				|| '',			// toast alert for .bs-validate
16115					_toast_delay 		= _t.data('error-toast-delay')				|| 0,			// toast alert for .bs-validate
16116					_toast_pos 			= _t.data('error-toast-position')			|| "top-right",	// toast alert for .bs-validate
16117					_toast_success		= _t.data('success-toast-text')				|| "",
16118
16119					_controlAlerts		= _t.attr('data-ajax-control-alerts')				|| "false",
16120					_controlSuccess		= _t.attr('data-ajax-control-alert-succes')			|| "",
16121					_controlUnexpected	= _t.attr('data-ajax-control-alert-unexpected')		|| "",
16122					_controlMandatory	= _t.attr('data-ajax-control-alert-mandaroty')		|| "",
16123
16124			    	// show|hide container for error|success
16125			    	_onSucessShow 		= _t.data('ajax-inline-alert-succes')		|| '',
16126			    	_onErrorShow 		= _t.data('ajax-inline-alert-error')		|| '',
16127
16128			    	// autoclose modal on success
16129			    	_modalCloseOnSuccess 		= _t.data('modal-autoclose-on-success')			|| 'false',
16130			    	_modalCloseOnSuccessDelay 	= _t.data('modal-autoclose-on-success-delay')	|| 0;
16131
16132		    	if(_onSucessShow != '' || _onErrorShow != '') {
16133		    		if(_target == '#middle')
16134		    			_target = '';
16135		    	}
16136
16137				// the most uglies bool hack
16138				var _scrollErrUp 		= _scrollErrUp+'';
16139				var _updateURL 			= _updateURL+'';
16140
16141				// Assign a random id if not exist
16142				if(_formID == '') {
16143					var _formID = 'js_' + $.SOW.helper.randomStr(10);
16144					_t.attr('id', _formID);
16145				}
16146
16147				// Bootstrap Validation +++++++++++++++++++++++++++++++++++++++++++++++++++
16148				// This part already exists in _formvalidate.js
16149				// We use it again here in case the file is not loaded!
16150
16151				// default reset
16152				window.ajax_form_stop = false;
16153
16154				// Form Element
16155				var _form = document.getElementById(_formID);
16156
16157				if(_t.hasClass('bs-validate')) {
16158
16159					// hide all errors info
16160					jQuery('.bs-validate-info').addClass('hide hide-force');
16161
16162					if(typeof $.SOW.core.toast === 'object')
16163						$.SOW.core.toast.destroy();
16164
16165					if(_form.checkValidity() === false) {
16166
16167
16168						// -- message|toast ---
16169						if(_toast_text != '') {
16170
16171							if(typeof $.SOW.core.toast === 'object') {
16172
16173								if(Number(_toast_delay) < 1)
16174									var _toast_delay = 4000;
16175
16176								$.SOW.core.toast.show('danger', '', _toast_text, _toast_pos, Number(_toast_delay), true);
16177
16178							} else {
16179
16180								alert(_toast_text);
16181
16182							}
16183
16184						} else {
16185
16186							// show error info
16187							jQuery('.bs-validate-info', _t).removeClass('hide hide-force'); // show error info
16188
16189							// error info delay timeout
16190							var _delay = jQuery('.bs-validate-info', _t).data('error-alert-delay') || 3000;
16191
16192							// hide error info in X seconds
16193							setTimeout(function() {
16194								jQuery('.bs-validate-info', _t).addClass('hide hide-force');
16195							}, Number(_delay));
16196
16197						}
16198						// -- -- -- --
16199
16200						// show|hide custom containers
16201						if(_onErrorShow != '') {
16202							jQuery(_onSucessShow).addClass('hide hide-force');
16203							jQuery(_onErrorShow).removeClass('hide hide-force');
16204						}
16205
16206						// Focus invalid element and scroll
16207						jQuery('.form-control:invalid', _t).first().focus();
16208
16209						// Do not animate inside modal!
16210						if(typeof $.SOW.helper.scrollAnimate === "function" && _scrollErrUp == 'true' && !jQuery('.modal').hasClass('show')) {
16211							var _formEl = jQuery('input:invalid, select:invalid, textarea:invalid', _t);
16212							$.SOW.helper.scrollAnimate(_formEl, 0, false, 200);
16213						}
16214						// -- -- -- --
16215
16216						e.preventDefault();
16217						e.stopPropagation();
16218						window.ajax_form_stop = true;
16219					}
16220
16221
16222					_t.addClass('was-validated');
16223
16224
16225					// Stop here!
16226					if(window.ajax_form_stop === true)
16227						return;
16228
16229				} else {
16230
16231					if(_form.checkValidity() === false) {
16232
16233						e.preventDefault();
16234						e.stopPropagation();
16235						window.ajax_form_stop = true;
16236					}
16237
16238				}
16239
16240				// Stop here!
16241				if(window.ajax_form_stop === true)
16242					return;
16243
16244				// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16245
16246
16247				// Start the show
16248				e.preventDefault();
16249
16250				if(_action == '') {
16251
16252					$.SOW.helper.consoleLog('Ajax request: form action missing!');
16253
16254					if(typeof $.SOW.core.toast === 'object') {
16255
16256						$.SOW.core.toast.show('danger', 'Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
16257
16258					} else {
16259
16260						alert("[404] Unexpected internal error!");
16261
16262					}
16263
16264					return;
16265				}
16266
16267
16268				if(_method.toLowerCase() == 'post') {
16269
16270					var formData 		= new FormData(this);
16271					var __processData 	= false;
16272					var __contentType 	= false;
16273
16274				} else {
16275
16276					var __processData 	= true;
16277					var __contentType 	= _contentType || $.SOW.core.ajax_form.config.contentType;
16278					var formData 		= _t.serializeArray();
16279
16280				}
16281
16282
16283				jQuery.ajax({
16284					url: 			_action,
16285					data: 			formData,
16286					type: 			_method,
16287					dataType: 		_dataType || $.SOW.core.ajax_form.config.dataType,
16288					headers: 		$.SOW.core.ajax_form.config.headers,
16289					crossDomain: 	$.SOW.core.ajax_form.config.crossDomain,
16290					contentType: 	__contentType,
16291					processData: 	__processData,
16292					cache: 			false,
16293
16294					beforeSend: function() {
16295
16296						// icon over form
16297						if(_showLoadingIcon == 'true')
16298							$.SOW.helper.loadingSpinner('show', _t);
16299
16300						// Disable submit button
16301						jQuery(this).attr('disabled', true).addClass('disabled');
16302
16303					},
16304
16305					error: 	function(XMLHttpRequest, textStatus, errorThrown) {
16306
16307						// if debug enabled, see config
16308						if($.SOW.config.sow__debug_enable === true) {
16309
16310							$.SOW.helper.consoleLog('----------------------------');
16311							$.SOW.helper.consoleLog('--- AJAX  REQUEST ERROR ----');
16312							$.SOW.helper.consoleLog('1. XMLHttpRequest:');
16313							$.SOW.helper.consoleLog(XMLHttpRequest);
16314							$.SOW.helper.consoleLog('2. textStatus:');
16315							$.SOW.helper.consoleLog(textStatus);
16316							$.SOW.helper.consoleLog('3. errorThrown:');
16317							$.SOW.helper.consoleLog(errorThrown);
16318							$.SOW.helper.consoleLog('----------------------------');
16319
16320						}
16321
16322						$.SOW.helper.loadingSpinner('hide');
16323
16324						if(typeof $.SOW.core.toast === 'object') {
16325
16326							$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!', _toast_pos, 0, true);
16327
16328						} else {
16329
16330							alert("[404] Unexpected internal error!");
16331
16332						}
16333
16334						// show|hide custom containers
16335						if(_onErrorShow != '') {
16336							jQuery(_onSucessShow).addClass('hide hide-force');
16337							jQuery(_onErrorShow).removeClass('hide hide-force');
16338						}
16339
16340						// Enable submit button
16341						jQuery(this).attr('disabled', false).removeClass('disabled');
16342					},
16343
16344					success: function(data) {
16345
16346						$.SOW.helper.loadingSpinner('hide');
16347						$.SOW.helper.consoleLog(data);
16348
16349						// Enable submit button
16350						jQuery(this).attr('disabled', false).removeClass('disabled');
16351						var hasErrors = false;
16352
16353						// Control alerts
16354						if(_controlAlerts+'' == 'true') {
16355
16356							// reset first
16357							var hasErrors = true;
16358							jQuery(_controlSuccess).addClass('hide hide-force');
16359							jQuery(_controlUnexpected).addClass('hide hide-force');
16360							jQuery(_controlMandatory).addClass('hide hide-force');
16361
16362							if(data == '{:success:}') {
16363								jQuery(_controlSuccess).removeClass('hide hide-force');
16364								var hasErrors = false;
16365								var data = '';
16366							}
16367
16368							else if(data == '{:err:required:}')
16369								jQuery(_controlMandatory).removeClass('hide hide-force');
16370
16371							else if(data == '{:err:unexpected:}')
16372								jQuery(_controlUnexpected).removeClass('hide hide-force');
16373
16374
16375							if(hasErrors === true) {
16376
16377								// this is a server message - debug only!
16378								if($.SOW.config.sow__debug_enable === true)
16379									jQuery(_target).empty().html(data);
16380								else
16381									jQuery(_target).empty().html('Server Error!');
16382
16383
16384								_t.removeClass('was-validated');
16385								return;
16386							}
16387
16388						}
16389
16390
16391
16392						// Callbat and/or Reset
16393						if(_callback == '') {
16394
16395							// Reset Form
16396							jQuery('input:not([type=hidden])', _t).val('');
16397							jQuery('textarea:not(.hide)', _t).val('');
16398
16399							if(_target != '')
16400								jQuery(_target).empty().html(data);
16401
16402							// reset form validation
16403							_t.removeClass('was-validated');
16404
16405						} else {
16406
16407							if(typeof $.SOW.helper.executeFunctionByName === "function")
16408								$.SOW.helper.executeFunctionByName(_callback, window, _t, data);
16409
16410						}
16411
16412
16413
16414						// Update URL
16415						if(_updateURL == 'true' && $.SOW.core.ajax_navigation === 'object')
16416							$.SOW.core.ajax_navigation.__historyPushState(_action, '', data);
16417
16418
16419						if(_target != '' && typeof $.SOW.helper.scrollAnimate === "function" && _scrollErrUp == 'true') {
16420							var _elResponse = jQuery(_target || _onSucessShow);
16421							if(_elResponse.length)
16422								$.SOW.helper.scrollAnimate(_elResponse, 0, false, 200);
16423						}
16424
16425
16426						// show|hide custom containers
16427						if(_onSucessShow != '') {
16428							jQuery(_onSucessShow).removeClass('hide hide-force');
16429							jQuery(_onErrorShow).addClass('hide hide-force');
16430						}
16431
16432
16433
16434						// if form is on modal
16435						if(_modalCloseOnSuccess+'' == 'true') {
16436
16437							setTimeout(function() {
16438								jQuery('#sow_ajax_modal').modal('hide');
16439							}, Number(_modalCloseOnSuccessDelay));
16440
16441						}
16442
16443
16444						// success tost, if text provided
16445						if(typeof $.SOW.core.toast === 'object' && _toast_success != '')
16446							$.SOW.core.toast.show('success', '', _toast_success, _toast_pos, 1500, true);
16447
16448
16449					}
16450
16451				});
16452
16453
16454			});
16455
16456
16457		},
16458
16459	}
16460
16461})(jQuery);
16462/**
16463 *
16464 *	[SOW] Ajax Select
16465 *
16466 *	@author 		Dorin Grigoras
16467 *					www.stepofweb.com
16468 *
16469 *	@Dependency 	-
16470 *	@Usage			$.SOW.core.ajax_select.init('select.js-ajax');
16471 *
16472 *
16473 **/
16474;(function ($) {
16475	'use strict';
16476
16477
16478	/**
16479	 *
16480	 *	@vars
16481	 *
16482	 *
16483	 **/
16484	var scriptInfo 		= 'SOW Ajax Select';
16485	window.ajax_select_chain_process = null;
16486
16487
16488
16489	$.SOW.core.ajax_select = {
16490
16491
16492		/**
16493		 *
16494		 *	@config
16495		 *
16496		 *
16497		 **/
16498		config: {
16499
16500			method 							: 'GET',
16501			contentType 					: '',
16502			dataType 						: '',
16503			headers 						: '',
16504			crossDomain 					: '',
16505			data_params 					: {ajax:'true'},
16506
16507			/*
16508				callback_example = function(el, data, modal_container) {
16509					// el 				= element 				$(this)
16510					// data 			= server response 			(html|string)
16511					// modal_container = container to push data  	(string)
16512				}
16513			*/
16514			callback_function 	: ''
16515		},
16516
16517
16518
16519		/**
16520		 *
16521		 *	@collection
16522		 *
16523		 *
16524		 **/
16525		collection: $(),
16526
16527
16528
16529		/**
16530		 *
16531		 *	@init
16532		 *
16533		 *
16534		 **/
16535		init: function (selector, config) {
16536
16537			var __selector 			= $.SOW.helper.__selector(selector);
16538			var __config 			= $.SOW.helper.check_var(config);
16539
16540			this.selector 			= __selector[0]; 	// '#selector'
16541			this.collection 		= __selector[1]; 	// $('#selector')
16542			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
16543
16544
16545
16546			if(jQuery(this.selector).length < 1)
16547				return;
16548
16549
16550			// -- * --
16551			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
16552			// -- * --
16553
16554
16555			// 1. Has no selector
16556			if(!this.selector) {
16557				$.SOW.core.ajax_select.process($('select.js-ajax'));
16558				return this.collection;
16559			}
16560
16561			// 2. Has selector
16562			return this.collection.each(function() {
16563
16564				$.SOW.core.ajax_select.process($(this));
16565
16566			});
16567
16568		},
16569
16570
16571
16572		/**
16573		 *
16574		 *	@process
16575		 *
16576		 *
16577		 **/
16578		process: function(_this) {
16579
16580
16581			/**
16582
16583				Form Populate
16584
16585			**/
16586			var populate_form = _this.data('form-target') || '';
16587			if(populate_form != '') {
16588
16589				_this.not('.js-ajaxified').addClass('js-ajaxified').on('change', function() {
16590
16591					var _method 				= _this.data('ajax-method') 			|| $.SOW.core.ajax_select.config.method,
16592						_url 					= _this.data('ajax-url') 				|| '',
16593						_params 				= _this.data('ajax-params') 			|| '',
16594						_thisVal 				= _this.val() 							|| '',
16595						data_params 			= $.SOW.core.ajax_select.config.data_params;
16596						data_params['value'] 	= _thisVal;
16597
16598					if(_url == '')
16599						return;
16600
16601
16602					// reset
16603					if(_thisVal == '') {
16604
16605						jQuery('input[type=text], input[type=number], input[type=tel], textarea', populate_form).val('');
16606						jQuery('input[type=checkbox]', populate_form).prop('checked', false);
16607
16608						jQuery('select', populate_form).val(0);
16609
16610						// Refresh bootstrap select
16611						if(typeof $.SOW.vendor.bootstrap_select === 'object')
16612							$.SOW.vendor.bootstrap_select.refresh(_el);
16613
16614						return;
16615					}
16616
16617
16618
16619					if(_params != '') {
16620
16621						var ajax_params_arr = $.SOW.helper.params_parse(_params);
16622						for (var i = 0; i < ajax_params_arr.length; ++i) {
16623							data_params[ajax_params_arr[i][0]] = ajax_params_arr[i][1];
16624						}
16625
16626					}
16627
16628
16629					jQuery.ajax({
16630						url:			_url,
16631						type: 			_method,
16632						data: 			data_params,
16633						contentType: 	$.SOW.core.ajax_select.config.contentType,
16634						dataType: 		$.SOW.core.ajax_select.config.dataType,
16635						headers: 		$.SOW.core.ajax_select.config.headers,
16636						crossDomain: 	$.SOW.core.ajax_select.config.crossDomain,
16637
16638						beforeSend: function() {
16639							$.SOW.helper.consoleLog('Params request sent to the server:');
16640							$.SOW.helper.consoleLog(_url);
16641							$.SOW.helper.consoleLog(data_params);
16642						},
16643
16644						error: 	function(XMLHttpRequest, textStatus, errorThrown) {
16645
16646							// if debug enabled, see config
16647							if($.SOW.config.sow__debug_enable === true) {
16648
16649								$.SOW.helper.consoleLog('----------------------------');
16650								$.SOW.helper.consoleLog('--- AJAX  REQUEST ERROR ----');
16651								$.SOW.helper.consoleLog('1. XMLHttpRequest:');
16652								$.SOW.helper.consoleLog(XMLHttpRequest);
16653								$.SOW.helper.consoleLog('2. textStatus:');
16654								$.SOW.helper.consoleLog(textStatus);
16655								$.SOW.helper.consoleLog('3. errorThrown:');
16656								$.SOW.helper.consoleLog(errorThrown);
16657								$.SOW.helper.consoleLog('----------------------------');
16658
16659							}
16660
16661							if(typeof $.SOW.core.toast === 'object') {
16662								$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
16663							} else {
16664								alert("[404] Unexpected internal error!");
16665							}
16666
16667						},
16668
16669						success: function(data) {
16670
16671							if(typeof data !== 'object') {
16672								$.SOW.helper.consoleLog('----------------------------');
16673								$.SOW.helper.consoleLog('Select Form Populate : Not JSON! Aborting...');
16674								$.SOW.helper.consoleLog('----------------------------');
16675								return;
16676							}
16677
16678							for(var i = 0; i < data.length; i++) {
16679
16680								for(var key in data[i]) {
16681
16682									var _el = $(populate_form + ' #' + key);
16683									if(_el.length < 1)
16684										var _el = $(populate_form + ' .' + key);
16685									if(_el.length < 1)
16686										continue;
16687
16688
16689									// file : skip
16690									if(_el.attr('type') == 'file')
16691										continue;
16692
16693									// checkbox & radio
16694									if(_el.attr('type') == 'checkbox' || _el.attr('type') == 'radio')
16695										if(data[i][key] > 0 || data[i][key] == true) { _el.prop('checked', true); } else { _el.prop('checked', false); }
16696
16697									// input
16698									else if(_el.is('input'))
16699										_el.val(data[i][key]);
16700
16701									// textarea
16702									else if(_el.is('textarea'))
16703										_el.val(data[i][key]);
16704
16705									// select
16706									else if(_el.is('select')) {
16707
16708										_el.val(data[i][key]);
16709
16710										// Refresh bootstrap select
16711										if(typeof $.SOW.vendor.bootstrap_select === 'object')
16712											$.SOW.vendor.bootstrap_select.refresh(_el);
16713
16714									}
16715
16716								}
16717
16718
16719							}
16720
16721
16722						}
16723
16724					});
16725
16726				});
16727
16728				return;
16729			}
16730
16731
16732
16733
16734
16735
16736			/**
16737
16738				Self Populate
16739
16740			**/
16741			var self_populate_url = _this.data('ajax-url-self-populate') || '';
16742
16743			if(self_populate_url != '') {
16744
16745				var _method 		= _this.data('ajax-method') 			|| $.SOW.core.ajax_select.config.method,
16746					_params 		= _this.data('ajax-params') 			|| '',
16747					_callback 		= _this.data('ajax-callback-function') 	|| $.SOW.core.ajax_select.config.callback_function,
16748					data_params 	= $.SOW.core.ajax_select.config.data_params,
16749
16750					_val 			= '',
16751					_label 			= ':on_load:';
16752
16753				if(_params != '') {
16754
16755					var ajax_params_arr = $.SOW.helper.params_parse(_params);
16756					for (var i = 0; i < ajax_params_arr.length; ++i) {
16757						data_params[ajax_params_arr[i][0]] = ajax_params_arr[i][1];
16758					}
16759
16760				}
16761
16762
16763				$.SOW.core.ajax_select.ajax_process(self_populate_url, _method, data_params, _this, _val, _label, _this, _callback, 'self');
16764
16765			}
16766
16767
16768
16769
16770
16771
16772			/**
16773
16774				Populate on change
16775
16776			**/
16777			_this.not('.js-ajaxified').addClass('js-ajaxified').on('change', function() {
16778
16779				var _t 				= jQuery(this),
16780					_val 			= _t.val() 								|| '',
16781					_label 			= jQuery('option:selected', _t).text() 	|| '',
16782					_callback 		= _t.data('ajax-callback-function') 	|| $.SOW.core.ajax_select.config.callback_function,
16783					_target 		= _t.data('ajax-target') 				|| '';
16784
16785				if(_target != '') {
16786
16787					// Get url from #target
16788					var el_target 		= jQuery(_target),
16789						_url 			= el_target.data('ajax-url') 				|| '',
16790						_method 		= el_target.data('ajax-method') 			|| $.SOW.core.ajax_select.config.method,
16791						_params 		= el_target.data('ajax-params') 			|| '',
16792						data_params 	= $.SOW.core.ajax_select.config.data_params;
16793
16794
16795					if(_url != '') {
16796
16797						if(_params != '') {
16798
16799							var ajax_params_arr = $.SOW.helper.params_parse(_params);
16800							for (var i = 0; i < ajax_params_arr.length; ++i) {
16801								data_params[ajax_params_arr[i][0]] = ajax_params_arr[i][1];
16802							}
16803
16804						}
16805
16806						data_params['value'] = _val;
16807
16808
16809						$.SOW.core.ajax_select.ajax_process(_url, _method, data_params, el_target, _val, _label, _t, _callback, 'target');
16810
16811					}
16812
16813				}
16814
16815
16816
16817
16818
16819
16820
16821
16822
16823				/**
16824
16825					Show container
16826
16827				**/
16828				// hide all first
16829				_t.children('option').each(function() {
16830					var __t = jQuery(this).data('show-container') || '';
16831					if(__t != '')
16832						jQuery(__t).addClass('hide hide-force');
16833				});
16834
16835				// show selected
16836				var _container = _t.find(':selected').data('show-container') 	|| '';
16837				if(_container != '')
16838					jQuery(_container).removeClass('hide hide-force');
16839
16840			});
16841
16842
16843		},
16844
16845
16846
16847
16848
16849		/**
16850		 *
16851		 *	@ajax_process
16852		 *
16853		 *
16854		 **/
16855		ajax_process: function(_url, _method, data_params, el_target, _val, _label, _t, _callback, process_type) {
16856
16857			jQuery.ajax({
16858				url:			_url,
16859				type: 			_method,
16860				data: 			data_params,
16861				contentType: 	$.SOW.core.ajax_select.config.contentType,
16862				dataType: 		$.SOW.core.ajax_select.config.dataType,
16863				headers: 		$.SOW.core.ajax_select.config.headers,
16864				crossDomain: 	$.SOW.core.ajax_select.config.crossDomain,
16865
16866				beforeSend: function() {},
16867
16868				error: 	function(XMLHttpRequest, textStatus, errorThrown) {
16869
16870					// if debug enabled, see config
16871					if($.SOW.config.sow__debug_enable === true) {
16872
16873						$.SOW.helper.consoleLog('----------------------------');
16874						$.SOW.helper.consoleLog('--- AJAX  REQUEST ERROR ----');
16875						$.SOW.helper.consoleLog('1. XMLHttpRequest:');
16876						$.SOW.helper.consoleLog(XMLHttpRequest);
16877						$.SOW.helper.consoleLog('2. textStatus:');
16878						$.SOW.helper.consoleLog(textStatus);
16879						$.SOW.helper.consoleLog('3. errorThrown:');
16880						$.SOW.helper.consoleLog(errorThrown);
16881						$.SOW.helper.consoleLog('----------------------------');
16882
16883					}
16884
16885					if(typeof $.SOW.core.toast === 'object') {
16886						$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
16887					} else {
16888						alert("[404] Unexpected internal error!");
16889					}
16890
16891				},
16892
16893				success: function(data) {
16894
16895					var selected_val 				= _val;
16896					var selected_label 				= _label;
16897					var process_recursive 			= null;
16898					var process_recursive_selected 	= '';
16899
16900					$.SOW.helper.consoleLog(data);
16901
16902					// remove disabled
16903					el_target.removeAttr('disabled');
16904
16905
16906					try {
16907
16908						var _data = JSON.parse(data);
16909
16910					} catch(err) {
16911
16912						var _data = data;
16913
16914					}	var data = null; // clear/reset
16915
16916
16917					// Clear select
16918					el_target.find('option').remove();
16919
16920					if(_data.length > 0) {
16921
16922						// Walk through json data
16923						for (var i = 0; i < _data.length; i++) {
16924
16925							if(typeof _data[i]['label'] === 'undefined')
16926								continue;
16927
16928							if(typeof _data[i]['value'] === 'undefined')
16929								_data[i]['value'] = '';
16930
16931							if(_data[i]['label'] == '' && _data[i]['value'] == '')
16932								continue;
16933
16934							// -- -- --
16935							var o = new Option(_data[i]['label'], _data[i]['value']);
16936							jQuery(o).html(_data[i]['label']);
16937
16938							// selected
16939							if(typeof _data[i]['selected'] !== 'undefined' && _data[i]['selected'] == true) {
16940								jQuery(o).attr('selected', 'selected');
16941								var process_recursive_selected = _data[i]['value'];
16942							}
16943
16944							// show container
16945							if(typeof _data[i]['show_container'] !== 'undefined') {
16946								jQuery(o).attr('data-show-container', _data[i]['show_container']);
16947
16948								if(process_recursive_selected == _data[i]['value'])
16949									jQuery(_data[i]['show_container']).removeClass('hide hide-force');
16950							}
16951
16952
16953							el_target.append(o);
16954							// -- -- --
16955
16956
16957							if(_data[i]['selected'] && _data[i]['selected'] === true) {
16958								// var selected_val 	= _data[i]['value'],
16959								// 	selected_label 		= _data[i]['label'];
16960
16961								if(process_type === 'self')
16962									var process_recursive = true;
16963
16964							}
16965
16966
16967						}
16968
16969					} else {
16970
16971						// set disabled
16972						el_target.prop('disabled', true).attr('disabled', '');
16973
16974					}
16975
16976
16977					// Refresh bootstrap select
16978					if(typeof $.SOW.vendor.bootstrap_select === 'object')
16979						$.SOW.vendor.bootstrap_select.refresh(el_target);
16980
16981
16982					setTimeout(function () {
16983
16984						// Callback
16985						if(_callback != '' && typeof _callback !== 'undefined')
16986							$.SOW.core.ajax_select.ajax_callback(_callback, _t, selected_val, selected_label);
16987
16988
16989
16990						/**
16991
16992							Callback on change
16993
16994						**/
16995						if(el_target !== null) {
16996
16997							el_target.not('.js-callbackified').addClass('js-callbackified').on('change', function() {
16998
16999								var _t 				= jQuery(this),
17000									_val 			= _t.val() 								|| '',
17001									_label 			= _t.find('option:selected').text() 	|| '',
17002									_callback 		= _t.data('ajax-callback-function') 	|| $.SOW.core.ajax_select.config.callback_function;
17003
17004
17005								// Callback
17006								if(_callback != '' && typeof _callback !== 'undefined')
17007									$.SOW.core.ajax_select.ajax_callback(_callback, _t, _val, _label);
17008
17009							});
17010
17011						}
17012
17013
17014
17015						/**
17016
17017							Recursive
17018							Used by select on load
17019							data-ajax-url-self-populate
17020
17021						**/
17022						if(process_recursive === true && el_target.data('ajax-target')) {
17023
17024							// Get url from #target
17025							var _selector 		= el_target.data('ajax-target') 			|| '',
17026								el_target2 		= jQuery(_selector),
17027								_url 			= el_target2.data('ajax-url') 				|| '',
17028								_method 		= el_target2.data('ajax-method') 			|| $.SOW.core.ajax_select.config.method,
17029								_params 		= el_target2.data('ajax-params') 			|| '',
17030								data_params 	= $.SOW.core.ajax_select.config.data_params;
17031
17032							if(_url == '')
17033								return;
17034
17035							if(_params != '') {
17036
17037								var ajax_params_arr = $.SOW.helper.params_parse(_params);
17038								for (var i = 0; i < ajax_params_arr.length; ++i) {
17039									data_params[ajax_params_arr[i][0]] = ajax_params_arr[i][1];
17040								}
17041
17042							}
17043
17044							data_params['value'] = process_recursive_selected;
17045
17046
17047							$.SOW.core.ajax_select.ajax_process(_url, _method, data_params, el_target2, '', '', el_target, _callback, 'target');
17048
17049						}
17050
17051					}, 100);
17052
17053
17054				}
17055
17056			});
17057
17058		},
17059
17060
17061
17062
17063		/**
17064		 *
17065		 *	@ajax_callback
17066		 *
17067		 *
17068		 **/
17069		ajax_callback: function(_callback, _t, value, label) {
17070
17071			if(_callback != '' && typeof $.SOW.helper.executeFunctionByName === 'function')
17072				$.SOW.helper.executeFunctionByName(_callback, window, _t, value, label);
17073
17074		}
17075
17076	}
17077
17078})(jQuery);
17079/**
17080 *
17081 *	[SOW] Ajax Modal
17082 *
17083 *	@author 		Dorin Grigoras
17084 *					www.stepofweb.com
17085 *
17086 *	@Dependency 	-
17087 *	@Usage			$.SOW.core.ajax_modal.init('.js-ajax-modal');
17088 *
17089	// Programtically Create Modal 	: 		      url , 'modal-md', 'true' (centered), 'backdrop' (optional), callback (optional)
17090	$.SOW.core.ajax_modal.createFromThinAir(modalUrl, 'modal-lg', 'true', 'static', callback);
17091
17092	// Programtically Attach Element/Link ( $('.selector') or '.selector' )
17093	$.SOW.core.ajax_modal.attach(selector);
17094
17095 *
17096 **/
17097;(function ($) {
17098	'use strict';
17099
17100
17101	/**
17102	 *
17103	 *	@vars
17104	 *
17105	 *
17106	 **/
17107	var scriptInfo 		= 'SOW Ajax Modal';
17108
17109
17110
17111	$.SOW.core.ajax_modal = {
17112
17113
17114		/**
17115		 *
17116		 *	@config
17117		 *
17118		 *
17119		 **/
17120		config: {
17121			method 							: 'GET',
17122			contentType 					: '', 	// jQuery params
17123			dataType 						: '', 	// jQuery params
17124			headers 						: '', 	// jQuery params
17125			crossDomain 					: '', 	// jQuery params
17126			data_params 					: {ajax:'true'},
17127
17128			modal_container 				: '#sow_ajax_modal',
17129			modal_size 						: 'modal-md',
17130			modal_centered 					: 'false',
17131
17132			/*
17133				callback_example = function(el, data, modal_container) {
17134					// el 				= element 				$(this)
17135					// data 			= server response 			(html|string)
17136					// modal_container = container to push data  	(string:#middle)
17137				}
17138			*/
17139			callback_function 	: ''
17140		},
17141
17142
17143
17144		/**
17145		 *
17146		 *	@collection
17147		 *
17148		 *
17149		 **/
17150		collection: $(),
17151
17152
17153
17154		/**
17155		 *
17156		 *	@init
17157		 *
17158		 *
17159		 **/
17160		init: function (selector, config) {
17161
17162			var __selector 			= $.SOW.helper.__selector(selector);
17163			var __config 			= $.SOW.helper.check_var(config);
17164
17165			this.selector 			= __selector[0]; 	// '#selector'
17166			this.collection 		= __selector[1]; 	// $('#selector')
17167			this.selector_orig 		= __selector[2]; 	// $('#selector') // without ajax container prefix
17168			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
17169
17170
17171			if(jQuery(this.selector).length < 1)
17172				return;
17173
17174
17175			// -- * --
17176			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
17177			// -- * --
17178
17179
17180			// Create modal container
17181			$.SOW.core.ajax_modal.ajax_modal_template();
17182
17183
17184
17185			// 1. Has no selector
17186			if(!this.selector) {
17187				$.SOW.core.ajax_modal.ajax_modal($('.js-ajax-modal'));
17188				return $('.js-ajax-modal');
17189			}
17190
17191			// 2. Has selector
17192			return this.collection.each(function() {
17193
17194				$.SOW.core.ajax_modal.ajax_modal($(this));
17195
17196			});
17197
17198		},
17199
17200
17201
17202		/**
17203		 *
17204		 *	@ajax_modal
17205		 *
17206		 *
17207		 *
17208		 **/
17209		ajax_modal: function(_this) {
17210
17211			var _selector 			= this.selector,
17212				_selector_orig 		= this.selector_orig,
17213				_modal_container 	= this.config.modal_container,
17214				_modal_size 		= this.config.modal_size,
17215				_callback 			= this.config.callback_function,
17216				_method 			= this.config.method,
17217				_modal_centered 	= this.config.modal_centered;
17218
17219			// precech to avoid useless bind. checked again on click!
17220			var _href 				= _this.attr('href') 	|| '',
17221				_href_data	 		= _this.data('href') 	|| '';
17222
17223			if(_href_data != '')
17224				_href = _href_data;
17225
17226			if(_href == '')
17227				return;
17228
17229
17230
17231			_this.not('.js-modalified').addClass('js-modalified').on('click', function(e) {
17232				e.preventDefault();
17233
17234				var _t 					= jQuery(this),
17235					_href 				= _t.attr('href') 							|| '',
17236					_href_data	 		= _t.data('href') 							|| '',
17237					_modalType	 		= _t.attr('data-ajax-modal-type') 			|| '', 				// video (or more in the future)
17238					_target 			= _t.data('ajax-modal-container') 			|| _modal_container,
17239					_modal_callback 	= _t.data('ajax-modal-callback-function') 	|| _callback, 		// callback function to call, on modal load
17240					_modal_size 		= _t.data('ajax-modal-size') 				|| _modal_size, 	// modal-sm, modal-md, modal-lg , modal-full
17241					_modal_backgdrop 	= _t.data('ajax-modal-backdrop') 			|| '', 				// data-backdrop="static"  	-  do not close on click
17242					_modal_centered		= _t.data('ajax-modal-centered') 			|| _modal_centered, // true|false
17243					_method				= _t.data('ajax-modal-method') 				|| _method; 		// true|false
17244
17245				if(_href_data != '')
17246					_href = _href_data;
17247
17248				if(_href == '' || _href == '#' || _href == 'javascript:;')
17249					return;
17250
17251
17252				// Ignore by request!
17253				if(_t.hasClass('js-ignore'))
17254					return;
17255
17256
17257				/*
17258					Empty ajax modal on close
17259					else, plugins like selectpicker will not refresh
17260				*/	jQuery(_target + ' .modal-content').empty();
17261
17262
17263
17264				// Close any open dropdown
17265				jQuery('.dropdown-menu:not(.dropdown-menu-hover)').parent().find('a[data-toggle="dropdown"][aria-expanded="true"]').attr('aria-expanded', 'false').dropdown('hide');
17266
17267				// Call the trigger
17268				$.SOW.core.ajax_modal.modalAjaxShow(_href, _target, _modal_size, _modal_centered, _modal_backgdrop, _modal_callback, _method, _modalType);
17269
17270			});
17271
17272
17273			// Modals on load
17274			$.SOW.core.ajax_modal.ajax_modal_onLoad();
17275
17276		},
17277
17278			/**
17279			 *
17280			 *	Ajax Process
17281			 *	:: Helper
17282			 *
17283			 **/
17284			modalAjaxShow: function(_href, _target, _modal_size, _modal_centered, _modal_backgdrop, _modal_callback, _method, _modalType) {
17285
17286				var _modal_size 		= typeof _modal_size 		!== 'undefined' ? _modal_size 		: this.config.modal_size;
17287				var _modal_centered 	= typeof _modal_centered 	!== 'undefined' ? _modal_centered 	: this.config.modal_centered;
17288				var _modal_backgdrop 	= typeof _modal_backgdrop 	!== 'undefined' ? _modal_backgdrop 	: '';
17289				var _modal_callback 	= typeof _modal_callback 	!== 'undefined' ? _modal_callback 	: '';
17290
17291
17292				// Create modal container (if not exists)
17293				$.SOW.core.ajax_modal.ajax_modal_template();
17294
17295
17296				if(_href == '#' || _href == '')
17297					return;
17298
17299				if(_target == '')
17300					var _target = this.config.modal_container;
17301
17302				if(_modal_size == '')
17303					var _modal_size = this.config.modal_size;  // modal-lg , modal-full
17304
17305				// --
17306
17307
17308				// Remove any known size class
17309				jQuery('.modal-dialog', _target).removeClass('modal-dialog-centered modal-sm modal-lg modal-xl modal-full');
17310
17311				// Add size class by request
17312				if(_modal_size != '')
17313					jQuery('.modal-dialog', _target).addClass(_modal_size);
17314
17315				// centered
17316				if(_modal_centered == true)
17317					jQuery('.modal-dialog', _target).addClass('modal-dialog-centered');
17318
17319				// static, do not close on click
17320				if(_modal_backgdrop != '') {
17321					var _backdrop = 'static';
17322					var _keyboard = false;
17323				} else {
17324					var _backdrop = 'dynamic';
17325					var _keyboard = true;
17326				}
17327
17328				// RESET - needed to load a modal from another modal
17329				jQuery('.modal-backdrop').remove();
17330
17331
17332				// ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
17333				// is video modal! stop here! process video!
17334				if(_modalType.toLowerCase() +'' == 'video') {
17335
17336					var _backdrop = 'dynamic'; 	// forced
17337					var embedData = $.SOW.helper.videoEmbedFromUrl(_href, 1); // 1 = autoplay
17338
17339					if(embedData === null) {
17340
17341						if(typeof $.SOW.core.toast === 'object') {
17342							$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
17343						} else {
17344							alert("[404] Unexpected internal error!");
17345						}
17346
17347						return false;
17348					}
17349
17350
17351
17352
17353					// load modal
17354					var _loader = '<div class="text-center p-6 fs--30 text-muted '+$.SOW.config.sow__icon_loading+'"></div>';
17355					jQuery(_target).modal('dispose').modal({backdrop: _backdrop, keyboard:_keyboard}).find('.modal-content').html(_loader);
17356
17357					setTimeout(function () {
17358
17359						jQuery(_target).find('.modal-content')
17360										.html(embedData)
17361										.addClass('rounded-xl bg-dark shadow-primary-xs border border-dark bw--3')
17362										.prepend('<button type="button" class="close pointer position-absolute top-0 end-0 mt--n50 mx-1 text-white z-index-100" data-dismiss="modal" aria-label="Close"><span class="fi fi-close fs--25" aria-hidden="true"></span></button>');
17363
17364
17365						// try another way to start the video! AdBlock is problematic!
17366						jQuery('iframe', _target).attr('src', jQuery('iframe', _target).data('autoplay-src'));
17367
17368					}, 450);
17369
17370
17371					// Destroy on close! Too much customization!
17372					// And anyway, else, video remain to play on background!
17373					jQuery(_target).on('hidden.bs.modal', function (e) {
17374						jQuery(_target).remove();
17375					});
17376
17377
17378
17379
17380					return false;
17381				}
17382				// ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
17383
17384
17385
17386				// Ajax Request
17387				jQuery.ajax({
17388					url:			_href,
17389					type: 			_method,
17390					data: 			$.SOW.core.ajax_modal.config.data_params,
17391					contentType: 	$.SOW.core.ajax_modal.config.contentType,
17392					dataType: 		$.SOW.core.ajax_modal.config.dataType,
17393					headers: 		$.SOW.core.ajax_modal.config.headers,
17394					crossDomain: 	$.SOW.core.ajax_modal.config.crossDomain,
17395
17396					beforeSend: function() {
17397
17398						var _loader = '<div class="text-center p-6 fs--30 text-muted '+$.SOW.config.sow__icon_loading+'"></div>';
17399						jQuery(_target).modal('dispose').modal({backdrop: _backdrop, keyboard:_keyboard}).find('.modal-content').html(_loader);
17400
17401					},
17402
17403					error: 	function(XMLHttpRequest, textStatus, errorThrown) {
17404
17405						if(typeof $.SOW.core.toast === 'object') {
17406							$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
17407						} else {
17408							alert("[404] Unexpected internal error!");
17409						}
17410
17411						// if debug enabled, see config
17412						if($.SOW.config.sow__debug_enable === true) {
17413							$.SOW.helper.consoleLog('----------------------------');
17414							$.SOW.helper.consoleLog('--- AJAX REQUEST ERROR ----');
17415							$.SOW.helper.consoleLog(' - MODAL -');
17416							$.SOW.helper.consoleLog('1. XMLHttpRequest:');
17417							$.SOW.helper.consoleLog(XMLHttpRequest);
17418							$.SOW.helper.consoleLog('2. textStatus:');
17419							$.SOW.helper.consoleLog(textStatus);
17420							$.SOW.helper.consoleLog('3. errorThrown:');
17421							$.SOW.helper.consoleLog(errorThrown);
17422							$.SOW.helper.consoleLog('----------------------------');
17423						}
17424
17425					},
17426
17427					success: function(data) {
17428
17429						jQuery(_target).find('.modal-content').html(data);
17430
17431						setTimeout(function () {
17432
17433							// Optional callback function
17434							if(_modal_callback != '' && typeof $.SOW.helper.executeFunctionByName === 'function')
17435								$.SOW.helper.executeFunctionByName(_modal_callback, window, _target);
17436
17437							// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
17438							// reinit inside ajax container
17439							$.SOW.reinit(_target);
17440							// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
17441
17442							// focus first input element
17443							jQuery('input:visible:enabled:first', _target).focus();
17444
17445
17446						}, 450);
17447
17448					}
17449
17450				});
17451
17452
17453			},
17454
17455
17456
17457
17458
17459		/**
17460		 *
17461		 *	@ajax_modal_template
17462		 *
17463		 *
17464		 **/
17465		ajax_modal_template: function() {
17466
17467			if(jQuery(this.config.modal_container).length > 0)
17468				return;
17469
17470			var modal_container = this.config.modal_container.replace('#', ''),
17471				_tpl = '<div class="modal fade" id="' + modal_container + '" role="dialog" tabindex="-1" aria-hidden="true">'
17472						+ '<div class="modal-dialog '+ this.config.modal_size +'" role="document">'
17473
17474							+ '<div class="modal-content"><!-- content added by ajax --></div>'
17475
17476						+ '</div>'
17477					+ '</div>';
17478
17479			$.SOW.globals.elBody.append(_tpl);
17480			$(this.config.modal_container).modal('handleUpdate');
17481
17482		},
17483
17484
17485
17486
17487
17488		/**
17489		 *
17490		 *	@createFromThinAir
17491		 * Programtically Create Modal 	: 		      url , 'modal-md', 'true' (centered), 'backdrop' (optional), callback (optional)
17492		 * $.SOW.core.ajax_modal.createFromThinAir(modalUrl, 'modal-lg', 'true', 'static', callback);
17493		 *
17494		 **/
17495		createFromThinAir: function(url, modal_size, modal_centered, modal_backdrop, modal_callback) {
17496
17497			if(!url)
17498				$.SOW.helper.consoleLog('SOW Ajax Modal : [createFromThinAir()] : No url provided!');
17499
17500
17501			if(!this.selector_orig)
17502				this.selector_orig = '.js-ajax-modal';
17503
17504			if(!modal_size)
17505				modal_size = 'modal-md';
17506
17507			if(!modal_centered)
17508				modal_centered = 'false';
17509
17510			if(!modal_backdrop)
17511				modal_backdrop = '';
17512
17513			if(!modal_callback)
17514				modal_callback = '';
17515
17516			// Create DOM
17517			var selectorClass = this.selector_orig.replace('.', '');
17518			$.SOW.globals.elBody.append('<a id="ajax_modal_create_tmp" href="'+url+'" class="hide '+selectorClass+'"></a>');
17519
17520			// Add Attributes
17521			jQuery('#ajax_modal_create_tmp')
17522				.attr('data-ajax-modal-size', 			modal_size)
17523				.attr('data-ajax-modal-centered', 		modal_centered)
17524				.attr('data-ajax-modal-backdrop', 		modal_backdrop)
17525				.attr('data-ajax-callback-function', 	modal_callback);
17526
17527			// Init this plugin
17528			$.SOW.core.ajax_modal.init(this.selector_orig);
17529			jQuery('#ajax_modal_create_tmp').trigger('click');
17530
17531			// Delete, not needed anymore!
17532			setTimeout(function() {
17533				jQuery('#ajax_modal_create_tmp').off().remove();
17534			},350);
17535
17536			return true;
17537		},
17538
17539
17540
17541
17542
17543
17544		/**
17545		 *
17546		 *	@ajax_modal_onLoad
17547		 *
17548		 **/
17549		ajax_modal_onLoad: function() {
17550
17551			jQuery('.js-ajax-modal.js-onload'+this.selector).not('.js-loadmodalified').addClass('js-loadmodalified').each(function() {
17552
17553				var _t 			= jQuery(this),
17554					_delay 		= jQuery(this).attr('data-ajax-modal-delay') || 3000,
17555					_ID 		= _t.attr('id') || '';
17556
17557				if(_ID != '') {
17558					var modalCookie = Cookies.get(_ID, { path: '/' });
17559					if(modalCookie == '1')
17560						return;
17561				}
17562
17563				setTimeout(function() {
17564					_t.trigger('click');
17565				}, Number(_delay));
17566
17567			});
17568
17569		},
17570
17571
17572
17573
17574
17575		/**
17576		 *
17577		 *	@attach
17578		 * 	Programtically Init For Element
17579		 * 	$.SOW.core.ajax_modal.attach(bg_element|string_id_class);
17580		 *
17581		 **/
17582		attach: function(href) {
17583
17584			// obj required
17585			var el = (typeof href === 'string') ? jquery(href) : href;
17586
17587			// unbind
17588			if(el.hasClass('js-modalified'))
17589				el.off().removeClass('js-modalified');
17590
17591			// add required
17592			el.addClass('js-ajax-modal');
17593
17594			// init
17595			$.SOW.core.ajax_modal.ajax_modal(el);
17596			setTimeout(function() {
17597				el.trigger('click');
17598			},200);
17599
17600			return true;
17601
17602		},
17603
17604
17605
17606
17607
17608		/**
17609		 *
17610		 *	@Return Selector
17611		 *
17612		 *
17613		 **/
17614		__selector: function() {
17615			return this.selector_orig;
17616		}
17617
17618
17619	}
17620
17621})(jQuery);
17622/**
17623 *
17624 *	[SOW] Ajax Confirm
17625 *
17626 *	@author 		Dorin Grigoras
17627 *					www.stepofweb.com
17628 *
17629 *	@Dependency 	-
17630 *	@Usage			$.SOW.core.ajax_confirm.init('.js-ajax-confirm');
17631 *
17632 *
17633 **/
17634;(function ($) {
17635	'use strict';
17636
17637
17638	/**
17639	 *
17640	 *	@vars
17641	 *
17642	 *
17643	 **/
17644	var scriptInfo 		= 'SOW Ajax Confirm';
17645
17646
17647
17648	$.SOW.core.ajax_confirm = {
17649
17650
17651		/**
17652		 *
17653		 *	@config
17654		 *
17655		 *
17656		 **/
17657		config: {
17658			method 							: 'GET', 	// (ajax mode only)
17659			contentType 					: '', 		// jQuery params (ajax mode only)
17660			dataType 						: '', 		// jQuery params (ajax mode only)
17661			headers 						: '', 		// jQuery params (ajax mode only)
17662			crossDomain 					: '', 		// jQuery params (ajax mode only)
17663			data_params 					: {ajax:'true'},// jQuery params (ajax mode only)
17664
17665			confirm_container 				: '#sow_ajax_confirm',
17666			confirm_size 					: '',
17667			confirm_centered 				: false,
17668
17669			confirm_type 					: '', 			// primary|secondary|success|warning|danger|info; empty = regular/clean
17670			confirm_mode 					: 'regular', 	// ajax|regular
17671			confirm_title 					: 'Please Confirm',
17672			confirm_body 					: 'Are you sure?',
17673
17674			btn_class_yes 					: 'btn-sm btn-primary',
17675			btn_class_no 					: 'btn-sm btn-light',
17676			btn_text_yes 					: 'Confirm',
17677			btn_text_no 					: 'Cancel',
17678			btn_icon_yes 					: 'fi fi-check',
17679			btn_icon_no 					: 'fi fi-close',
17680
17681			/*
17682				callback_example = function(el, data) {
17683					// el 				= link clicked 				$(this)
17684					// data 			= server response 			(html|string)
17685				}
17686			*/
17687			callback_function 				: ''
17688
17689		},
17690
17691
17692
17693		/**
17694		 *
17695		 *	@collection
17696		 *
17697		 *
17698		 **/
17699		collection: $(),
17700
17701
17702
17703		/**
17704		 *
17705		 *	@init
17706		 *
17707		 *
17708		 **/
17709		init: function (selector, config) {
17710
17711			var __selector 			= $.SOW.helper.__selector(selector);
17712			var __config 			= $.SOW.helper.check_var(config);
17713
17714			this.selector 			= __selector[0]; 	// '#selector'
17715			this.collection 		= __selector[1]; 	// $('#selector')
17716			this.selector_orig 		= __selector[2]; 	// $('#selector') // without ajax container prefix
17717			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
17718
17719
17720			if(jQuery(this.selector).length < 1)
17721				return;
17722
17723
17724			// -- * --
17725			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
17726			// -- * --
17727
17728
17729			// Create modal container
17730			$.SOW.core.ajax_confirm.ajax_confirm_template();
17731
17732
17733			// 1. Has no selector
17734			if(!this.selector) {
17735				$.SOW.core.ajax_confirm.ajax_confirm($('a.js-ajax-confirm'));
17736				return this.collection;
17737			}
17738
17739			// 2. Has selector
17740			return this.collection.each(function() {
17741
17742				$.SOW.core.ajax_confirm.ajax_confirm($(this));
17743
17744			});
17745
17746		},
17747
17748
17749
17750		/**
17751		 *
17752		 *	@ajax_confirm
17753		 *
17754
17755		<a href="URL-HERE"
17756			class="js-ajax-confirm"
17757
17758			data-ajax-confirm-size="modal-md"
17759			data-ajax-confirm-centered="false"
17760
17761			data-ajax-confirm-callback-function=""
17762			data-ajax-confirm-type="ajax"
17763			data-ajax-confirm-method="GET"
17764
17765			data-ajax-confirm-title="Please Confirm"
17766			data-ajax-confirm-body="Are you sure? Delete this item?"
17767
17768			data-ajax-confirm-btn-yes-text="Confirm"
17769			data-ajax-confirm-btn-yes-class="btn-sm btn-primary"
17770			data-ajax-confirm-btn-yes-icon="fi fi-check"
17771
17772			data-ajax-confirm-btn-no-text="Cancel"
17773			data-ajax-confirm-btn-no-class="btn-sm btn-light"
17774			data-ajax-confirm-btn-no-icon="fi fi-close"
17775
17776			rel="nofollow">
17777			Confirm
17778		</a>
17779
17780			data-ajax-confirm-size="modal-sm|modal-md|modal-lg|modal-full"
17781
17782			data-ajax-confirm-callback-function="_myCustomFunc" 	(optional - your custom function called on load)
17783			Example:
17784				var _myCustomFunc = function(el, data) {
17785					el = button element
17786					data = ajax result from server
17787					alert('My Function Called! Do something like... reinit some plugins');
17788				}
17789
17790		 *
17791		 *
17792		 **/
17793		ajax_confirm: function(_this) {
17794
17795			var _selector 			= this.selector,
17796				_selector_orig 		= this.selector_orig,
17797				_confirm_container 	= this.config.confirm_container,
17798				_confirm_size 		= this.config.confirm_size,
17799				_confirm_centered 	= this.config.confirm_centered,
17800				_confirm_callback 	= this.config.callback_function,
17801
17802				confirm_method 		= this.config.method,
17803				confirm_mode 		= this.config.confirm_mode,
17804				confirm_type 		= this.config.confirm_type,
17805				confirm_title 		= this.config.confirm_title,
17806				confirm_body 		= this.config.confirm_body,
17807
17808				btn_class_yes 		= this.config.btn_class_yes,
17809				btn_class_no 		= this.config.btn_class_no,
17810				btn_text_yes 		= this.config.btn_text_yes,
17811				btn_text_no 		= this.config.btn_text_no,
17812				btn_icon_yes 		= this.config.btn_icon_yes,
17813				btn_icon_no 		= this.config.btn_icon_no;
17814
17815
17816			var _href 		= _this.attr('href') || '',
17817				_href_data 	= _this.data('href') || '';
17818
17819			if(_href_data != '')
17820				_href = _href_data;
17821
17822
17823			if(_href == '')
17824				return;
17825
17826			_this.attr('data-href', _href);
17827			_this.attr('href', '#');
17828
17829
17830			_this.not('.js-ajaxconfirmified').addClass('js-ajaxconfirmified').on('click', function(e) {
17831				e.preventDefault();
17832
17833				var _t 					= jQuery(this),
17834			    	_href 				= _t.data('href') 							|| '#',
17835
17836			    	_target 			= _t.data('ajax-confirm-container') 		|| _confirm_container, 	// modal (id or class)
17837					_modal_confirm_size = _t.data('ajax-confirm-size') 				|| _confirm_size, 		// modal-sm, modal-md, modal-lg , modal-full
17838					_modal_centered		= _t.data('ajax-confirm-centered') 			|| _confirm_centered, 	// true|false
17839					_confirmCallback	= _t.data('ajax-confirm-callback-function')	|| _confirm_callback, 	// custom function
17840					_confirmType 		= _t.data('ajax-confirm-type')				|| confirm_type,		// confirmation type: danger|warning|etc. empty for normal/clean
17841					_confirmMode 		= _t.data('ajax-confirm-mode')				|| confirm_mode,		// confirmation type: regular|ajax
17842					_confirmMethod 		= _t.data('ajax-confirm-method')			|| confirm_method,		// confirmation method: GET|POST
17843
17844			    	_confirmTitle		= _t.data('ajax-confirm-title') 			|| confirm_title,		// modal title
17845			    	_confirmBody 		= _t.data('ajax-confirm-body') 				|| confirm_body,		// message | question
17846
17847			    	_confirmBtnYesTxt 	= _t.data('ajax-confirm-btn-yes-text') 		|| btn_text_yes,		// button text
17848			    	_confirmBtnYesClass = _t.data('ajax-confirm-btn-yes-class') 	|| btn_class_yes,		// button class
17849			    	_confirmBtnYesIcon 	= _t.data('ajax-confirm-btn-yes-icon') 		|| btn_icon_yes,		// button icon. eg: fi fi-check
17850
17851			    	_confirmBtnNoTxt 	= _t.data('ajax-confirm-btn-no-text') 		|| btn_text_no,			// button text
17852			    	_confirmBtnNoClass 	= _t.data('ajax-confirm-btn-no-class') 		|| btn_class_no,		// button class
17853			    	_confirmBtnNoIcon 	= _t.data('ajax-confirm-btn-no-icon') 		|| btn_icon_no;			// button icon. eg: fi fi-check
17854
17855
17856
17857				// Ignore by request!
17858				if(_t.hasClass('js-ignore'))
17859					return;
17860
17861
17862				// Always create new modal
17863				$.SOW.core.ajax_confirm.ajax_confirm_template();
17864
17865				// Close any open dropdown
17866				jQuery('.dropdown-menu:not(.dropdown-menu-hover)').parent().find('a[data-toggle="dropdown"][aria-expanded="true"]').attr('aria-expanded', 'false').dropdown('hide');
17867
17868
17869				// Add size class by request
17870				jQuery('.modal-dialog', _target).removeClass('modal-sm, modal-md, modal-lg, modal-xlg, modal-full bg-primary-soft bg-secondary-soft bg-success-soft bg-warning-soft bg-danger-soft bg-pink-soft bg-indigo-soft bg-purple-soft').addClass(_modal_confirm_size);
17871
17872
17873				// Header Bg Color
17874				jQuery('.modal-header', _target).removeClass('bg-primary-soft bg-secondary-soft bg-success-soft bg-warning-soft bg-danger-soft bg-info-soft bg-pink-soft bg-indigo-soft bg-purple-soft border-0');
17875				if(_confirmType != '')
17876					jQuery('.modal-header', _target).addClass('bg-'+_confirmType+'-soft border-0');
17877
17878
17879				// centered
17880				(_modal_centered+'' == 'true') ? jQuery('.modal-dialog', _target).addClass('modal-dialog-centered') : jQuery('.modal-dialog', _target).removeClass('modal-dialog-centered');
17881
17882
17883				// Reset
17884				jQuery('.btn-confirm-yes', _target).attr('class', '').attr('class', 'btn btn-confirm-yes');
17885				jQuery('.btn-confirm-no', _target).attr('class', '').attr('class', 'btn btn-confirm-no');
17886				jQuery('.btn-confirm-yes>i', _target).remove();
17887				jQuery('.btn-confirm-no>i', _target).remove();
17888				jQuery(_target + ' .modal-footer').removeClass('hide');
17889
17890
17891				// Add Icons
17892				if(_confirmBtnYesIcon.length > 1)
17893					var _confirmBtnYesTxt = '<i class="' + _confirmBtnYesIcon + '"></i> ' + _confirmBtnYesTxt;
17894
17895				if(_confirmBtnNoIcon.length > 1)
17896					var _confirmBtnNoTxt = '<i class="' + _confirmBtnNoIcon + '"></i> ' + _confirmBtnNoTxt;
17897
17898				jQuery('.btn-confirm-yes', _target).attr('href', _href).html(_confirmBtnYesTxt).addClass(_confirmBtnYesClass);
17899				jQuery('.btn-confirm-no', _target).html(_confirmBtnNoTxt).addClass(_confirmBtnNoClass);
17900
17901				jQuery('.modal-title', _target).html(_confirmTitle);
17902				jQuery('.modal-body', _target).html(_confirmBody);
17903
17904				jQuery(_target).modal('show');
17905
17906				// CONFIRMATION AJAX REQUEST
17907				if(_confirmMode == 'ajax') {
17908
17909					jQuery('.btn-confirm-yes', _target).unbind('click').on("click", function(e) {
17910						e.preventDefault();
17911
17912						jQuery.ajax({
17913							url: 			_href,
17914							type: 			_confirmMethod,
17915							data: 			$.SOW.core.ajax_confirm.config.data_params,
17916							contentType: 	$.SOW.core.ajax_confirm.config.contentType,
17917							dataType: 		$.SOW.core.ajax_confirm.config.dataType,
17918							headers: 		$.SOW.core.ajax_confirm.config.headers,
17919							crossDomain: 	$.SOW.core.ajax_confirm.config.crossDomain,
17920
17921							beforeSend: function() {
17922
17923								$.SOW.helper.loadingSpinner('show', _target + ' .modal-content');
17924								jQuery('.btn-confirm-yes', _target).addClass('disabled').prop('disabled', true);
17925							},
17926
17927							error: 	function(XMLHttpRequest, textStatus, errorThrown) {
17928
17929								$.SOW.helper.loadingSpinner('hide');
17930								jQuery('.btn-confirm-yes', _target).removeClass('disabled').prop('disabled', false);
17931
17932								if(typeof $.SOW.core.toast === 'object') {
17933
17934									$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!',  'top-center', 0, true);
17935									jQuery(_target).modal('hide');
17936
17937								} else {
17938									alert("[404] Unexpected internal error!");
17939								}
17940
17941							},
17942
17943							success: function(data) {
17944
17945								$.SOW.helper.loadingSpinner('hide');
17946
17947								jQuery(_target + ' .modal-footer').addClass('hide');
17948								jQuery(_target + ' .modal-content .modal-body').html('<div class="js-modal-confirm-ok pt--20 pb--30 text-center animate-bouncein"><i class="'+$.SOW.config.sow__icon_check+' fs--40 text-muted"></i></div>');
17949								jQuery('.btn-confirm-yes', _target).removeClass('disabled').prop('disabled', false);
17950
17951								setTimeout(function(){
17952
17953									jQuery(_target).modal('hide');
17954
17955								},500);
17956
17957
17958								if(_confirmCallback != '' && typeof $.SOW.helper.executeFunctionByName === 'function')
17959									$.SOW.helper.executeFunctionByName(_confirmCallback, window, _t, data);
17960
17961
17962							}
17963						});
17964
17965					});
17966
17967				} else {
17968
17969					// Callback Function
17970					if(_confirmCallback != '' && typeof $.SOW.helper.executeFunctionByName === 'function') {
17971						jQuery('.btn-confirm-yes', _target).unbind('click').on('click', function(e) {
17972							e.preventDefault();
17973							$.SOW.helper.executeFunctionByName(_confirmCallback, window, _t);
17974						});
17975					}
17976
17977
17978					jQuery('.btn-confirm-yes', _target).unbind('click').on("click", function(e) {
17979						jQuery(_target).modal('hide');
17980					});
17981
17982				}
17983
17984
17985			});
17986
17987			return true;
17988		},
17989
17990
17991
17992
17993
17994		/**
17995		 *
17996		 *	@ajax_confirm_template
17997		 *
17998		 *
17999		 **/
18000		ajax_confirm_template: function() {
18001
18002			// remove last
18003			jQuery(this.config.confirm_container).remove();
18004
18005			var confirm_container = this.config.confirm_container.replace('#', ''),
18006				_tpl = '<div class="modal fade" id="' + confirm_container + '" role="dialog" tabindex="-1" aria-labelledby="modal-title-confirm" aria-hidden="true">'
18007						+ '<div class="modal-dialog '+ this.config.confirm_size +'" role="document">'
18008
18009							+ '<div class="modal-content">'
18010
18011								+ '<div class="modal-header">'
18012
18013									+ '<h5 id="modal-title-confirm" class="modal-title font-light fs--18">'
18014										+ this.config.confirm_title
18015									+ '</h5>'
18016
18017									+ '<button type="button" class="close" data-dismiss="modal" aria-label="Close">'
18018										+ '<span class="fi fi-close fs--18" aria-hidden="true"></span>'
18019									+ '</button>'
18020
18021								+ '</div>'
18022
18023								+ '<div class="modal-body pt--30 pb--30">'
18024
18025									+ this.config.confirm_body
18026
18027								+ '</div>'
18028
18029								+ '<div class="modal-footer">'
18030
18031									+ '<a href="#" class="btn pt--10 pb--10 fs--16 btn-confirm-yes '+ this.config.btn_class_yes +'">'
18032										+ this.config.btn_text_yes
18033									+ '</a>'
18034
18035									+ '<a href="#" class="btn pt--10 pb--10 fs--16 btn-confirm-no '+ this.config.btn_class_no +'" data-dismiss="modal">'
18036										+ this.config.btn_text_no
18037									+ '</a>'
18038
18039								+ '</div>'
18040
18041							+ '</div>'
18042
18043						+ '</div>'
18044					+ '</div>';
18045
18046
18047			$.SOW.globals.elBody.append(_tpl);
18048			$(this.config.confirm_container).modal('handleUpdate');
18049
18050			// clear
18051			_tpl = null;
18052
18053		},
18054
18055
18056
18057
18058		/**
18059		 *
18060		 *	@Return Selector
18061		 *
18062		 *
18063		 **/
18064		__selector: function() {
18065			return this.selector_orig;
18066		}
18067
18068
18069	}
18070
18071})(jQuery);
18072/**
18073 *
18074 *	[SOW] Form Advanced
18075 *
18076 *	@author 		Dorin Grigoras
18077 *					www.stepofweb.com
18078 *
18079 *	@Dependency 	-
18080 *	@Usage			$.SOW.core.file_upload.init('input[type="file"].custom-file-input');
18081 *
18082 *
18083 **/
18084;(function ($) {
18085	'use strict';
18086
18087
18088	/**
18089	 *
18090	 *	@vars
18091	 *
18092	 *
18093	 **/
18094	var scriptInfo 				= 'SOW File Upload';
18095	window.fileInventory 		= {};
18096	window.filesLastBulk 		= [];
18097	window.filesSizeBulk 		= 0;
18098	window.browser_hasIssues 	= false; 		// example: safari do not allow input file cloning. So we mark it as having issues
18099
18100
18101	$.SOW.core.file_upload = {
18102
18103
18104		/**
18105		 *
18106		 *	@config
18107		 *
18108		 *
18109		 **/
18110		config: {
18111
18112			// toast messages
18113			toast_pos: 								'bottom-center',
18114			toast_delay: 							2000,
18115
18116			browsers_with_issues: 					['safari'],		// browsers with issues (are treated different by file input)
18117
18118		},
18119
18120
18121
18122		/**
18123		 *
18124		 *	@collection
18125		 *
18126		 *
18127		 **/
18128		collection: $(),
18129
18130
18131
18132		/**
18133		 *
18134		 *	@init
18135		 *
18136		 *
18137		 **/
18138		init: function (selector, config) {
18139
18140			var __selector 			= $.SOW.helper.__selector(selector);
18141			var __config 			= $.SOW.helper.check_var(config);
18142
18143			this.selector 			= __selector[0]; 	// '#selector'
18144			this.collection 		= __selector[1]; 	// $('#selector')
18145			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
18146
18147
18148			// Mark browser with issues (eample: safari do not allow cloning input file)
18149			var browser_vendor 	= $.SOW.helper.get_browser();
18150			if(this.config.browsers_with_issues.indexOf(browser_vendor) !== -1)
18151				window.browser_hasIssues = true;
18152
18153
18154			// 1. Has no selector
18155			if(!this.selector) {
18156				$.SOW.core.file_upload.file_upload__init('input[type="file"].custom-file-input');
18157				return this.collection;
18158			}
18159
18160			// 2. Has selector
18161			$.SOW.core.file_upload.file_upload__init(this.selector);
18162
18163
18164			// No chaining!
18165			return null;
18166		},
18167
18168
18169
18170
18171		/**
18172		 *
18173		 *	@file_upload__init
18174		 *	File Input|Upload
18175		 *
18176		 *
18177		 **/
18178		file_upload__init: function(_this) {
18179
18180
18181			/*
18182
18183				First setup
18184					: unique identifier
18185					: empty inventory array
18186					: correcting human errors (like array name missing on multiple files)
18187
18188			*/
18189			jQuery(_this).each(function() {
18190
18191				var _t 				 	= jQuery(this),
18192					is_multiple			= _t.attr('multiple') 						|| false,
18193					input_name 			= _t.attr('name') 							|| '',
18194					preview_delete 		= _t.data('file-ajax-delete-enable') 		|| false,
18195					preview_reorder 	= _t.data('file-ajax-reorder-enable') 		|| false,
18196					fileInputIdentifier = $.SOW.helper.randomStr(4, 'N');
18197
18198
18199				// add unique identifier for each file input
18200				_t.attr('data-js-advanced-identifier', fileInputIdentifier);
18201
18202				// create empty array
18203				window.fileInventory[fileInputIdentifier] = [];
18204
18205				// name array missing on multiple input upload
18206				if(is_multiple !== false && input_name.indexOf('[]') === -1)
18207					_t.attr('name', input_name+'[]');
18208
18209
18210				// Used by preadded files
18211				if(preview_delete != false) {
18212
18213					if(is_multiple != false)
18214						$.SOW.core.file_upload.file_upload__preview_delbtn_bind_multiple(_t, true);
18215
18216					if(is_multiple == false)
18217						$.SOW.core.file_upload.file_upload__preview_delbtn_bind_single(_t, true);
18218
18219				}
18220
18221				if(preview_reorder != false)
18222					$.SOW.core.file_upload.file_upload__preview__reorder_bind(_t, true);
18223
18224
18225			});
18226
18227
18228			jQuery(_this).not('.js-advancified').addClass('js-advancified').on('change',function(e) {
18229
18230				var _t 						= jQuery(this),
18231					fileInputIdentifier 	= _t.data('js-advanced-identifier') 				|| '', // static, real identifier for each file input
18232					is_multiple				= _t.attr('multiple') 								|| false,
18233					file_name 				= (is_multiple === false) ? _t.get(0).files[0].name.replace('C:\\fakepath\\', " ") : '',
18234					label_orig 				= _t.next('.custom-file-label').attr('data-orig') 	|| '',
18235					exts_allowed 			= _t.data('file-ext') 								|| '',
18236					exist_error_txt  		= _t.data('file-exist-err-msg') 					|| 'File already exist: ',
18237					exts_error_txt  		= _t.data('file-ext-err-msg') 						|| 'Allowed: ',
18238					size_error_txt  		= _t.data('file-size-err-item-msg') 				|| 'File too large! ',
18239					size_error_txt_total	= _t.data('file-size-err-total-msg') 				|| 'Total size exceeded!',
18240					selected_txt 			= _t.data('file-size-err-total-msg') 				|| 'selected', // in case preview is not used
18241					max_error_txt_total		= _t.data('file-size-err-max-msg') 					|| 'Maximum allowed files:',
18242					toast_position			= _t.data('file-toast-position') 					|| 'bottom-center',
18243					max_size_per_file  		= _t.data('file-max-size-kb-per-file') 				|| 0,
18244					max_size_total  		= _t.data('file-max-size-kb-total') 				|| 0,
18245					max_files  				= _t.data('file-max-total-files') 					|| 0,
18246					btn_clear_files  		= _t.data('file-btn-clear') 						|| 'a.js-advanced-form-input-clone-clear',
18247					preview_container		= _t.data('file-preview-container') 				|| '',
18248					preview_height 			= _t.data('file-preview-img-height') 				|| 120,
18249					preview_info 			= _t.data('file-preview-show-info') 				|| false,
18250					preview_info 			= _t.data('file-preview-show-info') 				|| false,
18251					preview_list_type 		= _t.data('file-preview-list-type') 				|| 'box',
18252					preview_class 			= _t.data('file-preview-class') 					|| '',
18253					preview_as_cover 		= _t.data('file-preview-img-cover') 				|| false,
18254					preview_reorder 		= _t.data('file-ajax-reorder-enable') 				|| false,
18255					preview_delete 			= _t.data('file-ajax-delete-enable') 				|| false,
18256
18257					// @Ajax
18258					ajax_process_enable  	= _t.data('file-ajax-upload-enable')				|| false; 	// false by default!
18259
18260
18261
18262
18263				// Force preview as cover for lists
18264				if(preview_list_type == 'list')
18265					preview_as_cover = true;
18266
18267
18268				// Some settings
18269				_t.attr('data-orig-name', jQuery(this).attr('name'));
18270
18271
18272				if(label_orig == '') {
18273					label_orig = _t.next('.custom-file-label').html() || 'Choose file';
18274					_t.next('.custom-file-label').attr('data-orig', label_orig);
18275				}
18276
18277
18278				if(exts_allowed != '')
18279					exts_allowed = exts_allowed.split(",").map(function(ext) {
18280										return ext.trim();
18281									});
18282
18283
18284				// Always reset on safari and single file
18285				// SAFARI ISSUE: Cloning input file is not supported!
18286				if(window.browser_hasIssues === true || is_multiple === false) {
18287
18288					window.fileInventory[fileInputIdentifier] = [];
18289
18290					if(ajax_process_enable != true) {
18291						jQuery('.js-file-input-item', preview_container).remove();
18292						jQuery(btn_clear_files).addClass('hide');
18293					}
18294
18295				}
18296
18297
18298
18299				/*
18300
18301					Single File : add file name
18302
18303				*/
18304				if(is_multiple === false)
18305					_t.next('.custom-file-label').text(file_name);
18306				else
18307					_t.next('.custom-file-label').text(_t.get(0).files.length + ' ' + selected_txt); // in case preview is not used
18308
18309
18310
18311
18312
18313				/*
18314
18315					2. Preview & Logics
18316
18317				*/
18318				var input_name 			= _t.attr('name') || _t.data('orig-name'),
18319					_clone 				= _t.clone(true).off(), // turn off binds from clone
18320					_bulkNo 			= 'bulkNo_' + $.SOW.helper.randomStr(8),
18321					total_files 		= _t.get(0).files.length,
18322					file_size_kb_bulk 	= 0;
18323
18324
18325				// set back "Choose file" label
18326				if(is_multiple !== false)
18327					_t.next('.custom-file-label').html(label_orig);
18328
18329
18330
18331				for (var i = 0; i < total_files; ++i) {
18332
18333					var file 			= _t.get(0).files[i],
18334						file_ext 		= file.name.substring(file.name.lastIndexOf('.')+1, file.name.length) || null,
18335						file_size_kb 	= $.SOW.helper.byte2kb(file.size),
18336						_rand 			= 'rand_' + $.SOW.helper.randomStr(3),
18337						file_img 		= '<div class="js-advanced-form-default-preview absolute-full d-table w-100 h--120"><div class="d-table-cell align-middle text-center"><span class="fs--30 text-gray-500">?</span></div></div>',
18338						_concat 		= file.name+':'+file.size+':'+fileInputIdentifier;
18339						window.filesLastBulk.push(_rand); // because are already in the dom!
18340
18341
18342
18343					/*
18344
18345						Maximum files
18346
18347					*/
18348					if(max_files > 0) {
18349
18350						var total_files_current = jQuery('.js-file-input-item', preview_container).length;
18351
18352						if(parseInt(total_files_current) >= max_files) {
18353
18354							var _msg = max_error_txt_total + ' ' + max_files;
18355
18356							if(typeof $.SOW.core.toast === 'object') {
18357								$.SOW.core.toast.show('danger', '', _msg, toast_position, 6000, true);
18358							} else {
18359								alert(_msg);
18360							}
18361
18362							// delete input & images of this input
18363							$.SOW.core.file_upload.file_upload__del_bulk(_t, _bulkNo, btn_clear_files, preview_container, input_name, fileInputIdentifier);
18364							return;
18365
18366						}
18367
18368					}
18369
18370
18371
18372					/*
18373
18374						Maximum total upload
18375
18376					*/
18377					if(max_size_total > 0) {
18378
18379						// because window.filesSizeBulk is calculated at the end
18380						var filesSizeBulk_current = file_size_kb_bulk + window.filesSizeBulk ;
18381
18382						if(parseInt(filesSizeBulk_current) > parseInt(max_size_total)) {
18383
18384							var _msg = size_error_txt_total + ' <hr>(' + max_size_total+'kb)';
18385
18386							if(typeof $.SOW.core.toast === 'object')
18387								$.SOW.core.toast.show('danger', '', _msg, toast_position, 6000, true);
18388
18389							// delete input & images of this input
18390							$.SOW.core.file_upload.file_upload__del_bulk(_t, _bulkNo, btn_clear_files, preview_container, input_name, fileInputIdentifier);
18391
18392							return;
18393
18394						}
18395					}
18396
18397
18398
18399
18400					// Check file size
18401					if(max_size_per_file > 0) {
18402
18403						if(parseInt(file_size_kb) > parseInt(max_size_per_file)) {
18404
18405							var _msg = size_error_txt + ' <hr>' + file.name +'<br>(' + file_size_kb+'kb / '+max_size_per_file+'Kb)';
18406
18407							if(typeof $.SOW.core.toast === 'object')
18408								$.SOW.core.toast.show('danger', '', _msg, toast_position, 6000, true);
18409
18410							// delete input & images of this input
18411							$.SOW.core.file_upload.file_upload__del_bulk(_t, _bulkNo, btn_clear_files, preview_container, input_name, fileInputIdentifier);
18412
18413							return;
18414
18415						}
18416
18417					}
18418
18419
18420					// Sum the size of all files in this bulk
18421					// if everything is ok, will add to window.filesSizeBulk
18422					file_size_kb_bulk += file_size_kb;
18423
18424
18425					// check allowed extension
18426					if(exts_allowed != '' && exts_allowed.indexOf(file_ext) === -1) {
18427
18428						var _msg = exts_error_txt + ' ' + exts_allowed.join(', ');
18429
18430						if(typeof $.SOW.core.toast === 'object') {
18431							$.SOW.core.toast.show('danger', '', _msg, toast_position, 4500, true);
18432						} else {
18433							alert(_msg);
18434						}
18435
18436
18437						// delete input & images of this input
18438						$.SOW.core.file_upload.file_upload__del_bulk(_t, _bulkNo, btn_clear_files, preview_container, input_name, fileInputIdentifier);
18439
18440						return;
18441
18442					}
18443
18444
18445					/*
18446
18447						File already exists
18448
18449					*/
18450					if(window.fileInventory[fileInputIdentifier].indexOf(_concat) !== -1) {
18451
18452						if(typeof $.SOW.core.toast === 'object')
18453							$.SOW.core.toast.show('danger', '', exist_error_txt + '<br> '+file.name, toast_position, 4500, true);
18454
18455
18456						// delete input & images of this input
18457						$.SOW.core.file_upload.file_upload__del_bulk(_t, _bulkNo, btn_clear_files, preview_container, input_name, fileInputIdentifier);
18458
18459						return;
18460
18461					}
18462
18463
18464					// add file to inventory
18465					window.fileInventory[fileInputIdentifier].push(_concat);
18466
18467
18468					// preview image
18469					if(preview_container != '') {
18470
18471						var _tpl = $.SOW.core.file_upload.file_upload__preview_tpl(file, file_ext, _rand, _bulkNo, preview_height, preview_info, preview_class, ajax_process_enable, preview_delete, preview_as_cover, preview_list_type, is_multiple);
18472						jQuery(preview_container).append(_tpl);
18473
18474						// bind delete button
18475						if(ajax_process_enable === true) {
18476
18477							if(preview_delete != false) {
18478
18479								if(is_multiple != false)
18480									$.SOW.core.file_upload.file_upload__preview_delbtn_bind_multiple(_t, false);
18481
18482								if(is_multiple == false)
18483									$.SOW.core.file_upload.file_upload__preview_delbtn_bind_single(_t, false);
18484
18485							}
18486
18487							if(preview_reorder === true)
18488								$.SOW.core.file_upload.file_upload__preview__reorder_bind(_t, false);
18489
18490						}
18491
18492						// image preview ---------------------------------------
18493						if (file_ext == "gif" || file_ext == "png" || file_ext == "jpg" || file_ext == "jpeg")
18494							$.SOW.core.file_upload.file_upload__preview_img_render('#'+_rand, file, preview_as_cover, preview_list_type);
18495
18496					}
18497
18498
18499				}
18500
18501
18502				// show `remove all files` button
18503				$.SOW.core.file_upload.file_upload__btn_clear_bind(btn_clear_files, _t, preview_container, input_name, fileInputIdentifier);
18504
18505
18506
18507				// 1. append cloned element
18508				// safari DO NOT support file input cloning!
18509				// also not allowing hidden file inputs - so we use .viewport-out class, just in case, for future chrome/etc updates
18510				if(window.browser_hasIssues !== true) {
18511
18512					// hard to debug with all variables. We remove them, never used as a clone!
18513					_clone.removeAttr('class name data-orig-name aria-describedby data-file-ajax-upload-url data-file-ajax-upload-params data-file-ajax-delete-params data-file-ajax-callback-function data-file-ajax-toast-success-txt data-file-ajax-toast-error-txt data-file-ajax-upload-enable data-file-ajax-reorder-enable data-file-ajax-reorder-url data-js-advanced-identifier data-js-file-input-clone js-advanced-identifier data-file-ext data-file-max-size-kb-per-file data-file-max-size-kb-total data-file-max-total-files data-file-ext-err-msg data-file-exist-err-msg data-file-size-err-item-msg data-file-size-err-total-msg data-file-size-err-max-msg data-file-toast-position data-file-preview-container data-file-preview-img-height data-file-preview-show-info data-file-btn-clear data-file-preview-class data-file-preview-img-cover file-preview-list-type data-file-ajax-progressbar-custom data-file-ajax-progressbar-disable');
18514					_clone.attr('id', _bulkNo).attr('name', input_name);
18515
18516					_t.val('').removeAttr('name').attr('data-orig-name', input_name);
18517
18518					// This container holds all clonned inputs
18519					if(jQuery('#js_advanced_form_identifier_'+fileInputIdentifier).length < 1) {
18520						var __el = _t.next();
18521
18522						// If input is inside a <label>
18523						if(_t.parents('label').length > 0)
18524							__el = _t.parents('label');
18525
18526						// bootstrap custom file
18527						else if(_t.parents('div.custom-file').length > 0) {
18528							__el = _t.parents('div.custom-file');
18529
18530							if(_t.parents('div.input-group').length > 0)
18531								__el = _t.parents('div.input-group');
18532
18533						}
18534
18535						// If input is directly inside a <form>
18536						if(_t.parent('form').length > 0)
18537							__el = _t;
18538
18539						__el.after('<div id="js_advanced_form_identifier_'+fileInputIdentifier+'" class="viewport-out w--50 h--50 opacity-0"></div>');
18540					}
18541
18542					jQuery('#js_advanced_form_identifier_'+fileInputIdentifier).append(_clone);
18543
18544					window.filesLastBulk = [];
18545					window.filesSizeBulk += file_size_kb_bulk;
18546
18547				}
18548
18549
18550
18551
18552				/**
18553
18554					AJAX : UPLOAD
18555
18556				**/
18557				if(ajax_process_enable === true) {
18558
18559					// Block input
18560					_t.addClass('disabled').prop('disabled', true);
18561					_t.parents('.btn').a
18561ddClass('disabled active');
18562
18563					// Wait a little bit for the previews to show up!
18564					setTimeout(function() {
18565
18566						// are added back by ajax if no error
18567						_t.removeClass('disabled').prop('disabled', false);
18568						_t.parents('.btn').removeClass('disabled active');
18569						$.SOW.core.file_upload.file_upload__ajax_upload(fileInputIdentifier, _bulkNo);
18570
18571					}, 350);
18572				}
18573
18574				// console.log(window.fileInventory);
18575
18576			});
18577
18578
18579
18580
18581		},
18582
18583			// reset to intial state
18584			file_upload__reset: function(_t, btn_clear_files, preview_container, input_name, fileInputIdentifier) {
18585
18586				jQuery('.js-file-input-item', preview_container).remove();
18587				jQuery(btn_clear_files).addClass('hide');
18588
18589				// restoring back to original
18590				_t.val('').attr('name', input_name).removeAttr('data-orig-name').prop('disabled', false);
18591
18592				// remove the entire container holding cloned/inputs
18593				jQuery('#js_advanced_form_identifier_'+fileInputIdentifier).remove();
18594
18595				// set back "Choose file" label
18596				var label_orig = _t.next('.custom-file-label').attr('data-orig') || 'Choose file';
18597					_t.next('.custom-file-label').html(label_orig);
18598
18599				window.fileInventory[fileInputIdentifier] = [];
18600				window.filesLastBulk = [];
18601
18602			},
18603
18604			// clear input values
18605			file_upload__clear: function(fileInputIdentifier) {
18606
18607				jQuery('input[type="file"][data-js-advanced-identifier="'+fileInputIdentifier+'"]').val('').prop('disabled', false);
18608
18609			},
18610
18611			file_upload__preview_tpl: function(file, file_ext, item_unique_id, _bulkNo, h, preview_info, preview_class, ajax_process_enable, preview_delete, preview_as_cover, preview_list_type, is_multiple) {
18612
18613
18614
18615				var default_preview_height 	= (h == 'auto' || h == '100%') ? h : 120,
18616					img_fluid 				= '';
18617
18618
18619				if(typeof h !== 'number') {
18620
18621					switch(preview_list_type) {
18622
18623						case 'list': 		var h = 50;
18624											break;
18625
18626						// 'box'
18627						default: 			var h = default_preview_height;
18628											var img_fluid = 'img-fluid';
18629
18630					}
18631
18632				}
18633
18634				// 50px min. height for `list` type
18635				if(preview_list_type == 'list' && h < 50)
18636					var h = 50;
18637
18638				var __h = (typeof h !== 'number') ? '100%' : h + 'px';
18639
18640
18641				switch(preview_as_cover) {
18642
18643					case true: 			var item_style = 'width: '+__h+'; height: '+__h+';';
18644										break;
18645
18646					// false
18647					default: 			var item_style = 'min-width: '+__h+'; min-height: '+__h+'; width: auto; height: auto;';
18648
18649				}
18650
18651
18652				var _loadingIcon 		= '<i class="' + $.SOW.config.sow__icon_loading + ' fs--30"></i>';
18653				var _loadingIconSize 	= (preview_list_type == 'list') ? 'fs--20' : 'fs--30';
18654
18655				// default preview class
18656				if(preview_class == '')
18657					var preview_class = (preview_list_type == 'list') ? 'show-hover-container shadow-md mb-2 rounded' : 'show-hover-container shadow-md m-2 rounded';
18658
18659				// Default : Show Loading
18660				var file_img = '<span class="js-advanced-form-default-preview absolute-full d-flex align-items-center justify-content-center opacity-6 '+_loadingIconSize+' '+$.SOW.config.sow__icon_loading+'"></span>';
18661
18662				// bytes to size
18663				var human_size = $.SOW.helper.byte2size(file.size);
18664
18665				// Image -or- extension
18666				// Default append. src = transaprent png base64
18667				var file_is_image = false;
18668				if (file_ext == "gif" || file_ext == "png" || file_ext == "jpg" || file_ext == "jpeg" || file_ext == "jpeg") {
18669					var file_is_image = true;
18670					file_img += '<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="" class="hide animate-bouncein js-file-input-preview mw-100 '+img_fluid+'" height="'+h+'">';
18671				}
18672
18673				else if (file_ext != '') {
18674					var file_ext_font_size = (h < 80) ? 'fs--20' : 'fs--30';
18675					var file_ext_font_size = (preview_list_type == 'list') ? 'fs--18' : file_ext_font_size;
18676					var file_img = '<span class="absolute-full d-flex align-items-center justify-content-center '+file_ext_font_size+' opacity-6 text-uppercase text-truncate">'+file_ext+'</span>';
18677				}
18678
18679				var pos_start 	= ($.SOW.globals.direction == 'ltr') ? 'left-0' : 'right-0';
18680				var pos_end 	= ($.SOW.globals.direction == 'ltr') ? 'right-0' : 'left-0';
18681
18682
18683
18684
18685
18686
18687				// 1. LIST : START TEMPLATE
18688				// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
18689				if(preview_list_type == 'list') {
18690
18691					var _tpl = '<div data-id="0" data-file-name="'+file.name+'" data-file-size="'+file.size+'" id="'+item_unique_id+'" class="js-file-input-item '+_bulkNo+' d-flex clearfix position-relative '+preview_class+'">';
18692
18693						// delete button
18694						if(preview_delete != false) {
18695
18696							_tpl += '<a href="#" data-item-id="'+item_unique_id+'" data-id="0" data-file-name="'+file.name+'" class="js-file-item-del position-absolute absolute-top show-hover-item '+pos_end+' z-index-2">'
18697										+ '<span class="d-inline-block btn btn-sm bg-danger text-white pt--4 pb--4 pl--10 pr--10 m--1">'
18698											+ '<i class="'+$.SOW.config.sow__icon_close+' m-0"></i>'
18699										+ '</span>'
18700									+ '</a>';
18701
18702						}
18703
18704							// image | file 														required min-* because of flex...
18705							_tpl += '<div class="position-relative d-inline-block bg-cover" style="width:'+h+'px; min-width:'+h+'px; height:'+h+'px">' + file_img + '</div>';
18706
18707							_tpl += '<div class="pl--15 pr--15 flex-fill d-flex min-w-0 align-items-center">';
18708
18709								// file name
18710								_tpl += '<span class="text-truncate d-block line-height-1">' + file.name;
18711
18712									// file size
18713									if(preview_info != false)
18714										_tpl += '<br><span class="fs--12 d-block pt-1">'+human_size+'</span>';
18715
18716								_tpl += '</span>';
18717
18718							_tpl += '</div>';
18719
18720						// ajax loading
18721						if(ajax_process_enable === true) {
18722							_tpl += '<span class="hide hide-force js-file-input-preview-ajax-uploading absolute-full d-flex align-items-center justify-content-center overlay-light overlay-opacity-8 z-index-2 pl--15 pr--15">'
18723									+ _loadingIcon
18724								 + '</span>';
18725						}
18726
18727
18728					_tpl += '</div>';
18729
18730					return _tpl;
18731
18732				}
18733				// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
18734
18735
18736
18737
18738
18739
18740
18741				// 2. BOX : START TEMPLATE
18742				// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
18743				var _tpl = '<span data-id="0" data-file-name="'+file.name+'" data-file-size="'+file.size+'" id="'+item_unique_id+'" class="js-file-input-item '+_bulkNo+' d-inline-block position-relative overflow-hidden text-center '+preview_class+'" style="'+item_style+'">';
18744
18745				_tpl += (preview_as_cover !== false) ? '' : file_img;
18746				// _tpl += '<span class="overlay-dark overlay-opacity-1 absolute-full"></span>'
18747
18748
18749				// header (file name) to non-image files!
18750				if(file_is_image === false || preview_info != false) {
18751
18752					_tpl += '<span class="js-file-input-preview-header text-white position-absolute w-100 top-0 left-0 right-0 clearfix overlay-dark overlay-opacity-2">'
18753							+ '<span class="text-truncate d-block fs--12 pl--5 pr--5">' + file.name + '</span>'
18754						 + '</span>';
18755				}
18756
18757				// footer
18758				if(preview_info != false) {
18759
18760					// file will be populated (or not) by reader (reason: async)
18761					_tpl += '<span class="js-file-input-preview-footer text-white position-absolute w-100 bottom-0 left-0 right-0 clearfix overlay-dark overlay-opacity-2">'
18762								+ '<span class="js-file-input-file-info-size text-truncate d-block fs--12 pl--5 pr--5">'+human_size+'</span>'
18763						  + '</span>';
18764
18765				}
18766
18767				// ajax only
18768				if(ajax_process_enable === true) {
18769
18770					// delete button
18771					if(preview_delete != false && is_multiple != false) {
18772
18773						_tpl += '<a href="#" data-item-id="'+item_unique_id+'" data-id="0" data-file-name="'+file.name+'" class="js-file-item-del position-absolute absolute-top show-hover-item '+pos_start+' z-index-2">'
18774									+ '<span class="d-inline-block btn btn-sm bg-danger text-white pt--4 pb--4 pl--10 pr--10 m--1">'
18775										+ '<i class="'+$.SOW.config.sow__icon_close+' m-0"></i>'
18776									+ '</span>'
18777								+ '</a>';
18778					}
18779
18780					// ajax loading
18781					_tpl += '<span class="hide hide-force js-file-input-preview-ajax-uploading absolute-full d-flex align-items-center justify-content-center overlay-light overlay-opacity-8 z-index-3">'
18782							+_loadingIcon
18783						 + '</span>';
18784
18785				}
18786
18787
18788				_tpl += '</span>';
18789
18790				return _tpl;
18791				// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
18792
18793
18794			},
18795
18796			file_upload__preview_img_render: function(id, file, preview_as_cover, preview_list_type) {
18797
18798				var reader = new FileReader();
18799				reader.onload = function(s) {
18800
18801					jQuery(id + ' .js-advanced-form-default-preview').remove();
18802
18803					if(preview_as_cover !== false) {
18804
18805						var __id = (preview_list_type == 'list') ? id + '>.bg-cover' : id;
18806						jQuery(__id).css("background-image", "url(" + s.target.result + ")").addClass('bg-cover').removeClass('hide');
18807
18808					} else {
18809
18810						jQuery(id + ' img.js-file-input-preview').attr('src', s.target.result).removeClass('hide');
18811
18812					}
18813
18814				}
18815
18816				reader.readAsDataURL(file);
18817
18818			},
18819
18820			// delete last bulk added (multiple file only)
18821			file_upload__del_bulk: function(_t, _bulkNo, btn_clear_files, preview_container, input_name, fileInputIdentifier) {
18822
18823				// clear last added!
18824				for (var b = 0; b < window.filesLastBulk.length; ++b) {
18825
18826					// remove last bulk added only
18827					jQuery('#'+_bulkNo).remove(); // file input
18828					jQuery('.'+_bulkNo).remove(); // images
18829
18830					// check if other files are there. if not, reset
18831					var _remains = jQuery('.js-file-input-item', preview_container).length;
18832					if(_remains < 1)
18833						$.SOW.core.file_upload.file_upload__reset(_t, btn_clear_files, preview_container, input_name, fileInputIdentifier);
18834
18835				}
18836
18837				// reset
18838				$.SOW.core.file_upload.file_upload__clear(fileInputIdentifier);
18839				window.fileInventory[fileInputIdentifier] = [];
18840
18841			},
18842
18843			file_upload__preview_delbtn_bind_multiple: function(_t, request_from_preadded) {
18844
18845				var fileInputIdentifier = _t.attr('data-js-advanced-identifier') 	|| '',
18846					preview_container 	= _t.attr('data-file-preview-container') 	|| '',
18847					preview_delete 		= _t.attr('data-file-ajax-delete-enable') 	|| false,
18848					ajax_url 			= _t.attr('data-file-ajax-delete-url') 		|| _t.attr('data-file-ajax-upload-url'),
18849					ajax_params 		= _t.attr('data-file-ajax-delete-params') 	|| '',
18850					is_multiple 		= _t.attr('multiple') 						|| false,
18851					preview_height 		= _t.attr('data-file-preview-img-height') 	|| '120';
18852
18853				if(preview_container == '' || is_multiple == false)
18854					return;
18855
18856				else if(ajax_url == '' || preview_delete == false) {
18857
18858					// remove delete button
18859					jQuery(preview_container + ' a.js-file-item-del').remove();
18860
18861					return;
18862				}
18863
18864				// --
18865
18866
18867				// Setting up preadded files
18868				if(request_from_preadded === true) {
18869					jQuery(preview_container + ' .js-file-input-item').each(function() {
18870
18871						var elItemPreadded 		= jQuery(this),
18872							_preaddedItemId		= 'rand_' + $.SOW.helper.randomStr(3);
18873
18874						elItemPreadded.attr('id', _preaddedItemId);
18875
18876						jQuery('img', elItemPreadded).attr('height', preview_height);
18877						jQuery('a.js-file-item-del', elItemPreadded).attr('data-item-id', _preaddedItemId); 		// DOM item id
18878
18879					});
18880				}
18881
18882				var btn_file_del = preview_container + ' a.js-file-item-del';
18883				$.SOW.core.file_upload.file_upload__preview_item_del_ajax(fileInputIdentifier, btn_file_del, ajax_params, ajax_url);
18884
18885			},
18886
18887			file_upload__preview_delbtn_bind_single: function(_t, request_from_preadded) {
18888
18889				var fileInputIdentifier = _t.attr('data-js-advanced-identifier') 	|| '',
18890					preview_container 	= _t.attr('data-file-preview-container') 	|| '',
18891					preview_delete 		= _t.attr('data-file-ajax-delete-enable') 	|| false,
18892					ajax_url 			= _t.attr('data-file-ajax-delete-url') 		|| _t.attr('data-file-ajax-upload-url'),
18893					ajax_params 		= _t.attr('data-file-ajax-delete-params') 	|| '',
18894					btn_clear 			= _t.attr('data-file-btn-clear') 			|| '',
18895					is_multiple 		= _t.attr('multiple') 						|| false;
18896
18897				if(is_multiple != false || btn_clear == '' || ajax_url == '' || preview_delete == false)
18898					return;
18899
18900				// We use the same button as "delete" button normally added by the template
18901				jQuery(btn_clear).addClass('js-file-item-del');
18902
18903				// Setting up
18904				var elItemPreadded 		= jQuery(preview_container + ' .js-file-input-item'),
18905					_preaddedFileName 	= elItemPreadded.attr('data-file-name') 	|| '',
18906					_preaddedItemId		= elItemPreadded.attr('id') 				|| '';
18907
18908				if(elItemPreadded.length < 1)
18909					return;
18910
18911				// Disable input
18912				_t.prop('disabled', true);
18913
18914				if(_preaddedItemId == '') {
18915					_preaddedItemId	= 'rand_' + $.SOW.helper.randomStr(3);
18916					elItemPreadded.attr('id', _preaddedItemId);
18917				}
18918
18919				jQuery(btn_clear).attr('data-item-id', _preaddedItemId); 		// DOM item id
18920
18921				$.SOW.core.file_upload.file_upload__preview_item_del_ajax(fileInputIdentifier, btn_clear, ajax_params, ajax_url);
18922
18923				// REQUIRED: AFTER file_upload__preview_item_del_ajax()
18924				if(request_from_preadded === true) {
18925					var input_name 	= _t.attr('name') || _t.data('orig-name');
18926					$.SOW.core.file_upload.file_upload__btn_clear_bind(btn_clear, _t, preview_container, input_name, fileInputIdentifier);
18927				}
18928
18929			},
18930
18931			file_upload__preview_item_del_ajax: function(fileInputIdentifier, btn_file_del, ajax_params, ajax_url) {
18932
18933				jQuery(btn_file_del).not('.js-advancified').addClass('js-advancified').on('click', function(e) {
18934					e.preventDefault();
18935
18936					var elBtn 		= jQuery(this),
18937						item_id 	= elBtn.attr('data-item-id') 					|| '';
18938
18939					if(item_id == '') // required
18940						return;
18941
18942					var elItem 		= $('#'+item_id),
18943						fileName 	= elItem.attr('data-file-name') 				|| '',
18944						fileSize 	= elItem.attr('data-file-size') 				|| 0,
18945						fileID 		= elItem.attr('data-id') 						|| 0;
18946
18947					if(fileName == '' && item_id == '') {
18948						$.SOW.helper.consoleLog('Delete request not sent!');
18949						$.SOW.helper.consoleLog('Please provide: data-id  -OR-  data-file-name ');
18950						return;
18951					}
18952
18953
18954					/*
18955
18956						Form & custom params
18957
18958					*/
18959					var formDataDel = new FormData();
18960					formDataDel.append('action', 'delete_file');
18961					formDataDel.append('ajax', 'true');
18962
18963					var ajax_params_arr = $.SOW.helper.params_parse(ajax_params);
18964					for (var i = 0; i < ajax_params_arr.length; ++i) {
18965						formDataDel.append(ajax_params_arr[i][0], ajax_params_arr[i][1]);
18966					}
18967
18968					// Add required params to form
18969					formDataDel.append('file_name', fileName);
18970					formDataDel.append('file_id', fileID);
18971					formDataDel.append('__info', '`file_id` = internal/database file id. 0 = not provided!');
18972
18973					// --
18974
18975					$.ajax({
18976						url: 			ajax_url,
18977						cache: 			false,
18978						contentType: 	false,
18979						processData: 	false,
18980						data: 			formDataDel,
18981						type: 			'POST',
18982						headers: 		'',
18983						crossDomain: 	'',
18984
18985						beforeSend: function() {
18986
18987
18988						},
18989
18990						success: function (data) {
18991
18992							$.SOW.helper.consoleLog(data);
18993
18994							// remove file from the list
18995							if(item_id != '')
18996								jQuery('#'+item_id).remove();
18997
18998
18999
19000							// remove from inventory, or the file could not be added again
19001							if(fileSize != '') {
19002
19003								var _concat = fileName+':'+fileSize+':'+fileInputIdentifier;
19004								for (var inventoryIndex in window.fileInventory[fileInputIdentifier]) {
19005									if(window.fileInventory[fileInputIdentifier][inventoryIndex] == _concat) {
19006										window.fileInventory[fileInputIdentifier].splice(inventoryIndex,1);
19007										break;
19008									}
19009								} // --
19010
19011							}
19012
19013						},
19014
19015						error: function (data) {
19016
19017							$.SOW.helper.consoleLog(data);
19018
19019							if(typeof $.SOW.core.toast === 'object') {
19020								$.SOW.core.toast.show('danger', '', '404 Server Error!', $.SOW.core.file_upload.config.toast_pos, $.SOW.core.file_upload.config.toast_delay, true);
19021							} else {
19022								alert('404 Server Error!');
19023							}
19024
19025						},
19026
19027					});
19028
19029				});
19030
19031			},
19032
19033			file_upload__preview__reorder_bind: function(_t, request_from_preadded) {
19034
19035				var sortableProcessDelay = 0;
19036
19037				if(typeof $.SOW.vendor.sortable !== 'object') {
19038
19039					$.SOW.helper.consoleLog('Ajax Image Reorder : Require Sortablejs Vendor!');
19040					return;
19041
19042				} else {
19043
19044					// sortable is external?
19045					if (typeof Sortable !== 'function') {
19046
19047						var sortableProcessDelay = 1300;
19048
19049						if($.SOW.config.autoinit['sortable']) {
19050							var _selector 	= $.SOW.config.autoinit['sortable'][1];
19051							var _config 	= $.SOW.config.autoinit['sortable'][2];
19052							var _class 		= _selector.replace('.', '');
19053							jQuery('#middle').append('<span class="hide '+_class+'"></span>');
19054							$.SOW.vendor.sortable.init(_selector, _config);
19055						} else { return false; }
19056					}
19057
19058				}
19059
19060
19061				var fileInputIdentifier 	= _t.attr('data-js-advanced-identifier') 			|| '',
19062					fileInputName 			= _t.attr('name') 									|| _t.attr('data-orig-name'),
19063					preview_container 		= _t.attr('data-file-preview-container') 			|| '',
19064					ajax_url 				= _t.attr('data-file-ajax-reorder-url') 			|| _t.attr('data-file-ajax-upload-url'),
19065					ajax_params 			= _t.attr('data-file-ajax-reorder-params') 			|| '',
19066					reorder_toast_success 	= _t.attr('data-file-ajax-reorder-toast-success') 	|| '',
19067					reorder_toast_position 	= _t.attr('data-file-ajax-reorder-toast-position') 	|| '',
19068					preview_reorder 		= _t.attr('data-file-ajax-reorder-enable') 			|| false;
19069
19070				if(preview_container == '')
19071					return;
19072
19073				else if(ajax_url == '' || preview_reorder == false) {
19074
19075					// remove draggable attribute
19076					jQuery(preview_container + ' .js-file-input-item').removeAttr('draggable');
19077
19078					return;
19079
19080				}
19081
19082				// --
19083
19084				// add .js-ignore filter for all other items that are not files (texts, titles, etc)
19085				jQuery('>:not(.js-file-input-item)', preview_container).addClass('js-ignore');
19086
19087				// Add Sortable required params
19088				jQuery(preview_container).attr('data-ajax-update-url', ajax_url);
19089				jQuery(preview_container).attr('data-ajax-update-params', ajax_params);
19090				jQuery(preview_container).attr('data-ajax-update-identifier', fileInputName.replace('[]', ''));
19091
19092				if(reorder_toast_success != '')
19093					jQuery(preview_container).attr('data-update-toast-success', reorder_toast_success);
19094
19095				if(reorder_toast_position != '')
19096					jQuery(preview_container).attr('data-update-toast-position', reorder_toast_position);
19097
19098				setTimeout(function() {
19099					$.SOW.vendor.sortable.process($(preview_container));
19100				}, sortableProcessDelay);
19101
19102			},
19103
19104			file_upload__btn_clear_bind: function(btn_clear_files, _t, preview_container, input_name, fileInputIdentifier) {
19105
19106				// show `remove all files` button
19107				jQuery(btn_clear_files).removeClass('hide').on('click', function(e) {
19108					e.preventDefault();
19109
19110					// added by file_upload__preview_delbtn_bind_single()
19111					jQuery(this).removeAttr('data-item-id data-id data-file-name');
19112
19113					$.SOW.core.file_upload.file_upload__reset(_t, btn_clear_files, preview_container, input_name, fileInputIdentifier);
19114				});
19115
19116			},
19117
19118			file_upload__ajax_upload: function(fileInputIdentifier, _bulkNo) {
19119
19120
19121				if(_bulkNo == '' && fileInputIdentifier == '') {
19122					$.SOW.helper.consoleLog('Ajax Image Upload Status : Identifiers missing!');
19123					return;
19124				}
19125
19126
19127				// Getting Data
19128				var fileInventory 		= [],
19129					elFileInput 		= jQuery('input[type="file"][data-js-advanced-identifier="'+fileInputIdentifier+'"]'),
19130					ajax_url 			= elFileInput.data('file-ajax-upload-url') 				|| '',
19131					ajax_params 		= elFileInput.data('file-ajax-upload-params') 			|| '',
19132					msg_success 		= elFileInput.data('file-ajax-toast-success-txt') 		|| '',
19133					msg_error 			= elFileInput.data('file-ajax-toast-error-txt') 		|| '',
19134					btn_remove 			= elFileInput.data('file-btn-clear') 					|| '',
19135					form_name 			= elFileInput.attr('name') 								|| elFileInput.data('orig-name'),
19136					ajax_callback 		= elFileInput.data('file-ajax-callback-function') 		|| '',
19137					is_multiple 		= elFileInput.attr('multiple') 							|| false,
19138					preview_container 	= elFileInput.data('file-preview-container') 			|| '',
19139					preview_reorder 	= elFileInput.data('file-ajax-reorder-enable') 			|| false,
19140					progressDisabled 	= elFileInput.data('file-ajax-progressbar-disable') 	|| false,
19141					toast_position		= elFileInput.data('file-toast-position') 				|| $.SOW.core.file_upload.config.toast_pos;
19142
19143
19144				// search for from as parent, if exists
19145				if(ajax_url == '') {
19146
19147					if(elFileInput.parents('form').length > 0)
19148						ajax_url = elFileInput.parents('form').attr('action');
19149
19150				}
19151
19152				// still empty?
19153				if(ajax_url == '') {
19154					$.SOW.helper.consoleLog('Ajax Image Upload Status : [data-file-ajax-upload-url] : Missing -or- Empty!');
19155					return;
19156				}
19157
19158
19159
19160
19161
19162
19163
19164
19165
19166
19167
19168				/*
19169
19170					1. Bulk only
19171
19172				*/
19173				if(_bulkNo != '') {
19174
19175					if(window.browser_hasIssues === true) {
19176						var _t = jQuery('input[type="file"][data-js-advanced-identifier="'+fileInputIdentifier+'"]');
19177					} else {
19178						var _t = jQuery('input[type="file"]#'+_bulkNo);
19179					}
19180
19181
19182					for (var i = 0; i < _t.get(0).files.length; ++i) {
19183						fileInventory.push(_t.get(0).files[i]);
19184					}
19185
19186
19187				/*
19188
19189					2. All bulks at once (for safari or other browsers with issue)
19190
19191				*/
19192				} else {
19193
19194					if(window.browser_hasIssues === true) {
19195						var _t = jQuery('input[type="file"][data-js-advanced-identifier="'+fileInputIdentifier+'"]');
19196					} else {
19197						var _t = jQuery('#js_advanced_form_identifier_'+fileInputIdentifier+'>input[type="file"]');
19198					}
19199
19200
19201					_t.each(function() {
19202
19203						var files 	= jQuery(this).get(0).files;
19204
19205						for (var i = 0; i < files.length; ++i) {
19206							fileInventory.push(files[i]);
19207						}
19208
19209					});
19210
19211				}
19212
19213
19214
19215
19216
19217
19218
19219				// Safe Check
19220				if(fileInventory.length < 1) {
19221					$.SOW.helper.consoleLog('Ajax Image Upload Status : No file found to upload!');
19222					return;
19223				}
19224
19225
19226
19227
19228				// Create form
19229				var formData = new FormData();
19230				// -- -- -- --
19231
19232
19233
19234
19235
19236				// Add custom params to post +++++++++++++++++++++++++++++++++++++++
19237				var ajax_params_arr = $.SOW.helper.params_parse(ajax_params);
19238				for (var i = 0; i < ajax_params_arr.length; ++i) {
19239					formData.append(ajax_params_arr[i][0], ajax_params_arr[i][1]);
19240				}
19241
19242				// Of course, our eternal param :)
19243				formData.append('ajax', 'true');
19244				// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19245
19246
19247
19248
19249
19250				// add files to form +++++++++++++++++++++++++++++++++++++++++++++++
19251				for (var i = 0; i < fileInventory.length; ++i) {
19252					formData.append(form_name, fileInventory[i]);
19253				}
19254				// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19255
19256
19257
19258
19259
19260				$.ajax({
19261					url: 			ajax_url,
19262					cache: 			false,
19263					contentType: 	false,
19264					processData: 	false,
19265					data: 			formData,
19266					type: 			'POST',
19267					enctype: 		'multipart/form-data',
19268					headers: 		'',
19269					crossDomain: 	'',
19270
19271					beforeSend: function() {
19272
19273						jQuery('.js-file-input-item.'+_bulkNo+' .js-file-input-preview-ajax-uploading').removeClass('hide hide-force');
19274						// jQuery(btn_remove).addClass('hide hide-force'); // button "remove files"
19275
19276						elFileInput.addClass('disabled').prop('disabled', true);
19277						elFileInput.parents('.btn').addClass('disabled active');
19278						elFileInput.parent().find('.js-file-input-ajax-loader').removeClass('hide hide-force');
19279
19280						// Create progress bar
19281						$.SOW.core.file_upload.file_upload__ajax_upload_progressbar_init(elFileInput);
19282
19283					},
19284
19285					success: function (data) {
19286
19287						$.SOW.helper.consoleLog(data);
19288						elFileInput.removeClass('disabled').prop('disabled', false);
19289						elFileInput.parents('.btn').removeClass('disabled active');
19290						elFileInput.parent().find('.js-file-input-ajax-loader').addClass('hide hide-force');
19291
19292						jQuery('.js-file-input-item.'+_bulkNo+' .js-file-input-preview-ajax-uploading i').replaceWith('<i class="'+$.SOW.config.sow__icon_check+' fs--20 pt--5 text-success w--40 h--40 d-inline-block text-center bg-success-soft rounded-circle opacity-8 animate-bouncein"></i>');
19293						setTimeout(function() {
19294
19295							jQuery('.js-file-input-item.'+_bulkNo+' .js-file-input-preview-ajax-uploading').fadeOut(200, function() {
19296								jQuery(this).remove();
19297							});
19298
19299						}, $.SOW.core.file_upload.config.toast_delay);
19300
19301
19302						if(typeof $.SOW.core.toast === 'object' && msg_success != '')
19303							$.SOW.core.toast.show('success', '', msg_success, toast_position, $.SOW.core.file_upload.config.toast_delay, true);
19304
19305
19306						// callback function
19307						if(ajax_callback != '' && typeof $.SOW.helper.executeFunctionByName === "function")
19308							$.SOW.helper.executeFunctionByName(ajax_callback, window, data, elFileInput); // input element is returned because of safari issues (bulk is empty)
19309
19310						// Destroy progress bar
19311						$.SOW.core.file_upload.file_upload__ajax_upload_progressbar_destroy(elFileInput, false);
19312
19313
19314						// Disable input
19315						if(is_multiple === false)
19316							elFileInput.prop('disabled', true);
19317
19318						/**
19319
19320							UPDATE FOR REORDER
19321							If backend provided required data (internal id)
19322
19323							data-id="0"
19324							data-file-name="file.jpg"
19325
19326
19327							PHP Example
19328							Server response format:
19329
19330								$response = array(
19331									'file_list'	=> array(
19332
19333										// original file name 		internal id
19334										'orig_file_name_1.jpg'		=> 1,
19335										'orig_file_name_2.jpg'		=> 345,
19336
19337										// ...
19338
19339									),
19340
19341									// more stuff for callback (if used)
19342									'something_else'	=> array(),
19343								);
19344
19345								echo json_encode($response);
19346								exit;
19347
19348						**/
19349						// if(preview_reorder != false) {
19350
19351							/* test */ // var data = {"file_list":{"orig_file_name_1.jpg":1,"orig_file_name_2.jpg":345},"something_else":[]}
19352							try {
19353
19354								var _json = JSON.parse(data);
19355
19356							} catch(err) {
19357
19358								// No json, we do nothing!
19359								var _json = '';
19360
19361							}
19362
19363							if(_json != '') {
19364
19365								if(typeof _json['file_list'] !== 'undefined') {
19366
19367									for (var fileName in _json['file_list']) {
19368
19369										jQuery(preview_container + ' .js-file-input-item[data-file-name="'+fileName+'"]').attr('data-id', _json['file_list'][fileName]);
19370
19371									}
19372
19373								}
19374
19375								// Bind reorder
19376								$.SOW.core.file_upload.file_upload__preview__reorder_bind(jQuery(preview_container), true);
19377
19378							}
19379
19380						// } // end preview reorder
19381
19382					},
19383
19384					error: function (data) {
19385
19386						$.SOW.helper.consoleLog(data);
19387
19388						elFileInput.removeClass('disabled').prop('disabled', false);
19389						elFileInput.parents('.btn').removeClass('disabled active');
19390						elFileInput.parent().find('.js-file-input-ajax-loader').addClass('hide hide-force');
19391
19392						jQuery('.js-file-input-item.'+_bulkNo+' .js-file-input-preview-ajax-uploading i').replaceWith('<i title="Ajax upload error!" class="'+$.SOW.config.sow__icon_close+' fs--20 text-success w--40 h--40 pt--5 d-inline-block text-center bg-danger-soft rounded-circle opacity-8 animate-bouncein"></i>');
19393						if(typeof $.SOW.core.toast === 'object' && msg_error != '')
19394							$.SOW.core.toast.show('danger', '', msg_error, toast_position, $.SOW.core.file_upload.config.toast_delay, true);
19395
19396						// Destroy progress bar
19397						$.SOW.core.file_upload.file_upload__ajax_upload_progressbar_destroy(elFileInput, false);
19398
19399					},
19400
19401					// progress bar
19402					xhr: function() {
19403
19404						var __xhr = new XMLHttpRequest();
19405
19406						__xhr.upload.addEventListener("progress", function(e) {
19407
19408							if(e.lengthComputable && progressDisabled == false) {
19409
19410								var ___percent 	= e.loaded / e.total,
19411									___percent 	= Math.round(___percent * 100); 	// (___percent * 100);  -or-  Math.round(___percent * 100);
19412
19413								$('.js_file_input_progress__'+fileInputIdentifier + ' .js-file-input-upload-percent').text(___percent+'%');
19414								$('.js_file_input_progress__'+fileInputIdentifier + ' .progress-bar').
19414css('width', ___percent+'%');
19415								$('.js_file_input_progress__'+fileInputIdentifier + ' .progress-bar').attr('aria-valuenow', ___percent);
19416
19417								if(___percent >= 100) {
19418
19419									// we add "ok" icon only to the dynamic progress created by this script, not to custom
19420									$('.js_file_input_progress__'+fileInputIdentifier + ' .js-file-input-upload-percent.js-file-input-upload-percent-dynamic').prepend('<i class="'+$.SOW.config.sow__icon_check+' fs--10 animate-bouncein"></i> &nbsp; ');
19421
19422									// we add some common classes as helpers to custom progress, in case needed as extra!
19423									$('.js_file_input_progress__'+fileInputIdentifier + ', .js_file_input_progress__'+fileInputIdentifier + ' .js-file-input-upload-percent:not(.js-file-input-upload-percent-dynamic) .group-icon').addClass('active');
19424
19425								}
19426
19427							}
19428
19429						}, false);
19430
19431						return __xhr;
19432
19433					}
19434
19435
19436				});
19437
19438			},
19439
19440			file_upload__ajax_upload_progressbar_init: function(elFileInput) {
19441
19442				if(elFileInput.length < 1)
19443					return;
19444
19445				var fileInputIdentifier = elFileInput.data('js-advanced-identifier') 			|| '',
19446					customProgress 		= elFileInput.data('file-ajax-progressbar-custom') 		|| '',
19447					progressDisabled 	= elFileInput.data('file-ajax-progressbar-disable') 	|| false,
19448					__next 				= elFileInput.next();
19449
19450				if(fileInputIdentifier == '' || progressDisabled != false)
19451					return;
19452
19453
19454
19455
19456
19457
19458
19459				// ++ ++ ++ ++ ++ ++ ++ Check custom progress ++ ++ ++ ++ ++ ++
19460				if(jQuery(customProgress).length > 0) {
19461
19462					var elCustomProgress = jQuery(customProgress);
19463
19464					// usually first init, should have the class in place each call (new upload)
19465					if(!elCustomProgress.hasClass('js_file_input_progress__' + fileInputIdentifier))
19466						elCustomProgress.addClass('js_file_input_progress__' + fileInputIdentifier);
19467
19468
19469					// Reset progress. If previously used should be at 100% now
19470					jQuery('.progress-bar', elCustomProgress).css('width', '0%');
19471					jQuery('.progress-bar', elCustomProgress).css('width', '0%');
19472					jQuery('.js-file-input-upload-percent', elCustomProgress).text('0%');
19473					elCustomProgress.removeClass('hide hide-force');
19474
19475
19476					// Done! Ajax function will do the update!
19477					return;
19478
19479				}
19480				// ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
19481
19482
19483
19484
19485
19486
19487
19488				// ++ ++ ++ ++ ++ Finding a place for progress bar ++ ++ ++ ++ ++
19489				// If input is inside a <label>
19490				if(elFileInput.parents('label').length > 0)
19491					__next = elFileInput.parents('label');
19492
19493				// bootstrap custom file
19494				else if(elFileInput.parents('div.custom-file').length > 0)
19495					__next = elFileInput.parents('div.custom-file');
19496				// ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
19497
19498
19499
19500				// Remove first, in case already exists!
19501				jQuery('.js_file_input_progress__'+fileInputIdentifier).remove();
19502
19503
19504
19505				// PROGRESS TEMPLATE ++++++++++++
19506				var _tpl = '<span class="js_file_input_progress__'+fileInputIdentifier+' animate-bouncein transition-all-ease-500 position-absolute w-100 mb--n5 bottom-0 left-0 right-0 h--3">'
19507								+ '<span class="progress rounded h--3">'
19508									+ '<span class="progress-bar bg-success" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></span>'
19509								+ '</span>'
19510								+ '<i class="js-file-input-upload-percent js-file-input-upload-percent-dynamic float-start mb--n20 z-index-2 text-dark fs--11">0%</i>'
19511							+ '</span>';
19512				// ++++++++++++++++++++++++++++++
19513				__next.append(_tpl); 	// Append inside, absolute position used!
19514				// ++++++++++++++++++++++++++++++
19515
19516
19517				// Done! Ajax function will do the update!
19518
19519			},
19520
19521			file_upload__ajax_upload_progressbar_destroy: function(elFileInput, elDestroyForReal) {
19522
19523
19524				if(elFileInput.length < 1)
19525					return;
19526
19527				var fileInputIdentifier = elFileInput.data('js-advanced-identifier') || '';
19528
19529				if(fileInputIdentifier == '')
19530					return;
19531
19532
19533
19534				// Wait a little bit, sometimes the upload is too fast for small files
19535				// and we want to impress the visitor with our shiny progress bar pointing to 100% DONE!
19536				// Whooo!
19537				setTimeout(function() {
19538
19539					jQuery('.js_file_input_progress__'+fileInputIdentifier).not('.js-ignore').fadeOut(800, function() {
19540
19541
19542						/*
19543
19544							Should be removed only dynamic progress bars
19545							Custom ones should only be hidden, if .js-ignore not present, of course!
19546
19547						*/
19548						if(elDestroyForReal === true)
19549							jQuery(this).remove();
19550
19551					});
19552
19553				}, 1000);
19554
19555			},
19556
19557			file_upload__destroy: function(container) {
19558				var container = (typeof container === 'undefined') ? '' : container;
19559
19560				jQuery(container + ' ' + $.SOW.core.file_upload.config.selector_advanced_file).each(function() {
19561
19562					var _t 			= jQuery(this),
19563						input_name 	= _t.attr('name') || _t.data('orig-name');
19564
19565					// remove class
19566					_t.removeClass('js-advancified');
19567
19568					// destroy any progress bar
19569					$.SOW.core.file_upload.file_upload__ajax_upload_progressbar_destroy(_t, true);
19570
19571					// restoring back to original
19572					_t.val('').attr('name', input_name).removeAttr('data-orig-name');
19573
19574					// set back "Choose file" label
19575					var label_orig = _t.next('.custom-file-label').attr('data-orig') || 'Choose file';
19576					_t.next('.custom-file-label').html(label_orig);
19577
19578					// replace with a clone!
19579					var _cl = _t.clone().off('change');
19580					_t.replaceWith(_cl);
19581
19582					jQuery('div>.js-file-input-item:first-child').parent().empty();
19583
19584				});
19585
19586				window.fileInventory 		= {};
19587				window.filesLastBulk 		= [];
19588				window.filesSizeBulk 		= 0;
19589
19590			}
19591
19592	}
19593
19594})(jQuery);
19595/**
19596 *
19597 *	[SOW] Toast
19598 *
19599 *	@author 		Dorin Grigoras
19600 *					www.stepofweb.com
19601 *
19602 *	@Dependency 	-
19603 *	@Usage			$.SOW.core.toast.init('.toast-on-load');
19604 *
19605 *
19606 **/
19607;(function ($) {
19608	'use strict';
19609
19610
19611	/**
19612	 *
19613	 *	@vars
19614	 *
19615	 *
19616	 **/
19617	var scriptInfo 		= 'SOW Toast';
19618
19619
19620
19621	$.SOW.core.toast = {
19622
19623
19624		/**
19625		 *
19626		 *	@config
19627		 *
19628		 *
19629		 **/
19630		config: {
19631			animation: 'fade'
19632		},
19633
19634
19635
19636		/**
19637		 *
19638		 *	@collection
19639		 *
19640		 *
19641		 **/
19642		collection: $(),
19643
19644
19645
19646		/**
19647		 *
19648		 *	@init
19649		 *
19650		 *
19651		 **/
19652		init: function (selector, config) {
19653
19654			var __selector 			= $.SOW.helper.__selector(selector);
19655			var __config 			= $.SOW.helper.check_var(config);
19656
19657			this.selector 			= __selector[0]; 	// '#selector'
19658			this.collection 		= __selector[1]; 	// $('#selector')
19659			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
19660
19661
19662
19663			if(jQuery(this.selector).length < 1)
19664				return;
19665
19666
19667
19668			// -- * --
19669			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
19670			// -- * --
19671
19672
19673			// 1. Has no selector
19674			if(!this.selector) {
19675				$.SOW.core.toast.toast_on_load('.toast-on-load');
19676				return this.collection;
19677			}
19678
19679			// 2. Has selector
19680			return this.collection.each(function() {
19681
19682				$.SOW.core.toast.toast_on_load($(this));
19683
19684			});
19685
19686		},
19687
19688
19689
19690		/**
19691		 *
19692		 *	@show
19693		 *	Direct callable
19694		 *
19695
19696			$.SOW.core.toast.show(type, title, body, pos, delay, fill);
19697				type 			= '', success, danger, warning, info
19698				title 			= toast title 	(optional)
19699				body 			= toast body 	(required)
19700				pos 			= top-left, top-right, bottom-left, bottom-right, top-center, bottom-center
19701				delay 			= autoclose in ms
19702				fill 			= background color [true|false]
19703
19704
19705
19706			1. NO AUTOHIDE
19707				$.SOW.core.toast.show('', 'Default', 'Body Text Here', 'top-right');
19708				$.SOW.core.toast.show('danger', 'Error', 'Body Text Here', 'top-right');
19709				$.SOW.core.toast.show('success', 'Success', 'Body Text Here', 'top-right');
19710				$.SOW.core.toast.show('warning', 'Warning', 'Body Text Here', 'top-right');
19711				$.SOW.core.toast.show('info', 'Info', 'Body Text Here', 'top-right');
19712
19713			2. AUTOHIDE
19714				$.SOW.core.toast.show('', 'Default', 'Body Text Here', 'top-right', 3000);
19715				$.SOW.core.toast.show('danger', 'Error', 'Body Text Here', 'top-right', 3000);
19716				$.SOW.core.toast.show('success', 'Success', 'Body Text Here', 'top-right', 3000);
19717				$.SOW.core.toast.show('warning', 'Warning', 'Body Text Here', 'top-right', 3000);
19718				$.SOW.core.toast.show('info', 'Info', 'Body Text Here', 'top-right', 3000);
19719
19720			3. NO TITLE
19721				$.SOW.core.toast.show('', '', 'Body Text Here', 'top-right');
19722				$.SOW.core.toast.show('danger', '', 'Body Text Here', 'top-right');
19723				$.SOW.core.toast.show('success', '', 'Body Text Here', 'top-right');
19724				$.SOW.core.toast.show('warning', '', 'Body Text Here', 'top-right');
19725				$.SOW.core.toast.show('info', '', 'Body Text Here', 'top-right');
19726
19727			1. NO TITLE + BACKGROUND FILL
19728				$.SOW.core.toast.show('', '', 'Body Text Here', 'top-right', 0, true);
19729				$.SOW.core.toast.show('danger', '', 'Body Text Here', 'top-right', 0, true);
19730				$.SOW.core.toast.show('success', '', 'Body Text Here', 'top-right', 0, true);
19731				$.SOW.core.toast.show('warning', '', 'Body Text Here', 'top-right', 0, true);
19732				$.SOW.core.toast.show('info', '', 'Body Text Here', 'top-right', 0, true);
19733
19734
19735			Clear all toasts
19736				$.SOW.core.toast.destroy();
19737
19738		 *
19739		 *
19740		 **/
19741		show: function(t_type, t_title, t_body, t_pos, t_delay, t_bg_fill) {
19742
19743			var t_type 		= typeof t_type 	!== 'undefined' ? t_type 	: '', 		// default|success|danger[error]|warning|info
19744				t_title 	= typeof t_title 	!== 'undefined' ? t_title 	: '',
19745				t_body 		= typeof t_body 	!== 'undefined' ? t_body 	: '',
19746				t_pos 		= typeof t_pos 		!== 'undefined' ? t_pos 	: 'top-left',
19747				t_delay 	= typeof t_delay 	!== 'undefined' ? t_delay 	: 0,
19748				t_bg_fill 	= typeof t_bg_fill 	!== 'undefined' ? t_bg_fill : false;
19749
19750			if(t_type == 'error')
19751				var t_type = 'danger';
19752
19753			else if(t_type == 'default')
19754				var t_type = '';
19755
19756			// In case body is empty but we have the title - switch between them!
19757			if(t_body == '' && t_title != '') {
19758				var t_body 		= t_title;
19759				var t_title 	= '';
19760			}
19761
19762
19763			// --
19764
19765
19766			// top right
19767			if(t_pos == 'top-right') {
19768				var _posClass 	= 'fixed-top right-0';
19769				var _wrapperID 	= 'wrapper_toast_tr';
19770				var t_spacing	= 'mt--15 mr--30';
19771			}
19772
19773			// bottom right
19774			else if(t_pos == 'bottom-right') {
19775				var _posClass 	= 'fixed-bottom right-0';
19776				var _wrapperID 	= 'wrapper_toast_br';
19777				var t_spacing	= 'mb--15 mr--30';
19778			}
19779
19780			// top left
19781			else if(t_pos == 'top-left') {
19782				var _posClass 	= 'fixed-top left-0';
19783				var _wrapperID 	= 'wrapper_toast_tl';
19784				var t_spacing	= 'mt--15 ml--30';
19785			}
19786
19787			// bottom left
19788			else if(t_pos == 'bottom-left') {
19789				var _posClass 	= 'fixed-bottom left-0';
19790				var _wrapperID 	= 'wrapper_toast_bl';
19791				var t_spacing	= 'mb--15 ml--30';
19792			}
19793
19794			// top center
19795			if(t_pos == 'top-center') {
19796				var _posClass 	= 'fixed-top mx-auto';
19797				var _wrapperID 	= 'wrapper_toast_tc';
19798				var t_spacing	= 'mt--15';
19799			}
19800
19801
19802			// bottom center
19803			if(t_pos == 'bottom-center') {
19804				var _posClass 	= 'fixed-bottom mx-auto';
19805				var _wrapperID 	= 'wrapper_toast_bc';
19806				var t_spacing	= 'mb--15';
19807			}
19808
19809
19810			// --
19811
19812			// Toast icon indicator
19813			var t_icon 		= (t_type != '') ? '<i class="float-start rounded-circle w--15 h--15 mt--3 bg-'+t_type+'"></i>' : '';
19814
19815			// Autohide in ms
19816			var t_delay_bs 	= (t_delay > 0) ? ' data-delay="'+t_delay+'" data-autohide="true"' : ' data-autohide="false" ';
19817
19818			// Close Button & Progress
19819			if(t_delay > 0) {
19820
19821				var t_close 		= '';
19822				var t_progress 		= '<div class="mt--n1"><div class="progress h--1 bg-transparent"><div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 100%; background-color: #121212; opacity:0.2"></div></div></div>';
19823
19824			} else {
19825
19826				var _btnCloseClass 	= (t_title == '') ? ' fs--10 mt--n1 ' : '';
19827				var t_close 		= '<button type="button" class="close float-end'+_btnCloseClass+'" data-dismiss="toast" aria-label="Close"><span class="fi fi-close fs--16" aria-hidden="true"></span></button>';
19828				var t_progress 		= '';
19829
19830			}
19831
19832
19833			// --
19834
19835			// Create specific main container if not exists (to avoid destroying current toasts)
19836			if(jQuery('#'+_wrapperID).length < 1)
19837				jQuery('body').append('<div id="'+_wrapperID+'" class="w-100 max-w-300 max-h-75vh scrollable-vertical rounded z-index-9999 '+_posClass+'"></div>');
19838
19839
19840			// --
19841
19842
19843			// BUILD HTML TOAST
19844			var t_main_class = (t_bg_fill === true && t_type != '') ? 'b--0 bg-'+t_type : 'bg-white';
19845			var _toastBody = '<div class="toast js-toast '+$.SOW.core.toast.config.animation+' '+t_main_class+' '+t_spacing+'" role="alert" aria-live="polite" aria-atomic="true" '+t_delay_bs+'>';
19846
19847			// No title
19848			if(t_title != '') {
19849
19850				// remove icon on fill
19851				t_icon = (t_bg_fill === true) ? '' : t_icon;
19852
19853				var t_header_class = (t_bg_fill === true && t_type != '') ? ' bg-transparent overlay-dark overlay-opacity-1 text-white' : '';
19854
19855				var _toastBody = _toastBody + '<div class="toast-header'+t_header_class+'">'
19856
19857					+ '<div class="w-100 text-truncate">'
19858						+ t_icon
19859						+ '<strong>' + t_title + '</strong>'
19860					+ '</div>'
19861
19862					+ '<div class="w--180 text-align-end">'
19863						//+ '<small class="d-inline-block pt--6 w--80 text-truncate">11 mins ago</small>'
19864						+ t_close
19865					+ '</div>'
19866
19867				+ '</div>';
19868
19869			}
19870
19871			// Add close button to body, because we have no title
19872			var _closeBtnBody = (t_title == '') ? t_close : '';
19873
19874			// Add Color to body text if no title available
19875			if(t_title == '') {
19876
19877				if(t_bg_fill === true && (t_type == 'success-soft' || t_type == 'danger-soft' || t_type == 'info-soft' || t_type == 'warning-soft' || t_type == 'primary-soft' || t_type == 'pink-soft' || t_type == 'indigo-soft')) {
19878					var t_txt_color = '';
19879				} else  {
19880					var t_txt_color = (t_bg_fill === true && t_type != '') ? 'text-white' : 'text-'+t_type;
19881				}
19882
19883				var t_body 		= '<div class="pt--15 pb--15 '+t_txt_color+'">' + t_body + '</div>';
19884
19885			} else {
19886
19887				var t_body 		= (t_bg_fill === true && t_type != '') ? '<div class="pt--5 pb--10 text-white">' + t_body + '</div>' : t_body;
19888
19889			}
19890
19891			var _toastBody = _toastBody + t_progress
19892				+ '<div class="toast-body">' + _closeBtnBody + t_body + '</div>'
19893			+ '</div>';
19894
19895			// Prepend
19896			jQuery('#'+_wrapperID).prepend(_toastBody);
19897
19898			// Reinit toast
19899			jQuery('#'+_wrapperID+' .js-toast:not(.hide)').toast('show');
19900
19901
19902			// --
19903
19904
19905			// Animate progress bar
19906			if(t_delay > 0)
19907				jQuery('#'+_wrapperID + ' .js-toast:not(.hide):first-child .progress>.progress-bar').filter(':not(:animated)').stop().animate({width:'100%'}, 0).stop().animate({width:'0%'}, t_delay);
19908
19909
19910			// --
19911
19912
19913			// Cleanup
19914			setTimeout(function () {
19915
19916				jQuery('#'+_wrapperID + ' .js-toast.hide').remove();
19917
19918			}, t_delay + 1500);
19919
19920		},
19921
19922
19923
19924
19925
19926		/**
19927		 *
19928		 *	@toast_template
19929		 *
19930
19931			Toast on page load, by HTML code
19932
19933			<!--
19934
19935				Toast On Load
19936				Add anywhere on your HTML page to show toas on load
19937
19938					data-type 			= '', success, danger, warning, info
19939					data-title 			= toast title 	(optional)
19940					data-body 			= toast body 	(required)
19941					data-pos 			= top-left, top-right, bottom-left, bottom-right, top-center, bottom-center
19942					data-delay 			= autoclose in ms
19943					data-fill 			= background color fill [true|false]
19944
19945			-->
19946			<div class="hide toast-on-load"
19947				data-type="danger"
19948				data-title=""
19949				data-body="Welcome to Smarty"
19950				data-pos="top-right"
19951				data-delay="4000"
19952				data-fill="true"
19953			></div>
19954
19955		 *
19956		 **/
19957		toast_on_load: function(_this) {
19958
19959			_this.each(function() {
19960
19961				var _t 		= jQuery(this),
19962					_type 	= _t.data('toast-type') 		|| '',
19963					_title 	= _t.data('toast-title') 		|| '',
19964					_body 	= _t.data('toast-body') 		|| '',
19965					_delay 	= _t.data('toast-delay') 		|| 0,
19966					_pos 	= _t.data('toast-pos') 			|| 'top-right',
19967					_fill 	= _t.data('toast-fill') 		|| true;
19968
19969				// safe correction
19970				_fill = (_fill != true) ? false : true;
19971
19972				// show toast
19973				$.SOW.core.toast.show(_type, _title, _body, _pos, _delay, _fill);
19974
19975				// not needed
19976				// remove to avoid triggering again on ajax loads!
19977				_t.remove();
19978
19979			});
19980
19981		},
19982
19983
19984
19985		/**
19986		 *
19987		 *	@clear
19988		 *
19989		 **/
19990		destroy: function() {
19991
19992			jQuery('#wrapper_toast_tr, #wrapper_toast_br, wrapper_toast_tl, #wrapper_toast_bl, #wrapper_toast_tc, #wrapper_toast_bc').remove();
19993
19994		}
19995
19996	}
19997
19998})(jQuery);
19999/**
20000 *
20001 *	[SOW] Dropdown
20002 *
20003 *	@author 		Dorin Grigoras
20004 *					www.stepofweb.com
20005 *
20006 *	@Dependency 	-
20007 *	@Usage			$.SOW.core.dropdown_click_ignore.init('.dropdown-menu.dropdown-click-ignore');
20008 *
20009 *
20010 **/
20011;(function ($) {
20012	'use strict';
20013
20014
20015	/**
20016	 *
20017	 *	@vars
20018	 *
20019	 *
20020	 **/
20021	var scriptInfo 		= 'SOW Dropdown Click Ignore';
20022
20023
20024	$.SOW.core.dropdown_click_ignore = {
20025
20026
20027		/**
20028		 *
20029		 *	@config
20030		 *
20031		 *
20032		 **/
20033		config: {},
20034
20035
20036
20037		/**
20038		 *
20039		 *	@collection
20040		 *
20041		 *
20042		 **/
20043		collection: $(),
20044
20045
20046
20047		/**
20048		 *
20049		 *	@init
20050		 *
20051		 *
20052		 **/
20053		init: function (selector, config) {
20054
20055			var __selector 			= $.SOW.helper.__selector(selector);
20056			var __config 			= $.SOW.helper.check_var(config);
20057
20058			this.selector 			= __selector[0]; 	// '#selector'
20059			this.collection 		= __selector[1]; 	// $('#selector')
20060			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
20061
20062			// in case the class is changed
20063			if(jQuery(this.selector).length < 1)
20064				return;
20065
20066
20067			// -- * --
20068			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
20069			// -- * --
20070
20071
20072			// Stop clicks on empty dropdown links
20073			$.SOW.core.dropdown_click_ignore.stop_dd_empty_link($('.dropdown-menu a'));
20074
20075
20076			// 1. Has no selector
20077			if(!this.selector) {
20078				$.SOW.core.dropdown_click_ignore.process($(".dropdown-menu.dropdown-click-ignore"));
20079				return $(".dropdown-menu.dropdown-click-ignore");
20080			}
20081
20082
20083			// 2. Has selector
20084			return this.collection.each(function() {
20085
20086				$.SOW.core.dropdown_click_ignore.process($(this));
20087
20088			});
20089
20090
20091		},
20092
20093
20094
20095		/**
20096		 *
20097		 *	@process
20098		 * 	keep a dropdown open on self container click
20099		 *
20100		 **/
20101		process: function(_this) {
20102
20103			/*
20104				If any form is present inside dropdown,
20105				the dropdown will not close.
20106				So we skip dropdowns with forms!
20107
20108				Still is an issue on outside form click!!!
20109			*/
20110			if(jQuery('form', _this).length > 0) {
20111
20112				// we try to use the same class inside!
20113				jQuery('.dropdown-click-ignore', _this).on('click', function(e) {
20114					e.stopPropagation();
20115				})
20116
20117				return;
20118			}
20119
20120
20121			_this.on('click', function(e) {
20122				e.stopPropagation();
20123			});
20124
20125		},
20126
20127
20128
20129
20130		/**
20131		 *
20132		 *	@stop_dd_empty_link
20133		 * 	Stop clicks on empty dropdown links
20134		 *
20135		 **/
20136		stop_dd_empty_link: function(_this) {
20137
20138			_this.not('[data-toggle="collapse"]').on("click", function(e) {
20139
20140				var _t 			= jQuery(this),
20141					_href 		= jQuery(this).attr('href') || '#';
20142
20143				// prevent empty href click
20144				if(_href == '#' && !_t.hasClass('js-ignore'))
20145					e.preventDefault();
20146
20147			});
20148
20149		}
20150
20151	};
20152
20153
20154})(jQuery);
20155/**
20156 *
20157 *	[SOW] Dropdown
20158 *
20159 *	@author 		Dorin Grigoras
20160 *					www.stepofweb.com
20161 *
20162 *	@Dependency 	$.SOW.core.dropdown_click_ignore
20163 * 	@Usage 			$.SOW.core.dropdown.init('.dropdown-menu.dropdown-menu-hover');
20164 *
20165 *
20166 **/
20167;(function ($) {
20168	'use strict';
20169
20170
20171	/**
20172	 *
20173	 *	@vars
20174	 *
20175	 *
20176	 **/
20177	var scriptInfo 		= 'SOW Dropdown';
20178
20179
20180	$.SOW.core.dropdown = {
20181
20182
20183		/**
20184		 *
20185		 *	@config
20186		 *
20187		 *
20188		 **/
20189		config: {},
20190
20191
20192
20193		/**
20194		 *
20195		 *	@collection
20196		 *
20197		 *
20198		 **/
20199		collection: $(),
20200
20201
20202
20203		/**
20204		 *
20205		 *	@init
20206		 *
20207		 *
20208		 **/
20209		init: function (selector, config) {
20210
20211			var __selector 			= $.SOW.helper.__selector(selector);
20212			var __config 			= $.SOW.helper.check_var(config);
20213
20214			this.selector 			= __selector[0]; 	// '#selector'
20215			this.collection 		= __selector[1]; 	// $('#selector')
20216			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
20217
20218
20219			// Update text on click
20220			$.SOW.core.dropdown.onClickUpdateText();
20221
20222
20223			if(jQuery(this.selector).length < 1)
20224				return;
20225
20226
20227			// Dependency Check
20228			if(typeof $.SOW.core.dropdown_click_ignore !== 'object')
20229				$.SOW.helper.consoleLog('[sow.dropdown] Missing [sow.dropdown_click_ignore]');
20230
20231
20232			// -- * --
20233			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
20234			// -- * --
20235
20236
20237			$.SOW.core.dropdown.process(this.collection);
20238			return this.collection;
20239
20240		},
20241
20242
20243
20244		/**
20245		 *
20246		 *	@process
20247
20248			@Fix|Hack
20249			MULTILEVEL DROPDOWN ON MOBILE
20250
20251			Issue: nested|multi level dropdowns are not supported in Bootstrap v3+
20252
20253			So the issue is: we cannot use $().dropdown('hide|show|toggle') from documentation
20254			Bootstrap was developed for a single level, not multilevel.
20255			So we have to hack it somehow to allow multilevel, especially on mobile.
20256
20257			Ugly but a necesity! 99% better than developing a new mega menu from scratch!
20258
20259
20260			NOTE: we ignore dropdowns without .dropdown-menu-hover
20261			Are working on click
20262
20263		 *
20264		 **/
20265		process: function(_this) {
20266
20267			_this.parent().find('.dropdown>a[data-toggle="dropdown"]').on('click', function(e) {
20268
20269				var _t 				= jQuery(this);
20270					this.collection = _t;
20271
20272				/*
20273
20274					Mobile devices only!
20275
20276				*/
20277				if($.SOW.globals.is_mobile === true) {
20278
20279					if(!_t.parent('.dropdown').hasClass('show')) {
20280
20281						// first click : open
20282						$.SOW.core.dropdown.__ddBSControl(_t, 'show');
20283
20284						// now close all other open parent dropdowns
20285						_t.parent('.dropdown').parent().find('.dropdown.show>a[data-toggle="dropdown"]').not(this).each(function() {
20286							$.SOW.core.dropdown.__ddBSControl(jQuery(this), 'hide');
20287						});
20288
20289					} else {
20290
20291						// second click : close
20292						$.SOW.core.dropdown.__ddBSControl(_t, 'hide');
20293
20294						// now close all childs, if any
20295						_t.parent('.dropdown').find('.dropdown-menu .dropdown>a[data-toggle="dropdown"]').each(function(e) {
20296							$.SOW.core.dropdown.__ddBSControl(jQuery(this), 'hide');
20297						});
20298
20299					}
20300
20301					// Stop here, block bootstrap to run its dropdowns stuff
20302					e.stopPropagation();
20303
20304				}
20305
20306			});
20307
20308		},
20309
20310
20311
20312		/**
20313		 *
20314		 *	@__ddBSControl
20315		 *	:: Helper
20316		 *
20317		 **/
20318		__ddBSControl: function(_t, status) {
20319
20320			if(status == 'show') {
20321
20322				_t.attr('aria-expanded','true').parent('.dropdown').addClass('show');
20323				_t.next('.dropdown-menu').addClass('show');
20324
20325			} else {
20326
20327				_t.attr('aria-expanded','false').parent('.dropdown').removeClass('show');
20328				_t.next('.dropdown-menu').removeClass('show');
20329
20330
20331			}
20332
20333		},
20334
20335
20336
20337
20338
20339
20340		/**
20341		 *
20342		 *	@onClickUpdateText
20343		 *
20344		 *
20345		 **/
20346		onClickUpdateText: function() {
20347
20348			jQuery('.dropdown-menu-click-update a.dropdown-item, .dropdown-menu-click-update a.dropdown-link').not('.js-dropdown-triggerified').addClass('js-dropdown-triggerified').on('click', function(e) {
20349
20350				var _t 			= jQuery(this);
20351
20352				var dropdownContainer = _t.parents('.dropdown-menu-click-update');
20353				jQuery('a.dropdown-item, a.dropdown-link', dropdownContainer).removeClass('active');
20354				_t.addClass('active');
20355
20356
20357				// find button trigger & update text
20358				var dropdownBtnTrigger = dropdownContainer.parent().find('[data-toggle="dropdown"]');
20359				if(dropdownBtnTrigger) {
20360					var dropdownBtnTextToUpdate = jQuery('.js-trigger-text', _t).text();
20361					if(dropdownBtnTextToUpdate)
20362						jQuery('.js-trigger-text', dropdownBtnTrigger).text(dropdownBtnTextToUpdate);
20363				}
20364
20365
20366
20367				setTimeout(function() {
20368
20369					// Close dropdown on link click
20370					// if no .dropdown-click-ignore is present
20371					if(!dropdownContainer.hasClass('dropdown-click-ignore') && dropdownContainer.hasClass('show'))
20372						dropdownContainer.dropdown('hide');
20373
20374					// Callback
20375					var callBack = dropdownContainer.attr('data-dropdown-callback') || '';
20376					if(callBack != '') {
20377						if(typeof window[callBack] === 'function')
20378							window[callBack](_t.attr('href'));
20379					}
20380
20381				}, 0);
20382
20383				e.preventDefault();
20384
20385			});
20386
20387			return true;
20388		}
20389
20390	};
20391
20392
20393})(jQuery);
20394/**
20395 *
20396 *	[SOW] Dropdown Ajax
20397 *
20398 *	@author 		Dorin Grigoras
20399 *					www.stepofweb.com
20400 *
20401 *	@Dependency 	$.SOW.core.dropdown_click_ignore
20402 * 					$.SOW.core.dropdown
20403 * 	@Usage 			$.SOW.core.dropdown_ajax.init('a[data-toggle="dropdown"]');
20404 *
20405 *
20406 **/
20407;(function ($) {
20408	'use strict';
20409
20410
20411	/**
20412	 *
20413	 *	@vars
20414	 *
20415	 *
20416	 **/
20417	var scriptInfo 		= 'SOW Dropdown Ajax';
20418	var ddTimeKepper 	= {};
20419
20420
20421	$.SOW.core.dropdown_ajax = {
20422
20423
20424		/**
20425		 *
20426		 *	@config
20427		 *
20428		 *
20429		 **/
20430		config: {
20431
20432			// general
20433			loading_icon: 			'fi fi-circle-spin fi-spin',
20434			clearCacheInterval: 	1000 * 60, 	// 1 min
20435
20436
20437			// json only : dropdown strating|ending tags
20438			tpl_start: 				'<ul class="list-unstyled m-0 p-0">',
20439			tpl_end: 				'</ul>',
20440
20441			tpl_ItemStart: 			'<li class="dropdown-item">',
20442			tpl_ItemStartWChilds: 	'<li class="dropdown-item dropdown">',
20443			tpl_ItemEnd: 			'</li>',
20444
20445			tpl_Child_Start: 		'<ul class="dropdown-menu dropdown-menu-hover dropdown-menu-block-md shadow-lg b-0 m-0">',
20446			tpl_Divider: 			'<li class="dropdown-divider"></li>',
20447
20448		},
20449
20450
20451
20452		/**
20453		 *
20454		 *	@collection
20455		 *
20456		 *
20457		 **/
20458		collection: $(),
20459
20460
20461
20462		/**
20463		 *
20464		 *	@init
20465		 *
20466		 *
20467		 **/
20468		init: function (selector, config) {
20469
20470			var __selector 			= $.SOW.helper.__selector(selector);
20471			var __config 			= $.SOW.helper.check_var(config);
20472
20473			this.selector 			= __selector[0]; 	// '#selector'
20474			this.collection 		= __selector[1]; 	// $('#selector')
20475			this.selector_orig 		= __selector[2]; 	// $('#selector') // without ajax container prefix
20476			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
20477
20478
20479			if(jQuery(this.selector).length < 1)
20480				return;
20481
20482
20483			// -- * --
20484			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
20485			// -- * --
20486
20487
20488			$.SOW.core.dropdown_ajax.process(this.collection);
20489			return this.collection;
20490
20491		},
20492
20493
20494
20495		/**
20496		 *
20497		 *	@process
20498		 *
20499		 **/
20500		process: function(_this) {
20501
20502			// Required
20503			if(_this.data('dropdown-ajax
20503-source') == '')
20504				return;
20505
20506
20507			// Initial Setup
20508			if($.SOW.globals.is_mobile === true) {
20509
20510				var jQ_actions = 'click';
20511
20512			} else {
20513
20514				var jQ_actions = 'click mouseover';
20515
20516				// Hover only, remove click
20517				if(_this.next().closest('.dropdown-menu').hasClass('dropdown-menu-hover'))
20518					var jQ_actions = 'mouseover';
20519
20520			}
20521
20522
20523			// Repopulate dropdowns from cache, if exists
20524			$.SOW.core.dropdown_ajax.repopulateFromCache();
20525
20526
20527			// mouse over|click
20528			_this.on(jQ_actions, function(e) {
20529
20530				var _t 					= jQuery(this),
20531					_source 			= _t.data('dropdown-ajax-source') 			|| '',
20532					_mode 				= _t.data('dropdown-ajax-mode') 			|| 'html',	// html|json
20533					_clearCacheInterval	= _t.data('dropdown-ajax-refresh-interval') || $.SOW.core.dropdown_ajax.config.clearCacheInterval,
20534					_reloadAlways 		= _t.data('dropdown-ajax-reload-always') 	|| false,
20535					_loadIcon 			= _t.data('dropdown-ajax-loadicon') 		|| $.SOW.core.dropdown_ajax.config.loading_icon,
20536					_container 			= _t.next().closest('.dropdown-menu') 		|| '',
20537					_useCache 			= _t.attr('data-dropdown-ajax-cache') 		|| 'false',
20538					_containerID 		= _container.attr('id')						|| '',
20539					_method				= _t.data('dropdown-ajax-method') 			|| 'GET',
20540					_contentType		= _t.data('dropdown-ajax-contentType') 		|| '',
20541					_dataType			= _t.data('dropdown-ajax-dataType') 		|| '';
20542
20543
20544				if(_source == '' || _container == '')
20545					return;
20546
20547
20548				// Add an ID to dropdown container if empty
20549				if(_containerID == '') {
20550					var _containerID = 'rand_' + $.SOW.helper.randomStr(8);
20551					_container.attr('id', _containerID);
20552				}
20553
20554
20555				// Cached? Check expired
20556				if(_useCache+'' == 'true' && _t.hasClass('js-cached')) {
20557					var $continue = $.SOW.core.dropdown_ajax.validateCache(_source);
20558					if($continue === false)
20559						return;
20560				}
20561
20562
20563				/*
20564					force : overwrite
20565					do not reload data on mouse over
20566				*/
20567				if(jQ_actions == 'mouseover' && $.SOW.globals.is_mobile === false)
20568					_reloadAlways = false;
20569
20570
20571				// Refresh Interval!
20572				if(_reloadAlways == false && _clearCacheInterval > 0)
20573					$.SOW.core.dropdown_ajax.process_clearCacheInterval(_t, _containerID, _clearCacheInterval);
20574
20575
20576				// Content already successfully loaded and reload on each click|show is disabled
20577				if(_reloadAlways == false && _t.hasClass('js-dropdownified'))
20578					return;
20579
20580
20581				// set initialized
20582				_container.addClass('js-dropdownified');
20583
20584
20585				// Ajax
20586				jQuery.ajax({
20587					url:			_source,
20588					data: 			(_mode === 'json') ? {} : {ajax:"true"},
20589					type: 			_method,
20590					contentType: 	_contentType 	|| 'application/x-www-form-urlencoded; charset=UTF-8',
20591					dataType: 		_dataType 		|| null,
20592					headers: 		'',
20593					crossDomain: 	'',
20594
20595					beforeSend: function() {
20596
20597						_container.html('<div class="js-dd-ajax-loader text-center rounded p-3"><i class="' + _loadIcon + ' h5 text-gray-400"></i></div>');
20598
20599					},
20600
20601					error: 	function(XMLHttpRequest, textStatus, errorThrown) {
20602
20603						if(typeof $.SOW.core.toast === 'object') {
20604
20605							$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
20606
20607						} else {
20608
20609							// alert("[404] Unexpected internal error!");
20610
20611						}
20612
20613						// if debug enabled, see config
20614						if($.SOW.config.sow__debug_enable === true) { // optional, just to skip so many callings
20615							$.SOW.helper.consoleLog('----------------------------');
20616							$.SOW.helper.consoleLog('--- AJAX  DROPDOWN ERROR ---');
20617							$.SOW.helper.consoleLog('1. XMLHttpRequest:');
20618							$.SOW.helper.consoleLog(XMLHttpRequest);
20619							$.SOW.helper.consoleLog('2. textStatus:');
20620							$.SOW.helper.consoleLog(textStatus);
20621							$.SOW.helper.consoleLog('3. errorThrown:');
20622							$.SOW.helper.consoleLog(errorThrown);
20623							$.SOW.helper.consoleLog('----------------------------');
20624						}
20625
20626					},
20627
20628					success: function(data) {
20629
20630						_t.addClass('js-dropdownified');
20631
20632						/* json */
20633						if(_mode === 'json')
20634							var data = $.SOW.core.dropdown_ajax.process_json(data);
20635
20636						// push data
20637						_container.html(data);
20638
20639
20640						// Add to cache
20641						if(_useCache+'' == 'true')
20642							$.SOW.core.dropdown_ajax.addToCache(_source, data);
20643
20644
20645						/*
20646							Reinits [mobile required]
20647						*/
20648						// SOW :: Dropdown
20649						if(typeof $.SOW.core.dropdown === 'object')
20650							$.SOW.core.dropdown.process(_container);
20651
20652						// SOW :: Dropdown Click Ignore
20653						if(typeof $.SOW.core.dropdown_click_ignore === 'object') {
20654							var _containerLinks = $('a', _container);
20655							$.SOW.core.dropdown_click_ignore.stop_dd_empty_link(_containerLinks);
20656						}
20657
20658						// SOW :: Ajax Navigation
20659						if(typeof $.SOW.core.ajax_navigation === 'object')
20660							$.SOW.core.ajax_navigation.__initFor('#' + _containerID);
20661
20662
20663						// -- * --
20664						$.SOW.helper.consoleLog('[#'+_containerID+'] Dropdown Ajax Content Loaded! ' + _source, 'color: #999999;');
20665						// -- * --
20666
20667
20668						// Reinit Plugins : HTML only
20669						if(_mode == 'html') {
20670							var _target = '#'+_containerID;
20671
20672							// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20673							// reinit inside ajax container
20674							if($.SOW.config.sow__debug_enable === true) { // just to avoid always calling the helper
20675								$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
20676								$.SOW.helper.consoleLog(scriptInfo, 'color: #6dbb30; font-weight: bold; font-size:14px;');
20677								$.SOW.helper.consoleLog('Ajax Reinit For: ' + _target);
20678								$.SOW.helper.consoleLog(window.location.href);
20679								$.SOW.helper.consoleLog('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++');
20680							}
20681
20682							$.SOW.reinit(_target);
20683							// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20684
20685						}
20686
20687					}
20688
20689				});
20690
20691			});
20692
20693		},
20694
20695
20696
20697
20698		/**
20699		 *
20700		 *	@process_json
20701		 *
20702		 *
20703		 *
20704		 **/
20705		process_json: function(data) {
20706
20707			try {
20708
20709				var _data = JSON.parse(data);
20710
20711			} catch(err) {
20712
20713				var _data = data;
20714
20715			}
20716
20717			/* --------------------------------- */
20718			var _tpl  = '';
20719				_tpl += $.SOW.core.dropdown_ajax.config.tpl_start;
20720				_tpl += $.SOW.core.dropdown_ajax.process_json_build_tree(_data);
20721				_tpl += $.SOW.core.dropdown_ajax.config.tpl_end;
20722			/* --------------------------------- */
20723
20724
20725			return _tpl;
20726
20727		},
20728
20729
20730
20731
20732		/**
20733		 *
20734		 *	@process_json_build_tree
20735		 * 	Recursive
20736		 *
20737		 *
20738		 **/
20739		process_json_build_tree: function(data) {
20740
20741			var _tpl = '';
20742
20743			if(typeof data === 'undefined')
20744				return _tpl;
20745
20746			for (var i = 0; i < data.length; i++) {
20747
20748				/* 0. Divider -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20749				if(typeof data[i].divider !== 'undefined' && data[i].divider === true) {
20750					_tpl += $.SOW.core.dropdown_ajax.config.tpl_Divider;
20751					continue;
20752				}
20753				/* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20754
20755
20756				/* 1. Text -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20757				else if(typeof data[i].text !== 'undefined' && data[i].text.length > 0) {
20758					_tpl += $.SOW.core.dropdown_ajax.config.tpl_ItemStart + data[i].text + $.SOW.core.dropdown_ajax.config.tpl_ItemEnd;
20759					continue;
20760				}
20761				/* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20762
20763
20764
20765				var has_childs 		= (typeof data[i].childs !== 'undefined' && data[i].childs.length > 0) ? true : false;
20766
20767
20768				/* 2. tpl start <li> -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20769				_tpl 				+= (has_childs === true) ? $.SOW.core.dropdown_ajax.config.tpl_ItemStartWChilds :  $.SOW.core.dropdown_ajax.config.tpl_ItemStart;
20770				/* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20771
20772
20773
20774				/* 3. add link -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20775				var _childsTag 		 = (has_childs === true) ?  ' data-toggle="dropdown"' : '';
20776
20777				var _class 	 		 = (typeof data[i].class 	!== 'undefined' && data[i].class != '')			? ' ' + data[i].class 	: '';
20778					_class 	 		+= (typeof data[i].active 	!== 'undefined' && data[i].active == true) 		? ' active' 			: '';
20779					_class 	 		+= (typeof data[i].disabled !== 'undefined' && data[i].disabled == true) 	? ' disabled' 			: '';
20780
20781				var _icon 	 		 = (typeof data[i].icon 	!== 'undefined' && data[i].icon != '') 			? '<i class="'+data[i].icon+'"></i>' : '';
20782				var _target 	 	 = (typeof data[i].target 	!== 'undefined' && data[i].target != '')		? ' target="'+data[i].target+'"' : '';
20783
20784				_tpl 				+= '<a href="'+data[i].url+'" class="dropdown-link' + _class + '"' + _childsTag + _target+'>' + _icon + data[i].label + '</a>';
20785				/* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20786
20787
20788
20789				/* 4. recursive childs  -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20790				if(has_childs === true) {
20791					_tpl 			+= $.SOW.core.dropdown_ajax.config.tpl_Child_Start;
20792					_tpl 			+= $.SOW.core.dropdown_ajax.process_json_build_tree(data[i].childs);
20793					_tpl 			+= $.SOW.core.dropdown_ajax.config.tpl_end;
20794				}
20795				/* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20796
20797
20798
20799				/* 5. tpl end </li>  -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20800				_tpl 				+= $.SOW.core.dropdown_ajax.config.tpl_ItemEnd;
20801				/* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
20802
20803			}
20804
20805
20806			/* return final tpl */
20807			return _tpl;
20808		},
20809
20810
20811
20812
20813		/**
20814		 *
20815		 *	@process_clearCacheInterval
20816		 *
20817		 *
20818		 *
20819		 **/
20820		process_clearCacheInterval: function(_t, _containerID, _clearCacheInterval) {
20821
20822			var timestampNow = new Date().getTime();
20823
20824			// First click/hover
20825			// Refresh : Cache Added!
20826			if(typeof ddTimeKepper[_containerID] === 'undefined')
20827				ddTimeKepper[_containerID] = timestampNow;
20828
20829			// Cache Refreshed & Content Reloaded
20830			else if((timestampNow - ddTimeKepper[_containerID]) > _clearCacheInterval) {
20831				ddTimeKepper[_containerID] = timestampNow;
20832				_t.removeClass('js-dropdownified');
20833			}
20834
20835		},
20836
20837
20838
20839
20840
20841
20842
20843		/**
20844		 *
20845		 *	@addToCache
20846		 *
20847		 **/
20848		addToCache: function(_URL, data) {
20849
20850			// Skip
20851			if(jQuery('body[data-dropdown-ajax-cache-ignore="true"]').length > 0) {
20852				localStorage.removeItem('cachedDropdowns');
20853				return;
20854			}
20855
20856			// Get from cache!
20857			var cachedDropdowns 	= localStorage.getItem("cachedDropdowns");
20858			var cachedDropdownsArr 	= (cachedDropdowns) ? JSON.parse(cachedDropdowns) : {};
20859
20860			// create a hash from URL
20861			var hash = $.SOW.helper.strhash(_URL);
20862			var timestampNow = new Date().getTime();
20863
20864			cachedDropdownsArr[hash] = { url:_URL, html:data, timestamp:timestampNow }
20865			localStorage.setItem("cachedDropdowns", JSON.stringify(cachedDropdownsArr));
20866
20867			return true;
20868
20869		},
20870
20871
20872
20873		/**
20874		 *
20875		 *	@repopulateFromCache
20876		 *
20877		 **/
20878		repopulateFromCache: function() {
20879
20880			// Skip
20881			if(jQuery('body[data-dropdown-ajax-cache-ignore="true"]').length > 0)
20882				return;
20883
20884			// Get from cache!
20885			var cachedDropdowns = localStorage.getItem("cachedDropdowns");
20886			if(!cachedDropdowns)
20887				return false;
20888
20889			// Array conversion
20890			var cachedDropdownsArr = JSON.parse(cachedDropdowns);
20891			for(var key in cachedDropdownsArr) {
20892				jQuery('[data-dropdown-ajax-source="'+cachedDropdownsArr[key]['url']+'"]').addClass('js-cached').next().closest('.dropdown-menu').html(cachedDropdownsArr[key]['html']);
20893			}
20894
20895			return true;
20896		},
20897
20898
20899
20900
20901
20902
20903		/**
20904		 *
20905		 *	@validateCache
20906		 *
20907		 **/
20908		validateCache: function(_URL) {
20909
20910			// Get from cache!
20911			var cachedDropdowns 	= localStorage.getItem("cachedDropdowns");
20912			if(!cachedDropdowns)
20913				return true; // true = continue
20914
20915			// Parse cache & create hash from url
20916			var cachedDropdownsArr 	= JSON.parse(cachedDropdowns);
20917			var hash 				= $.SOW.helper.strhash(_URL);
20918
20919			// Cache Refreshed & Content Reloaded
20920			var timestampNow = new Date().getTime();
20921			if((timestampNow - cachedDropdownsArr[hash]['timestamp']) > 60*30) {
20922						cachedDropdownsArr[hash] = {};
20923				delete 	cachedDropdownsArr[hash];
20924
20925				// reset
20926				localStorage.setItem("cachedDropdowns", JSON.stringify(cachedDropdownsArr));
20927				return true; // true = continue
20928
20929			}
20930
20931			return false; // false = stop, cache is valid!
20932
20933		},
20934
20935
20936
20937
20938
20939	};
20940
20941
20942})(jQuery);
20943/**
20944 *
20945 *	[SOW] Count Animate
20946 *
20947 *	@author 		Dorin Grigoras
20948 *					www.stepofweb.com
20949 *
20950 *	@Dependency 	-
20951 *	@Usage 			$.SOW.core.count_animate.init()
20952 * 	@Ajax Support 	YES
20953 *
20954 *
20955 **/
20956;(function ($) {
20957	'use strict';
20958
20959
20960	/**
20961	 *
20962	 *	@vars
20963	 *
20964	 *
20965	 **/
20966	var scriptInfo 				= 'SOW Count Animate';
20967	window.sowCountInterval 	= null;
20968	window.sowCountBtnList 		= {};
20969	// window.startScrollPos 		= 0;
20970
20971
20972	$.SOW.core.count_animate = {
20973
20974
20975
20976		/**
20977		 *
20978		 *	@config
20979		 *
20980		 *
20981		 **/
20982		config: {
20983			count_duration 	: 1500,
20984			easing 			: 'easeInOutExpo', // easeOutExpo, easeInOutExpo, linear, swing
20985		},
20986
20987
20988
20989		/**
20990		 *
20991		 *	@collection
20992		 *
20993		 *
20994		 **/
20995		collection: $(),
20996
20997
20998
20999		/**
21000		 *
21001		 *	@init
21002		 *
21003		 *
21004		 **/
21005		init: function (selector, config) {
21006
21007			var el_selector 		= '[data-toggle=count]';
21008			var btn_selector 		= '[data-count-target]';
21009
21010			var __config 			= $.SOW.helper.check_var(config);
21011			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
21012
21013
21014			// init button
21015			$.SOW.core.count_animate.btn_process(el_selector, btn_selector);
21016			// --
21017
21018
21019			if($(el_selector).length < 1) {
21020
21021 				// stop everything
21022 				if(window.sowCountInterval !== null) {
21023 					clearInterval(window.sowCountInterval);
21024 					window.sowCountInterval = null;
21025 					$(el_selector).stop(true, true); // stop all animations
21026 				}
21027
21028				return;
21029			}
21030
21031
21032			// -- * --
21033			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
21034			// -- * --
21035
21036
21037			// On Load
21038			// window.startScrollPos = jQuery(window).scrollTop() || 0; // used on scroll up
21039			$.SOW.core.count_animate.process($(el_selector));
21040
21041
21042
21043			var scrolling 	= false;
21044			$(window).scroll(function() {
21045				scrolling = true;
21046			});
21047
21048			window.sowCountInterval = setInterval( function() {
21049
21050				if(scrolling) {
21051					scrolling = false;
21052					$.SOW.core.count_animate.process($(el_selector));
21053				}
21054
21055			}, 250);
21056
21057
21058			// it's always cool to return something that nobody will ever need :)
21059			return $(el_selector);
21060
21061		},
21062
21063
21064
21065
21066
21067		/**
21068		 *
21069		 *	@process
21070		 *
21071		 *
21072		 **/
21073		process: function(_this) {
21074
21075			// custom easing
21076			$.SOW.core.count_animate.custom_easing();
21077
21078			var topPos		= jQuery(window).scrollTop() || 0;
21079            var scrollPos 	= ($.SOW.globals.height || 0) + topPos;
21080
21081            _this.not('.js-count-completed').each(function(e) {
21082
21083            	var _t 				= jQuery(this),
21084	            	_offset 		= _t.offset(),
21085	            	elOffsetTop 	= _offset.top || 0;
21086
21087
21088	            /**
21089
21090		            Known issue: refresh when scroll is on middle
21091
21092		            // on scroll up (from refresh)
21093		            var elOffsetTop2 = elOffsetTop + $.SOW.globals.height;
21094		            if(window.startScrollPos > $.SOW.globals.height && scrollPos < elOffsetTop2)
21095		            	$.SOW.core.count_animate.animate(_t);
21096
21097		            // on scroll down
21098	        		else if (window.startScrollPos < $.SOW.globals.height && scrollPos > elOffsetTop)
21099	        			$.SOW.core.count_animate.animate(_t);
21100
21101				**/
21102
21103        		/* on scroll down only */
21104        		if (scrollPos > elOffsetTop)
21105        			$.SOW.core.count_animate.animate(_t);
21106
21107            });
21108
21109        },
21110
21111
21112
21113
21114		/**
21115		 *
21116		 *	@animate
21117		 *
21118		 *
21119		 **/
21120        animate: function(_t) {
21121
21122			var count_from 		= _t.attr('data-count-from') 		|| 0,
21123				count_to 		= _t.attr('data-count-to') 			|| 0,
21124				count_duration 	= _t.attr('data-count-duration') 	|| $.SOW.core.count_animate.count_duration,
21125				count_display	= _t.attr('data-count-display')		|| false,
21126				callback 		= _t.data('count-callback') 		|| '',
21127				count_decimals	= _t.data('count-decimals') 		|| '',
21128				oncomplete 		= _t.data('count-oncomplete') 		|| '';
21129
21130			if(count_from == count_to)
21131				return;
21132
21133			// https://api.jquery.com/animate/
21134			jQuery({sowCount:count_from}).animate({sowCount:count_to}, {
21135
21136                duration: 	Number(count_duration),
21137                easing: 	$.SOW.core.count_animate.easing, //'linear', 'swing'
21138                queue: 		true,
21139
21140                step: function(curr) {
21141
21142
21143
21144                    var numRes 	= count_to.substr(0, count_to.indexOf('.')),
21145                    	_val 	= (numRes) ? parseFloat(curr).toFixed(2) : Math.floor(curr);
21146
21147                   	if(count_decimals)
21148                   		var _val = parseFloat(_val).toFixed(count_decimals);
21149
21150					if(count_display === 'currency')
21151						var _val = $.SOW.helper.currencyFormat( parseFloat(_val) );
21152
21153					_t.text(_val);
21154                },
21155
21156                start: function() {
21157
21158                	_t.addClass('js-count-completed');
21159
21160                },
21161
21162				complete: function() {
21163
21164					if(callback != '' && typeof $.SOW.helper.executeFunctionByName === "function")
21165						$.SOW.helper.executeFunctionByName(callback, window, _t);
21166
21167
21168					if(typeof oncomplete === 'object') {
21169
21170						if(oncomplete.target) {
21171
21172							if(oncomplete.action.toLowerCase() == 'show')
21173								jQuery(oncomplete.target).removeClass('hide hide-force');
21174
21175							else if(oncomplete.action.toLowerCase() == 'hide')
21176								jQuery(oncomplete.target).addClass('hide hide-force');
21177
21178							if(oncomplete.class)
21179								jQuery(oncomplete.target).addClass(oncomplete.class);
21180
21181						}
21182					}
21183
21184				},
21185
21186				done: function(_e) {
21187					_e.stop(true, true);
21188				}
21189
21190            });
21191
21192        },
21193
21194
21195
21196
21197
21198		/**
21199		 *
21200		 *	@btn_process
21201		 *
21202		 *
21203		 **/
21204        btn_process: function(el_selector, btn_selector) {
21205
21206        	if(jQuery(btn_selector).length < 1)
21207        		return;
21208
21209			// custom easing
21210			$.SOW.core.count_animate.custom_easing();
21211
21212        	// reset for each page (ajax required)
21213        	window.sowCountBtnList = {};
21214
21215        	jQuery(btn_selector).each(function() {
21216
21217        		var _thisBtn 	= jQuery(this),
21218					_action 	= (_thisBtn.is('a') || _thisBtn.is('button')) ? 'click' : 'change';
21219
21220	        	_thisBtn.on(_action, function(e) {
21221
21222	        		var _t 			= jQuery(this),
21223	        			_href		= _t.attr('href') 					|| null,
21224	        			_target		= _t.data('count-target') 			|| null,
21225	        			_math 		= _t.data('count-math') 			|| null;
21226
21227	        		if(!_target)	return;
21228	        		if(_href) 		e.preventDefault(); // links only!
21229	    			jQuery(_target).stop(true, true); 	// stop any animation
21230	    			_t.toggleClass('active'); 			// mark active
21231
21232
21233
21234	    			// :: MATH
21235	        		// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
21236	        		$.SOW.core.count_animate.btn_process_math(_t);
21237	        		// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
21238
21239
21240
21241	    			// :: TOGGLE
21242	        		// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
21243	        		$.SOW.core.count_animate.btn_process_toggle(_target);
21244	    			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
21245
21246
21247	        	});
21248
21249
21250        	});
21251
21252        },
21253
21254
21255
21256
21257
21258		/**
21259		 *
21260		 *	@btn_process_math
21261		 *
21262		 *
21263		 **/
21264		btn_process_math: function(_t) {
21265
21266    		var _target		= _t.data('count-target') 			|| '',
21267    			_tMth 		= jQuery(_target),
21268    			_math 		= _t.data('count-math') 			|| '0',
21269    			_math 		= Number(_math),
21270    			is_select 	= _t.is('select'),
21271    			el_type 	= _t.attr('type'); // radio|checkbox
21272
21273
21274			// Select
21275			if(is_select) {
21276
21277				var _val 		= _t.find(':selected').data('count-math') 	|| 0
21278					_lastCalc 	= _tMth.attr('data-count-to') 				|| 0,
21279					_calculate 	= _val;
21280
21281			// Checkbox, Radio, etc
21282			} else {
21283
21284	    		if(_math < 1)
21285	    			return;
21286
21287				var _lastCalc 	= _tMth.attr('data-count-last-math') 	|| 0,
21288					_lastCalc 	= Number(_lastCalc), // last calculation
21289	    			_baseVal	= _tMth.attr('data-count-base-to') 		|| '',
21290					_currVal 	= _tMth.attr('data-count-to') 			|| 0,
21291					_currVal 	= Number(_currVal);
21292
21293				if(_baseVal == '') {
21294					var _baseVal 	= _currVal,
21295						_lastCalc 	= _currVal;
21296						_tMth.attr('data-count-base-to', _currVal);
21297				}
21298
21299				if(el_type == 'radio')
21300					var _calculate = (_t.hasClass('active') || _t.is(':checked')) ? Number(_baseVal) + _math : Number(_lastCalc) - _math;
21301
21302
21303				else // invert the math because 'active' class is toggled before
21304					var _calculate = (_t.hasClass('active') || _t.is(':checked')) ? Number(_lastCalc) + _math : Number(_lastCalc) - _math;
21305
21306			}
21307
21308			_tMth.attr('data-toggle', 'count'); // just in case!
21309			_tMth.attr('data-count-last-math', _calculate);
21310			_tMth.attr('data-count-from', _lastCalc);
21311			_tMth.attr('data-count-to', _calculate);
21312			$.SOW.core.count_animate.animate(_tMth);
21313
21314		},
21315
21316
21317
21318
21319
21320		/**
21321		 *
21322		 *	@btn_process_toggle
21323		 *
21324		 *
21325		 **/
21326		btn_process_toggle: function(_target) {
21327
21328			jQuery(_target).each(function(e) {
21329
21330				var _el 		= jQuery(this),
21331					_json		= _el.data('count-toggle') 	|| '',
21332					_elID 		= _el.attr('id') 			|| '';
21333
21334	       		if(_elID == '') {
21335        			_elID = 'rand_' + $.SOW.helper.randomStr(3);
21336        			_el.attr('id', _elID);
21337        		}
21338
21339				if(typeof _json === 'object') {
21340
21341        			// in case a button is used to toggle only one value (from-to)
21342        			if(!_json[1])
21343        				_json[1] = {"from":_json[0]['to'], "to":_json[0]['from'], "duration":_json[0]['duration']};
21344
21345
21346        			if(window.sowCountBtnList[_elID] === 1) {
21347
21348        				_el.attr('data-toggle', 'count');
21349        				_el.attr('data-count-from', (_json[1]['from'] != '0') ? _json[1]['to'] : _json[0]['from'] );
21350        				_el.attr('data-count-to', _json[0]['to']);
21351        				_el.attr('data-count-duration', _json[0]['duration']);
21352
21353        				window.sowCountBtnList[_elID] = 0;
21354
21355        			} else {
21356
21357        				_el.attr('data-toggle', 'count');
21358        				_el.attr('data-count-from', _json[1]['from']);
21359        				_el.attr('data-count-to', _json[1]['to']);
21360        				_el.attr('data-count-duration', _json[1]['duration']);
21361
21362        				window.sowCountBtnList[_elID] = 1;
21363        			}
21364
21365        			$.SOW.core.count_animate.animate(_el);
21366
21367				}
21368
21369			});
21370
21371		},
21372
21373
21374
21375
21376
21377		/**
21378		 *
21379		 *	@custom_easing
21380		 *
21381		 *
21382		 **/
21383		custom_easing: function() {
21384
21385			$.extend($.easing, {
21386				easeInOutExpo: function (x, t, b, c, d) {
21387					if (t==0) return b;
21388					if (t==d) return b+c;
21389					if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
21390					return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
21391				},
21392				easeOutExpo: function (x, t, b, c, d) {
21393					return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
21394				},
21395			});
21396
21397		}
21398	};
21399
21400
21401})(jQuery);
21402/**
21403 *
21404 *	[SOW] Btn Toggle
21405 *
21406 *	@author 		Dorin Grigoras
21407 *					www.stepofweb.com
21408 *
21409 *	@Dependency 	-
21410 *	@Usage			$.SOW.core.btn_toggle.init('.btn-toggle');
21411 *
21412 *
21413 **/
21414;(function ($) {
21415	'use strict';
21416
21417
21418	/**
21419	 *
21420	 *	@vars
21421	 *
21422	 *
21423	 **/
21424	var scriptInfo 		= 'SOW Btn Toggle';
21425
21426
21427	$.SOW.core.btn_toggle = {
21428
21429
21430		/**
21431		 *
21432		 *	@config
21433		 *
21434		 *
21435		 **/
21436		config: {
21437			method 							: 'GET',
21438			contentType 					: '', 	// jQuery params
21439			dataType 						: '', 	// jQuery params
21440			headers 						: '', 	// jQuery params
21441			crossDomain 					: '', 	// jQuery params
21442			data_params 					: {ajax:'true'},
21443		},
21444
21445
21446
21447		/**
21448		 *
21449		 *	@collection
21450		 *
21451		 *
21452		 **/
21453		collection: $(),
21454
21455
21456
21457		/**
21458		 *
21459		 *	@init
21460		 *
21461		 *
21462		 **/
21463		init: function (selector, config) {
21464
21465			var __selector 			= $.SOW.helper.__selector(selector);
21466			var __config 			= $.SOW.helper.check_var(config);
21467
21468			this.selector 			= __selector[0]; 	// '#selector'
21469			this.collection 		= __selector[1]; 	// $('#selector')
21470			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
21471
21472
21473			if(jQuery(this.selector).length < 1)
21474				return;
21475
21476
21477			// -- * --
21478			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
21479			// -- * --
21480
21481
21482			// 1. Has no selector
21483			if(!this.selector) {
21484				$.SOW.core.btn_toggle.process($('.btn-toggle'));
21485				return this.collection;
21486			}
21487
21488			// 2. Has selector
21489			return this.collection.each(function() {
21490
21491				$.SOW.core.btn_toggle.process($(this));
21492
21493			});
21494
21495		},
21496
21497
21498
21499		/**
21500		 *
21501		 *	@process
21502		 *
21503
21504			<!-- toggle -->
21505			<button class="btn btn-secondary btn-toggle btn-icon btn-circle" data-toggle="popover" data-placement="left" title="Popover title" data-content="And here's some amazing content. It's very engaging. Right?">
21506				<span class="group-icon">
21507					<i class="mdi mdi-help-circle-outline"></i>
21508					<i class="mdi mdi-close"></i>
21509				</span>
21510			</button>
21511
21512			<!-- Toggle fullscreen container -->
21513			<a href="javascript:;" class="btn-toggle" data-toggle-container-class="fullscreen" data-toggle-body-class="overflow-hidden" data-target="#footer">
21514				<span class="group-icon">
21515					<i class="fi fi-expand"></i>
21516					<i class="fi fi-shrink"></i>
21517				</span>
21518			</a>
21519
21520		 *
21521		 **/
21522		process: function(_this) {
21523
21524
21525						// bind once
21526			_this.not(".js-togglified").addClass('js-togglified').on("click", function(e) {
21527
21528
21529				// BUTTON TRIGGER - LIKE MOBILE MENU
21530				var _t 					= jQuery(this),
21531					_target 			= _t.data('target') 						|| '',
21532					_targetRw 			= _t.data('toggle-target') 					|| '',	// because data-target might be used by collapse!
21533					_target2 			= _t.data('target-2') 						|| '',
21534					_toastMessage 		= _t.data('toast-success-message') 			|| '',
21535					_toastPos 			= _t.data('toast-success-position') 		|| 'top-center',
21536					_temporized 		= _t.data('toggle-temporized') 				|| 0,
21537					_toggleClass 		= _t.data('toggle-container-class') 		|| '',	// toggle class for a specific container
21538					_toggleClass2 		= _t.data('toggle-container-class-2') 		|| '',	// toggle class for a specific container
21539					_requestOn 			= _t.data('toggle-ajax-url-on') 			|| '',	// send request to the server when on
21540					_requestOff 		= _t.data('toggle-ajax-url-off') 			|| '',	// send request to the server when off
21541					_requestMethod 		= _t.data('toggle-ajax-method') 			|| $.SOW.core.btn_toggle.config.method,	// send request to the server when off
21542					_bodyToggleClass 	= _t.data('toggle-body-class') 				|| '';	// toggle class for body
21543
21544
21545				// Stop!
21546				if(_t.hasClass('disabled'))
21547					return;
21548
21549				// example: Like button - stop if off is not set but on is set!
21550				// Means only LIKE allowed!
21551				if(_requestOff == '' && _requestOn != '' && _t.hasClass('active'))
21552					return null;
21553
21554
21555				// set|uset active class
21556				_t.toggleClass('active');
21557
21558
21559				if(_target == '' && _targetRw != '')
21560					_target = _targetRw;
21561
21562
21563				if(_target != '' && _toggleClass != '') {
21564
21565					jQuery(_target).toggleClass(_toggleClass);
21566					e.preventDefault();
21567
21568				}
21569
21570				if(_target2 != '' && _toggleClass != '')
21571					jQuery(_target2).toggleClass(_toggleClass2);
21572
21573
21574				if(_bodyToggleClass != '') {
21575
21576					jQuery('body').toggleClass(_bodyToggleClass);
21577					e.preventDefault();
21578
21579				}
21580
21581
21582
21583				if(_temporized > 0) {
21584
21585					setTimeout(function() {
21586
21587						if(_target != '' && _toggleClass != '')
21588							jQuery(_target).removeClass(_toggleClass);
21589
21590						if(_target2 != '' && _toggleClass2 != '')
21591							jQuery(_target2).removeClass(_toggleClass2);
21592
21593						if(_bodyToggleClass != '')
21594							jQuery('body').removeClass(_bodyToggleClass);
21595
21596						_t.removeClass('active');
21597
21598					}, Number(_temporized));
21599
21600
21601					// NO AJAX REQUESTS IF _temporized SET
21602					return;
21603				}
21604
21605
21606
21607
21608
21609
21610
21611				/**
21612
21613					Ajax Request
21614					---------------------------------------------------------------
21615
21616				**/
21617				if(_requestOff == '' && _requestOn == '')
21618					return null;
21619
21620
21621				e.preventDefault();
21622				var _url = _t.hasClass('active') ? _requestOn : _requestOff;
21623
21624
21625				// Ajax Request
21626				jQuery.ajax({
21627					url:			_url,
21628					type: 			_requestMethod,
21629					data: 			$.SOW.core.btn_toggle.config.data_params,
21630					contentType: 	$.SOW.core.btn_toggle.config.contentType,
21631					dataType: 		$.SOW.core.btn_toggle.config.dataType,
21632					headers: 		$.SOW.core.btn_toggle.config.headers,
21633					crossDomain: 	$.SOW.core.btn_toggle.config.crossDomain,
21634
21635					beforeSend: function() {
21636
21637						$.SOW.helper.consoleLog('SOW Btn Toggle [Ajax][Request Sent]: ' + _url);
21638
21639					},
21640
21641					error: 	function(XMLHttpRequest, textStatus, errorThrown) {
21642
21643						if(typeof $.SOW.core.toast === 'object') {
21644							$.SOW.core.toast.show('danger', '404 Error', 'Unexpected Internal error!', 'bottom-center', 0, true);
21645						} else {
21646							alert("[404] Unexpected internal error!");
21647						}
21648
21649						// if debug enabled, see config
21650						if($.SOW.config.sow__debug_enable === true) {
21651							$.SOW.helper.consoleLog('----------------------------');
21652							$.SOW.helper.consoleLog('--- AJAX REQUEST ERROR ----');
21653							$.SOW.helper.consoleLog(' - MODAL -');
21654							$.SOW.helper.consoleLog('1. XMLHttpRequest:');
21655							$.SOW.helper.consoleLog(XMLHttpRequest);
21656							$.SOW.helper.consoleLog('2. textStatus:');
21657							$.SOW.helper.consoleLog(textStatus);
21658							$.SOW.helper.consoleLog('3. errorThrown:');
21659							$.SOW.helper.consoleLog(errorThrown);
21660							$.SOW.helper.consoleLog('----------------------------');
21661						}
21662
21663					},
21664
21665					success: function(data) {
21666
21667						$.SOW.helper.consoleLog('SOW Btn Toggle [Ajax][Server Response]: ' + data);
21668
21669
21670						// OPk, disable Like button!
21671						if(_requestOff == '' && _requestOn != '')
21672							_t.addClass('disabled');
21673
21674
21675						if(_toastMessage != '' && typeof $.SOW.core.toast === 'object')
21676							$.SOW.core.toast.show('success', '', _toastMessage, _toastPos, 1500, true);
21677
21678					}
21679
21680				});
21681
21682
21683			});
21684		},
21685
21686
21687	};
21688
21689
21690})(jQuery);
21691/**
21692 *
21693 *	[SOW] Nav Deep
21694 *
21695 *	@author 		Dorin Grigoras
21696 *					www.stepofweb.com
21697 *
21698 *	@Dependency 	-
21699 *	@Usage 			$.SOW.core.nav_deep.init('.nav-deep', {speed:200});
21700 *
21701 *
21702 **/
21703;(function ($) {
21704	'use strict';
21705
21706
21707	/**
21708	 *
21709	 *	@vars
21710	 *
21711	 *
21712	 **/
21713	var scriptInfo 		= 'SOW Nav Deep';
21714	window.firstLoad 	= true;
21715
21716	$.SOW.core.nav_deep = {
21717
21718
21719		/**
21720		 *
21721		 *	@config
21722		 *
21723		 *
21724		 **/
21725		config: {
21726			speed: 200
21727		},
21728
21729
21730
21731		/**
21732		 *
21733		 *	@collection
21734		 *
21735		 *
21736		 **/
21737		collection: $(),
21738
21739
21740
21741		/**
21742		 *
21743		 *	@init
21744		 *
21745		 *
21746		 **/
21747		init: function (selector, config) {
21748
21749			var __selector 			= $.SOW.helper.__selector(selector);
21750			var __config 			= $.SOW.helper.check_var(config);
21751
21752			this.selector 			= __selector[0]; 	// '#selector'
21753			this.collection 		= __selector[1]; 	// $('#selector')
21754			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
21755
21756
21757			// Nav Tabs
21758			$.SOW.core.nav_deep.process_tabs();
21759
21760
21761			if(jQuery(this.selector).length < 1)
21762				return;
21763
21764
21765			// -- * --
21766			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
21767			// -- * --
21768
21769
21770			// on page refresh, scroll sidebar to active link/item
21771			// in case there are many links!
21772			if(window.firstLoad) {
21773				window.firstLoad = false;
21774				$.SOW.core.nav_deep.asideScrollToActiveLink(this.selector);
21775			}
21776
21777
21778			// 1. Has no selector
21779			if(!this.selector) {
21780				$.SOW.core.nav_deep.process($('.nav-deep'));
21781				return this.collection;
21782			}
21783
21784			// 2. Has selector
21785			return this.collection.each(function() {
21786
21787				$.SOW.core.nav_deep.process($(this));
21788
21789			});
21790
21791		},
21792
21793
21794
21795		/**
21796		 *
21797		 *	@process
21798		 *
21799		 *
21800		 **/
21801		process: function(_this) {
21802
21803			_this.not('.js-ajaxified').addClass('js-ajaxified').each(function() {
21804
21805				var _tnd 		= jQuery(this),
21806					js_ignore 	= _tnd.hasClass('js-ignore');
21807
21808				$('.nav-link', jQuery(this)).on('click', function(e) {
21809
21810					var _t 							= jQuery(this),
21811						_href 						= _t.attr('href') 	|| '#',
21812						_target 					= _t.attr('target') || '';
21813
21814
21815					// Ignore on target _blank, _self...
21816					if(_target != '')
21817						return;
21818
21819
21820
21821					if(!_t.parent('.nav-item').hasClass('active')) {
21822
21823						// 1. Open
21824						$.SOW.core.nav_deep.nav_deep_open(_t);
21825
21826					} else {
21827
21828						// 2. Close
21829						$.SOW.core.nav_deep.nav_deep_close(_t);
21830
21831					}
21832
21833
21834
21835					// 3. Close all other open navs only if .js-ignore is not present!
21836					if(!js_ignore)
21837						$.SOW.core.nav_deep.nav_deep_close_all(_t);
21838
21839
21840
21841					// --
21842					if(_href == '#' || _href == '#!')
21843						e.preventDefault();
21844
21845				});
21846
21847			});
21848
21849		},
21850
21851
21852
21853
21854
21855
21856		/**
21857
21858			:: Single Item
21859			Navigation Links : Open
21860
21861		**/
21862		nav_deep_open: function(_t) {
21863
21864			_t.next('ul').slideDown(this.config.speed, function(e) {
21865				_t.parent('.nav-item').addClass('active');
21866				jQuery(this).css({"display":""}); // remove display: block
21867			});
21868
21869		},
21870
21871
21872
21873		/**
21874
21875			:: Single Item
21876			Navigation Links : Close
21877
21878
21879		**/
21880		nav_deep_close: function(_t) {
21881
21882			_t.next('ul').slideUp(this.config.speed, function(e) {
21883				_t.parent('.nav-item').removeClass('active');
21884				jQuery(this).css({"display":""}); // remove display: block
21885			});
21886
21887		},
21888
21889
21890
21891
21892		/**
21893
21894			:: Multiple Items
21895			Navigation Links : Close Active
21896
21897
21898		**/
21899		nav_deep_close_all: function(_t) {
21900
21901			// Close all open parents
21902			_t.parent('.nav-item').parent().find('.nav-item.active').not(_t.parent('.nav-item')).find('ul.nav').slideUp(this.config.speed, function(e) {
21903
21904				jQuery(this).parent('.nav-item.active').removeClass('active').next().find('ul.nav').css({"display":""}); // remove display: block added by slideUp()
21905
21906			});
21907
21908
21909			// Single link (no childs) - add .active. Ajax Purpose!
21910			if(_t.next().find('ul.nav').length < 1)
21911				_t.parent('.nav-item').addClass('active');
21912
21913
21914			// Remove .active from singles (without childs) - ajax purpose only
21915			setTimeout(function() { // do not interfere with the one above!
21916				_t.parent('.nav-item').parent().find('.nav-item.active').not(_t.parent('.nav-item')).removeClass('active');
21917			}, this.config.speed + 30);
21918
21919		},
21920
21921
21922
21923
21924
21925		/**
21926		 *
21927		 *	@asideScrollToActiveLink
21928		 *
21929			on page refresh, scroll sidebar to active link/item
21930			needed when there are many links!
21931
21932			Do not move this function to sow.sidebar.js
21933			this selector is needed!
21934		 *
21935		 **/
21936		asideScrollToActiveLink: function(selector) {
21937
21938			if(jQuery('aside '+selector+' .nav-item.active').length < 1)
21939				return;
21940
21941			var activeLinkOffset 		= jQuery('aside '+selector+' .nav-item.active').offset();
21942			var scrollableDivOffset 	= jQuery('aside .scrollable-vertical').offset();
21943
21944			// issue when window height is smaller and element is fixed/absolute outside of viewport
21945			if(!scrollableDivOffset || !activeLinkOffset) return;
21946
21947			var scrollDivTo 			=  (activeLinkOffset.top - scrollableDivOffset.top) - Math.round($.SOW.globals.height / 8);
21948
21949			if(activeLinkOffset.top < $.SOW.globals.height)
21950				return;
21951
21952			jQuery('aside .scrollable-vertical:not(.js-ignore)').animate({
21953				scrollTop: scrollDivTo
21954			}, 0);
21955
21956		},
21957
21958
21959
21960
21961
21962		/**
21963		 *
21964		 *	@process_tabs
21965		 *	@add to any tab link: .nav-link-remember
21966		 *
21967		 **/
21968		process_tabs: function() {
21969
21970			// add to localStorage
21971			jQuery('a.nav-link-remember').on('click', function(e) {
21972				localStorage.setItem('activeNavTab', jQuery(e.target).attr('href'));
21973			});
21974
21975			// get from localStorage
21976			var activeNavTab = localStorage.getItem('activeNavTab');
21977			if(activeNavTab) {
21978				jQuery('a.nav-link-remember[href="' + activeNavTab + '"]').tab('show');
21979			}
21980
21981		}
21982
21983
21984	};
21985
21986
21987})(jQuery);
21988/**
21989 *
21990 *	[SOW] Form Validate
21991 *
21992 *	@author 		Dorin Grigoras
21993 *					www.stepofweb.com
21994 *
21995 *	@Dependency 	-
21996 *	@Usage			$.SOW.core.form_validate.init('form.bs-validate');
21997 *
21998 *
21999 **/
22000;(function ($) {
22001	'use strict';
22002
22003
22004	/**
22005	 *
22006	 *	@vars
22007	 *
22008	 *
22009	 **/
22010	var scriptInfo 		= 'SOW Form Validate';
22011
22012
22013
22014
22015	$.SOW.core.form_validate = {
22016
22017
22018		/**
22019		 *
22020		 *	@config
22021		 *
22022		 *
22023		 **/
22024		config: {},
22025
22026
22027
22028		/**
22029		 *
22030		 *	@collection
22031		 *
22032		 *
22033		 **/
22034		collection: $(),
22035
22036
22037
22038		/**
22039		 *
22040		 *	@init
22041		 *
22042		 *
22043		 **/
22044		init: function (selector, config) {
22045
22046			var __selector 			= $.SOW.helper.__selector(selector);
22047			var __config 			= $.SOW.helper.check_var(config);
22048
22049			this.selector 			= __selector[0]; 	// '#selector'
22050			this.collection 		= __selector[1]; 	// $('#selector')
22051			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
22052
22053
22054			if(jQuery(this.selector).length < 1)
22055				return;
22056
22057
22058			// -- * --
22059			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
22060			// -- * --
22061
22062
22063			// 1. Has no selector
22064			if(!this.selector) {
22065				$.SOW.core.form_validate.form_validate($('form.bs-validate'));
22066				return this.collection;
22067			}
22068
22069			// 2. Has selector
22070			return this.collection.each(function() {
22071
22072				$.SOW.core.form_validate.form_validate($(this));
22073
22074			});
22075
22076		},
22077
22078
22079
22080		/**
22081		 *
22082		 *	@form_validate
22083		 *
22084		 *
22085		 *
22086		 **/
22087		form_validate: function(_this) {
22088
22089			var _selector 		= this.selector;
22090
22091	 		// Stop if ajax form already in action!
22092			if(jQuery(_selector).hasClass('.js-ajax') && typeof $.SOW.core.ajax_form === 'object') {
22093				$.SOW.helper.consoleLog('Ajax Form Detected! ' + scriptInfo + ' Skipped!');
22094				return;
22095			}
22096
22097
22098			_this.submit(function(e) {
22099
22100				var _t 					= jQuery(this),
22101					_formID				= _t.attr('id')							|| '',
22102					_scrollErrUp 		= _t.attr('data-error-scroll-up') 		|| 'false',
22103					_toast_text 		= _t.data('error-toast-text')			|| '',			// toast alert for .bs-validate
22104					_toast_delay 		= _t.data('error-toast-delay')			|| 0,			// toast alert for .bs-validate
22105					_toast_pos 			= _t.data('error-toast-position')		|| "top-right";	// toast alert for .bs-validate
22106
22107				// Assign a random id if not exist
22108				if(_formID == '') {
22109					var _formID = 'js_' + $.SOW.helper.randomStr(10);
22110					_t.attr('id', _formID);
22111				}
22112
22113				// Check if form already handled by ajax
22114				if(typeof $.SOW.core.ajax_form === 'object' && _t.hasClass('js-ajax'))
22115					return;
22116
22117				var _form = document.getElementById(_formID);
22118
22119				// hide all errors info
22120				jQuery('.bs-validate-info', _t).addClass('hide hide-force');
22121
22122				if(typeof $.SOW.core.toast === 'object')
22123					$.SOW.core.toast.destroy();
22124
22125
22126				if(!_form.checkValidity()) {
22127
22128
22129					// -- message|toast ---
22130					if(_toast_text != '') {
22131
22132						if(typeof $.SOW.core.toast === 'object') {
22133
22134							if(Number(_toast_delay) < 1)
22135								var _toast_delay = 4000;
22136
22137							$.SOW.core.toast.show('danger', '', _toast_text, _toast_pos, Number(_toast_delay), true);
22138
22139						} else {
22140
22141							alert(_toast_text);
22142
22143						}
22144
22145					} else {
22146
22147						// show error info
22148						jQuery('.bs-validate-info', _t).removeClass('hide hide-force'); // show error info
22149
22150						// error info delay timeout
22151						var _delay = jQuery('.bs-validate-info', _t).data('error-alert-delay') || 3000;
22152
22153						// hide error info in X seconds
22154						setTimeout(function() {
22155							jQuery('.bs-validate-info', _t).addClass('hide hide-force');
22156						}, Number(_delay));
22157
22158					}
22159					// -- -- -- --
22160
22161					// Focus invalid element and scroll
22162					jQuery('.form-control:invalid', _t).first().focus();
22163
22164					// Do not animate inside modal!
22165					if(typeof $.SOW.helper.scrollAnimate === "function" && (_scrollErrUp+'' == 'true') && !jQuery('.modal').hasClass('show')) {
22166						var _formEl = jQuery('input:invalid, select:invalid, textarea:invalid', _t);
22167						$.SOW.helper.scrollAnimate(_formEl, 0, false, 200);
22168					}
22169					// -- -- -- --
22170
22171					e.preventDefault();
22172					e.stopPropagation();
22173
22174				}  else {
22175
22176					// disable on submit to avoid multiple click
22177					jQuery('.btn-bs-validate').attr('disabled', true);
22178
22179					if(typeof $.SOW.core.toast === 'object')
22180						$.SOW.core.toast.destroy();
22181
22182				}
22183
22184				_t.addClass('was-validated');
22185
22186
22187			});
22188
22189
22190		},
22191
22192	}
22193
22194})(jQuery);
22195/**
22196 *
22197 *	[SOW] Form Advanced
22198 *
22199 *	@author 		Dorin Grigoras
22200 *					www.stepofweb.com
22201 *
22202 *	@Dependency 	-
22203 *	@Usage			$.SOW.core.form_advanced.init();
22204 *
22205 *
22206 **/
22207;(function ($) {
22208	'use strict';
22209
22210
22211	/**
22212	 *
22213	 *	@vars
22214	 *
22215	 *
22216	 **/
22217	var scriptInfo 				= 'SOW Form Advanced';
22218
22219
22220	$.SOW.core.form_advanced = {
22221
22222
22223		/**
22224		 *
22225		 *	@config
22226		 *
22227		 *
22228		 **/
22229		config: {
22230
22231			/*
22232
22233				1. Bulk
22234				@form_advanced_bulk
22235
22236			*/
22237			selector_advanced_bulk: 			"a.js-form-advanced-bulk",
22238			advanced_bulk_selected_require: 	false,
22239
22240				// toast messages
22241				toast_pos: 							'bottom-center',
22242				toast_delay: 						2000,
22243				toast_msg_noitems: 					'No Items Selected!',
22244
22245
22246
22247			/*
22248
22249				2. Form input numeric limit
22250				@form_advanced_numeric_limit
22251
22252			*/
22253			selector_advanced_numeric_limit: 		"input.js-form-advanced-limit",
22254
22255
22256
22257
22258			/*
22259
22260				3. Form char count
22261				@form_advanced_char_count_down
22262
22263			*/
22264			selector_advanced_char_count_down: 		"input.js-form-advanced-char-count-down, textarea.js-form-advanced-char-count-down",
22265			selector_advanced_char_count_up: 		"input.js-form-advanced-char-count-up, textarea.js-form-advanced-char-count-up",
22266			selector_advanced_type_toggle: 			".btn-password-type-toggle",
22267
22268		},
22269
22270
22271
22272		/**
22273		 *
22274		 *	@collection
22275		 *
22276		 *
22277		 **/
22278		collection: $(),
22279
22280
22281
22282		/**
22283		 *
22284		 *	@init
22285		 *
22286		 *
22287		 **/
22288		init: function (selector, config) {
22289
22290			var __selector 			= $.SOW.helper.__selector(selector);
22291			var __config 			= $.SOW.helper.check_var(config);
22292
22293			this.selector 			= __selector[0]; 	// '#selector'
22294			this.collection 		= __selector[1]; 	// $('#selector')
22295			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
22296
22297
22298			// 1. Bulk
22299			$.SOW.core.form_advanced.form_advanced_bulk(this.config.selector_advanced_bulk);
22300
22301			// 2. Form input numeric limit
22302			$.SOW.core.form_advanced.form_advanced_numeric_limit(this.config.selector_advanced_numeric_limit);
22303
22304			// 3. Form char count down
22305			$.SOW.core.form_advanced.form_advanced_char_count_down(this.config.selector_advanced_char_count_down);
22306
22307			// 4. Form char count up
22308			$.SOW.core.form_advanced.form_advanced_char_count_up(this.config.selector_advanced_char_count_up);
22309
22310			// 5. Form password toggle
22311			$.SOW.core.form_advanced.form_advanced_type_toggle(this.config.selector_advanced_type_toggle);
22312
22313			// 6. Misc
22314			$.SOW.core.form_advanced.formatCreditCard();
22315			$.SOW.core.form_advanced.formAdvancedList();
22316			$.SOW.core.form_advanced.formAdvancedReset();
22317
22318
22319			// No chaining
22320			return null;
22321
22322		},
22323
22324
22325
22326		/**
22327		 *
22328		 *	@form_advanced_bulk
22329		 	Form actions[submit] using a regular link
22330		 *
22331		 *
22332		 *
22333		 **/
22334		form_advanced_bulk: function(_this) {
22335
22336			// -- * --
22337			if(jQuery(_this).length > 0)
22338				$.SOW.helper.consoleLog('Init : ' + scriptInfo);
22339			// -- * --
22340
22341
22342			jQuery(_this).not('.js-form-advancified').addClass('js-form-advancified').on('click', function(e) {
22343				e.preventDefault();
22344
22345				var _t 							= jQuery(this),
22346
22347					_citems						= _t.data('js-form-advanced-bulk-container-items') 						|| 'table tbody',		// from what container to count checked items?
22348					_reqSelectedItems 			= _t.data('js-form-advanced-bulk-required-selected')					|| $.SOW.core.form_advanced.config.advanced_bulk_selected_require,
22349					_requiredMsg 				= _t.data('js-form-advanced-bulk-required-txt-error') 					|| $.SOW.core.form_advanced.config.toast_msg_noitems,
22350					_requiredMsgPos 			= _t.data('js-form-advanced-bulk-required-txt-position') 				|| $.SOW.core.form_advanced.config.toast_pos,		// button icon
22351
22352					// Modal
22353					_reqModalCustom 			= _t.data('js-form-advanced-bulk-required-custom-modal') 				|| '', // modal id
22354					_reqModalCustomAjaxUrl		= _t.data('js-form-advanced-bulk-required-custom-modal-content-ajax')	|| '',
22355
22356					_reqModalType 				= _t.data('js-form-advanced-bulk-required-modal-type')					|| 'secondary',
22357					_reqModalSize 				= _t.data('js-form-advanced-bulk-required-modal-size')					|| 'modal-md',
22358					_reqModalTitle 				= _t.data('js-form-advanced-bulk-required-modal-txt-title')				|| 'Please Confirm',
22359					_reqModalTxtSubtitle 		= _t.data('js-form-advanced-bulk-required-modal-txt-subtitle')			|| '-',
22360					_reqModalTxtBodyTxt			= _t.data('js-form-advanced-bulk-required-modal-txt-body-txt')			|| 'Are you sure?',
22361					_reqModalTxtBodyInfo		= _t.data('js-form-advanced-bulk-required-modal-txt-body-info')			|| '',
22362					_reqModalBtnTxtYes 			= _t.data('js-form-advanced-bulk-required-modal-btn-text-yes')			|| 'Submit',
22363					_reqModalBtnTxtNo 			= _t.data('js-form-advanced-bulk-required-modal-btn-text-no')			|| 'Cancel',
22364					_reqModalBtnIcoYes 			= _t.data('js-form-advanced-bulk-required-modal-btn-icon-yes') 			|| $.SOW.config.sow__icon_check,		// button icon
22365					_reqModalBtnIcoNo 			= _t.data('js-form-advanced-bulk-required-modal-btn-icon-no') 			|| $.SOW.config.sow__icon_close,		// button icon
22366
22367					// Form
22368					_formID 					= _t.attr('data-js-form-advanced-form-id')								|| '', // form#id .attr REQUIRED, or old one used!
22369					_formSubmitNoConfirm 		= _t.data('js-form-advanced-bulk-submit-without-confirmation')			|| 'false',
22370
22371					// Hidden action input
22372					_formActionID				= _t.data('js-form-advanced-bulk-hidden-action-id')						|| '#action',
22373					_formActionVal				= _t.data('js-form-advanced-bulk-hidden-action-value')					|| '';
22374
22375				// count selecteditems & update
22376				var total_selected_items = jQuery(_citems + " input:checked").length;
22377
22378
22379
22380				// Check for required selected items
22381				if(_reqSelectedItems == true && Number(total_selected_items) < 1) {
22382
22383					// SHOW ERROR
22384					if(typeof $.SOW.core.toast === 'object') {
22385						$.SOW.core.toast.destroy();
22386						$.SOW.core.toast.show('danger', '', _requiredMsg, _requiredMsgPos, $.SOW.core.form_advanced.config.toast_delay, true);
22387					} else {
22388						alert(_requiredMsg);
22389					}
22390
22391					e.stopPropagation();
22392					return;
22393
22394				}
22395
22396
22397
22398
22399
22400
22401				// Update action hidden input
22402				if(_formActionVal != '')
22403					jQuery(_formActionID).val(_formActionVal);
22404
22405
22406				// Direct submit, no confirmation
22407				if(_formSubmitNoConfirm != 'false') {
22408					jQuery(_formID).unbind().submit(); // unbind required
22409					return;
22410				}
22411
22412
22413				// Button Icons
22414				if(_reqModalBtnIcoYes.length > 1)
22415					var _reqModalBtnTxtYes = '<i class="' + _reqModalBtnIcoYes + '"></i> ' + _reqModalBtnTxtYes;
22416
22417				if(_reqModalBtnIcoNo.length > 1)
22418					var _reqModalBtnTxtNo = '<i class="' + _reqModalBtnIcoNo + '"></i> ' + _reqModalBtnTxtNo;
22419
22420
22421				// Replacements
22422				_reqModalTitle 			= _reqModalTitle.replace('{{no_selected}}', total_selected_items);
22423				_reqModalTxtBodyTxt 	= _reqModalTxtBodyTxt.replace('{{no_selected}}', total_selected_items);
22424				_reqModalTxtBodyInfo 	= _reqModalTxtBodyInfo.replace('{{no_selected}}', total_selected_items);
22425				_reqModalTxtSubtitle 	= _reqModalTxtSubtitle.replace('{{no_selected}}', total_selected_items);
22426
22427
22428				// Additional info
22429				var _reqModalTxtBodyTxt = (_reqModalTxtBodyInfo != '') ? _reqModalTxtBodyTxt + '<span class="d-block d-block fs--12 mt--3">' + _reqModalTxtBodyInfo + '</span>' : _reqModalTxtBodyTxt;
22430
22431
22432
22433
22434
22435
22436
22437
22438				// 1. Inline Modal
22439				if(_reqModalCustom != '') {
22440
22441					// Update selected items counter
22442					if(_reqModalCustom != '')
22443						$.SOW.core.form_advanced.form_advanced_bulk_counter_update(total_selected_items);
22444
22445
22446					// SHOW MODAL
22447					jQuery(_reqModalCustom).modal('show');
22448
22449
22450					// LOAD FROM AJAX
22451					if(_reqModalCustomAjaxUrl != '') {
22452
22453						jQuery(_reqModalCustom).find('.modal-content').load(_reqModalCustomAjaxUrl, function() {
22454
22455							// Update selected items counter
22456							$.SOW.core.form_advanced.form_advanced_bulk_counter_update(total_selected_items);
22457
22458						});
22459
22460					}
22461
22462					// stop here
22463					return;
22464
22465
22466				}
22467
22468
22469
22470
22471				// 2. Generated modal
22472				var _tpl = '<div class="modal fade" id="js_advanced_form_bulk_modal_confirm" role="dialog" tabindex="-1" aria-labelledby="modal-title-confirm" aria-hidden="true">'
22473					+ '<div class="modal-dialog '+_reqModalSize+'" role="document">'
22474
22475						+ '<div class="modal-content">'
22476
22477							+ '<div class="modal-header b-0 bg-'+_reqModalType+'-soft">'
22478
22479								+ '<h5 id="modal-title-confirm" class="modal-title font-light fs--18 line-height-1">'
22480									+ _reqModalTitle
22481									+ '<small class="d-block fs--12 mt--3">'+_reqModalTxtSubtitle+'</small>'
22482								+ '</h5>'
22483
22484								+ '<button type="button" class="close" data-dismiss="modal" aria-label="Close">'
22485									+ '<span class="'+$.SOW.config.sow__icon_close+' fs--18" aria-hidden="true"></span>'
22486								+ '</button>'
22487
22488							+ '</div>'
22489
22490							+ '<div class="modal-body fs--18 pt--30 pb--30">'
22491
22492									+ _reqModalTxtBodyTxt
22493
22494							+ '</div>'
22495
22496							+ '<div class="modal-footer">'
22497
22498								+ '<button type="submit" class="btn pt--10 pb--10 fs--16 btn-js-advanced-form-bulk-confirm-yes btn-'+ _reqModalType +'">'
22499									+ _reqModalBtnTxtYes
22500								+ '</button>'
22501
22502								+ '<a href="#" class="btn pt--10 pb--10 fs--16 btn-js-advanced-form-bulk-confirm-no btn-light" data-dismiss="modal">'
22503									+ _reqModalBtnTxtNo
22504								+ '</a>'
22505
22506							+ '</div>'
22507
22508						+ '</div>'
22509
22510					+ '</div>'
22511				+ '</div>';
22512
22513				// Add modal to DOM
22514
22515				$('#js_advanced_form_bulk_modal_confirm').remove();
22516				$(_formID).append(_tpl); // REQUIRED INSIDE THE FORM! Because of Submit button!
22517
22518				// Show Modal
22519				$('#js_advanced_form_bulk_modal_confirm').modal('handleUpdate').modal('show');
22520
22521				// Custom Ajax Content
22522				if(_reqModalCustomAjaxUrl != '') {
22523
22524					jQuery('#js_advanced_form_bulk_modal_confirm .modal-body').empty().append('<div class="py-4 text-center animate-bouncein"><i class="'+$.SOW.config.sow__icon_loading+' fs--40 text-muted"></i></div>');
22525
22526					jQuery('#js_advanced_form_bulk_modal_confirm .modal-body').load(_reqModalCustomAjaxUrl, function() {
22527
22528						// Update selected items counter
22529						$.SOW.core.form_advanced.form_advanced_bulk_counter_update(total_selected_items);
22530
22531					});
22532				}
22533
22534				return;
22535
22536
22537			});
22538
22539
22540		},
22541
22542
22543
22544
22545		/**
22546		 *
22547		 *	@form_advanced_bulk_counter_update
22548		 *	:: Helper
22549		 *
22550		 *
22551		 **/
22552		form_advanced_bulk_counter_update: function(total_selected_items) {
22553
22554			// Update selected items
22555			jQuery('.js-form-advanced-selected-items').html(total_selected_items);
22556
22557		},
22558
22559
22560		/**
22561		 *
22562		 *	@form_advanced_numeric_limit
22563		 	Input min/max limits
22564
22565				<!-- input limit + hidden message -->
22566				<div class="position-relative">
22567
22568					<span class="js-form-advanced-limit-info badge badge-warning hide animate-bouncein position-absolute absolute-top m--2">
22569						please, order between 1 and 48.
22570					</span>
22571
22572					<input type="number" value="8" min="1" max="48" class="form-control js-form-advanced-limit">
22573				</div>
22574				<!-- /input limit + hidden message -->
22575
22576		 *
22577		 *
22578		 *
22579		 **/
22580		form_advanced_numeric_limit: function(_this) {
22581
22582			if(jQuery(_this).length < 1)
22583				return;
22584
22585			jQuery(_this).keyup(function() {
22586				var _t 		= jQuery(this),
22587					_val 	= _t.val() 		 || '',
22588					_min 	= _t.attr('min') || '',
22589					_max 	= _t.attr('max') || '';
22590
22591				if(_min == '' || _max == '')
22592					return;
22593
22594				if(Number(_val) < Number(_min))
22595					_t.val(_min);
22596
22597				else if(Number(_val) > Number(_max)) {
22598					_t.val(_max);
22599
22600					// Optional simple info message
22601					$.SOW.core.form_advanced.form_advanced_simple_alert(_t);
22602				}
22603
22604
22605			});
22606
22607		},
22608
22609
22610
22611		/**
22612		 *
22613		 *	@form_advanced_char_count_down
22614		 	Char Count Down
22615
22616			<!-- input -->
22617			<div class="position-relative">
22618
22619				<span class="js-form-advanced-limit-info badge badge-warning hide animate-bouncein position-absolute absolute-top m--2">
22620					100 chars limit
22621				</span>
22622
22623				<input type="text" name="-" class="form-control js-form-advanced-char-count-down" data-output-target=".js-form-advanced-char-left" value="" maxlength="100">
22624
22625				<div class="fs--12 text-muted text-align--end mt--3">
22626					characters left: <span class="js-form-advanced-char-left">100</span>
22627				</div>
22628
22629			</div>
22630
22631			<br>
22632
22633			<!-- textarea -->
22634			<div class="position-relative">
22635
22636				<span class="js-form-advanced-limit-info badge badge-warning hide animate-bouncein position-absolute absolute-top m--2">
22637					100 chars limit
22638				</span>
22639
22640				<textarea class="js-form-advanced-char-count-down form-control" data-output-target=".js-form-advanced-char-left2" maxlength="100"></textarea>
22641
22642				<div class="fs--12 text-muted text-align--end mt--3">
22643					characters left: <span class="js-form-advanced-char-left2">100</span>
22644				</div>
22645
22646			</div>
22647
22648		 *
22649		 *
22650		 *
22651		 **/
22652		form_advanced_char_count_down: function(_this) {
22653
22654
22655			if(jQuery(_this).length < 1)
22656				return;
22657
22658			jQuery(_this).keyup(function(e) {
22659
22660				var _t 		= jQuery(this),
22661					_val 	= _t.val(),
22662					_length = _val.length,
22663					_max 	= _t.attr('maxlength') 		|| 0,
22664					_output = _t.data('output-target') 	|| '.char-left';
22665
22666				if(_max < 1 && _output != '')
22667					return;
22668
22669				if(_length >= _max) {
22670					_t.val(_val.substring(0, _max - 1)); // limit - remove anything over maximum allowed
22671					jQuery(_output).html('0');
22672
22673					// Optional simple info message
22674					$.SOW.core.form_advanced.form_advanced_simple_alert(_t);
22675
22676				} else {
22677					var _left = _max - _length;
22678					jQuery(_output).html(_left);
22679				}
22680
22681
22682			});
22683
22684		},
22685
22686
22687
22688
22689
22690		/**
22691		 *
22692		 *	@form_advanced_char_count_up
22693		 	Char Count Up
22694
22695
22696			Remove maxlength for no limit, only to count chars
22697
22698
22699
22700			<!-- input -->
22701			<div class="position-relative">
22702
22703				<span class="js-form-advanced-limit-info badge badge-warning hide animate-bouncein position-absolute absolute-top m--2">
22704					100 chars limit
22705				</span>
22706
22707				<input type="text" name="-" class="form-control js-form-advanced-char-count-up" data-output-target=".js-form-advanced-char-total" value="" maxlength="100">
22708
22709				<div class="fs--12 text-muted text-align--end mt--3">
22710					characters: <span class="js-form-advanced-char-total">0</span> / 100
22711				</div>
22712
22713			</div>
22714
22715			<br>
22716
22717			<!-- textarea -->
22718			<div class="position-relative">
22719
22720				<span class="js-form-advanced-limit-info badge badge-warning hide animate-bouncein position-absolute absolute-top m--2">
22721					100 chars limit
22722				</span>
22723
22724				<textarea class="js-form-advanced-char-count-up form-control" data-output-target=".js-form-advanced-char-total2" maxlength="100"></textarea>
22725
22726				<div class="fs--12 text-muted text-align--end mt--3">
22727					characters: <span class="js-form-advanced-char-total2">0</span> / 100
22728				</div>
22729
22730			</div>
22731
22732		 *
22733		 *
22734		 *
22735		 **/
22736		form_advanced_char_count_up: function(_this) {
22737
22738			if(jQuery(_this).length < 1)
22739				return;
22740
22741			jQuery(_this).keyup(function() {
22742
22743				var _t 		= jQuery(this),
22744					_val 	= _t.val(),
22745					_length = _val.length 				|| 0,
22746					_max 	= _t.attr('maxlength') 		|| 0,
22747					_output = _t.data('output-target') 	|| '.char-count';
22748
22749				jQuery(_output).html(_length);
22750
22751				// limit if specified
22752				if(_length >= _max && _max > 0) {
22753					_t.val(_val.substring(0, _max)); // limit - remove anything over maximum allowed
22754
22755					// Optional simple info message
22756					$.SOW.core.form_advanced.form_advanced_simple_alert(_t);
22757				}
22758
22759			});
22760
22761		},
22762
22763
22764
22765
22766		/**
22767		 *
22768		 *	@form_advanced_simple_alert
22769		 *	Optional form alert
22770		 *
22771		 *
22772		 **/
22773		form_advanced_simple_alert: function(_this) {
22774
22775			_this.next('.js-form-advanced-limit-info').removeClass('hide');
22776			_this.prev('.js-form-advanced-limit-info').removeClass('hide');
22777
22778			setTimeout(function() {
22779				_this.next('.js-form-advanced-limit-info').addClass('hide');
22780				_this.prev('.js-form-advanced-limit-info').addClass('hide');
22781			}, 3000);
22782
22783		},
22784
22785
22786
22787
22788		/**
22789		 *
22790		 *	@form_advanced_type_toggle
22791		 *
22792		 *
22793		 **/
22794		form_advanced_type_toggle: function(_this) {
22795
22796			if(jQuery(_this).length < 1)
22797				return;
22798
22799			jQuery(_this).on('click', function(e) {
22800				e.preventDefault();
22801
22802				var _target = jQuery(this).data('target') || '';
22803
22804				if(_target == '')
22805					return;
22806
22807				jQuery(this).toggleClass('active');
22808				if(jQuery(_target).attr('type') == 'password') {
22809					jQuery(_target).attr('type', 'text');
22810				} else {
22811					jQuery(_target).attr('type', 'password');
22812				}
22813
22814			});
22815
22816		},
22817
22818
22819
22820
22821		/**
22822		 *
22823		 *	@formAdvancedList
22824		 * 	on a list, reveal/expand selected (example: payment method - checkout)
22825		 *
22826		 **/
22827		formAdvancedList: function() {
22828
22829			jQuery('.form-advanced-list').each(function() {
22830
22831				var _t = jQuery(this);
22832
22833				jQuery('.form-advanced-list-reveal', _t).on('change', function() {
22834
22835					var __t 		= jQuery(this),
22836						__target 	= __t.data('form-advanced-target') || '';
22837
22838					// hide all first
22839					jQuery('.form-advanced-list-reveal-item', _t).addClass('hide hide-force');
22840
22841					// reveal selected
22842					if(__target != '')
22843						jQuery(__target).removeClass('hide hide-force');
22844
22845				})
22846
22847			});
22848
22849		},
22850
22851
22852
22853
22854
22855		/**
22856		 *
22857		 *	@formAdvancedReset
22858		 * 	reset form on button click
22859		 *
22860		 **/
22861		formAdvancedReset: function() {
22862
22863			jQuery('.form-advanced-reset').not('.js-ignore').not('.js-advancified').addClass('js-advancified').each(function() {
22864
22865				var _t 		= jQuery(this),
22866					_target = _t.data('target-reset');
22867
22868				if(_target == '')
22869					return null;
22870
22871				jQuery(_target+' input').on('change', function() {
22872					_t.removeClass('hide hide-force');
22873				});
22874
22875				jQuery(_target+' textarea').on('change', function() {
22876					_t.removeClass('hide hide-force');
22877				});
22878
22879
22880
22881				// reset button click
22882				_t.on('click', function(e) {
22883					e.preventDefault();
22884
22885					jQuery(_target+' input').val('');
22886					jQuery(_target+' textarea').val('');
22887					jQuery(_target+' input[type=checkbox]').prop('checked', false);
22888					jQuery(_target+' input[type=radio]').prop('checked', false);
22889
22890					// hide reset button
22891					if(!_t.hasClass('js-ignore'))
22892						_t.addClass('hide hide-force');
22893
22894				});
22895
22896
22897			});
22898
22899
22900
22901
22902		},
22903
22904
22905
22906
22907
22908		/**
22909		 *
22910		 *	@formatCreditCard
22911		 *
22912		 *
22913		 **/
22914		formatCreditCard: function() {
22915
22916
22917			/*
22918
22919				Credit card number
22920
22921			*/
22922			jQuery('input.cc-format.cc-number').keyup(function() {
22923
22924				var _t 				= jQuery(this),
22925					val 			= _t.val() || '',
22926					targetCardType 	= _t.data('card-type') || '';
22927
22928				// format
22929				var cc_formatted = $.SOW.core.form_advanced.formatCardNumber(val);
22930				_t.val(cc_formatted);
22931
22932				// Credit card type
22933				if(targetCardType != '') {
22934					var cc_type = $.SOW.core.form_advanced.detectCardType(val);
22935					var cc_type = (cc_type) ? cc_type.name : '';
22936					jQuery(targetCardType).val(cc_type);
22937				}
22938
22939			});
22940
22941
22942			/*
22943
22944				Credit card expire
22945
22946			*/
22947			jQuery('input.cc-format.cc-expire').keyup(function(e) {
22948
22949				var _t 				= jQuery(this),
22950					val 			= _t.val() || '',
22951					code 			= e.keyCode,
22952					allowedKeys 	= [8];
22953
22954				if(allowedKeys.indexOf(code) !== -1) {
22955					return;
22956				}
22957
22958				e.target.value = e.target.value.replace(
22959					/^([1-9]\/|[2-9])$/g, '0$1/' // 3 > 03/
22960					).replace(
22961					/^(0[1-9]|1[0-2])$/g, '$1/' // 11 > 11/
22962					).replace(
22963					/^([0-1])([3-9])$/g, '0$1/$2' // 13 > 01/3
22964					).replace(
22965					/^(0?[1-9]|1[0-2])([0-9]{2})$/g, '$1/$2' // 141 > 01/41
22966					).replace(
22967					/^([0]+)\/|[0]+$/g, '0' // 0/ > 0 and 00 > 0
22968					).replace(
22969					/[^\d\/]|^[\/]*$/g, '' // To allow only digits and `/`
22970					).replace(
22971					/\/\//g, '/' // Prevent entering more than 1 `/`
22972				);
22973
22974			});
22975
22976		},
22977
22978
22979
22980		/**
22981		 *
22982		 *	@formatCardNumber
22983		 * 	https://www.peterbe.com/plog/cc-formatter
22984		 *
22985		 **/
22986		formatCardNumber: function(value) {
22987
22988			var v 		= value.replace(/\s+/g, '').replace(/[^0-9]/gi, '');
22989			var matches = v.match(/\d{4,16}/g);
22990			var match 	= matches && matches[0] || '';
22991			var parts 	= [];
22992
22993			for (var i=0, len=match.length; i<len; i+=4) {
22994				parts.push(match.substring(i, i+4));
22995			}
22996
22997			if(parts.length) {
22998				return parts.join(' ');
22999			} else {
23000				return value;
23001			}
23002
23003		},
23004
23005
23006
23007
23008		/**
23009		 *
23010		 *	@detectCardType
23011		 *
23012		 *
23013		 **/
23014		detectCardType: function(number) {
23015
23016		    var card_types = [
23017		      {
23018		        name: 'amex',
23019		        pattern: /^3[47]/,
23020		        valid_length: [15]
23021		      }, {
23022		        // name: 'diners_club_carte_blanche',
23023		        name: 'diners',
23024		        pattern: /^30[0-5]/,
23025		        valid_length: [14]
23026		      }, {
23027		        // name: 'diners_club_international',
23028		        name: 'diners',
23029		        pattern: /^36/,
23030		        valid_length: [14]
23031		      }, {
23032		        name: 'jcb',
23033		        pattern: /^35(2[89]|[3-8][0-9])/,
23034		        valid_length: [16]
23035		      }, {
23036		        name: 'laser',
23037		        pattern: /^(6304|670[69]|6771)/,
23038		        valid_length: [16, 17, 18, 19]
23039		      }, {
23040		        // name: 'visa_electron',
23041		        name: 'visa',
23042		        pattern: /^(4026|417500|4508|4844|491(3|7))/,
23043		        valid_length: [16]
23044		      }, {
23045		        name: 'visa',
23046		        pattern: /^4/,
23047		        valid_length: [16]
23048		      }, {
23049		        name: 'mastercard',
23050		        pattern: /^5[1-5]/,
23051		        valid_length: [16]
23052		      }, {
23053		        name: 'maestro',
23054		        pattern: /^(5018|5020|5038|6304|6759|676[1-3])/,
23055		        valid_length: [12, 13, 14, 15, 16, 17, 18, 19]
23056		      }, {
23057		        name: 'discover',
23058		        pattern: /^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/,
23059		        valid_length: [16]
23060		      }
23061		    ];
23062
23063
23064			var _j, _len1, _ref1, card, card_type, options = {};
23065			var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
23066
23067
23068			if (options.accept == null) {
23069				options.accept = (function() {
23070				var _i, _len, _results;
23071					_results = [];
23072
23073				for (_i = 0, _len = card_types.length; _i < _len; _i++) {
23074					card = card_types[_i];
23075					_results.push(card.name);
23076				}
23077
23078				return _results;
23079
23080				})();
23081			}
23082
23083			var  _ref = options.accept;
23084			for (var _i = 0, _len = _ref.length; _i < _len; _i++) {
23085				card_type = _ref[_i];
23086
23087				if (__indexOf.call((function() {
23088					var _j, _len1, _results = [];
23089
23090					for (var _j = 0, _len1 = card_types.length; _j < _len1; _j++) {
23091						card = card_types[_j];
23092						_results.push(card.name);
23093					}
23094
23095					return _results;
23096
23097				})(), card_type) < 0) {
23098
23099					// throw "Credit card type '" + card_type + "' is not supported";
23100
23101				}
23102			}
23103
23104			_ref1 = (function() {
23105				var _k, _len1, _ref1, _results = [];
23106
23107				for (_k = 0, _len1 = card_types.length; _k < _len1; _k++) {
23108					card = card_types[_k];
23109					if (_ref1 = card.name, __indexOf.call(options.accept, _ref1) >= 0) {
23110						_results.push(card);
23111					}
23112				}
23113
23114				return _results;
23115
23116			})();
23117
23118			for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
23119				card_type = _ref1[_j];
23120
23121				if (number.match(card_type.pattern)) {
23122					return card_type;
23123				}
23124
23125			}
23126
23127			return null;
23128
23129
23130			/**
23131		    var re = {
23132		        electron: 		/^(4026|417500|4405|4508|4844|4913|4917)\d+$/,
23133		        maestro: 		/^(5018|5020|5038|5612|5893|6304|6759|6761|6762|6763|0604|6390)\d+$/,
23134		        dankort: 		/^(5019)\d+$/,
23135		        interpayment: 	/^(636)\d+$/,
23136		        unionpay: 		/^(62|88)\d+$/,
23137		        visa: 			/^4[0-9]{12}(?:[0-9]{3})?$/,
23138		        mastercard: 	/^5[1-5][0-9]{14}$/,
23139		        amex: 			/^3[47][0-9]{13}$/,
23140		        diners: 		/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
23141		        discover: 		/^6(?:011|5[0-9]{2})[0-9]{12}$/,
23142		        jcb: 			/^(?:2131|1800|35\d{3})\d{11}$/
23143		    };
23144
23145		    for(var key in re) {
23146		        if(re[key].test(number)) {
23147		            return key;
23148		        }
23149		    }
23150		    **/
23151
23152		}
23153
23154	}
23155
23156})(jQuery);
23157/**
23158 *
23159 *	[SOW] Check All
23160 *
23161 *	@author 		Dorin Grigoras
23162 *					www.stepofweb.com
23163 *
23164 *	@Dependency 	-
23165 *	@Usage			$.SOW.core.checkall.init('.checkall');
23166 *
23167 *
23168 **/
23169;(function ($) {
23170	'use strict';
23171
23172
23173	/**
23174	 *
23175	 *	@vars
23176	 *
23177	 *
23178	 **/
23179	var scriptInfo 		= 'SOW Check All';
23180
23181
23182	$.SOW.core.checkall = {
23183
23184
23185		/**
23186		 *
23187		 *	@collection
23188		 *
23189		 *
23190		 **/
23191		collection: $(),
23192
23193
23194
23195		/**
23196		 *
23197		 *	@init
23198		 *
23199		 *
23200		 **/
23201		init: function (selector, config) {
23202
23203			var __selector 			= $.SOW.helper.__selector(selector);
23204			this.selector 			= __selector[0]; 	// '#selector'
23205			this.collection 		= __selector[1]; 	// $('#selector')
23206
23207
23208			if(jQuery(this.selector).length < 1)
23209				return;
23210
23211			// -- * --
23212			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
23213			// -- * --
23214
23215
23216			$.SOW.core.checkall.process(this.collection);
23217			return null;
23218
23219		},
23220
23221
23222
23223		/**
23224		 *
23225		 *	@process
23226		 *
23227		 *
23228		 **/
23229		process: function(_this) {
23230
23231			this.collection.on('click', function () {
23232				var _target = jQuery(this).data('checkall-container');
23233
23234				jQuery(_target + ' input:checkbox').not(this).prop('checked', this.checked);
23235
23236				// when starting to deselect some checboxes, remove checkall
23237				jQuery(_target + ' input:checkbox').bind("click", function () {
23238
23239					if(!jQuery(this).is(":checked")) {
23240						jQuery('input.checkall[data-checkall-container="'+_target+'"]').prop('checked', false);
23241					}
23242
23243				});
23244
23245
23246				// other checkall
23247				if(jQuery(this).is(":checked")) {
23248					jQuery('input.checkall[data-checkall-container="'+_target+'"]').prop('checked', true);
23249				} else {
23250					jQuery('input.checkall[data-checkall-container="'+_target+'"]').prop('checked', false);
23251				}
23252
23253			});
23254
23255		},
23256
23257
23258	};
23259
23260
23261})(jQuery);
23262/**
23263 *
23264 *	[SOW] GDPR
23265 *
23266 *	@author 		Dorin Grigoras
23267 *					www.stepofweb.com
23268 *
23269 *	@Dependency 	-
23270 *	@Usage			$.SOW.core.gdpr.init('#gdpr');
23271 *
23272 *
23273 **/
23274;(function ($) {
23275	'use strict';
23276
23277
23278	/**
23279	 *
23280	 *	@vars
23281	 *
23282	 *
23283	 **/
23284	var scriptInfo 		= 'SOW GDPR';
23285
23286
23287	$.SOW.core.gdpr = {
23288
23289
23290		/**
23291		 *
23292		 *	@config
23293		 *
23294		 *
23295		 **/
23296		config: {
23297
23298			cookie_name: 	'__gdpr',
23299			cookie_expire: 	365,
23300			cookie_path: 	$.SOW.globals.cookie_secure, // 'SameSite=None; secure' (Google)
23301
23302		},
23303
23304
23305
23306		/**
23307		 *
23308		 *	@collection
23309		 *
23310		 *
23311		 **/
23312		collection: $(),
23313
23314
23315
23316		/**
23317		 *
23318		 *	@init
23319		 *
23320		 *
23321		 **/
23322		init: function (selector, config) {
23323
23324			var __selector 			= $.SOW.helper.__selector(selector);
23325			var __config 			= $.SOW.helper.check_var(config);
23326
23327			this.selector 			= __selector[0]; 	// '#selector'
23328			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
23329
23330
23331			if(jQuery(this.selector).length < 1)
23332				return;
23333
23334
23335			// -- * --
23336			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
23337			// -- * --
23338
23339
23340
23341			// 1. Has no selector
23342			if(!this.selector) {
23343				$.SOW.core.gdpr.process('#gdpr');
23344				return this.collection;
23345			}
23346
23347			// 2. Has selector
23348			$.SOW.core.gdpr.process(this.selector);
23349			return this.collection;
23350
23351		},
23352
23353
23354
23355		/**
23356		 *
23357		 *	@process
23358		 *
23359
23360			<!--
23361				GDPR POPUP
23362
23363				Reset GDPR:
23364					$.SOW.core.gdpr.destroy();
23365					OR BY HASH: #del:gdpr
23366
23367				By hitting 'Accept' Button, cookie is 0 => all cookies accepted.
23368
23369				++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23370
23371				Extend Consent by level:
23372						0 = accept all cookies!
23373						1 = website only
23374						2 = website + advertising
23375						... more if needed
23376
23377					JS USAGE:
23378						$.SOW.core.gdpr.extend(2); //  // allow website + advertising
23379
23380
23381					BACKEND:
23382						Backend should use the cookie specified in config (default: cookie_name: '__gdpr')
23383
23384			-->
23385			<div id="gdpr" class="hide bg-white rounded-lg shadow-lg w-100 max-w-350 p--30 m--15 position-fixed fixed-bottom right-0 z-index-9999">
23386
23387				<h3 class="fs--18 mb-4">
23388
23389					<a href="#" class="close mt--n3">
23390						<span class="fi fi-close fs--18" aria-hidden="true"></span>
23391					</a>
23392
23393					Smarty Cookies
23394
23395				</h3>
23396
23397				<hr>
23398
23399				<p class="lead">
23400					We use cookies to improve your experience on our site and to show you personalised ads.
23401				</p>
23402
23403				<a href="#" class="btn btn-primary btn-cookie-accept btn-lg btn-block">
23404					Accept &amp; Continue
23405				</a>
23406
23407				<hr class="mt-4 mb-4">
23408
23409				<p class="m--0">
23410
23411					<span class="d-block">Need to learn more?</span>
23412
23413					<a href="#" class="link-muted">Privacy Policy</a>
23414
23415					&ndash; and &ndash;
23416
23417					<a href="../page/cookie.html" class="link-muted">Cookie Policy</a>
23418
23419				</p>
23420			</div>
23421			<!-- /GDPR POPUP -->
23422
23423		 *
23424		 **/
23425		process: function(_selector) {
23426
23427			var __gdpr = Cookies.get($.SOW.core.gdpr.config.cookie_name, { path: $.SOW.core.gdpr.config.cookie_path });
23428
23429			// --
23430
23431			// Delete by hash
23432			if(window.location.hash == '#del:gdpr') {
23433				$.SOW.helper.consoleLog($.SOW.core.gdpr.config.cookie_name+': Hash Request');
23434				$.SOW.core.gdpr.destroy();
23435				var __gdpr = null;
23436			}
23437
23438			// --
23439
23440			if(__gdpr == null) {
23441				$.SOW.helper.consoleLog($.SOW.core.gdpr.config.cookie_name+': Shown');
23442				jQuery(_selector).removeClass('hide hide-force');
23443			} else {
23444				$.SOW.helper.consoleLog($.SOW.core.gdpr.config.cookie_name+': Refresh');
23445				Cookies.set($.SOW.core.gdpr.config.cookie_name, __gdpr, { expires: $.SOW.core.gdpr.config.cookie_expire, path: $.SOW.core.gdpr.config.cookie_path }); // refresh
23446				jQuery(_selector).remove(); // just in case
23447				return;
23448			}
23449
23450			// --
23451
23452			// Accept Button
23453			jQuery(' a.btn-cookie-accept:not(.js-gdprified)').addClass('js-gdprified').on('click', function(e) {
23454				e.preventDefault();
23455
23456				/*
23457					values:
23458						0 = accept all cookies!
23459						1 = website only
23460						2 = website + advertising
23461				*/
23462				Cookies.set($.SOW.core.gdpr.config.cookie_name, 0, { expires: $.SOW.core.gdpr.config.cookie_expire, path: $.SOW.core.gdpr.config.cookie_path });
23463				jQuery(_selector).remove(); // just in case
23464				$.SOW.helper.consoleLog($.SOW.core.gdpr.config.cookie_name+': Accepted. Delete cookie by hash: #del:gdpr (developing purpose)');
23465
23466			});
23467
23468			// --
23469
23470			// Extend Button
23471			jQuery('.btn-cookie-extend:not(.js-gdprified)').addClass('js-gdprified').on('click', function(e) {
23472				e.preventDefault();
23473
23474				var __gdprLevel = jQuery(this).data('cookie-level') || 0;
23475				$.SOW.core.gdpr.extend(__gdprLevel);
23476
23477			});
23478
23479			// --
23480
23481			// Close Button
23482			jQuery(' a.close:not(.js-gdprified)').addClass('js-gdprified').on('click', function(e) {
23483				e.preventDefault();
23484
23485				jQuery(_selector).addClass('hide hide-force');
23486
23487			});
23488
23489		},
23490
23491
23492
23493
23494		/*
23495			Direct Set:
23496
23497				__gdprLevel
23498					0 = accept all cookies!
23499					1 = website only
23500					2 = website + advertising
23501					... more if needed
23502
23503			Usage:
23504				$.SOW.core.gdpr.extend(2); // allow website + advertising
23505		*/
23506		extend: function(__gdprLevel) {
23507			$.SOW.core.gdpr.destroy();
23508			$.SOW.helper.consoleLog($.SOW.core.gdpr.config.cookie_name + ': Level: ' + __gdprLevel);
23509			Cookies.set($.SOW.core.gdpr.config.cookie_name, __gdprLevel, { expires: $.SOW.core.gdpr.config.cookie_expire, path: $.SOW.core.gdpr.config.cookie_path });
23510			return true;
23511		},
23512
23513
23514
23515
23516		/**
23517		 *
23518		 *	@destroy
23519		 * 	$.SOW.core.gdpr.destroy();
23520		 *
23521		 *
23522		 **/
23523		destroy: function() {
23524
23525			Cookies.remove($.SOW.core.gdpr.config.cookie_name, { path: '' });
23526			Cookies.remove($.SOW.core.gdpr.config.cookie_name, { path: '/' });
23527			Cookies.remove($.SOW.core.gdpr.config.cookie_name, { path: $.SOW.core.gdpr.config.cookie_path });
23528			$.SOW.helper.consoleLog($.SOW.core.gdpr.config.cookie_name + ' : Cookie Deleted');
23529			return true;
23530
23531		}
23532
23533
23534	};
23535
23536
23537})(jQuery);
23538/**
23539 *
23540 *	[SOW] Sidebar
23541 *
23542 *	@author 		Dorin Grigoras
23543 *					www.stepofweb.com
23544 *
23545 *	@Dependency 	-
23546 *	@Usage			$.SOW.core.sidebar.init();
23547 *
23548 *
23549 **/
23550;(function ($) {
23551	'use strict';
23552
23553
23554	/**
23555	 *
23556	 *	@vars
23557	 *
23558	 *
23559	 **/
23560	var scriptInfo 		= 'SOW Sidebar';
23561
23562
23563	$.SOW.core.sidebar = {
23564
23565
23566		/**
23567		 *
23568		 *	@config
23569		 *
23570		 *
23571		 **/
23572		config: {},
23573
23574
23575
23576		/**
23577		 *
23578		 *	@collection
23579		 *
23580		 *
23581		 **/
23582		collection: $(),
23583
23584
23585
23586		/**
23587		 *
23588		 *	@init
23589		 *
23590		 *
23591		 **/
23592		init: function (selector, config) {
23593
23594			if(jQuery('aside').length < 1)
23595				return;
23596
23597			// -- * --
23598			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
23599			// -- * --
23600
23601
23602			$.SOW.core.sidebar.sidebar_toggle();
23603			$.SOW.core.sidebar.sidebar_minify();
23604			$.SOW.core.sidebar.sidebar_extended();
23605
23606			return this.collection;
23607
23608		},
23609
23610
23611
23612		/**
23613		 *
23614		 *	@sidebar_toggle
23615		 * 	Mobile show|hide sidebar
23616		 *
23617		 **/
23618		sidebar_toggle: function() {
23619
23620
23621			jQuery('.btn-sidebar-toggle').on('click', function(e) {
23622				e.preventDefault();
23623
23624				var _href = jQuery(this).attr('href') || '';
23625
23626				if(_href == '' || _href == '#')
23627					return;
23628
23629				jQuery(_href).toggleClass('js-aside-show');
23630				$.SOW.helper.overlay('toggle');
23631
23632				jQuery(this).toggleClass('active');
23633
23634				if( $("#sidebar-toggler").length > 0 ) {
23635					setTimeout(function() {
23636						$("#sidebar-toggler").toggleClass('cross');
23637					}, 800);
23638				}
23639
23640				// toggle back on overlay click
23641				jQuery('#overlay-default').unbind().on('click', function(e) {
23642					$.SOW.helper.overlay('hide');
23643					jQuery(_href).removeClass('js-aside-show');
23644					jQuery('.btn-sidebar-toggle').removeClass('active');
23645					if( $("#sidebar-toggler").length > 0 ) {
23646						setTimeout(function() {
23647							$("#sidebar-toggler").removeClass('cross');
23648						}, 800);
23649					}
23650				});
23651
23652			});
23653
23654
23655			/**
23656
23657				CLOSE SIDEBAR ON ITEM CLICK
23658				Add to nav: .nav-link-click-close
23659
23660			**/
23661			if($.SOW.globals.is_mobile === true) {
23662
23663				jQuery('nav.nav-link-click-close a.nav-link').on('click', function() {
23664					var _href = jQuery(this).attr('href');
23665
23666					if(_href != '#' && _href != '#!' && _href != 'javascript:;') {
23667						$.SOW.helper.overlay('hide');
23668						jQuery('aside').removeClass('js-aside-show');
23669						jQuery('.btn-sidebar-toggle').removeClass('active');
23670					}
23671
23672				});
23673
23674			}
23675
23676		},
23677
23678
23679
23680
23681		/**
23682		 *
23683		 *	@sidebar_minify
23684		 * 	href used as a target ID
23685		 *
23686		 **/
23687	 	sidebar_minify: function() {
23688
23689			jQuery('.btn-aside-minify').on('click', function(e) {
23690				e.preventDefault();
23691
23692				var _href = jQuery(this).attr('href') || '';
23693
23694				if(_href == '' || _href == '#' || _href == '#!' || _href == 'javascript:;')
23695					return;
23696
23697				$.SOW.globals.elBody.toggleClass('aside-min');
23698			});
23699
23700	 	},
23701
23702
23703
23704
23705		/**
23706		 *
23707		 *	@sidebar_extended
23708		 *
23709		 *
23710		 **/
23711	 	sidebar_extended: function() {
23712
23713			jQuery('.btn-aside-item-extended-close').unbind().on('click', function(e) {
23714				e.preventDefault();
23715
23716				jQuery(this).parent().closest('.nav-item.active').removeClass('active');
23717
23718			});
23719
23720	 	},
23721
23722
23723
23724
23725		/**
23726		 *
23727		 *	@sidebar_dispose
23728		 *
23729		 *
23730		 **/
23731	 	sidebar_dispose: function() {
23732
23733			jQuery('.btn-sidebar-toggle').unbind('click');
23734			jQuery('.btn-sidebar-toggle-minify').unbind('click');
23735			jQuery('.btn-aside-item-extended-close').unbind('click');
23736			jQuery('.nav-deep .nav-link').unbind('click');
23737
23738	 	},
23739
23740	};
23741
23742
23743})(jQuery);
23744/**
23745 *
23746 *	[SOW] Scroll To
23747 *
23748 *	@author 		Dorin Grigoras
23749 *					www.stepofweb.com
23750 *
23751 *	@Dependency 	-
23752 *	@Usage			$.SOW.core.scroll_to.init('a.scroll-to', {speed:400});
23753 *
23754 *
23755 **/
23756;(function ($) {
23757	'use strict';
23758
23759
23760	/**
23761	 *
23762	 *	@vars
23763	 *
23764	 *
23765	 **/
23766	var scriptInfo 		= 'SOW Scroll To';
23767
23768
23769	$.SOW.core.scroll_to = {
23770
23771
23772		/**
23773		 *
23774		 *	@config
23775		 *
23776		 *
23777		 **/
23778		config: {
23779
23780	        // button scroll to speed
23781	        speed:               400,
23782
23783	        // scroll 2 top
23784	        s2t_enable:         true,
23785	        s2t_class:          'btn-secondary',
23786	        s2t_position:       'end',   // start = left, end = right (inverted for RT
23786L)
23787	        s2t_mob_minH:       1200,	// min. content height to show on mobile
23788	        s2t_dsk_minH:       2300,	// min. content to show on desktop
23789	        // when scrolling, button is shown if currentScroll > minH / 2
23790
23791		},
23792
23793
23794
23795		/**
23796		 *
23797		 *	@collection
23798		 *
23799		 *
23800		 **/
23801		collection: $(),
23802
23803
23804
23805		/**
23806		 *
23807		 *	@init
23808		 *
23809		 *
23810		 **/
23811		init: function (selector, config) {
23812
23813			var __selector 			= $.SOW.helper.__selector(selector);
23814			var __config 			= $.SOW.helper.check_var(config);
23815
23816			this.selector 			= __selector[0]; 	// '#selector'
23817			this.collection 		= __selector[1]; 	// $('#selector')
23818			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
23819
23820
23821
23822			// Scroll to top when user scroll %
23823			if($.SOW.core.scroll_to.config.s2t_enable === true)
23824				$.SOW.core.scroll_to.scrollToTop();
23825
23826
23827
23828			if(jQuery(this.selector).length < 1)
23829				return;
23830
23831
23832			// -- * --
23833			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
23834			// -- * --
23835
23836
23837			// 1. Has no selector
23838			if(!this.selector) {
23839				$.SOW.core.scroll_to.process($('.scroll-to'));
23840				return this.collection;
23841			}
23842
23843			// 2. Has selector
23844			return this.collection.each(function() {
23845
23846				$.SOW.core.scroll_to.process($(this));
23847
23848			});
23849
23850		},
23851
23852
23853
23854		/**
23855		 *
23856		 *	@process
23857		 *
23858
23859			<a href="#top" class="scroll-animate">Go to top</a>
23860			<a href="#div_id" class="scroll-animate">Go to a section</a>
23861
23862		 *
23863		 **/
23864		process: function(_this) {
23865
23866			var config_speed = this.config.speed;
23867
23868			// SCROLL TO [LINK]
23869			_this.not('.js-scrolltoified').addClass('js-scrolltoified').on("click", function(e) {
23870				e.preventDefault();
23871
23872				var _t 				= jQuery(this),
23873					_href 			= _t.attr('href') 				|| '',
23874					_offset			= _t.data('offset') 			|| 0,
23875					_toggle			= _t.data('toggle') 			|| '',
23876					_expanded		= _t.attr('aria-expanded') 		|| '',
23877					_hash			= _t.data('update-hash')		|| 'false',
23878					_speed 			= _t.data('speed') 				|| config_speed,
23879					_delay			= _t.data('delay')				|| 0;
23880
23881
23882				// add a delay if this has also a collapse option
23883				if(_toggle == 'collapse')
23884					_delay = (_delay > 0) ? _delay : 300; // bootstrap default is 400
23885
23886				// Scroll (helper.js)
23887				if(typeof $.SOW.helper.scrollAnimate === "function") {
23888
23889					setTimeout(function() {
23890
23891						// stop on collapse back
23892						// if(_toggle == 'collapse' && _expanded != '')
23893						if(_t.hasClass('collapsed'))
23894							return;
23895
23896						$.SOW.helper.scrollAnimate(_href, _offset, _hash, _speed);
23897
23898					}, Number(_delay) );
23899
23900				}
23901
23902			});
23903
23904		},
23905
23906
23907
23908		/**
23909		 *
23910		 *	@scroll to top
23911		 *
23912		 *
23913		 **/
23914		scrollToTop: function() {
23915
23916
23917			// reset always on load
23918			if(window.sowScrollToInterval !== null) {
23919				clearInterval(window.sowScrollToInterval);
23920				window.sowScrollToInterval = null;
23921
23922				jQuery('#btnScrollTo').remove();
23923			}
23924
23925
23926
23927			// Different for mobile/desktop
23928			var minInitHeight = $.SOW.globals.is_mobile === true ? $.SOW.core.scroll_to.config.s2t_mob_minH : $.SOW.core.scroll_to.config.s2t_dsk_minH;
23929
23930
23931			// do not init on short content
23932			if($(document).height() < minInitHeight)
23933				return;
23934
23935
23936			var _pos 		= $.SOW.globals.elBody.data('s2t-position') 	|| $.SOW.core.scroll_to.config.s2t_position;
23937			var _cls 		= $.SOW.globals.elBody.data('s2t-class') 		|| $.SOW.core.scroll_to.config.s2t_class;
23938			var _dis 		= $.SOW.globals.elBody.data('s2t-disable') 		|| 'false';
23939
23940			if(_dis+'' == 'true')
23941				return;
23942
23943
23944			// Disable on admin ; Enable only if specified:
23945			// data-s2t-disable="false"
23946			if($.SOW.globals.elBody.hasClass('layout-admin') && _dis+'' != 'false')
23947				return;
23948
23949
23950			// Is admin and has Footer
23951			var takeCareOfAdminFooter 	= false;
23952			if($.SOW.globals.elBody.hasClass('layout-admin') && jQuery('#footer').length > 0) {
23953
23954				var footerPos 				= 0;
23955				var tookCare 				= false;
23956				var btnScrollToMargins 		= 0;
23957				var footerHeight 			= jQuery('#footer').outerHeight();
23958
23959				if(footerHeight < 200) {
23960					var takeCareOfAdminFooter = true;
23961					var footerPos = $('#footer').offset().top;
23962					var btnScrollToMargins = footerHeight + 15 + Number($.SOW.globals.elBody.css('padding').replace("px", "") || 0) + Number($.SOW.globals.elBody.css('margin').replace("px", "") || 0);
23963				}
23964
23965			}
23966
23967
23968			// Create Element
23969			$.SOW.globals.elBody.append('<a aria-label="Scroll page to top" href="#" id="bt
23969nScrollTo" class="btn ' + _cls + ' position-fixed z-index-99 ' + _pos + '-0 bottom-0 m-2" style="display:none"><i class="m-0 fi fi-arrow-up"></i></a>');
23970
23971
23972			// bind click
23973			jQuery('#btnScrollTo').off().on('click', function(e) {
23974				e.preventDefault();
23975				$.SOW.helper.scrollAnimate('body', 0, false, 500);
23976			});
23977
23978
23979			var appearAtMin 					= minInitHeight / 2;
23980				window.isVisibleBtnScrollTo 	= false;
23981			var scrolling 						= false;
23982			var currScrollPos 					= 0;
23983
23984			$(window).scroll(function() {
23985				scrolling 		= true;
23986				currScrollPos 	= $(this).scrollTop();
23987			});
23988
23989			window.sowScrollToInterval = setInterval( function() {
23990
23991				if(scrolling) {
23992					scrolling = false;
23993
23994
23995					if (currScrollPos > appearAtMin) {
23996
23997						if(window.isVisibleBtnScrollTo === false) {
23998							window.isVisibleBtnScrollTo = true;
23999							jQuery('#btnScrollTo').fadeIn(400);
24000						}
24001
24002					} else {
24003
24004						if(window.isVisibleBtnScrollTo === true) {
24005							window.isVisibleBtnScrollTo = false;
24006							jQuery('#btnScrollTo').fadeOut(200);
24007						}
24008
24009					}
24010
24011
24012					// Admin footer : fix
24013					if(takeCareOfAdminFooter === true) {
24014						if(currScrollPos + $.SOW.globals.height > footerPos) {
24015							if(tookCare === false) {
24016								jQuery('#btnScrollTo').addClass('transition-all-ease-250').attr('style', "margin-bottom: "+ btnScrollToMargins +"px !important");
24017								tookCare = true;
24018							}
24019						} else {
24020							if(tookCare === true) {
24021								jQuery('#btnScrollTo').css({"margin-bottom":""});
24022								tookCare = false;
24023							}
24024						}
24025					}
24026
24027				}
24028
24029			}, 500);
24030
24031
24032		}
24033
24034	};
24035
24036
24037})(jQuery);
24038/**
24039 *
24040 *	[SOW] Inline Search
24041 *
24042 *	@author 		Dorin Grigoras
24043 *					www.stepofweb.com
24044 *
24045 *	@Dependency 	-
24046 *	@Usage 			$.SOW.core.search_inline.init('input.iqs-input');
24047 *
24048 *
24049 **/
24050;(function ($) {
24051	'use strict';
24052
24053
24054	/**
24055	 *
24056	 *	@vars
24057	 *
24058	 *
24059	 **/
24060	var scriptInfo 		= 'SOW Inline Search';
24061
24062
24063	$.SOW.core.search_inline = {
24064
24065
24066		/**
24067		 *
24068		 *	@config
24069		 *
24070		 *
24071		 **/
24072		config: {},
24073
24074
24075
24076		/**
24077		 *
24078		 *	@collection
24079		 *
24080		 *
24081		 **/
24082		collection: $(),
24083
24084
24085
24086		/**
24087		 *
24088		 *	@init
24089		 *
24090		 *
24091		 **/
24092		init: function (selector, config) {
24093
24094			var __selector 			= $.SOW.helper.__selector(selector);
24095			var __config 			= $.SOW.helper.check_var(config);
24096
24097			this.selector 			= __selector[0]; 	// '#selector'
24098			this.collection 		= __selector[1]; 	// $('#selector')
24099			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
24100
24101
24102			if(jQuery(this.selector).length < 1)
24103				return;
24104
24105
24106			/* Case Sensitive :contains */
24107			jQuery.extend(jQuery.expr[":"], {
24108				"containsIN": function(elem, i, match, array) {
24109					return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
24110				}
24111			});
24112
24113
24114
24115			// -- * --
24116			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
24117			// -- * --
24118
24119
24120			// 1. Has no selector
24121			if(!this.selector) {
24122				$.SOW.core.search_inline.process($('input.iqs-input'));
24123				return this.collection;
24124			}
24125
24126			// 2. Has selector
24127			return this.collection.each(function() {
24128
24129				$.SOW.core.search_inline.process($(this));
24130
24131			});
24132
24133		},
24134
24135
24136
24137		/**
24138		 *
24139		 *	@process
24140		 *
24141
24142			<input type="text" class="form-control iqs-input" data-container=".iqs-container" name="quick-filter" value="" placeholder="quick filter">
24143
24144			<div class="iqs-container">
24145
24146				<div class="iqs-item">
24147					<span>Something Here</span>
24148				</div>
24149
24150			</div>
24151
24152		 *
24153		 *
24154		 **/
24155		process: function(_this) {
24156
24157			var _container = _this.data('container') || '.iqs-container';
24158
24159			_this.keyup(function() {
24160
24161				var keywords = jQuery.trim(this.value);
24162
24163				if (keywords == "") {
24164
24165					jQuery(_container+" .iqs-item").removeClass('hide hide-force');
24166
24167				} else {
24168
24169					jQuery(_container+" .iqs-item").addClass('hide hide-force');
24170					jQuery(_container+' .iqs-item :containsIN('+keywords+')').closest(".iqs-item").removeClass('hide hide-force');
24171
24172				}
24173
24174			});
24175
24176		},
24177
24178	};
24179
24180
24181})(jQuery);
24182/**
24183 *
24184 *	[SOW] Timer Autohide
24185 *
24186 *	@author 		Dorin Grigoras
24187 *					www.stepofweb.com
24188 *
24189 *	@Dependency 	-
24190 *	@Usage			$.SOW.core.timer_autohide.init('.timer-autohide');
24191
24192 	<div class="timer-autohide" data-timer-autohide="4000">...</div>
24193
24194 *
24195 *
24196 **/
24197;(function ($) {
24198	'use strict';
24199
24200
24201	/**
24202	 *
24203	 *	@vars
24204	 *
24205	 *
24206	 **/
24207	var scriptInfo 		= 'SOW Timer Autohide';
24208
24209
24210	$.SOW.core.timer_autohide = {
24211
24212
24213		/**
24214		 *
24215		 *	@config
24216		 *
24217		 *
24218		 **/
24219		config: {},
24220
24221
24222
24223		/**
24224		 *
24225		 *	@collection
24226		 *
24227		 *
24228		 **/
24229		collection: $(),
24230
24231
24232
24233		/**
24234		 *
24235		 *	@init
24236		 *
24237		 *
24238		 **/
24239		init: function (selector, config) {
24240
24241			var __selector 			= $.SOW.helper.__selector(selector);
24242			var __config 			= $.SOW.helper.check_var(config);
24243
24244			this.selector 			= __selector[0]; 	// '#selector'
24245			this.collection 		= __selector[1]; 	// $('#selector')
24246			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
24247
24248
24249			if(jQuery(this.selector).length < 1)
24250				return;
24251
24252
24253			// -- * --
24254			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
24255			// -- * --
24256
24257
24258			// 1. Has no selector
24259			if(!this.selector) {
24260				$.SOW.core.timer_autohide.process($('.autohide'));
24261				return this.collection;
24262			}
24263
24264			// 2. Has selector
24265			return this.collection.each(function() {
24266
24267				$.SOW.core.timer_autohide.process($(this));
24268
24269			});
24270
24271		},
24272
24273
24274
24275		/**
24276		 *
24277		 *	@process
24278		 *
24279
24280			<div data-autohide="3000">
24281				....
24282			</div>
24283		 *
24284		 **/
24285		process: function(_this) {
24286
24287
24288			var _time = _this.data('timer-autohide') || 0;
24289
24290			if(_time < 1)
24291				return;
24292
24293
24294			setTimeout(function() {
24295
24296				_this.fadeOut(100, function() {
24297					// _this.remove();
24298				});
24299
24300			}, Number(_time));
24301
24302		},
24303
24304
24305	};
24306
24307
24308})(jQuery);
24309/**
24310 *
24311 *	[SOW] Timer Countdown
24312 *
24313 *	@author 		Dorin Grigoras
24314 *					www.stepofweb.com
24315 *
24316 *	@Dependency 	-
24317 *	@Usage			$.SOW.core.timer_countdown.init('.timer-countdown');
24318 *
24319 *
24320 **/
24321;(function ($) {
24322	'use strict';
24323
24324
24325	/**
24326	 *
24327	 *	@vars
24328	 *
24329	 *
24330	 **/
24331	var scriptInfo 			= 'SOW Timer Countdown';
24332	window.timeleft			= [];
24333	window._timerInterval 	= [];
24334
24335
24336	$.SOW.core.timer_countdown = {
24337
24338
24339		/**
24340		 *
24341		 *	@config
24342		 *
24343		 *
24344		 **/
24345		config: {},
24346
24347
24348
24349		/**
24350		 *
24351		 *	@collection
24352		 *
24353		 *
24354		 **/
24355		collection: $(),
24356
24357
24358
24359		/**
24360		 *
24361		 *	@init
24362		 *
24363		 *
24364		 **/
24365		init: function (selector, config) {
24366
24367			var __selector 			= $.SOW.helper.__selector(selector);
24368			var __config 			= $.SOW.helper.check_var(config);
24369
24370			this.selector 			= __selector[0]; 	// '#selector'
24371			this.collection 		= __selector[1]; 	// $('#selector')
24372			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
24373
24374			if(jQuery(this.selector).length < 1)
24375				return;
24376
24377
24378			// -- * --
24379			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
24380			// -- * --
24381
24382
24383			// 1. Has no selector
24384			if(!this.selector) {
24385				$.SOW.core.timer_countdown.process($('.timer-countdown'));
24386				return this.collection;
24387			}
24388
24389			// 2. Has selector
24390			return this.collection.each(function() {
24391
24392				$.SOW.core.timer_countdown.process($(this));
24393
24394			});
24395
24396		},
24397
24398
24399
24400		/**
24401		 *
24402		 *	@process
24403		 *
24404		 *
24405		 **/
24406		process: function(_this) {
24407
24408			var _time 		= _this.data('timer-countdown-from') 				|| '',
24409				_inline 	= _this.hasClass('timer-countdown-inline') ? true : false,
24410				_elID 		= _this.attr('id') 									|| '';
24411
24412			if(_time == '')
24413				return;
24414
24415
24416			// Remove hide class if exist
24417			_this.removeClass('hide hide-force');
24418
24419			var _rand = 'rand_' + $.SOW.helper.randomStr(8);
24420
24421			// if element has no id, add one
24422			if(_elID == '') {
24423				var _elID = _rand;
24424				_this.attr('id', _rand);
24425			}
24426
24427
24428			// Numeric - milisseconds|seconds passed
24429			if(typeof _time === 'number') {
24430
24431				// Calculate in seconds and set initial time left
24432				window.timeleft[_elID] = (_time > 1000) ? Math.round(_time / 1000) : Math.round(_time);
24433
24434			} else {
24435
24436				var _time 			= _time.trim(),
24437					__dateNow 		= new Date(),
24438					__dateFuture 	= new Date(_time),
24439					offset 			= __dateFuture.getTimezoneOffset() * 60 * 1000,
24440
24441					withOffset 		= __dateFuture.getTime(),
24442					withoutOffset 	= withOffset - offset,
24443					_msRemains 		= withOffset - __dateNow;
24444
24445
24446					window.timeleft[_elID] = Math.round(_msRemains / 1000);
24447
24448			}
24449
24450
24451			/*
24452				Date is in the past, no time left!
24453				Stop here, to avoid callback
24454			*/
24455			if(window.timeleft[_elID] < 1)
24456				return;
24457
24458
24459			// Show time before starting
24460			$.SOW.core.timer_countdown.timer_compute(_this, _elID, _inline, false);
24461
24462			// Start loop, each second
24463			window._timerInterval[_elID] = setInterval(function() {
24464
24465				$.SOW.core.timer_countdown.timer_compute(_this, _elID, _inline, true);
24466
24467			}, 1000);
24468
24469
24470		},
24471
24472
24473
24474
24475		/**
24476		 *
24477		 *	@timer_compute
24478		 *
24479		 *
24480		 **/
24481		timer_compute: function(_this, _elID, _inline, _calledByInterval) {
24482
24483			// If page switched by ajax or element removed,
24484			// the loop goes on and callback is fired
24485			// we avoid this by checking the element
24486			var __elID = _this.attr('id');
24487			if(jQuery('#'+__elID).length < 1) {
24488				$.SOW.core.timer_countdown.timer_compute_stop(_elID);
24489				return;
24490			}
24491
24492
24493
24494			// Time end! 00:00:00
24495			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
24496			if(window.timeleft[_elID] < 0) {
24497
24498				// Stop loop!
24499				$.SOW.core.timer_countdown.timer_compute_stop(_elID);
24500
24501				var _callback 		= _this.data('timer-countdown-callback-function') 	|| '',
24502					_endSelfHide 	= _this.data('timer-countdown-end-hide-self') 		|| false,
24503					_endTargetHide 	= _this.data('timer-countdown-end-hide-target') 	|| '';
24504
24505
24506				// Self hide
24507				if(_endSelfHide == true)
24508					_this.addClass('hide hide-force');
24509
24510				// Another container (or more separated by space) hide
24511				if(_endTargetHide != '')
24512					jQuery(_endTargetHide).addClass('hide hide-force');
24513
24514
24515
24516				// custom callback function
24517				if(_callback != '' && _calledByInterval === true) {
24518
24519					// get element id or assign a random one
24520					var _elID = _this.attr('id') || '';
24521					$.SOW.helper.executeFunctionByName(_callback, window, _elID);
24522
24523				}
24524
24525				return false;
24526			}
24527			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
24528
24529
24530
24531			// Compute output format time like 00:00:50
24532			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
24533			var __date 		= new Date(null);
24534							__date.setSeconds(window.timeleft[_elID]);
24535
24536			var timeString 	= __date.toISOString().substr(11, 8);
24537			var daysleft 	= $.SOW.helper.time_from_ms(window.timeleft[_elID] * 1000, 'd');
24538
24539			if(daysleft > 0) {
24540				var _cutHours 		= timeString.substr(0, 2);
24541				var _addedDaysHours = Number(_cutHours) + daysleft * 24;
24542				var timeString 		= _addedDaysHours + timeString.substr(2, 8);
24543			}
24544
24545
24546			// update timeleft
24547			window.timeleft[_elID] = Math.round(window.timeleft[_elID] - 1);
24548			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
24549
24550
24551			if(_inline === true)
24552				$.SOW.core.timer_countdown.timer2html(_this, timeString);
24553			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
24554
24555
24556			// update element
24557			else _this.html(timeString);
24558
24559		},
24560
24561
24562
24563
24564		/**
24565		 *
24566		 *	@timer_compute_stop
24567		 *
24568		 *
24569		 **/
24570		timer_compute_stop: function(_elID) {
24571
24572			// Stop loop!
24573			if(_elID)
24574				clearInterval(window._timerInterval[_elID]);
24575
24576			return true;
24577		},
24578
24579
24580
24581
24582		/**
24583		 *
24584		 *	@timer2html
24585		 *
24586		 *
24587		 **/
24588		timer2html: function(_this, timeString) {
24589			// return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); // working: return true if bisect year!
24590
24591			if(timeString == '00:00:00')
24592				return;
24593
24594
24595			var _timeSplit 		= timeString.split(':'),
24596				_hours 			= 0,
24597				_days 			= 0,
24598				_years 			= 0;
24599
24600
24601			// calc no of days
24602			if(_timeSplit[0] >= 24) {
24603				_days 	= Math.floor(_timeSplit[0] / 24); 	// round always down
24604				_hours 	= Math.floor(_timeSplit[0] % 24); 	// round always down
24605			}
24606
24607			// calc no of years
24608			if(_days >= 365)
24609				_years = Math.floor(_days / 365); 			// round always down
24610
24611
24612
24613			// update dom
24614			jQuery('.s', _this).text(_timeSplit[2]);		// seconds
24615			jQuery('.m', _this).text(_timeSplit[1]);		// minutes
24616			jQuery('.h', _this).text(_hours);				// hours
24617			jQuery('.d', _this).text(_days);				// days
24618			jQuery('.y', _this).text(_years);				// years
24619
24620
24621		}
24622
24623
24624	};
24625
24626
24627})(jQuery);
24628/**
24629 *
24630 *	[SOW] Google Font
24631 *
24632 *	@author 		Dorin Grigoras
24633 *					www.stepofweb.com
24634 *
24635 *	@Dependency 	-
24636 *	@Usage			$.SOW.core.gfont.init('[data-gfont]');
24637 *
24638 *
24639 **/
24640;(function ($) {
24641	'use strict';
24642
24643
24644	/**
24645	 *
24646	 *	@vars
24647	 *
24648	 *
24649	 **/
24650	var scriptInfo 		= 'SOW Google Font';
24651
24652
24653	$.SOW.core.gfont = {
24654
24655
24656		/**
24657		 *
24658		 *	@config
24659		 *
24660		 *
24661		 **/
24662		config: {},
24663
24664
24665
24666		/**
24667		 *
24668		 *	@collection
24669		 *
24670		 *
24671		 **/
24672		collection: $(),
24673
24674
24675
24676		/**
24677		 *
24678		 *	@init
24679		 *
24680		 *
24681		 **/
24682		init: function (selector, config) {
24683
24684			var __selector 			= $.SOW.helper.__selector(selector);
24685			var __config 			= $.SOW.helper.check_var(config);
24686
24687			this.selector 			= __selector[0]; 	// '#selector'
24688			this.collection 		= __selector[1]; 	// $('#selector')
24689			this.config 			= (__config !== null) ? $.extend({}, this.config, __config) : this.config;
24690
24691
24692			if(jQuery(this.selector).length < 1)
24693				return;
24694
24695
24696			// -- * --
24697			$.SOW.helper.consoleLog('Init : ' + scriptInfo);
24698			// -- * --
24699
24700
24701			// 1. Has no selector
24702			if(!this.selector) {
24703				$.SOW.core.gfont.process($('[data-gfont]'));
24704				return this.collection;
24705			}
24706
24707			// 2. Has selector
24708			return this.collection.each(function() {
24709
24710				$.SOW.core.gfont.process($(this));
24711
24712			});
24713
24714		},
24715
24716
24717
24718		/**
24719		 *
24720		 *	@process
24721		 *
24722		 *
24723		 **/
24724		process: function(_this) {
24725
24726			if(_this.hasClass('js-gfontified'))
24727				return;
24728
24729			var _font = _this.data('gfont') || '';
24730
24731			if(_font == '')
24732				return;
24733
24734			_this.addClass('js-gfontified');
24735			var _gfont 		= _font.replace(/ /g, '+');
24736			var _cssID 		= _font.replace(/ /g, '_').toLowerCase();
24737			var _rand 		= $.SOW.helper.randomStr(3, 'L');
24738			var _lnk 		= 'https://fonts.googleapis.com/css?family='+_gfont+':300,400,500,700&display=swap';
24739			var _el 		= jQuery('head #'+_cssID);
24740
24741			if(_el.length > 0) {
24742				var _class = _el.data('class');
24743				_this.addClass(_class);
24744				return;
24745			}
24746
24747			jQuery('head').append('<link id="'+_cssID+'" data-class="gfont_'+_rand+'" href="'+_lnk+'" rel="stylesheet">')
24748						  .append('<style type="text/css">'
24749									  + ".gfont_"+_rand+" { font-family: '"+_font+"', sans-serif !important; }"
24750								  +'</style>');
24751
24752			_this.addClass("gfont_"+_rand);
24753
24754		},
24755
24756
24757	};
24758
24759
24760})(jQuery);
24761/**
24762 *
24763 *	[SOW] Utils
24764 *
24765 *	@author 		Dorin Grigoras
24766 *					www.stepofweb.com
24767 *
24768 *	@Dependency 	-
24769 *	@Usage			$.SOW.core.utils.init();
24770 *
24771 *
24772 **/
24773;(function ($) {
24774	'use strict';
24775
24776
24777	/**
24778	 *
24779	 *	@vars
24780	 *
24781	 *
24782	 **/
24783	var scriptInfo 		= 'SOW Utils';
24784	var timeAgoList 	= [];
24785	var slideshowList 	= {};
24786
24787	$.SOW.core.utils = {
24788
24789
24790		/**
24791		 *
24792		 *	@config
24793		 *
24794		 *
24795		 **/
24796		config: {
24797
24798			// selectors
24799			selector__initialFromString 			: '.sow-util-initials',
24800			selector__timeAgo 						: '.sow-util-timeago',
24801			selector__cookie 						: '.sow-util-cookie',
24802			selector__slideshow 					: '.sow-util-slideshow',
24803
24804
24805			lang__timeAgo 							: {
24806															seconds 		: "less than a minute ago",
24807															minute 			: "about a minute ago",
24808															minutes 		: "%d minutes ago",
24809															hour 			: "about an hour ago",
24810															hours 			: "about %d hours ago",
24811															day 			: "a day ago",
24812															days 			: "%d days ago",
24813															month 			: "about a month ago",
24814															months 			: "%d months ago",
24815															year 			: "about a year ago",
24816															years 			: "%d years ago"
24817														},
24818		},
24819
24820
24821
24822		/**
24823		 *
24824		 *	@init
24825		 *
24826		 *
24827		 **/
24828		init: function (selector, config) {
24829
24830			var __selector 			= $.SOW.helper.__selector(selector);
24831			this.selector 			= __selector[0]; 	// '#selector'
24832
24833			// Initials from a string [name]
24834			$.SOW.core.utils.initialsFromString(this.selector+' '+$.SOW.core.utils.config.selector__initialFromString);
24835
24836			// Time Ago
24837			$.SOW.core.utils.timeAgo(this.selector+' '+$.SOW.core.utils.config.selector__timeAgo);
24838
24839			// Cookies
24840			$.SOW.core.utils.cookieUtil(this.selector+' '+$.SOW.core.utils.config.selector__cookie);
24841
24842			// Background Slideshow
24843			$.SOW.core.utils.slideshow(this.selector+' '+$.SOW.core.utils.config.selector__slideshow);
24844
24845
24846			return null;
24847
24848		},
24849
24850
24851
24852		/**
24853		 *
24854		 *	@initialsFromString
24855		 *
24856		 *
24857		 **/
24858		initialsFromString: function(selector) {
24859
24860			var el 		= jQuery(selector),
24861				loaded 	= false;
24862
24863			if(el.length < 1)
24864				return;
24865
24866
24867			el.not('.js-sowformstringified').addClass('js-sowformstringified').each(function(selector) {
24868
24869				var _t 			= jQuery(this),
24870					fullName 	= _t.data('initials') 						|| '',
24871					assignColor = jQuery(this).attr('data-assign-color') 	|| 'false';
24872
24873				if(fullName == '')
24874					return false;
24875
24876
24877				// Assign color by name
24878				if(assignColor+'' == 'true') {
24879
24880					var hash 	= 0,
24881						s 		= 70,	// saturation
24882						l 		= 90;	// lightness
24883
24884					for (var i = 0; i < fullName.length; i++) {
24885						hash = fullName.charCodeAt(i) + ((hash << 5) - hash);
24886					}
24887
24888					var h = hash % 360;
24889					_t.removeClass('bg-light').css({"background":'hsl('+h+', '+s+'%, '+l+'%)'});
24890
24891				}
24892
24893
24894				// Extract Initials
24895				var initials = fullName.match(/\b\w/g) || [];
24896					initials = ((initials.shift() || '') + (initials.pop() || '')).toUpperCase();
24897
24898
24899				// Push & remove ununsed!
24900				_t.text(initials).removeAttr('data-initials data-assign-color');
24901				loaded = true;
24902
24903			});
24904
24905
24906			// -- * --
24907			if(loaded === true)
24908				$.SOW.helper.consoleLog('Init : ' + scriptInfo + ' : Initials From String');
24909			// -- * --
24910
24911		},
24912
24913
24914
24915
24916		/**
24917		 *
24918		 *	@timeAgo
24919		 * 	inspired from jQuery timeago
24920		 * 	https://timeago.yarp.com/jquery.timeago.js
24921		 *
24922		 *
24923		 **/
24924		timeAgo: function(selector) {
24925
24926			var el 		= jQuery(selector),
24927				loaded 	= false;
24928
24929			if(el.length < 1)
24930				return;
24931
24932			/**
24933
24934				You can also set once an empty element if you have many timeago's.
24935				Example: &lt;span class="sow-util-timeago-lang" data-lang-timeago='{}'>
24936				Set it anywhere - bottom, etc!
24937
24938			**/
24939			var langBySpan = jQuery('span.sow-util-timeago-lang').data('lang') || '';
24940			if(typeof langBySpan === 'object')
24941				$.SOW.core.utils.config.lang__timeAgo = langBySpan;
24942
24943			if(typeof sow_util_timeago_lang === 'object')
24944				$.SOW.core.utils.config.lang__timeAgo = sow_util_timeago_lang;
24945			// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
24946
24947
24948			el.not('.js-sowtimeagofied').addClass('js-sowtimeagofied').each(function(selector) {
24949
24950				var _t 		= jQuery(this),
24951			    	time 	= _t.data('time') 	|| _t.attr('datetime'),
24952			    	live 	= _t.attr('live') 	|| 'false',
24953			    	lang 	= _t.data('lang') 	|| '',
24954			    	ID 		= _t.attr('id')		|| '';
24955
24956				if(!time)
24957					return
24958
24959				if(typeof lang === 'object')
24960					$.SOW.core.utils.config.lang__timeAgo = lang;
24961
24962				if(ID == '') {
24963					var ID = 'rand_' + $.SOW.helper.randomStr(3, 'N');
24964					_t.attr('id', ID);
24965				}
24966
24967
24968				$.SOW.core.utils.timeAgoLooper(_t, ID); // on load
24969
24970				// update time every minute
24971				if(live+'' == 'true') {
24972					timeAgoList[ID] = setInterval(function() {
24973						$.SOW.core.utils.timeAgoLooper(_t, ID);
24974					}, 60000);
24975				}
24976
24977				loaded == true;
24978
24979			});
24980
24981
24982			// -- * --
24983			if(loaded === true)
24984				$.SOW.helper.consoleLog('Init : ' + scriptInfo + ' : Time Ago');
24985			// -- * --
24986
24987		},
24988			timeAgoLooper: function(_t, ID) {
24989
24990				var time 		= _t.data('time') || _t.attr('datetime');
24991			    var templates 	= $.SOW.core.utils.config.lang__timeAgo;
24992			    var template 	= function (t, n) {
24993			        return templates[t] && templates[t].replace(/%d/i, Math.abs(Math.round(n)));
24994			    };
24995
24996				// parse iso8601
24997				if(typeof time === 'string') { // timestamp skipped!
24998
24999					time = time.replace(/\.\d+/,""); // remove milliseconds
25000					time = time.replace(/-/,"/").replace(/-/,"/");
25001					time = time.replace(/T/," ").replace(/Z/," UTC");
25002					time = time.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
25003					time = time.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900
25004
25005				}
25006
25007				var time 		= new Date(time * 1000 || time);
25008				var now 		= new Date();
25009				var seconds 	= ((now.getTime() - time) * .001) >> 0;
25010				var minutes 	= seconds / 60;
25011				var hours 		= minutes / 60;
25012				var days 		= hours / 24;
25013				var years 		= days / 365;
25014				var finalTime 	= (seconds < 45 && template('seconds', seconds) || seconds < 90 && template('minute', 1) || minutes < 45 && template('minutes', minutes) || minutes < 90 && template('hour', 1) || hours < 24 && template('hours', hours) || hours < 42 && template('day', 1) || days < 30 && template('days', days) || days < 45 && template('month', 1) || days < 365 && template('months', days / 30) || years < 1.5 && template('year', 1) || template('years', years));
25015
25016				// Update
25017			    _t.text(finalTime);
25018
25019			    // Do not refresh too old!
25020			    if(typeof timeAgoList[ID] !== 'undefined' && (days > 3 || years > 1))
25021			    	clearInterval(timeAgoList[ID]);
25022
25023			},
25024
25025
25026
25027
25028		/**
25029		 *
25030		 *	@cookieUtil
25031		 *
25032		 *
25033		 **/
25034		cookieUtil: function(selector) {
25035
25036			var el = jQuery(selector);
25037
25038			if(el.length < 1)
25039				return;
25040
25041
25042			el.not('.js-sowcookiefied').addClass('js-sowcookiefied').on('click', function(e) {
25043				e.preventDefault();
25044
25045				var _t 				= jQuery(this),
25046			    	_set 			= _t.data('cookie-set') 		|| '',
25047			    	_del 			= _t.data('cookie-del') 		|| '',
25048			    	_toggle 		= _t.data('cookie-toggle') 		|| '',
25049			    	_val 			= _t.data('cookie-val') 		|| '1',
25050			    	_expire 		= _t.data('cookie-expire') 		|| '7',
25051			    	_path 			= _t.data('cookie-path') 		|| $.SOW.globals.cookie_secure,
25052			    	toastMsgSet 	= _t.data('toast-msg-set') 		|| '',
25053			    	toastMsgDel 	= _t.data('toast-msg-del') 		|| '',
25054			    	toastMsgPos 	= _t.data('toast-msg-pos') 		|| 'top-center',
25055			    	toastTypeSet 	= _t.data('toast-msg-type-set') || 'success',
25056			    	toastTypeDel 	= _t.data('toast-msg-type-del') || 'success',
25057			    	toastMsg 		= '',
25058			    	toastType 		= '';
25059
25060
25061			    // SET
25062			    if(_set != '') {
25063			    	Cookies.set(_set, _val, { expires: _expire, path: _path });
25064			    	toastMsg 	= toastMsgSet;
25065			    	toastType 	= toastTypeSet;
25066			    }
25067
25068
25069			    // DEL
25070			    else if(_del != '') {
25071			    	Cookies.remove(_del, { path: _path });
25072			    	toastMsg 	= toastMsgDel;
25073			    	toastType 	= toastTypeDel;
25074			    }
25075
25076
25077			    // TOGGLE
25078			    else if(_toggle != '') {
25079			    	var chkCookie = Cookies.get(_toggle, { path: _path });
25080
25081			    	if(!chkCookie) {
25082			    		Cookies.set(_toggle, _val, { expires: _expire, path: _path });
25083			    		toastMsg 	= toastMsgSet;
25084			    		toastType 	= toastTypeSet;
25085			    	} else {
25086				    	Cookies.remove(_toggle, { path: _path });
25087				    	toastMsg 	= toastMsgDel;
25088				    	toastType 	= toastTypeDel;
25089			    	}
25090			    }
25091
25092
25093			    // TOAST MESSAGE
25094			    if(toastMsg != '' && typeof $.SOW.core.toast === 'object') {
25095			    	$.SOW.core.toast.destroy();
25096					$.SOW.core.toast.show(toastType, '', toastMsg, toastMsgPos, 1500, true);
25097			    }
25098
25099
25100			});
25101
25102		},
25103
25104
25105
25106
25107
25108		/**
25109		 *
25110		 *	@slideshow
25111		 *
25112		 *
25113		 **/
25114		slideshow: function(selector) {
25115
25116			var el 		= jQuery(selector),
25117				loaded 	= false;
25118
25119			if(el.length < 1)
25120				return;
25121
25122			el.each(function() {
25123
25124				var _t 				= jQuery(this),
25125					dataBgs 		= _t.data('sow-slideshow') 				|| '',
25126					dataBgsXs		= _t.data('sow-slideshow-xs') 			|| '',
25127					dataInterval 	= _t.data('sow-slideshow-interval') 	|| 4000,
25128					dataFadeDelay 	= _t.data('sow-slideshow-fade-delay') 	|| 1500,
25129					slideRand 		= 'sow_'+$.SOW.helper.randomStr(3, 'L');
25130
25131
25132				// Is Mobile!
25133				if($.SOW.globals.is_mobile === true && dataBgsXs.length > 10)
25134					dataBgs = dataBgsXs;
25135
25136				// should be a long string
25137				if(dataBgs.length < 10)
25138					return false;
25139
25140				// remove attribute, already got!
25141				_t.removeAttr('data-sow-slideshow');
25142
25143				// create a container, just to izolate stuff!
25144				_t.prepend('<div id="'+slideRand+'" class="sow-slideshow absolute-full z-index-0"></div>');
25145
25146				// Split by comma
25147				var arrImgs = dataBgs.split(',');
25148
25149				// Create array! Avoid checking the DOM each time!
25150				slideshowList[slideRand] 			= {};
25151				slideshowList[slideRand].current 	= 0;
25152				slideshowList[slideRand].itemsCount = 0;
25153				slideshowList[slideRand].timeOutInstance;
25154
25155				// Create each item and push it to the container
25156				for(var i = 0; i < arrImgs.length; i++) {
25157					var _class_ 	= (i === 0) ? 'sow-slideshow-current' : '';
25158					var _display_ 	= (i === 0) ? '' : 'display:none;';
25159
25160
25161					var imgInstance 		= new Image();
25162						imgInstance.src 	= arrImgs[i];
25163						imgInstance.onload 	= function(e) {/* on load - nothing */}
25164						imgInstance.onerror = function(e) {/* on error - nothing */}
25165
25166						jQuery('#'+slideRand).prepend('<span class="sow-slideshow-item sow-slideshow-item-'+i+' absolute-full bg-cover ' + _class_ + '" style="z-index:0;'+_display_+'background-image:url(' + imgInstance.src + ')"></span>');
25167						slideshowList[slideRand].itemsCount++;
25168				}
25169
25170				// no images - no loop needed!
25171				// first image is already visible!
25172				if(arrImgs.length < 2)
25173					return false;
25174
25175
25176				// Looper start!
25177				slideLooper();
25178				function slideLooper() {
25179					slideshowList[slideRand].timeOutInstance = setTimeout(function () {
25180
25181						// determine next image
25182						var next = slideshowList[slideRand].current + 1;
25183						if(next >= slideshowList[slideRand].itemsCount)
25184							next = 0;
25185
25186						jQuery('#'+slideRand+' span.sow-slideshow-item-'+slideshowList[slideRand].current).fadeOut(dataFadeDelay);
25187						jQuery('#'+slideRand+' span.sow-slideshow-item-'+next).fadeIn(dataFadeDelay);
25188						slideshowList[slideRand].current = next;
25189
25190						slideLooper();
25191
25192					}, dataInterval);
25193				}
25194
25195
25196
25197				// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
25198				// Pause on tab out of focus!
25199				function onVisibilityChanged() {
25200
25201					if (document.hidden || document.mozHidden || document.webkitHidden || document.msHidden) {
25202						// The tab has lost focus
25203						clearTimeout(slideshowList[slideRand].timeOutInstance);
25204					} else {
25205						// The tab has gained focus
25206						slideshowList[slideRand].timeOutInstance = setTimeout(slideLooper, dataInterval);
25207					}
25208
25209				}
25210
25211				document.addEventListener("visibilitychange", onVisibilityChanged, false);
25212				document.addEventListener("mozvisibilitychange", onVisibilityChanged, false);
25213				document.addEventListener("webkitvisibilitychange", onVisibilityChanged, false);
25214				document.addEventListener("msvisibilitychange", onVisibilityChanged, false);
25215				// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
25216
25217
25218				loaded = true;
25219
25220			});
25221
25222
25223
25224			// -- * --
25225			if(loaded === true)
25226				$.SOW.helper.consoleLog('Init : ' + scriptInfo + ' : Slideshow');
25227			// -- * --
25228
25229		}
25230
25231	};
25232
25233
25234})(jQuery);
25235/**
25236 * fuzzy.js v0.1.0
25237 * (c) 2016 Ben Ripkens
25238 * @license: MIT
25239 */
25240(function (context) {
25241  'use strict';
25242
25243  var fuzzy = function fuzzy(term, query) {
25244    var max = calcFuzzyScore(term, query);
25245    var termLength = term.length;
25246
25247    if (fuzzy.analyzeSubTerms) {
25248
25249      for (var i = 1; i < termLength && i < fuzzy.analyzeSubTermDepth; i++) {
25250        var subTerm = term.substring(i);
25251        var score = calcFuzzyScore(subTerm, query);
25252        if (score.score > max.score) {
25253          // we need to correct 'term' and 'matchedTerm', as calcFuzzyScore
25254          // does not now that it operates on a substring. Doing it only for
25255          // new maximum score to save some performance.
25256          score.term = term;
25257          score.highlightedTerm = term.substring(0, i) + score.highlightedTerm;
25258          max = score;
25259        }
25260      }
25261    }
25262
25263    return max;
25264  };
25265
25266  var calcFuzzyScore = function calcFuzzyScore(term, query) {
25267    var score = 0;
25268    var termLength = term.length;
25269    var queryLength = query.length;
25270    var highlighting = '';
25271    var ti = 0;
25272    // -1 would not work as this would break the calculations of bonus
25273    // points for subsequent character matches. Something like
25274    // Number.MIN_VALUE would be more appropriate, but unfortunately
25275    // Number.MIN_VALUE + 1 equals 1...
25276    var previousMatchingCharacter = -2;
25277
25278    for (var qi = 0; qi < queryLength && ti < termLength; qi++) {
25279      var qc = query.charAt(qi);
25280      var lowerQc = qc.toLowerCase();
25281
25282      for (; ti < termLength; ti++) {
25283        var tc = term.charAt(ti);
25284
25285        if (lowerQc === tc.toLowerCase()) {
25286          score++;
25287
25288          if ((previousMatchingCharacter + 1) === ti) {
25289            score += 2;
25290          }
25291
25292          highlighting += fuzzy.highlighting.before +
25293              tc +
25294              fuzzy.highlighting.after;
25295          previousMatchingCharacter = ti;
25296          ti++;
25297          break;
25298        } else {
25299          highlighting += tc;
25300        }
25301      }
25302    }
25303
25304    highlighting += term.substring(ti, term.length);
25305
25306    return {
25307      score: score,
25308      term: term,
25309      query: query,
25310      highlightedTerm: highlighting
25311    };
25312  };
25313
25314  fuzzy.matchComparator = function matchComparator(m1, m2) {
25315    return (m2.score - m1.score != 0) ? m2.score - m1.score : m1.term.length - m2.term.length;
25316  };
25317
25318  /*
25319   * Whether or not fuzzy.js should analyze sub-terms, i.e. also
25320   * check term starting positions != 0.
25321   *
25322   * Example:
25323   * Given the term 'Halleluja' and query 'luja'
25324   *
25325   * Fuzzy.js scores this combination with an 8, when analyzeSubTerms is
25326   * set to false, as the following matching string will be calculated:
25327   * Ha[l]lel[uja]
25328   *
25329   * If you activate sub temr analysis though, the query will reach a score
25330   * of 10, as the matching string looks as following:
25331   * Halle[luja]
25332   *
25333   * Naturally, the second version is more expensive than the first one.
25334   * You should therefore configure how many sub terms you which to analyse.
25335   * This can be configured through fuzzy.analyzeSubTermDepth = 10.
25336   */
25337  fuzzy.analyzeSubTerms = false;
25338
25339  /*
25340   * How many sub terms should be analyzed.
25341   */
25342  fuzzy.analyzeSubTermDepth = 10;
25343
25344  fuzzy.highlighting = {
25345    before: '<em>',
25346    after: '</em>'
25347  };
25348
25349  /*
25350   * Exporting the public API
25351   * ------------------------
25352   * In a browser, the library will be available through this.fuzzy. Should
25353   * requireJS be used, we register fuzzy.js through requireJS.
25354   * For other environments, CommonJS is supported.
25355   */
25356  if (typeof module !== 'undefined' && module.exports) {
25357    module.exports = fuzzy;
25358  } else if (typeof define === 'function') {
25359    define(function() {
25360      return fuzzy;
25361    });
25362  } else {
25363    /*
25364     * In case the global variable fuzzy needs to be reset to its previous
25365     * value, the fuzzy library is returned by this method.
25366     */
25367    var previousFuzzy = context.fuzzy;
25368    fuzzy.noConflict = function() {
25369      context.fuzzy = previousFuzzy;
25370      return fuzzy;
25371    };
25372
25373    context.fuzzy = fuzzy;
25374  }
25375})(this);
25376
25377$.SOW.config.sow__debug_enable = true;
25378if(typeof $.SOW.config.autoinit === 'undefined') { $.SOW.config.autoinit = {}; }
25379$.SOW.config.autoinit['sow_header'] = ['$.SOW.core.header.init','null', null,false];
25380$.SOW.config.autoinit['sow_search_suggest'] = ['$.SOW.core.search_suggest.init','form.js-ajax-search', null,false];
25381$.SOW.config.autoinit['sow_lazyload'] = ['$.SOW.core.lazyload.init','.lazy', null,true];
25382$.SOW.config.autoinit['sow_ajax_navigation'] = ['$.SOW.core.ajax_navigation.init','a.js-ajax', {enable:true,target_container:"#middle",parser_extract_enable:true,parser_force_push2target:false,parser_extract_element:"#middle, #page_js_files",page_404:"404.html",container2_element:"img.js-ajax-loaded-animate",container2_class:"animate-bouncein",data_params:{ajax:"true"},update_url:true,show_loading_icon:true,method:"GET",callback_function:"",callback_before_push:false,autoscroll_to_content:true,onpopstate_reload:true,custom_function_call:"",contentType:"",dataType:"",headers:"",crossDomain:""},true];
25383$.SOW.config.autoinit['sow_ajax_content'] = ['$.SOW.core.ajax_content.init','div.js-ajax, section.js-ajax', null,true];
25384$.SOW.config.autoinit['sow_ajax_form'] = ['$.SOW.core.ajax_form.init','form.js-ajax', null,true];
25385$.SOW.config.autoinit['sow_ajax_select'] = ['$.SOW.core.ajax_select.init','select.js-ajax', null,true];
25386$.SOW.config.autoinit['sow_ajax_modal'] = ['$.SOW.core.ajax_modal.init','.js-ajax-modal', {size:"modal-md"},true];
25387$.SOW.config.autoinit['sow_ajax_confirm'] = ['$.SOW.core.ajax_confirm.init','.js-ajax-confirm', null,true];
25388$.SOW.config.autoinit['sow_file_upload'] = ['$.SOW.core.file_upload.init','input[type="file"].custom-file-input', null,true];
25389$.SOW.config.autoinit['sow_toast'] = ['$.SOW.core.toast.init','div.toast-on-load', null,true];
25390$.SOW.config.autoinit['sow_dropdown_click_ignore'] = ['$.SOW.core.dropdown_click_ignore.init','.dropdown-menu.dropdown-click-ignore', null,true];
25391$.SOW.config.autoinit['sow_dropdown'] = ['$.SOW.core.dropdown.init','.dropdown-menu.dropdown-menu-hover', null,true];
25392$.SOW.config.autoinit['sow_dropdown_ajax'] = ['$.SOW.core.dropdown_ajax.init','a[data-toggle="dropdown"]', {loading_icon:"fi fi-circle-spin fi-spin",clearCacheInterval:1800000,tpl_start:"<ul class=\"list-unstyled m-0 p-0\">",tpl_end:"</ul>",tpl_ItemStart:"<li class=\"dropdown-item\">",tpl_ItemStartWChilds:"<li class=\"dropdown-item dropdown\">",tpl_ItemEnd:"</li>",tpl_Child_Start:"<ul class=\"dropdown-menu dropdown-menu-hover dropdown-menu-block-md shadow-lg b-0 m-0\">",tpl_Divider:"<li class=\"dropdown-divider\"></li>"},true];
25393$.SOW.config.autoinit['sow_count_animate'] = ['$.SOW.core.count_animate.
25393init','null', null,true];
25394$.SOW.config.autoinit['sow_btn_toggle'] = ['$.SOW.core.btn_toggle.init','.btn-toggle', null,true];
25395$.SOW.config.autoinit['sow_nav_deep'] = ['$.SOW.core.nav_deep.init','.nav-deep', {speed:150},true];
25396$.SOW.config.autoinit['sow_form_validate'] = ['$.SOW.core.form_validate.init','form.bs-validate', null,true];
25397$.SOW.config.autoinit['sow_form_advanced'] = ['$.SOW.core.form_advanced.init','null', null,true];
25398$.SOW.config.autoinit['sow_checkall'] = ['$.SOW.core.checkall.init','input.checkall', null,true];
25399$.SOW.config.autoinit['sow_gdpr'] = ['$.SOW.core.gdpr.init','#gdpr', {cookie_name:"__gdpr"},false];
25400$.SOW.config.autoinit['sow_sidebar'] = ['$.SOW.core.sidebar.init','null', null,false];
25401$.SOW.config.autoinit['sow_scroll_to'] = ['$.SOW.core.scroll_to.init','a.scroll-to', {speed:400,s2t_enable:true,s2t_class:"btn-secondary",s2t_position:"end",s2t_mob_minH:1200,s2t_dsk_minH:2300},true];
25402$.SOW.config.autoinit['sow_search_inline'] = ['$.SOW.core.search_inline.init','input.iqs-input', null,true];
25403$.SOW.config.autoinit['sow_timer_autohide'] = ['$.SOW.core.timer_autohide.init','.timer-autohide', null,true];
25404$.SOW.config.autoinit['sow_timer_countdown'] = ['$.SOW.core.timer_countdown.init','.timer-countdown', null,true];
25405$.SOW.config.autoinit['sow_gfont'] = ['$.SOW.core.gfont.init','[data-gfont]', null,true];
25406$.SOW.config.autoinit['sow_utils'] = ['$.SOW.core.utils.init','', {selector__initialFromString:".sow-util-initials",selector__timeAgo:".sow-util-timeago",selector__cookie:".sow-util-cookie",lang__timeAgo:{seconds:"less than a minute ago",minute:"about a minute ago",minutes:"%d minutes ago",hour:"about an hour ago",hours:"about %d hours ago",day:"a day ago",days:"%d days ago",month:"about a month ago",months:"%d months ago",year:"about a year ago",years:"%d years ago"}},true];
25407
25408// DETECT FIRST INTERACTION OF VISITOR:
25409let userInteraction = false;
25410let userPausedVideo	= false;
25411
25412["click", "touchmove"].forEach((eventName)=>{
25413	window.addEventListener(eventName, ()=> {
25414		if(!userInteraction) {
25415			try {
25416				userInteraction = true;
25417				var v = document.querySelector("video.scroll-play.inview");
25418				if( v !== null ) {
25419					v.play();
25420				}
25421				//console.log("User interaction detected.");
25422			}catch(e){
25423				console.warn(e.message);
25424			}
25425		}
25426	});
25427});
25428
25429function getHighest( elmo, target ) {
25430	if( $( elmo ).length > 0 && $( target ).length > 0 ) {
25431		setTimeout(function() {
25432			var hst = 0;
25433			$( elmo ).each(function() {
25434				if( $(this).height() > hst ) {
25435					hst = $(this).height();
25436				}
25437			});
25438			$( target ).height( hst + 100 );
25439		}, 1000);
25440	}
25441}
25442
25443function fitPartnerImage() {
25444	if( $("#partner-page-modal").length > 0 && $(window).width() < 767 ) {
25445		setTimeout(function() {
25446			$(".placeholder-img.img-set").height( Math.round($(".placeholder-img.img-set").width()*1.2125) );
25447			//document.querySelector(".placeholder-img.img-set").style.height = Math.round($(".placeholder-img.img-set").width()*1.33)+"px !important";
25448			console.log('PartnerIMG fitted.');
25449		}, 500);
25450	} else {
25451		console.log('no change.');
25452	}
25453}
25454
25455
25456if( $('.hl-on-scroll').length > 0 ) {
25457	function closest(array, number) {
25458		var num = 0;
25459		for (var i = array.length - 1; i >= 0; i--) {
25460			if(Math.abs(number - array[i].position) < Math.abs(number - array[num].position)) {
25461				num = i;
25462			}
25463		}
25464		return array[num].element;
25465	}
25466
25467	$(window).scroll(function() {
25468		if( $(window).width() >= 992 ) {
25469			var scrollTop = $(document).scrollTop() + ($(window).height() / 2) - 250;
25470		} else {
25471			var scrollTop = $(document).scrollTop() + ($(window).height() / 2) - 350;
25472		}
25473		var positions = [];
25474
25475		$('.hl-on-scroll').each(function() {
25476			$(this).removeClass("hover");
25477			positions.push({position:$(this).offset().top, element: $(this)});
25478			var video = $(this)[0].querySelector("video.scroll-play");
25479			if( video !== null ) {
25480				video.classList.remove("inview");
25481				if(userInteraction === true) {
25482					video.volume = 0;
25483					video.pause();
25484				}
25485			}
25486		});
25487
25488		var getClosest = closest(positions,scrollTop);
25489		getClosest.addClass("hover");
25490		var video = getClosest[0].querySelector("video.scroll-play");
25491		if( video !== null ) {
25492			video.classList.add("inview");
25493			if( userInteraction === true && userPausedVideo === false ) {
25494				var promise = video.play();
25495				if( promise !== undefined ) {
25496					promise.then(_ => {
25497						video.volume = 0.25;
25498					});
25499				}
25500			}
25501		}
25502	});
25503}
25504
25505if( $('.faq-container').length > 0 ) {
25506	$(".faq-container .card .collapse").on('show.bs.collapse', function() {
25507		$(this).parents('.card').addClass('background-shown');
25508	});
25509	$(".faq-container .card .collapse").on('hide.bs.collapse', function() {
25510		$(this).parents('.card').removeClass('background-shown');
25511	});
25512}
25513
25514getHighest(".swiper-rel-element","#swiper-related");
25515
25516if( $(".category-link").length > 0 ) {
25517	$(".category-link").each(function() {
25518		$(this).click(function(e) {
25519			e.preventDefault();
25520			e.stopPropagation();
25521			window.location.href = $(this).attr('href');
25522		});
25523	});
25524}
25525
25526
25527if(jQuery("#gmap.contact-map").length > 0) {
25528
25529	function contactMap() {
25530
25531		//var latLang = new google.maps.LatLng(47.001386,8.586857);
25532		var latLang = new google.maps.LatLng(47.004074532418144, 8.616762542818202);
25533
25534		var mapOptions = {
25535			zoom:17,
25536			center: latLang,
25537			disableDefaultUI: false,
25538			navigationControl: false,
25539			mapTypeControl: false,
25540			scrollwheel: false,
25541			mapTypeId: google.maps.MapTypeId.ROADMAP,
25542			styles: [
25543					{
25544						"featureType": "water",
25545						"elementType": "geometry",
25546						"stylers": [
25547							{
25548								"color": "#e9e9e9"
25549							},
25550							{
25551								"lightness": 17
25552							}
25553						]
25554					},
25555					{
25556						"featureType": "landscape",
25557						"elementType": "geometry",
25558						"stylers": [
25559							{
25560								"color": "#f5f5f5"
25561							},
25562							{
25563								"lightness": 20
25564							}
25565						]
25566					},
25567					{
25568						"featureType": "road.highway",
25569						"elementType": "geometry.fill",
25570						"stylers": [
25571							{
25572								"color": "#ffffff"
25573							},
25574							{
25575								"lightness": 17
25576							}
25577						]
25578					},
25579					{
25580						"featureType": "road.highway",
25581						"elementType": "geometry.stroke",
25582						"stylers": [
25583							{
25584								"color": "#ffffff"
25585							},
25586							{
25587								"lightness": 29
25588							},
25589							{
25590								"weight": 0.2
25591							}
25592						]
25593					},
25594					{
25595						"featureType": "road.arterial",
25596						"elementType": "geometry",
25597						"stylers": [
25598							{
25599								"color": "#ffffff"
25600							},
25601							{
25602								"lightness": 18
25603							}
25604						]
25605					},
25606					{
25607						"featureType": "road.local",
25608						"elementType": "geometry",
25609						"stylers": [
25610							{
25611								"color": "#ffffff"
25612							},
25613							{
25614								"lightness": 16
25615							}
25616						]
25617					},
25618					{
25619						"featureType": "poi",
25620						"elementType": "geometry",
25621						"stylers": [
25622							{
25623								"color": "#f5f5f5"
25624							},
25625							{
25626								"lightness": 21
25627							}
25628						]
25629					},
25630					{
25631						"featureType": "poi.park",
25632						"elementType": "geometry",
25633						"stylers": [
25634							{
25635								"color": "#dedede"
25636							},
25637							{
25638								"lightness": 21
25639							}
25640						]
25641					},
25642					{
25643						"elementType": "labels.text.stroke",
25644						"stylers": [
25645							{
25646								"visibility": "on"
25647							},
25648							{
25649								"color": "#ffffff"
25650							},
25651							{
25652								"lightness": 16
25653							}
25654						]
25655					},
25656					{
25657						"elementType": "labels.text.fill",
25658						"stylers": [
25659							{
25660								"saturation": 36
25661							},
25662							{
25663								"color": "#333333"
25664							},
25665							{
25666								"lightness": 40
25667							}
25668						]
25669					},
25670					{
25671						"elementType": "labels.icon",
25672						"stylers": [
25673							{
25674								"visibility": "off"
25675							}
25676						]
25677					},
25678					{
25679						"featureType": "transit",
25680						"elementType": "geometry",
25681						"stylers": [
25682							{
25683								"color": "#f2f2f2"
25684							},
25685							{
25686								"lightness": 19
25687							}
25688						]
25689					},
25690					{
25691						"featureType": "administrative",
25692						"elementType": "geometry.fill",
25693						"stylers": [
25694							{
25695								"color": "#fefefe"
25696							},
25697							{
25698								"lightness": 20
25699							}
25700						]
25701					},
25702					{
25703						"featureType": "administrative",
25704						"elementType": "geometry.stroke",
25705						"stylers": [
25706							{
25707								"color": "#fefefe"
25708							},
25709							{
25710								"lightness": 17
25711							},
25712							{
25713								"weight": 1.2
25714							}
25715						]
25716					}
25717				]
25718
25719		};
25720
25721		var map = new google.maps.Map(document.getElementById('gmap'), mapOptions);
25722		google.maps.event.trigger(map, 'resize');
25723		map.setZoom( map.getZoom() );
25724
25725		var marker = new google.maps.Marker({
25726			icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACcAAAArCAYAAAD7YZFOAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBG
25726CzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAABONJREFUeNrEmMFvG0UUh7+13dI0Ng0pVEJIEJCQcgmEI1zo7pEDyh+A1JY7EhUnTglIvSG1cEGIQ3JBAg5VwglBWW9JSQWFkoCsxFjJOgpWtlXjNE6dOl57h8vbauV61/baEU8aRfaMZ7/83pvfzKymlCIqDMOYBM4Bk8DZNkMs4DowBxSj5jJNk15CC4MzDOMsMB0CFBYWcBFYHgRcIgTsMpDtEQwZ/ycwwwAi1QI1IlCTfc47DbwAXOhnklblBgHmx3lgdiBwkspBgQUB34/7Y00p5Rd/tovxy1L0e8ApYAoY6+J3LwLFXhdEKlAjnVbhhTZWcVEWQSfVp+PUX0J8LGpVzpmmqZumWYwAf018Liq9Y3Fq7lxE/7xpmt3+xxfC/E1iKg5clGoXe5wvavybceAmI9JZ7HE+K0K9sdhW0iZWYjqAFfL95CDhlmPC7Q3KJKPgxvifIwru1ZhzhhV+MQ7c/TBvkoNALzEWsfpjwYXV1kiMffFyRF9R07SE9ngQ1hIdCn/aMIzzYZ3ZbFaTllBKvRtltJ7n5YDjwBPSjsv2mRKRtHZ76/UOCs0ahjFmmuZMEEomTExMTIyOjo5+omnaO1GSViqVW0AaUIEG0AQa0pqA5/dpuq6PALtdpKwIzHuet9hsNveVUqeTyeTbyWTyLTmhhIZSasuyrNcD6mgCoAlQE6gDh9I8QPlHpjhH8q6j0Wh8s7i4+AFwTBRPtaTRA1ygCjzwAX0rWThKv2o2mwvAAfBQFEsBQ8BJaWlR/0n5PgloPtzcEbIVl5aWvhVFHggksihOAsOBlpbvE49M2DTN+8D8EcHN67ruF71fU0og0oE2HADTWneIT48ILjivJik90aKYD6YFVq1KBC68VhwX76QaUBTrSYlCzwBPi8n7qp0QNatATeAe21s/GiSZUuqzbDZ7TGrrNPA88BLwHPAUkJE+gH3ZSmuPfK71dYRhGPYgTiRKqUXLsqbk4aeAM8CzAumvyIZAbQHrQEnU8x678QfUm+0XznGcr4BXBGxUlEoHvM4H2wX+Be4ErCb8RU6/6tVqtX9u3rz5uSg0FNhPE/JwV1K4CeQBWz43gnCJkJR83I9qtm2vAuOB+jojBjssyj2UFOZlEe61goXCWZY1p5S6EQdsZ2en6DhOXWprRKDSUnuaKFQA/gY2JK1uK1jkSbher1+KsU256+vrm7IK0/LX97AG4AA5eU223i6VHeGUUmppaSnruu7VXuC2t7e3q9VqMuD4Q6JWRdS6Bfwhqaz4ZhvnDtGwbftDpVS1G7CDg4OHhUJhR6BOymHSBe7KNfMX4LbYRrUTWCc4VSqVnN3d3SvdwBUKhXuBlalJkeeBG3Kg/QvYlo3f6+v2pZTygNrKyspsrVbLR01SKpX2y+WyJ75ZE4u4BfwE/CyQ5bDCj6McUqxl27ZnPM87bDfg8PCwadv2gTz4jqTwR+B74FcB3dd1vdELWEc4Ua/qOM5vjuN83W7M2tranuu6O8CavIBcAK6JVdwFDnVd9+LYUqqbUzZwL5/Pf5nJZN7IZDIv+x2bm5uVcrmcl3q
257266LarZUm9uXKhu0+qrdwDYq6url+r1elVWZ21jY+Ma8B1wVdTKATtAvV+wbpXzr2+71Wr190Kh8MX4+Ph7uVxuAfhBfGtLjuCuruuKAcV/AwDnrxMM7gFGVQAAAABJRU5ErkJggg==',
25727			position: latLang,
25728			map: map,
25729			title: ""
25730		});
25731
25732		marker.setMap(map);
25733		google.maps.event.addListener(marker, "click", function() {
25734			// Add optionally an action for when the marker is clicked
25735		});
25736
25737		// kepp googlemap responsive - center on resize
25738		google.maps.event.addDomListener(window, 'resize', function() {
25739			map.setCenter(latLang);
25740		});
25741
25742	}
25743
25744
25745	function showMap(initWhat) {
25746		var script 		= document.createElement('script');
25747		script.type 	= 'text/javascript';
25748		script.src 		= '//maps.google.com/maps/api/js?key=AIzaSyA8Ea7FZji6JDtI4DbaxIqcIvhfWJddijk&callback='+initWhat;
25749		document.body.appendChild(script);
25750	}
25751
25752	showMap('contactMap');
25753}
25754
25755
25756/* fitty v2.3.0 */
25757!function(e,t){if("function"==typeof define&&define.amd)define(["module","exports"],t);else if("undefined"!=typeof exports)t(module,exports);else{var n={exports:{}};t(n,n.exports),e.fitty=n.exports}}(this,function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var E=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(e[i]=n[i])}return e};t.default=function(n){if(n){var r={IDLE:0,DIRTY_CONTENT:1,DIRTY_LAYOUT:2,DIRTY:3},i=[],e=null,o="requestAnimationFrame"in n?function(){n.cancelAnimationFrame(e),e=n.requestAnimationFrame(function(){return u(i.filter(function(e){return e.dirty&&e.active}))})}:function(){},t=function(t){return function(){i.forEach(function(e){return e.dirty=t}),o()}},u=function(e){e.filter(function(e){return!e.styleComputed}).forEach(function(e){e.styleComputed=s(e)}),e.filter(f).forEach(d);var t=e.filter(c);t.forEach(l),t.forEach(function(e){d(e),a(e)}),t.forEach(p)},a=function(e){return e.dirty=r.IDLE},l=function(e){e.availableWidth=e.element.parentNode.clientWidth,e.currentWidth=e.element.scrollWidth,e.previousFontSize=e.currentFontSize,e.currentFontSize=Math.min(Math.max(e.minSize,e.availableWidth/e.currentWidth*e.previousFontSize),e.maxSize),e.whiteSpace=e.multiLine&&e.currentFontSize===e.minSize?"normal":"nowrap"},c=function(e){return e.dirty!==r.DIRTY_LAYOUT||e.dirty===r.DIRTY_LAYOUT&&e.element.parentNode.clientWidth!==e.availableWidth},s=function(e){var t=n.getComputedStyle(e.element,null);e.currentFontSize=parseInt(t.getPropertyValue("font-size"),10),e.display=t.getPropertyValue("display"),e.whiteSpace=t.getPropertyValue("white-space")},f=function(e){var t=!1;return!e.preStyleTestCompleted&&(/inline-/.test(e.display)||(t=!0,e.display="inline-block"),"nowrap"!==e.whiteSpace&&(t=!0,e.whiteSpace="nowrap"),e.preStyleTestCompleted=!0,t)},d=function(e){e.originalStyle||(e.originalStyle=e.element.getAttribute("style")||""),e.element.style.cssText=e.originalStyle+";white-space:"+e.whiteSpace+";display:"+e.display+";font-size:"+e.currentFontSize+"px"},p=function(e){e.element.dispatchEvent(new CustomEvent("fit",{detail:{oldValue:e.previousFontSize,newValue:e.currentFontSize,scaleFactor:e.currentFontSize/e.previousFontSize}}))},v=function(e,t){return function(){e.dirty=t,e.active&&o()}},m=function(e){b(e),e.newbie=!0,e.dirty=!0,i.push(e)},y=function(t){return function(){i=i.filter(function(e){return e.element!==t.element}),t.observeMutations&&t.observer.disconnect(),t.element.style.cssText=t.originalStyle}},h=function(e){return function(){e.active||(e.active=!0,o())}},S=function(e){return function(){return e.active=!1}},b=function(e){e.observeMutations&&(e.observer=new MutationObserver(v(e,r.DIRTY_CONTENT)),e.observer.observe(e.element,e.observeMutations))},w={minSize:16,maxSize:512,multiLine:!0,observeMutations:"MutationObserver"in n&&{subtree:!0,childList:!0,characterData:!0}},T=null,z=function(){n.clearTimeout(T),T=n.setTimeout(t(r.DIRTY_LAYOUT),D.observeWindowDelay)},F=["resize","orientationchange"];return Object.defineProperty(D,"observeWindow",{set:function(e){var t=(e?"add":"remove")+"EventListener";F.forEach(function(e){n[t](e,z)})}}),D.observeWindow=!0,D.observeWindowDelay=100,D.fitAll=t(r.DIRTY),D}function g(e,t){var n=E({},w,t),i=e.map(function(e){var t=E({},n,{element:e,active:!0});return m(t),{element:e,fit:v(t,r.DIRTY),unfreeze:h(t),freeze:S(t),unsubscribe:y(t)}});return o(),i}function D(e){var t,n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};return"string"==typeof e?g((t=document.querySelectorAll(e),[].slice.call(t)),n):g([e],n)[0]}}("undefined"==typeof window?null:window),e.exports=t.default});
25758
25759/* TouchSwipe v1.6.18 */
25760!function(factory){"function"==typeof define&&define.amd&&define.amd.jQuery?define(["jquery"],factory):factory("undefined"!=typeof module&&module.exports?require("jquery"):jQuery)}(function($){"use strict";function init(options){return!options||void 0!==options.allowPageScroll||void 0===options.swipe&&void 0===options.swipeStatus||(options.allowPageScroll=NONE),void 0!==options.click&&void 0===options.tap&&(options.tap=options.click),options||(options={}),options=$.extend({},$.fn.swipe.defaults,options),this.each(function(){var $this=$(this),plugin=$this.data(PLUGIN_NS);plugin||(plugin=new TouchSwipe(this,options),$this.data(PLUGIN_NS,plugin))})}function TouchSwipe(element,options){function touchStart(jqEvent){if(!(getTouchInProgress()||$(jqEvent.target).closest(options.excludedElements,$element).length>0)){var event=jqEvent.originalEvent?jqEvent.originalEvent:jqEvent;if(!event.pointerType||"mouse"!=event.pointerType||0!=options.fallbackToMouseEvents){var ret,touches=event.touches,evt=touches?touches[0]:event;return phase=PHASE_START,touches?fingerCount=touches.length:options.preventDefaultEvents!==!1&&jqEvent.preventDefault(),distance=0,direction=null,currentDirection=null,pinchDirection=null,duration=0,startTouchesDistance=0,endTouchesDistance=0,pinchZoom=1,pinchDistance=0,maximumsMap=createMaximumsData(),cancelMultiFingerRelease(),createFingerData(0,evt),!touches||fingerCount===options.fingers||options.fingers===ALL_FINGERS||hasPinches()?(startTime=getTimeStamp(),2==fingerCount&&(createFingerData(1,touches[1]),startTouchesDistance=endTouchesDistance=calculateTouchesDistance(fingerData[0].start,f
vendor: 16,482 bytes, line 25760
25760ingerData[1].start)),(options.swipeStatus||options.pinchStatus)&&(ret=triggerHandler(event,phase))):ret=!1,ret===!1?(phase=PHASE_CANCEL,triggerHandler(event,phase),ret):(options.hold&&(holdTimeout=setTimeout($.proxy(function(){$element.trigger("hold",[event.target]),options.hold&&(ret=options.hold.call($element,event,event.target))},this),options.longTapThreshold)),setTouchInProgress(!0),null)}}}function touchMove(jqEvent){var event=jqEvent.originalEvent?jqEvent.originalEvent:jqEvent;if(phase!==PHASE_END&&phase!==PHASE_CANCEL&&!inMultiFingerRelease()){var ret,touches=event.touches,evt=touches?touches[0]:event,currentFinger=updateFingerData(evt);if(endTime=getTimeStamp(),touches&&(fingerCount=touches.length),options.hold&&clearTimeout(holdTimeout),phase=PHASE_MOVE,2==fingerCount&&(0==startTouchesDistance?(createFingerData(1,touches[1]),startTouchesDistance=endTouchesDistance=calculateTouchesDistance(fingerData[0].start,fingerData[1].start)):(updateFingerData(touches[1]),endTouchesDistance=calculateTouchesDistance(fingerData[0].end,fingerData[1].end),pinchDirection=calculatePinchDirection(fingerData[0].end,fingerData[1].end)),pinchZoom=calculatePinchZoom(startTouchesDistance,endTouchesDistance),pinchDistance=Math.abs(startTouchesDistance-endTouchesDistance)),fingerCount===options.fingers||options.fingers===ALL_FINGERS||!touches||hasPinches()){if(direction=calculateDirection(currentFinger.start,currentFinger.end),currentDirection=calculateDirection(currentFinger.last,currentFinger.end),validateDefaultEvent(jqEvent,currentDirection),distance=calculateDistance(currentFinger.start,currentFinger.end),duration=calculateDuration(),setMaxDistance(direction,distance),ret=triggerHandler(event,phase),!options.triggerOnTouchEnd||options.triggerOnTouchLeave){var inBounds=!0;if(options.triggerOnTouchLeave){var bounds=getbounds(this);inBounds=isInBounds(currentFinger.end,bounds)}!options.triggerOnTouchEnd&&inBounds?phase=getNextPhase(PHASE_MOVE):options.triggerOnTouchLeave&&!inBounds&&(phase=getNextPhase(PHASE_END)),phase!=PHASE_CANCEL&&phase!=PHASE_END||triggerHandler(event,phase)}}else phase=PHASE_CANCEL,triggerHandler(event,phase);ret===!1&&(phase=PHASE_CANCEL,triggerHandler(event,phase))}}function touchEnd(jqEvent){var event=jqEvent.originalEvent?jqEvent.originalEvent:jqEvent,touches=event.touches;if(touches){if(touches.length&&!inMultiFingerRelease())return startMultiFingerRelease(event),!0;if(touches.length&&inMultiFingerRelease())return!0}return inMultiFingerRelease()&&(fingerCount=fingerCountAtRelease),endTime=getTimeStamp(),duration=calculateDuration(),didSwipeBackToCancel()||!validateSwipeDistance()?(phase=PHASE_CANCEL,triggerHandler(event,phase)):options.triggerOnTouchEnd||options.triggerOnTouchEnd===!1&&phase===PHASE_MOVE?(options.preventDefaultEvents!==!1&&jqEvent.cancelable!==!1&&jqEvent.preventDefault(),phase=PHASE_END,triggerHandler(event,phase)):!options.triggerOnTouchEnd&&hasTap()?(phase=PHASE_END,triggerHandlerForGesture(event,phase,TAP)):phase===PHASE_MOVE&&(phase=PHASE_CANCEL,triggerHandler(event,phase)),setTouchInProgress(!1),null}function touchCancel(){fingerCount=0,endTime=0,startTime=0,startTouchesDistance=0,endTouchesDistance=0,pinchZoom=1,cancelMultiFingerRelease(),setTouchInProgress(!1)}function touchLeave(jqEvent){var event=jqEvent.originalEvent?jqEvent.originalEvent:jqEvent;options.triggerOnTouchLeave&&(phase=getNextPhase(PHASE_END),triggerHandler(event,phase))}function removeListeners(){$element.off(START_EV,touchStart),$element.off(CANCEL_EV,touchCancel),$element.off(MOVE_EV,touchMove),$element.off(END_EV,touchEnd),LEAVE_EV&&$element.off(LEAVE_EV,touchLeave),setTouchInProgress(!1)}function getNextPhase(currentPhase){var nextPhase=currentPhase,validTime=validateSwipeTime(),validDistance=validateSwipeDistance(),didCancel=didSwipeBackToCancel();return!validTime||didCancel?nextPhase=PHASE_CANCEL:!validDistance||currentPhase!=PHASE_MOVE||options.triggerOnTouchEnd&&!options.triggerOnTouchLeave?!validDistance&&currentPhase==PHASE_END&&options.triggerOnTouchLeave&&(nextPhase=PHASE_CANCEL):nextPhase=PHASE_END,nextPhase}function triggerHandler(event,phase){var ret,touches=event.touches;return(didSwipe()||hasSwipes())&&(ret=triggerHandlerForGesture(event,phase,SWIPE)),(didPinch()||hasPinches())&&ret!==!1&&(ret=triggerHandlerForGesture(event,phase,PINCH)),didDoubleTap()&&ret!==!1?ret=triggerHandlerForGesture(event,phase,DOUBLE_TAP):didLongTap()&&ret!==!1?ret=triggerHandlerForGesture(event,phase,LONG_TAP):didTap()&&ret!==!1&&(ret=triggerHandlerForGesture(event,phase,TAP)),phase===PHASE_CANCEL&&touchCancel(event),phase===PHASE_END&&(touches?touches.length||touchCancel(event):touchCancel(event)),ret}function triggerHandlerForGesture(event,phase,gesture){var ret;if(gesture==SWIPE){if($element.trigger("swipeStatus",[phase,direction||null,distance||0,duration||0,fingerCount,fingerData,currentDirection]),options.swipeStatus&&(ret=options.swipeStatus.call($element,event,phase,direction||null,distance||0,duration||0,fingerCount,fingerData,currentDirection),ret===!1))return!1;if(phase==PHASE_END&&validateSwipe()){if(clearTimeout(singleTapTimeout),clearTimeout(holdTimeout),$element.trigger("swipe",[direction,distance,duration,fingerCount,fingerData,currentDirection]),options.swipe&&(ret=options.swipe.call($element,event,direction,distance,duration,fingerCount,fingerData,currentDirection),ret===!1))return!1;switch(direction){case LEFT:$element.trigger("swipeLeft",[direction,distance,duration,fingerCount,fingerData,currentDirection]),options.swipeLeft&&(ret=options.swipeLeft.call($element,event,direction,distance,duration,fingerCount,fingerData,currentDirection));break;case RIGHT:$element.trigger("swipeRight",[direction,distance,duration,fingerCount,fingerData,currentDirection]),options.swipeRight&&(ret=options.swipeRight.call($element,event,direction,distance,duration,fingerCount,fingerData,currentDirection));break;case UP:$element.trigger("swipeUp",[direction,distance,duration,fingerCount,fingerData,currentDirection]),options.swipeUp&&(ret=options.swipeUp.call($element,event,direction,distance,duration,fingerCount,fingerData,currentDirection));break;case DOWN:$element.trigger("swipeDown",[direction,distance,duration,fingerCount,fingerData,currentDirection]),options.swipeDown&&(ret=options.swipeDown.call($element,event,direction,distance,duration,fingerCount,fingerData,currentDirection))}}}if(gesture==PINCH){if($element.trigger("pinchStatus",[phase,pinchDirection||null,pinchDistance||0,duration||0,fingerCount,pinchZoom,fingerData]),options.pinchStatus&&(ret=options.pinchStatus.call($element,event,phase,pinchDirection||null,pinchDistance||0,duration||0,fingerCount,pinchZoom,fingerData),ret===!1))return!1;if(phase==PHASE_END&&validatePinch())switch(pinchDirection){case IN:$element.trigger("pinchIn",[pinchDirection||null,pinchDistance||0,duration||0,fingerCount,pinchZoom,fingerData]),options.pinchIn&&(ret=options.pinchIn.call($element,event,pinchDirection||null,pinchDistance||0,duration||0,fingerCount,pinchZoom,fingerData));break;case OUT:$element.trigger("pinchOut",[pinchDirection||null,pinchDistance||0,duration||0,fingerCount,pinchZoom,fingerData]),options.pinchOut&&(ret=options.pinchOut.call($element,event,pinchDirection||null,pinchDistance||0,duration||0,fingerCount,pinchZoom,fingerData))}}return gesture==TAP?phase!==PHASE_CANCEL&&phase!==PHASE_END||(clearTimeout(singleTapTimeout),clearTimeout(holdTimeout),hasDoubleTap()&&!inDoubleTap()?(doubleTapStartTime=getTimeStamp(),singleTapTimeout=setTimeout($.proxy(function(){doubleTapStartTime=null,$element.trigger("tap",[event.target]),options.tap&&(ret=options.tap.call($element,event,event.target))},this),options.doubleTapThreshold)):(doubleTapStartTime=null,$element.trigger("tap",[event.target]),options.tap&&(ret=options.tap.call($element,event,event.target)))):gesture==DOUBLE_TAP?phase!==PHASE_CANCEL&&phase!==PHASE_END||(clearTimeout(singleTapTimeout),clearTimeout(holdTimeout),doubleTapStartTime=null,$element.trigger("doubletap",[event.target]),options.doubleTap&&(ret=options.doubleTap.call($element,event,event.target))):gesture==LONG_TAP&&(phase!==PHASE_CANCEL&&phase!==PHASE_END||(clearTimeout(singleTapTimeout),doubleTapStartTime=null,$element.trigger("longtap",[event.target]),options.longTap&&(ret=options.longTap.call($element,event,event.target)))),ret}function validateSwipeDistance(){var valid=!0;return null!==options.threshold&&(valid=distance>=options.threshold),valid}function didSwipeBackToCancel(){var cancelled=!1;return null!==options.cancelThreshold&&null!==direction&&(cancelled=getMaxDistance(direction)-distance>=options.cancelThreshold),cancelled}function validatePinchDistance(){return null!==options.pinchThreshold?pinchDistance>=options.pinchThreshold:!0}function validateSwipeTime(){var result;return result=options.maxTimeThreshold?!(duration>=options.maxTimeThreshold):!0}function validateDefaultEvent(jqEvent,direction){if(options.preventDefaultEvents!==!1)if(options.allowPageScroll===NONE)jqEvent.preventDefault();else{var auto=options.allowPageScroll===AUTO;switch(direction){case LEFT:(options.swipeLeft&&auto||!auto&&options.allowPageScroll!=HORIZONTAL)&&jqEvent.preventDefault();break;case RIGHT:(options.swipeRight&&auto||!auto&&options.allowPageScroll!=HORIZONTAL)&&jqEvent.preventDefault();break;case UP:(options.swipeUp&&auto||!auto&&options.allowPageScroll!=VERTICAL)&&jqEvent.preventDefault();break;case DOWN:(options.swipeDown&&auto||!auto&&options.allowPageScroll!=VERTICAL)&&jqEvent.preventDefault();break;case NONE:}}}function validatePinch(){var hasCorrectFingerCount=validateFingers(),hasEndPoint=validateEndPoint(),hasCorrectDistance=validatePinchDistance();return hasCorrectFingerCount&&hasEndPoint&&hasCorrectDistance}function hasPinches(){return!!(options.pinchStatus||options.pinchIn||options.pinchOut)}function didPinch(){return!(!validatePinch()||!hasPinches())}function validateSwipe(){var hasValidTime=validateSwipeTime(),hasValidDistance=validateSwipeDistance(),hasCorrectFingerCount=validateFingers(),hasEndPoint=validateEndPoint(),didCancel=didSwipeBackToCancel(),valid=!didCancel&&hasEndPoint&&hasCorrectFingerCount&&hasValidDistance&&hasValidTime;return valid}function hasSwipes(){return!!(options.swipe||options.swipeStatus||options.swipeLeft||options.swipeRight||options.swipeUp||options.swipeDown)}function didSwipe(){return!(!validateSwipe()||!hasSwipes())}function validateFingers(){return fingerCount===options.fingers||options.fingers===ALL_FINGERS||!SUPPORTS_TOUCH}function validateEndPoint(){return 0!==fingerData[0].end.x}function hasTap(){return!!options.tap}function hasDoubleTap(){return!!options.doubleTap}function hasLongTap(){return!!options.longTap}function validateDoubleTap(){if(null==doubleTapStartTime)return!1;var now=getTimeStamp();return hasDoubleTap()&&now-doubleTapStartTime<=options.doubleTapThreshold}function inDoubleTap(){return validateDoubleTap()}function validateTap(){return(1===fingerCount||!SUPPORTS_TOUCH)&&(isNaN(distance)||distance<options.threshold)}function validateLongTap(){return duration>options.longTapThreshold&&DOUBLE_TAP_THRESHOLD>distance}function didTap(){return!(!validateTap()||!hasTap())}function didDoubleTap(){return!(!validateDoubleTap()||!hasDoubleTap())}function didLongTap(){return!(!validateLongTap()||!hasLongTap())}function startMultiFingerRelease(event){previousTouchEndTime=getTimeStamp(),fingerCountAtRelease=event.touches.length+1}function cancelMultiFingerRelease(){previousTouchEndTime=0,fingerCountAtRelease=0}function inMultiFingerRelease(){var withinThreshold=!1;if(previousTouchEndTime){var diff=getTimeStamp()-previousTouchEndTime;diff<=options.fingerReleaseThreshold&&(withinThreshold=!0)}return withinThreshold}function getTouchInProgress(){return!($element.data(PLUGIN_NS+"_intouch")!==!0)}function setTouchInProgress(val){$element&&(val===!0?($element.on(MOVE_EV,touchMove),$element.on(END_EV,touchEnd),LEAVE_EV&&$element.on(LEAVE_EV,touchLeave)):($element.off(MOVE_EV,touchMove,!1),$element.off(END_EV,touchEnd,!1),LEAVE_EV&&$element.off(LEAVE_EV,touchLeave,!1)),$element.data(PLUGIN_NS+"_intouch",val===!0))}function createFingerData(id,evt){var f={start:{x:0,y:0},last:{x:0,y:0},end:{x:0,y:0}};return f.start.x=f.last.x=f.end.x=evt.pageX||evt.clientX,f.start.y=f.last.y=f.end.y=evt.pageY||evt.clientY,fingerData[id]=f,f}function updateFingerData(evt){var id=void 0!==evt.identifier?evt.identifier:0,f=getFingerData(id);return null===f&&(f=createFingerData(id,evt)),f.last.x=f.end.x,f.last.y=f.end.y,f.end.x=evt.pageX||evt.clientX,f.end.y=evt.pageY||evt.clientY,f}function getFingerData(id){return fingerData[id]||null}function setMaxDistance(direction,distance){direction!=NONE&&(distance=Math.max(distance,getMaxDistance(direction)),maximumsMap[direction].distance=distance)}function getMaxDistance(direction){return maximumsMap[direction]?maximumsMap[direction].distance:void 0}function createMaximumsData(){var maxData={};return maxData[LEFT]=createMaximumVO(LEFT),maxData[RIGHT]=createMaximumVO(RIGHT),maxData[UP]=createMaximumVO(UP),maxData[DOWN]=createMaximumVO(DOWN),maxData}function createMaximumVO(dir){return{direction:dir,distance:0}}function calculateDuration(){return endTime-startTime}function calculateTouchesDistance(startPoint,endPoint){var diffX=Math.abs(startPoint.x-endPoint.x),diffY=Math.abs(startPoint.y-endPoint.y);return Math.round(Math.sqrt(diffX*diffX+diffY*diffY))}function calculatePinchZoom(startDistance,endDistance){var percent=endDistance/startDistance*1;return percent.toFixed(2)}function calculatePinchDirection(){return 1>pinchZoom?OUT:IN}function calculateDistance(startPoint,endPoint){return Math.round(Math.sqrt(Math.pow(endPoint.x-startPoint.x,2)+Math.pow(endPoint.y-startPoint.y,2)))}function calculateAngle(startPoint,endPoint){var x=startPoint.x-endPoint.x,y=endPoint.y-startPoint.y,r=Math.atan2(y,x),angle=Math.round(180*r/Math.PI);return 0>angle&&(angle=360-Math.abs(angle)),angle}function calculateDirection(startPoint,endPoint){if(comparePoints(startPoint,endPoint))return NONE;var angle=calculateAngle(startPoint,endPoint);return 45>=angle&&angle>=0?LEFT:360>=angle&&angle>=315?LEFT:angle>=135&&225>=angle?RIGHT:angle>45&&135>angle?DOWN:UP}function getTimeStamp(){var now=new Date;return now.getTime()}function getbounds(el){el=$(el);var offset=el.offset(),bounds={left:offset.left,right:offset.left+el.outerWidth(),top:offset.top,bottom:offset.top+el.outerHeight()};return bounds}function isInBounds(point,bounds){return point.x>bounds.left&&point.x<bounds.right&&point.y>bounds.top&&point.y<bounds.bottom}function comparePoints(pointA,pointB){return pointA.x==pointB.x&&pointA.y==pointB.y}var options=$.extend({},options),useTouchEvents=SUPPORTS_TOUCH||SUPPORTS_POINTER||!options.fallbackToMouseEvents,START_EV=useTouchEvents?SUPPORTS_POINTER?SUPPORTS_POINTER_IE10?"MSPointerDown":"pointerdown":"touchstart":"mousedown",MOVE_EV=useTouchEvents?SUPPORTS_POINTER?SUPPORTS_POINTER_IE10?"MSPointerMove":"pointermove":"touchmove":"mousemove",END_EV=useTouchEvents?SUPPORTS_POINTER?SUPPORTS_POINTER_IE10?"MSPointerUp":"pointerup":"touchend":"mouseup",LEAVE_EV=useTouchEvents?SUPPORTS_POINTER?"mouseleave":null:"mouseleave",CANCEL_EV=SUPPORTS_POINTER?SUPPORTS_POINTER_IE10?"MSPointerCancel":"pointercancel":"touchcancel",distance=0,direction=null,currentDirection=null,duration=0,startTouchesDistance=0,endTouchesDistance=0,pinchZoom=1,pinchDistance=0,pinchDirection=0,maximumsMap=null,$element=$(element),phase="start",fingerCount=0,fingerData={},startTime=0,endTime=0,previousTouchEndTime=0,fingerCountAtRelease=0,doubleTapStartTime=0,singleTapTimeout=null,holdTimeout=null;try{$element.on(START_EV,touchStart),$element.on(CANCEL_EV,touchCancel)}catch(e){$.error("events not supported "+START_EV+","+CANCEL_EV+" on jQuery.swipe")}this.enable=function(){return this.disable(),$element.on(START_EV,touchStart),$element.on(CANCEL_EV,touchCancel),$element},this.disable=function(){return removeListeners(),$element},this.destroy=function(){removeListeners(),$element.data(PLUGIN_NS,null),$element=null},this.option=function(property,value){if("object"==typeof property)options=$.extend(options,property);else if(void 0!==options[property]){if(void 0===value)return options[property];options[property]=value}else{if(!property)return options;$.error("Option "+property+" does not exist on jQuery.swipe.options")}return null}}var VERSION="1.6.18",LEFT="left",RIGHT="right",UP="up",DOWN="down",IN="in",OUT="out",
25760NONE="none",AUTO="auto",SWIPE="swipe",PINCH="pinch",TAP="tap",DOUBLE_TAP="doubletap",LONG_TAP="longtap",HORIZONTAL="horizontal",VERTICAL="vertical",ALL_FINGERS="all",DOUBLE_TAP_THRESHOLD=10,PHASE_START="start",PHASE_MOVE="move",PHASE_END="end",PHASE_CANCEL="cancel",SUPPORTS_TOUCH="ontouchstart"in window,SUPPORTS_POINTER_IE10=window.navigator.msPointerEnabled&&!window.PointerEvent&&!SUPPORTS_TOUCH,SUPPORTS_POINTER=(window.PointerEvent||window.navigator.msPointerEnabled)&&!SUPPORTS_TOUCH,PLUGIN_NS="TouchSwipe",defaults={fingers:1,threshold:75,cancelThreshold:null,pinchThreshold:20,maxTimeThreshold:null,fingerReleaseThreshold:250,longTapThreshold:500,doubleTapThreshold:200,swipe:null,swipeLeft:null,swipeRight:null,swipeUp:null,swipeDown:null,swipeStatus:null,pinchIn:null,pinchOut:null,pinchStatus:null,click:null,tap:null,doubleTap:null,longTap:null,hold:null,triggerOnTouchEnd:!0,triggerOnTouchLeave:!1,allowPageScroll:"auto",fallbackToMouseEvents:!0,excludedElements:".noSwipe",preventDefaultEvents:!0};$.fn.swipe=function(method){var $this=$(this),plugin=$this.data(PLUGIN_NS);if(plugin&&"string"==typeof method){if(plugin[method])return plugin[method].apply(plugin,Array.prototype.slice.call(arguments,1));$.error("Method "+method+" does not exist on jQuery.swipe")}else if(plugin&&"object"==typeof method)plugin.option.apply(plugin,arguments);else if(!(plugin||"object"!=typeof method&&method))return init.apply(this,arguments);return $this},$.fn.swipe.version=VERSION,$.fn.swipe.defaults=defaults,$.fn.swipe.phases={PHASE_START:PHASE_START,PHASE_MOVE:PHASE_MOVE,PHASE_END:PHASE_END,PHASE_CANCEL:PHASE_CANCEL},$.fn.swipe.directions={LEFT:LEFT,RIGHT:RIGHT,UP:UP,DOWN:DOWN,IN:IN,OUT:OUT},$.fn.swipe.pageScroll={NONE:NONE,HORIZONTAL:HORIZONTAL,VERTICAL:VERTICAL,AUTO:AUTO},$.fn.swipe.fingers={ONE:1,TWO:2,THREE:3,FOUR:4,FIVE:5,ALL:ALL_FINGERS}});
25761
25762
25763function prettyfieHempMate() {
25764	$(".prettyfie-hempmate").each(function() {
25765		var str = $(this).html();
25766			str = str.replace('Hemp', '<b>Hemp</b>');
25767			str = str.replace('HEMP', '<b>HEMP</b>');
25768		$(this).html( str );
25769	});
25770}
25771
25772function prettyfieVapeMate() {
25773	$(".prettyfie-vapemate").each(function() {
25774		var str = $(this).html();
25775			str = str.replace('Vape', '<b>Vape</b>');
25776			str = str.replace('VAPE', '<b>VAPE</b>');
25777		$(this).html( str );
25778	});
25779}
25780
25781function partnerModalClose() {
25782	if( partnerPopUp ) {
25783		$("#partner-page-modal").modal("hide");
25784		$(document.body).removeClass('modal-open');
25785		$(window.document).find('html').removeClass('modal-open');
25786	}
25787}
25788
25789function partnerModalOpen() {
25790	if( partnerPopUp ) {
25791		$(document.body).addClass('modal-open');
25792		$(window.document).find('html').addClass('modal-open');
25793		$("#partner-page-modal").modal({
25794			backdrop: 'static',
25795			keyboard: true,
25796			show: true
25797		});
25798	}
25799}
25800
25801function updateInvoiceFormSubmit() {
25802
25803	if( $("#cart-update-invoice").length > 0 ) {
25804		console.log("standard");
25805		$("#cart-update-invoice").data("yiiActiveForm").submitting = true; 
25806		$("#cart-update-invoice").yiiActiveForm("validate");
25807	}
25808
25809}
25810
25811function kundenModalOpen() {
25812	if( kundenPopUp ) {
25813		var bd = $("#modalKunde").attr("data-backdrop"),
25814			kb = $("#modalKunde").attr("data-keyboard");
25815		bd = (typeof bd !== 'undefined' && bd !== false) ? 'static' : true;
25816		kb = (typeof kb !== 'undefined' && kb !== false) ? false : true;
25817		$(document.body).addClass('modal-open');
25818		$(window.document).find('html').addClass('modal-open');
25819		$("#modalKunde").modal({
25820			backdrop: bd,
25821			keyboard: kb,
25822			show: true
25823		});
25824		kundenPopUp = false;
25825	}
25826}
25827
25828
25829
25830
25831
25832
25833
25834
25835
25836
25837
25838
25839
25840
25841
25842
25843
25844
25845
25846
25847function revealfaq(block, quest) {
25848	var revealent = "#" + block;
25849	revealent = revealent + quest;
25850	var revealSpeed = 700;
25851	if( $(revealent).length > 0 ) {
25852
25853		setTimeout(function() {
25854			$('html, body').animate({scrollTop: $( revealent ).offset().top -150}, revealSpeed);
25855			setTimeout(function() {
25856				$( revealent ).find('button').click();
25857				console.log( revealent );
25858			}, revealSpeed);
25859		}, revealSpeed);
25860	}
25861}
25862
25863$(document).ready(function() {
25864	if( $("#adult-modal").length > 0 ) {
25865		if( $("#adultCheck").length > 0 ) {
25866			$("#adultCheck").change(function() {
25867				if( document.getElementById("adultCheck").checked ) {
25868					$("#adultButton").removeClass("disabled");
25869				} else {
25870					$("#adultButton").addClass("disabled");
25871				}
25872			});
25873		}
25874		setTimeout(function() {
25875			$("#adult-modal").modal('show');
25876		}, 750);
25877	}
25878
25879	if( $("#modalChangeSponsor").length > 0 ) {
25880		setTimeout(function() {
25881			$("#modalChangeSponsor").modal('show');
25882		}, 450);
25883	}
25884
25885	if( $(".embed-responsive.embed-responsive-overlay").length > 0 ) {
25886		$(".embed-responsive.embed-responsive-overlay").each(function() {
25887			var childVID = $(this).children("video.no-controlls");
25888			if( childVID.length > 0 ) {
25889				childVID = childVID[0];
25890				childVID.controls = false;
25891				$(this).click( function() {
25892					if(childVID.paused && userInteraction === true) {
25893						var promise = childVID.play();
25894						if( promise !== undefined ) {
25895							promise.then(_ => {
25896								childVID.volume = 0.25;
25897								userPausedVideo = false;
25898							});
25899						}
25900					} else {
25901						childVID.volume = 0;
25902						userPausedVideo = true;
25903						childVID.pause();
25904					}
25905				});
25906				childVID.onpause = function() {
25907					if( childVID.nextElementSibling !== null ) {
25908						childVID.nextElementSibling.classList.add("show");
25909					}
25910				}
25911				childVID.onplay = function() {
25912					if( childVID.nextElementSibling !== null ) {
25913						childVID.nextElementSibling.classList.remove("show");
25914					}
25915				}
25916			}
25917		});
25918	}
25919
25920	if( $("#cat-headln").length > 0 ) {
25921		fitty('#cat-headln');
25922	}
25923	//if( $("#testi-container").length > 0 ) {
25924	if( $("#testimonials").length > 0 ) {
25925		setTimeout(function(){
25926			$("#testi-container").addClass("testi-0");
25927			var testiSlider = $("#testimonials")[0].swiper;
25928
25929			testiSlider.on("slideChange", function() {
25930				$("#testi-container").removeClass("testi-" + testiSlider.previousIndex);
25931				$("#testi-container").addClass("testi-" + testiSlider.activeIndex );
25932			});
25933		},2000);
25934	}
25935	if( $("#partner-page-modal").length > 0 && partnerAutoPopUp ) {
25936		setTimeout(function(){
25937			partnerModalOpen();
25938			fitPartnerImage();
25939		},1000);
25940	}
25941	if( $(".prettyfie-hempmate").length > 0 ) {
25942		prettyfieHempMate();
25943	}
25944	if( $(".prettyfie-vapemate").length > 0 ) {
25945		prettyfieVapeMate();
25946	}
25947	if( $("section.faqs").length > 0 && typeof revealAnswer !== 'undefined' && revealAnswer === true ) {
25948		revealfaq(block, quest);
25949	}
25950	if( $("#head-slider").length > 0 ) {
25951		setTimeout(function(){
25952			$("#head-slider").on("slide.bs.carousel", function(event) {
25953				$(".banner-background").each(function() {
25954					$(this)[0].style.backgroundColor = event.relatedTarget.getAttribute("data-bannerBG");
25955				});
25956				$(".banner-text-holder").each(function() {
25957					$(this).fadeOut(750,function() {
25958						$(this)[0].style.color = event.relatedTarget.getAttribute("data-textCOL");
25959					});
25960				});
25961			});
25962			$("#head-slider").on("slid.bs.carousel", function(event) {
25963				$(".banner-text-holder").each(function() {
25964					var diese = $(this);
25965					setTimeout(function() {
25966						diese.fadeIn(750);
25967					},300);
25968				});
25969			});
25970			console.log("Slider loaded.");
25971		},2000);
25972	}
25973	if( $("#kunden-geburtsdatum").length > 0 ) {
25974		$("#kunden-geburtsdatum").inputmask("dd.mm.yyyy");
25975	}
25976	if( $("#modalKunde").length > 0 && kundenPopUp === true ) {
25977		setTimeout(function() {
25978			$("#modalKunde").modal("show");
25979			kundenPopUp = false;
25980		}, 1111);
25981	}
25982
25983	refreshVoucherButton();
25984	thisSiteTitle = $('head > title').text();
25985});
25986
25987
25988$(".edit-link[data-action='edit-what']").click(function() {
25989		$( $(this).attr("data-parent") ).addClass("editing");
25990});
25991
25992$(".edit-link[data-action='edit-link']").click(function() {
25993	window.location.href = $(this).attr("data-prompt");
25994});
25995
25996$(".edit-link[data-action='edit-link-pjax']").click(function() {
25997	let thisLink = $(this).attr("data-container");
25998	if( thisLink !== "undefined" && thisLink !== "" && thisLink !== null ) {
25999		$.ajax({
26000			type	: 'GET',
26001			async	: false,
26002			cache	: false,
26003			url		: $(this).attr("data-prompt"),
26004			success	: function(data) {
26005				$.pjax.reload({
26006					container:	thisLink,
26007					async:		false
26008				});
26009			}
26010		});
26011	}
26012});
26013
26014$(".edit-what-abbort").click(function() {
26015	$( $(this).attr("data-parent") ).removeClass("editing");
26016});
26017
26018
26019function recoverSiteTitle() {
26020	setTimeout(function() {
26021		$('head > title').text( thisSiteTitle );
26022	}, 1000);
26023}
26024
26025function closeKDmodalANDsetAction(action, zusatz) {
26026	zusatz = typeof zusatz !== 'undefined' ? zusatz : '';
26027	let actions = ['update-user', 'update-invoice', 'update-shipping', 'changesponsor', 'select-payment'];
26028	if ( jQuery.inArray( action, actions ) ) {
26029		let url = window.location.href + 'action=' + action + zusatz;
26030		$.ajax({
26031			type	: 'GET',
26032			async	: false,
26033			cache	: false,
26034			url		: url,
26035			success	: $.pjax.reload({container:'#pjaxCart', async:false}),
26036			complete: $('#modalKunde').modal('hide')
26037		});
26038	}
26039}
26040
26041
26042function closeMyModal( modalID ) {
26043	if( $( modalID ).length > 0 ) {
26044		$( modalID ).modal('hide');
26045	} else {
26046		console.log(modalID + " nicht gefunden!");
26047	}
26048}
26049
26050function clickMyLink( linkID ) {
26051	if( $( linkID ).length > 0 ) {
26052		$( linkID ).click();
26053	} else {
26054		console.log(linkID + " nicht gefunden!");
26055	}
26056}
26057	
26058
26059function refreshVoucherButton() {
26060	if( $("#voucher-button").length > 0 ) {
26061		
26062		$("#voucher-button").unbind();
26063		$("#voucher-button").not(".inactive").on('click', function(e) {
26064			e.preventDefault();
26065			if( $("#voucher-button").hasClass("redeem-voucher") ) {
26066				$.ajax({
26067					type	: 'GET',
26068					data	: 'gutscheincode='+$('#neworder-gutscheincode').val(),
26069					async	: false,
26070					cache	: false,
26071					url		: $("#voucher-button").attr("data-url"),
26072					success	: function(error) {
26073						let VBerr = parseInt( error );
26074						switch( VBerr ) {
26075							case 0:
26076								$.pjax.reload({container: '#pjaxCart', async:false});
26077								$.pjax.reload({container: '#pjaxSeitenkorb', async:false});
26078								$.pjax.reload({container: '#pjaxWarenkorb', async:false});
26079								break;
26080							case 1:
26081								swal({
26082									title:	voucherButtonErrorSWAL[ VBerr ]['title'],
26083									html:	voucherButtonErrorSWAL[ VBerr ]['html'],
26084									type:	'error'
26085								});
26086								break;
26087							case 2:
26088								swal({
26089									title:	voucherButtonErrorSWAL[ VBerr ]['title'],
26090									html:	voucherButtonErrorSWAL[ VBerr ]['html'],
26091									type:	'error'
26092								});
26093								break;
26094							case 3:
26095								swal({
26096									title:	voucherButtonErrorSWAL[ VBerr ]['title'],
26097									html:	voucherButtonErrorSWAL[ VBerr ]['html'],
26098									type:	'error'
26099								});
26100								break;
26101							case 4:
26102								swal({
26103									title:	voucherButtonErrorSWAL[ VBerr ]['title'],
26104									html:	voucherButtonErrorSWAL[ VBerr ]['html'],
26105									type:	'error'
26106								});
26107								break;
26108							case 5:
26109								swal({
26110									title:	voucherButtonErrorSWAL[ VBerr ]['title'],
26111									html:	voucherButtonErrorSWAL[ VBerr ]['html'],
26112									type:	'error'
26113								});
26114								break;
26115							case 6:
26116								swal({
26117									title:	voucherButtonErrorSWAL[ VBerr ]['title'],
26118									html:	voucherButtonErrorSWAL[ VBerr ]['html'],
26119									type:	'error'
26120								});
26121								break;
26122							case 7:
26123								swal({
26124									title:	voucherButtonErrorSWAL[ VBerr ]['title'],
26125									html:	voucherButtonErrorSWAL[ VBerr ]['html'],
26126									type:	'error'
26127								});
26128								break;
26129						}
26130					}
26131				});
26132				return false;
26133			} else if( $("#voucher-button").hasClass("dismiss-voucher") ) {
26134				$.ajax({
26135					type	: 'GET',
26136					async	: false,
26137					cache	: false,
26138					url		: $("#voucher-button").attr("data-url"),
26139					success	: function(data) {
26140						$.pjax.reload({container: '#pjaxCart', async:false});
26141						$.pjax.reload({container: '#pjaxSeitenkorb', async:false});
26142						$.pjax.reload({container: '#pjaxWarenkorb', async:false});
26143					}
26144				});
26145				return false;
26146			}
26147		});
26148	}
26149}
26150
26151
26152function payment_selection( bezahloption ) {
26153	let $EL = $( "#"+bezahloption ),
26154		$CK	= $("#zahlart-" + $EL.attr("data-label")),
26155		$URL= $EL.attr("data-url") + "?bezahlart=" + $CK.attr("data-target");
26156	if( !$CK.is(":checked") ) {
26157		setTimeout(function() {
26158			$.ajax({
26159				type	: 'GET',
26160				async	: false,
26161				cache	: false,
26162				url		: $URL,
26163				complete: function(data) {
26164					$("#modalKunde").modal("hide");
26165					$.pjax.reload({container: '#pjaxCart', async:true});
26166				}
26167			});
26168		}, 500);
26169	}
26170}
26171
26172function zurKasseButton(e) {
26173    e = e || window.event;
26174    e.preventDefault();
26175
26176	$.ajax({
26177		type    : "GET",
26178		data	: "checkout = 1",
26179		cache   : false,
26180		async	: false,
26181		url		: zurKasseLink + '?checkout=1',
26182		complete: function() {
26183			window.location.href = zurKasseLink;
26184		}
26185	});
26186}
26187
26188
26189
26190
26191
26192
26193
26194
26195
26196
26197/**
26198 *
26199 *	@SIDECART FUNCTIONS
26200 *
26201 **/
26202function sidecart_toggle() {
26203	$("#sidecart").toggleClass('js-aside-show');
26204	$.SOW.helper.overlay('toggle');
26205
26206	// toggle back on overlay click
26207	$("#overlay-default").unbind().on('click', function(e) {
26208		$.SOW.helper.overlay('hide');
26209		$("#sidecart").removeClass('js-aside-show');
26210	});
26211	// toggle back on arrow click
26212	$("#sidecart-close-arrow").unbind().on('click', function(e) {
26213		$.SOW.helper.overlay('hide');
26214		$("#sidecart").removeClass('js-aside-show');
26215	});
26216	// toggle back on cross-click
26217	$("#sidecart-close-cross").unbind().on('click', function(e) {
26218		$.SOW.helper.overlay('hide');
26219		$("#sidecart").removeClass('js-aside-show');
26220	});
26221}
26222function sidecart_cartaction(whatwasdone) {
26223	$("#sidecart")[0].classList.remove('new-item-added','other-item-added','item-removed','item-deleted');
26224	$("#sidecart")[0].classList.add( whatwasdone );
26225}
26226function sidecart_changeActiveItem( clicked ) {
26227	$("#pjaxSeitenkorb > .sidecart-item-container").each(function() {
26228		let ae = $(this).attr('id');
26229		$( '#' + ae ).removeClass("active");
26230		setTimeout(function() {
26231			document.getElementById( ae ).classList.remove('status-1','status-2','status-3','status-4');
26232			document.getElementById( ae ).classList.add("status-0");
26233		}, 120);
26234	});
26235
26236	$( clicked ).addClass("active");
26237}
26238function sidecart_deleteItem( item, destination ) {
26239	let cartID = $( item ).attr("data-cartid");
26240	$( item ).fadeOut(220, function() {
26241		$.ajax({
26242			type	: 'POST',
26243			cache	: false,
26244			async	: false,
26245			url  	: destination,
26246			success	: function(response) {
26247				$.pjax.reload({container: '#pjaxWarenkorb', async:false});
26248				$.pjax.reload({container: '#pjaxSeitenkorb', async:false});
26249			}
26250		});
26251	});
26252}
26253
26254$(document).on('pjax:complete', function(e) {
26255
26256	var gespart = parseFloat( $('#pjax-cart-ersparnis').attr('data-pure') );
26257
26258	console.log( e.target.id );
26259
26260	// SHOW SIDECART AFTER ITEM ADDED TO CART
26261	if( e.currentTarget.activeElement.classList.contains("toggle-sidecart") && e.target.id == 'pjaxSeitenkorb' ) {
26262
26263		$("#sidecart-total").text( $("#pjax-cart-total").val() );
26264		$('#sidecart-ersparnis').text( $("#pjax-cart-ersparnis").val() );
26265
26266		if( gespart > 0 ) {
26267			$('#sidecart-ersparnis-total').removeClass('none');
26268		} else {
26269			$('#sidecart-ersparnis-total').addClass('none');
26270		}
26271		sidecart_toggle();
26272
26273	// UPDATE SIDECART TOTAL PRICE
26274	} else if( e.target.id == 'pjaxSeitenkorb' ) {
26275
26276		let cartPS = $("#pjaxSeitenkorb > .sidecart-item-container").length - 1;
26277		if( cartPS < 0 ) {
26278			$('#sidecart-total').text( $('#sidecart').attr('data-currency') + " 0,00" );
26279			$('#sidecart-ersparnis').text( $('#sidecart').attr('data-currency') + " 0,00" );
26280			$('#sidecart-ersparnis-total').addClass('none');
26281			setTimeout(function() {
26282				$("#sidecart-close-arrow").click();
26283			}, 333);
26284		} else {
26285			$("#sidecart-total").text( $("#pjax-cart-total").val() );
26286			$('#sidecart-ersparnis').text( $("#pjax-cart-ersparnis").val() );
26287			if( parseFloat($('#pjax-cart-ersparnis').attr('data-pure')) < 1 ) {
26288				$('#sidecart-ersparnis-total').addClass('none');
26289			}
26290		}
26291
26292		/*/* item-activation links
26293		$(".item-container-overlay").unbind().on('click', function(e) {
26294			sidecart_changeActiveItem( "#"+e.target.getAttribute("data-parent") );
26295		});
26296		*/
26297
26298
26299	/*
26300	} else if( e.target.id == 'pjaxWarenkorb' ) {
26301		return false;
26302	}
26303	*/
26304
26305
26306
26307	// #modalKunde -> Mask #kunden-geburtsdatum
26308	} else if( e.target.id == 'pjaxKunde' ) {
26309
26310		if( $("#kunden-geburtsdatum").length > 0 ) {
26311			$("#kunden-geburtsdatum").unbind().inputmask("dd.mm.yyyy");
26312		}
26313
26314	// #modalKunde -> AUTO OPEN
26315	} else if( e.target.id == 'pjaxCart' ) {
26316		console.log('kundenPopUp: '+kundenPopUp);
26317		if( kundenPopUp != false && $("#modalKunde").length > 0 ) {
26318			setTimeout(function() {
26319				$("#modalKunde").modal("show");
26320				kundenPopUp = false;
26321			}, 500);
26322		}
26323
26324		$(".edit-link[data-action='edit-what']").unbind().click(function() {
26325				$( $(this).attr("data-parent") ).addClass("editing");
26326		});
26327
26328		$(".edit-link[data-action='edit-link']").unbind().click(function() {
26329			window.location.href = $(this).attr("data-prompt");
26330		});
26331
26332		$(".edit-link[data-action='edit-link-pjax']").unbind().click(function() {
26333			let thisLink = $(this).attr("data-container");
26334			if( thisLink !== "undefined" && thisLink !== "" && thisLink !== null ) {
26335				$.ajax({
26336					type	: 'GET',
26337					async	: false,
26338					cache	: false,
26339					url		: $(this).attr("data-prompt"),
26340					success	: function(data) {
26341						$.pjax.reload({
26342							container:	thisLink,
26343							async:		false
26344						});
26345					}
26346				});
26347			}
26348		});
26349
26350		$(".edit-what-abbort").unbind().click(function() {
26351			$( $(this).attr("data-parent") ).removeClass("editing");
26352		});
26353
26354		links_in_text();
26355
26356	} else {
26357		console.log( e );
26358	}
26359
26360});
26361
26362
26363
26364
26365
26366
26367
26368/* item-activation links
26369$(".item-container-overlay").unbind().on('click', function(e) {
26370	sidecart_changeActiveItem( "#"+e.target.getAttribute("data-parent") );
26371});
26372*/
26373
26374
26375$("#pjax-cart-total").change(function() {
26376	$("#sidecart-total").text( $("#pjax-cart-total").val() );
26377});
26378
26379$("#pjax-cart-ersparnis").change(function() {
26380	$("#sidecart-ersparnis").text( $("#pjax-cart-ersparnis").val() );
26381});
26382
26383
26384
26385
26386
26387
26388
26389
26390
26391

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.