PageSourceSearch

https://www.webqda.net/wp-content/plugins/pressapps-knowledge-base…ressapps-knowledge-base-public.js?ver=1.0.0

js webqda.net collected 2026-09-24 10:26:53 UTC 77,647 bytes, 2,446 lines download raw bytes

1/**
2 *  Ajax Autocomplete for jQuery, version 1.2.24
3 *  (c) 2015 Tomas Kirda
4 *
5 *  Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
6 *  For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete
7 */
8
9/*jslint  browser: true, white: true, plusplus: true, vars: true */
10/*global define, window, document, jQuery, exports, require */
11
12// Expose plugin as an AMD module if AMD loader is present:
13(function (factory) {
14	'use strict';
15	if (typeof define === 'function' && define.amd) {
16		// AMD. Register as an anonymous module.
17		define(['jquery'], factory);
18	} else if (typeof exports === 'object' && typeof require === 'function') {
19		// Browserify
20		factory(require('jquery'));
21	} else {
22		// Browser globals
23		factory(jQuery);
24	}
25}(function ($) {
26	'use strict';
27
28	var
29		utils = (function () {
30			return {
31				escapeRegExChars: function (value) {
32					return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
33				},
34				createNode: function (containerClass) {
35					var div = document.createElement('div');
36					div.className = containerClass;
37					div.style.position = 'absolute';
38					div.style.display = 'none';
39					return div;
40				}
41			};
42		}()),
43
44		keys = {
45			ESC: 27,
46			TAB: 9,
47			RETURN: 13,
48			LEFT: 37,
49			UP: 38,
50			RIGHT: 39,
51			DOWN: 40
52		};
53
54	function Autocomplete(el, options) {
55		var noop = function () { },
56		    that = this,
57		    defaults = {
58			    ajaxSettings: {},
59			    autoSelectFirst: false,
60			    appendTo: document.body,
61			    serviceUrl: null,
62			    lookup: null,
63			    onSelect: null,
64			    width: 'auto',
65			    minChars: 1,
66			    maxHeight: 300,
67			    deferRequestBy: 0,
68			    params: {},
69			    formatResult: Autocomplete.formatResult,
70			    delimiter: null,
71			    zIndex: 9999,
72			    type: 'GET',
73			    noCache: false,
74			    onSearchStart: noop,
75			    onSearchComplete: noop,
76			    onSearchError: noop,
77			    preserveInput: false,
78			    containerClass: 'autocomplete-suggestions',
79			    tabDisabled: false,
80			    dataType: 'text',
81			    currentRequest: null,
82			    triggerSelectOnValidInput: true,
83			    preventBadQueries: true,
84			    lookupFilter: function (suggestion, originalQuery, queryLowerCase) {
85				    return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
86			    },
87			    paramName: 'query',
88			    transformResult: function (response) {
89				    return typeof response === 'string' ? $.parseJSON(response) : response;
90			    },
91			    showNoSuggestionNotice: false,
92			    noSuggestionNotice: 'No results',
93			    orientation: 'bottom',
94			    forceFixPosition: false
95		    };
96
97		// Shared variables:
98		that.element = el;
99		that.el = $(el);
100		that.suggestions = [];
101		that.badQueries = [];
102		that.selectedIndex = -1;
103		that.currentValue = that.element.value;
104		that.intervalId = 0;
105		that.cachedResponse = {};
106		that.onChangeInterval = null;
107		that.onChange = null;
108		that.isLocal = false;
109		that.suggestionsContainer = null;
110		that.noSuggestionsContainer = null;
111		that.options = $.extend({}, defaults, options);
112		that.classes = {
113			selected: 'autocomplete-selected',
114			suggestion: 'autocomplete-suggestion'
115		};
116		that.hint = null;
117		that.hintValue = '';
118		that.selection = null;
119
120		// Initialize and set options:
121		that.initialize();
122		that.setOptions(options);
123	}
124
125	Autocomplete.utils = utils;
126
127	$.Autocomplete = Autocomplete;
128
129	Autocomplete.formatResult = function (suggestion, currentValue) {
130		var pattern = '(' + utils.escapeRegExChars(currentValue) + ')';
131
132		return suggestion.value
133			.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>')
134			.replace(/&/g, '&amp;')
135			.replace(/</g, '&lt;')
136			.replace(/>/g, '&gt;')
137			.replace(/"/g, '&quot;')
138			.replace(/&lt;(\/?strong)&gt;/g, '<$1>');
139	};
140
141	Autocomplete.prototype = {
142
143		killerFn: null,
144
145		initialize: function () {
146			var that = this,
147			    suggestionSelector = '.' + that.classes.suggestion,
148			    selected = that.classes.selected,
149			    options = that.options,
150			    container;
151
152			// Remove autocomplete attribute to prevent native suggestions:
153			that.element.setAttribute('autocomplete', 'off');
154
155			that.killerFn = function (e) {
156				if ($(e.target).closest('.' + that.options.containerClass).length === 0) {
157					that.killSuggestions();
158					that.disableKillerFn();
159				}
160			};
161
162			// html() deals with many types: htmlString or Element or Array or jQuery
163			that.noSuggestionsContainer = $('<div class="autocomplete-no-suggestion"></div>')
164				.html(this.options.noSuggestionNotice).get(0);
165
166			that.suggestionsContainer = Autocomplete.utils.createNode(options.containerClass);
167
168			container = $(that.suggestionsContainer);
169
170			container.appendTo(options.appendTo);
171
172			// Only set width if it was provided:
173			if (options.width !== 'auto') {
174				container.width(options.width);
175			}
176
177			// Listen for mouse over event on suggestions list:
178			container.on('mouseover.autocomplete', suggestionSelector, function () {
179				that.activate($(this).data('index'));
180			});
181
182			// Deselect active element when mouse leaves suggestions container:
183			container.on('mouseout.autocomplete', function () {
184				that.selectedIndex = -1;
185				container.children('.' + selected).removeClass(selected);
186			});
187
188			// Listen for click event on suggestions list:
189			container.on('click.autocomplete', suggestionSelector, function () {
190				that.select($(this).data('index'));
191			});
192
193			that.fixPositionCapture = function () {
194				if (that.visible) {
195					that.fixPosition();
196				}
197			};
198
199			$(window).on('resize.autocomplete', that.fixPositionCapture);
200
201			that.el.on('keydown.autocomplete', function (e) { that.onKeyPress(e); });
202			that.el.on('keyup.autocomplete', function (e) { that.onKeyUp(e); });
203			that.el.on('blur.autocomplete', function () { that.onBlur(); });
204			that.el.on('focus.autocomplete', function () { that.onFocus(); });
205			that.el.on('change.autocomplete', function (e) { that.onKeyUp(e); });
206			that.el.on('input.autocomplete', function (e) { that.onKeyUp(e); });
207		},
208
209		onFocus: function () {
210			var that = this;
211			that.fixPosition();
212			if (that.options.minChars === 0 && that.el.val().length === 0) {
213				that.onValueChange();
214			}
215		},
216
217		onBlur: function () {
218			this.enableKillerFn();
219		},
220
221		abortAjax: function () {
222			var that = this;
223			if (that.currentRequest) {
224				that.currentRequest.abort();
225				that.currentRequest = null;
226			}
227		},
228
229		setOptions: function (suppliedOptions) {
230			var that = this,
231			    options = that.options;
232
233			$.extend(options, suppliedOptions);
234
235			that.isLocal = $.isArray(options.lookup);
236
237			if (that.isLocal) {
238				options.lookup = that.verifySuggestionsFormat(options.lookup);
239			}
240
241			options.orientation = that.validateOrientation(options.orientation, 'bottom');
242
243			// Adjust height, width and z-index:
244			$(that.suggestionsContainer).css({
245				'max-height': options.maxHeight + 'px',
246				'width': options.width + 'px',
247				'z-index': options.zIndex
248			});
249		},
250
251
252		clearCache: function () {
253			this.cachedResponse = {};
254			this.badQueries = [];
255		},
256
257		clear: function () {
258			this.clearCache();
259			this.currentValue = '';
260			this.suggestions = [];
261		},
262
263		disable: function () {
264			var that = this;
265			that.disabled = true;
266			clearInterval(that.onChangeInterval);
267			that.abortAjax();
268		},
269
270		enable: function () {
271			this.disabled = false;
272		},
273
274		fixPosition: function () {
275			// Use only when container has already its content
276
277			var that = this,
278			    $container = $(that.suggestionsContainer),
279			    containerParent = $container.parent().get(0);
280			// Fix position automatically when appended to body.
281			// In other cases force parameter must be given.
282			if (containerParent !== document.body && !that.options.forceFixPosition) {
283				return;
284			}
285
286			// Choose orientation
287			var orientation = that.options.orientation,
288			    containerHeight = $container.outerHeight(),
289			    height = that.el.outerHeight(),
290			    offset = that.el.offset(),
291			    styles = { 'top': offset.top, 'left': offset.left };
292
293			if (orientation === 'auto') {
294				var viewPortHeight = $(window).height(),
295				    scrollTop = $(window).scrollTop(),
296				    topOverflow = -scrollTop + offset.top - containerHeight,
297				    bottomOverflow = scrollTop + viewPortHeight - (offset.top + height + containerHeight);
298
299				orientation = (Math.max(topOverflow, bottomOverflow) === topOverflow) ? 'top' : 'bottom';
300			}
301
302			if (orientation === 'top') {
303				styles.top += -containerHeight;
304			} else {
305				styles.top += height;
306			}
307
308			// If container is not positioned to body,
309			// correct its position using offset parent offset
310			if(containerParent !== document.body) {
311				var opacity = $container.css('opacity'),
312				    parentOffsetDiff;
313
314				if (!that.visible){
315					$container.css('opacity', 0).show();
316				}
317
318				parentOffsetDiff = $container.offsetParent().offset();
319				styles.top -= parentOffsetDiff.top;
320				styles.left -= parentOffsetDiff.left;
321
322				if (!that.visible){
323					$container.css('opacity', opacity).hide();
324				}
325			}
326
327			// -2px to account for suggestions border.
328			if (that.options.width === 'auto') {
329				styles.width = (that.el.outerWidth() - 2) + 'px';
330			}
331
332			$container.css(styles);
333		},
334
335		enableKillerFn: function () {
336			var that = this;
337			$(document).on('click.autocomplete', that.killerFn);
338		},
339
340		disableKillerFn: function () {
341			var that = this;
342			$(document).off('click.autocomplete', that.killerFn);
343		},
344
345		killSuggestions: function () {
346			var that = this;
347			that.stopKillSuggestions();
348			that.intervalId = window.setInterval(function () {
349				if (that.visible) {
350					that.el.val(that.currentValue);
351					that.hide();
352				}
353
354				that.stopKillSuggestions();
355			}, 50);
356		},
357
358		stopKillSuggestions: function () {
359			window.clearInterval(this.intervalId);
360		},
361
362		isCursorAtEnd: function () {
363			var that = this,
364			    valLength = that.el.val().length,
365			    selectionStart = that.element.selectionStart,
366			    range;
367
368			if (typeof selectionStart === 'number') {
369				return selectionStart === valLength;
370			}
371			if (document.selection) {
372				range = document.selection.createRange();
373				range.moveStart('character', -valLength);
374				return valLength === range.text.length;
375			}
376			return true;
377		},
378
379		onKeyPress: function (e) {
380			var that = this;
381
382			// If suggestions are hidden and user presses arrow down, display suggestions:
383			if (!that.disabled && !that.visible && e.which === keys.DOWN && that.currentValue) {
384				that.suggest();
385				return;
386			}
387
388			if (that.disabled || !that.visible) {
389				return;
390			}
391
392			switch (e.which) {
393				case keys.ESC:
394					that.el.val(that.currentValue);
395					that.hide();
396					break;
397				case keys.RIGHT:
398					if (that.hint && that.options.onHint && that.isCursorAtEnd()) {
399						that.selectHint();
400						break;
401					}
402					return;
403				case keys.TAB:
404					if (that.hint && that.options.onHint) {
405						that.selectHint();
406						return;
407					}
408					if (that.selectedIndex === -1) {
409						that.hide();
410						return;
411					}
412					that.select(that.selectedIndex);
413					if (that.options.tabDisabled === false) {
414						return;
415					}
416					break;
417				case keys.RETURN:
418					if (that.selectedIndex === -1) {
419						that.hide();
420						return;
421					}
422					that.select(that.selectedIndex);
423					break;
424				case keys.UP:
425					that.moveUp();
426					break;
427				case keys.DOWN:
428					that.moveDown();
429					break;
430				default:
431					return;
432			}
433
434			// Cancel event if function did not return:
435			e.stopImmediatePropagation();
436			e.preventDefault();
437		},
438
439		onKeyUp: function (e) {
440			var that = this;
441
442			if (that.disabled) {
443				return;
444			}
445
446			switch (e.which) {
447				case keys.UP:
448				case keys.DOWN:
449					return;
450			}
451
452			clearInterval(that.onChangeInterval);
453
454			if (that.currentValue !== that.el.val()) {
455				that.findBestHint();
456				if (that.options.deferRequestBy > 0) {
457					// Defer lookup in case when value changes very quickly:
458					that.onChangeInterval = setInterval(function () {
459						that.onValueChange();
460					}, that.options.deferRequestBy);
461				} else {
462					that.onValueChange();
463				}
464			}
465		},
466
467		onValueChange: function () {
468			var that = this,
469			    options = that.options,
470			    value = that.el.val(),
471			    query = that.getQuery(value);
472
473			if (that.selection && that.currentValue !== query) {
474				that.selection = null;
475				(options.onInvalidateSelection || $.noop).call(that.element);
476			}
477
478			clearInterval(that.onChangeInterval);
479			that.currentValue = value;
480			that.selectedIndex = -1;
481
482			// Check existing suggestion for the match before proceeding:
483			if (options.triggerSelectOnValidInput && that.isExactMatch(query)) {
484				that.select(0);
485				return;
486			}
487
488			if (query.length < options.minChars) {
489				that.hide();
490			} else {
491				that.getSuggestions(query);
492			}
493		},
494
495		isExactMatch: function (query) {
496			var suggestions = this.suggestions;
497
498			return (suggestions.length === 1 && suggestions[0].value.toLowerCase() === query.toLowerCase());
499		},
500
501		getQuery: function (value) {
502			var delimiter = this.options.delimiter,
503			    parts;
504
505			if (!delimiter) {
506				return value;
507			}
508			parts = value.split(delimiter);
509			return $.trim(parts[parts.length - 1]);
510		},
511
512		getSuggestionsLocal: function (query) {
513			var that = this,
514			    options = that.options,
515			    queryLowerCase = query.toLowerCase(),
516			    filter = options.lookupFilter,
517			    limit = parseInt(options.lookupLimit, 10),
518			    data;
519
520			data = {
521				suggestions: $.grep(options.lookup, function (suggestion) {
522					return filter(suggestion, query, queryLowerCase);
523				})
524			};
525
526			if (limit && data.suggestions.length > limit) {
527				data.suggestions = data.suggestions.slice(0, limit);
528			}
529
530			return data;
531		},
532
533		getSuggestions: function (q) {
534			var response,
535			    that = this,
536			    options = that.options,
537			    serviceUrl = options.serviceUrl,
538			    params,
539			    cacheKey,
540			    ajaxSettings;
541
542			options.params[options.paramName] = q;
543			params = options.ignoreParams ? null : options.params;
544
545			if (options.onSearchStart.call(that.element, options.params) === false) {
546				return;
547			}
548
549			if ($.isFunction(options.lookup)){
550				options.lookup(q, function (data) {
551					that.suggestions = data.suggestions;
552					that.suggest();
553					options.onSearchComplete.call(that.element, q, data.suggestions);
554				});
555				return;
556			}
557
558			if (that.isLocal) {
559				response = that.getSuggestionsLocal(q);
560			} else {
561				if ($.isFunction(serviceUrl)) {
562					serviceUrl = serviceUrl.call(that.element, q);
563				}
564				cacheKey = serviceUrl + '?' + $.param(params || {});
565				response = that.cachedResponse[cacheKey];
566			}
567
568			if (response && $.isArray(response.suggestions)) {
569				that.suggestions = response.suggestions;
570				that.suggest();
571				options.onSearchComplete.call(that.element, q, response.suggestions);
572			} else if (!that.isBadQuery(q)) {
573				that.abortAjax();
574
575				ajaxSettings = {
576					url: serviceUrl,
577					data: params,
578					type: options.type,
579					dataType: options.dataType
580				};
581
582				$.extend(ajaxSettings, options.ajaxSettings);
583
584				that.currentRequest = $.ajax(ajaxSettings).done(function (data) {
585					var result;
586					that.currentRequest = null;
587					result = options.transformResult(data, q);
588					that.processResponse(result, q, cacheKey);
589					options.onSearchComplete.call(that.element, q, result.suggestions);
590				}).fail(function (jqXHR, textStatus, errorThrown) {
591					options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
592				});
593			} else {
594				options.onSearchComplete.call(that.element, q, []);
595			}
596		},
597
598		isBadQuery: function (q) {
599			if (!this.options.preventBadQueries){
600				return false;
601			}
602
603			var badQueries = this.badQueries,
604			    i = badQueries.length;
605
606			while (i--) {
607				if (q.indexOf(badQueries[i]) === 0) {
608					return true;
609				}
610			}
611
612			return false;
613		},
614
615		hide: function () {
616			var that = this,
617			    container = $(that.suggestionsContainer);
618
619			if ($.isFunction(that.options.onHide) && that.visible) {
620				that.options.onHide.call(that.element, container);
621			}
622
623			that.visible = false;
624			that.selectedIndex = -1;
625			clearInterval(that.onChangeInterval);
626			$(that.suggestionsContainer).hide();
627			that.signalHint(null);
628		},
629
630		suggest: function () {
631			if (this.suggestions.length === 0) {
632				if (this.options.showNoSuggestionNotice) {
633					this.noSuggestions();
634				} else {
635					this.hide();
636				}
637				return;
638			}
639
640			var that = this,
641			    options = that.options,
642			    groupBy = options.groupBy,
643			    formatResult = options.formatResult,
644			    value = that.getQuery(that.currentValue),
645			    className = that.classes.suggestion,
646			    classSelected = that.classes.selected,
647			    container = $(that.suggestionsContainer),
648			    noSuggestionsContainer = $(that.noSuggestionsContainer),
649			    beforeRender = options.beforeRender,
650			    html = '',
651			    category,
652			    formatGroup = function (suggestion, index) {
653				    var currentCategory = suggestion.data[groupBy];
654
655				    if (category === currentCategory){
656					    return '';
657				    }
658
659				    category = currentCategory;
660
661				    return '<div class="autocomplete-group"><strong>' + category + '</strong></div>';
662			    };
663
664			if (options.triggerSelectOnValidInput && that.isExactMatch(value)) {
665				that.select(0);
666				return;
667			}
668
669			// Build suggestions inner HTML:
670			$.each(that.suggestions, function (i, suggestion) {
671				if (groupBy){
672					html += formatGroup(suggestion, value, i);
673				}
674
675				html += '<div class="'+ ( PAKB.category ? 'autocomplete-with-category ' : '' )  + className + '" data-index="' + i + '"><span class="'+ suggestion.icon +'"></span> ' + formatResult(suggestion, value) + '</div>';
676			});
677
678			this.adjustContainerWidth();
679
680			noSuggestionsContainer.detach();
681			container.html(html);
682
683			if ($.isFunction(beforeRender)) {
684				beforeRender.call(that.element, container);
685			}
686
687			that.fixPosition();
688			container.show();
689
690			// Select first value by default:
691			if (options.autoSelectFirst) {
692				that.selectedIndex = 0;
693				container.scrollTop(0);
694				container.children('.' + className).first().addClass(classSelected);
695			}
696
697			that.visible = true;
698			that.findBestHint();
699		},
700
701		noSuggestions: function() {
702			var that = this,
703			    container = $(that.suggestionsContainer),
704			    noSuggestionsContainer = $(that.noSuggestionsContainer);
705
706			this.adjustContainerWidth();
707
708			// Some explicit steps. Be careful here as it easy to get
709			// noSuggestionsContainer removed from DOM if not detached properly.
710			noSuggestionsContainer.detach();
711			container.empty(); // clean suggestions if any
712			container.append(noSuggestionsContainer);
713
714			that.fixPosition();
715
716			container.show();
717			that.visible = true;
718		},
719
720		adjustContainerWidth: function() {
721			var that = this,
722			    options = that.options,
723			    width,
724			    container = $(that.suggestionsContainer);
725
726			// If width is auto, adjust width before displaying suggestions,
727			// because if instance was created before input had width, it will be zero.
728			// Also it adjusts if input width has changed.
729			// -2px to account for suggestions border.
730			if (options.width === 'auto') {
731				width = that.el.outerWidth() - 2;
732				container.width(width > 0 ? width : 300);
733			}
734		},
735
736		findBestHint: function () {
737			var that = this,
738			    value = that.el.val().toLowerCase(),
739			    bestMatch = null;
740
741			if (!value) {
742				return;
743			}
744
745			$.each(that.suggestions, function (i, suggestion) {
746				var foundMatch = suggestion.value.toLowerCase().indexOf(value) === 0;
747				if (foundMatch) {
748					bestMatch = suggestion;
749				}
750				return !foundMatch;
751			});
752
753			that.signalHint(bestMatch);
754		},
755
756		signalHint: function (suggestion) {
757			var hintValue = '',
758			    that = this;
759			if (suggestion) {
760				hintValue = that.currentValue + suggestion.value.substr(that.currentValue.length);
761			}
762			if (that.hintValue !== hintValue) {
763				that.hintValue = hintValue;
764				that.hint = suggestion;
765				(this.options.onHint || $.noop)(hintValue);
766			}
767		},
768
769		verifySuggestionsFormat: function (suggestions) {
770			// If suggestions is string array, convert them to supported format:
771			if (suggestions.length && typeof suggestions[0] === 'string') {
772				return $.map(suggestions, function (value) {
773					return { value: value, data: null };
774				});
775			}
776
777			return suggestions;
778		},
779
780		validateOrientation: function(orientation, fallback) {
781			orientation = $.trim(orientation || '').toLowerCase();
782
783			if($.inArray(orientation, ['auto', 'bottom', 'top']) === -1){
784				orientation = fallback;
785			}
786
787			return orientation;
788		},
789
790		processResponse: function (result, originalQuery, cacheKey) {
791			var that = this,
792			    options = that.options;
793
794			result.suggestions = that.verifySuggestionsFormat(result.suggestions);
795
796			// Cache results if cache is not disabled:
797			if (!options.noCache) {
798				that.cachedResponse[cacheKey] = result;
799				if (options.preventBadQueries && result.suggestions.length === 0) {
800					that.badQueries.push(originalQuery);
801				}
802			}
803
804			// Return if originalQuery is not matching current query:
805			if (originalQuery !== that.getQuery(that.currentValue)) {
806				return;
807			}
808
809			that.suggestions = result.suggestions;
810			that.suggest();
811		},
812
813		activate: function (index) {
814			var that = this,
815			    activeItem,
816			    selected = that.classes.selected,
817			    container = $(that.suggestionsContainer),
818			    children = container.find('.' + that.classes.suggestion);
819
820			container.find('.' + selected).removeClass(selected);
821
822			that.selectedIndex = index;
823
824			if (that.selectedIndex !== -1 && children.length > that.selectedIndex) {
825				activeItem = children.get(that.selectedIndex);
826				$(activeItem).addClass(selected);
827				return activeItem;
828			}
829
830			return null;
831		},
832
833		selectHint: function () {
834			var that = this,
835			    i = $.inArray(that.hint, that.suggestions);
836
837			that.select(i);
838		},
839
840		select: function (i) {
841			var that = this;
842			that.hide();
843			that.onSelect(i);
844		},
845
846		moveUp: function () {
847			var that = this;
848
849			if (that.selectedIndex === -1) {
850				return;
851			}
852
853			if (that.selectedIndex === 0) {
854				$(that.suggestionsContainer).children().first().removeClass(that.classes.selected);
855				that.selectedIndex = -1;
856				that.el.val(that.currentValue);
857				that.findBestHint();
858				return;
859			}
860
861			that.adjustScroll(that.selectedIndex - 1);
862		},
863
864		moveDown: function () {
865			var that = this;
866
867			if (that.selectedIndex === (that.suggestions.length - 1)) {
868				return;
869			}
870
871			that.adjustScroll(that.selectedIndex + 1);
872		},
873
874		adjustScroll: function (index) {
875			var that = this,
876			    activeItem = that.activate(index);
877
878			if (!activeItem) {
879				return;
880			}
881
882			var offsetTop,
883			    upperBound,
884			    lowerBound,
885			    heightDelta = $(activeItem).outerHeight();
886
887			offsetTop = activeItem.offsetTop;
888			upperBound = $(that.suggestionsContainer).scrollTop();
889			lowerBound = upperBound + that.options.maxHeight - heightDelta;
890
891			if (offsetTop < upperBound) {
892				$(that.suggestionsContainer).scrollTop(offsetTop);
893			} else if (offsetTop > lowerBound) {
894				$(that.suggestionsContainer).scrollTop(offsetTop - that.options.maxHeight + heightDelta);
895			}
896
897			if (!that.options.preserveInput) {
898				that.el.val(that.getValue(that.suggestions[index].value));
899			}
900			that.signalHint(null);
901		},
902
903		onSelect: function (index) {
904			var that = this,
905			    onSelectCallback = that.options.onSelect,
906			    suggestion = that.suggestions[index];
907
908			that.currentValue = that.getValue(suggestion.value);
909
910			if (that.currentValue !== that.el.val() && !that.options.preserveInput) {
911				that.el.val(that.currentValue);
912			}
913
914			that.signalHint(null);
915			that.suggestions = [];
916			that.selection = suggestion;
917
918			if ($.isFunction(onSelectCallback)) {
919				onSelectCallback.call(that.element, suggestion);
920			}
921		},
922
923		getValue: function (value) {
924			var that = this,
925			    delimiter = that.options.delimiter,
926			    currentValue,
927			    parts;
928
929			if (!delimiter) {
930				return value;
931			}
932
933			currentValue = that.currentValue;
934			parts = currentValue.split(delimiter);
935
936			if (parts.length === 1) {
937				return value;
938			}
939
940			return currentValue.substr(0, currentValue.length - parts[parts.length - 1].length) + value;
941		},
942
943		dispose: function () {
944			var that = this;
945			that.el.off('.autocomplete').removeData('autocomplete');
946			that.disableKillerFn();
947			$(window).off('resize.autocomplete', that.fixPositionCapture);
948			$(that.suggestionsContainer).remove();
949		}
950	};
951
952	// Create chainable jQuery plugin:
953	$.fn.autocomplete = $.fn.devbridgeAutocomplete = function (options, args) {
954		var dataKey = 'autocomplete';
955		// If function invoked without argument return
956		// instance of the first matched element:
957		if (arguments.length === 0) {
958			return this.first().data(dataKey);
959		}
960
961		return this.each(function () {
962			var inputElement = $(this),
963			    instance = inputElement.data(dataKey);
964
965			if (typeof options === 'string') {
966				if (instance && typeof instance[options] === 'function') {
967					instance[options](args);
968				}
969			} else {
970				// If instance already exists, destroy it:
971				if (instance && instance.dispose) {
972					instance.dispose();
973				}
974				instance = new Autocomplete(this, options);
975				inputElement.data(dataKey, instance);
976			}
977		});
978	};
979}));
980/*
981
982Tooltipster 3.3.0 | 2014-11-08
983A rockin' custom tooltip jQuery plugin
984
985Developed by Caleb Jacob under the MIT license http://opensource.org/licenses/MIT
986
987THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
988
989*/
990
991;(function ($, window, document) {
992
993	var pluginName = "tooltipster",
994		defaults = {
995			animation: 'fade',
996			arrow: true,
997			arrowColor: '',
998			autoClose: true,
999			content: null,
1000			contentAsHTML: false,
1001			contentCloning: true,
1002			debug: true,
1003			delay: 200,
1004			minWidth: 0,
1005			maxWidth: null,
1006			functionInit: function(origin, content) {},
1007			functionBefore: function(origin, continueTooltip) {
1008				continueTooltip();
1009			},
1010			functionReady: function(origin, tooltip) {},
1011			functionAfter: function(origin) {},
1012			hideOnClick: false,
1013			icon: '(?)',
1014			iconCloning: true,
1015			iconDesktop: false,
1016			iconTouch: false,
1017			iconTheme: 'tooltipster-icon',
1018			interactive: false,
1019			interactiveTolerance: 350,
1020			multiple: false,
1021			offsetX: 0,
1022			offsetY: 0,
1023			onlyOne: false,
1024			position: 'top',
1025			positionTracker: false,
1026			positionTrackerCallback: function(origin){
1027				// the default tracker callback will close the tooltip when the trigger is
1028				// 'hover' (see https://github.com/iamceege/tooltipster/pull/253)
1029				if(this.option('trigger') == 'hover' && this.option('autoClose')) {
1030					this.hide();
1031				}
1032			},
1033			restoration: 'current',
1034			speed: 350,
1035			timer: 0,
1036			theme: 'tooltipster-default',
1037			touchDevices: true,
1038			trigger: 'hover',
1039			updateAnimation: true
1040		};
1041	
1042	function Plugin(element, options) {
1043		
1044		// list of instance variables
1045		
1046		this.bodyOverflowX;
1047		// stack of custom callbacks provided as parameters to API methods
1048		this.callbacks = {
1049			hide: [],
1050			show: []
1051		};
1052		this.checkInterval = null;
1053		// this will be the user content shown in the tooltip. A capital "C" is used because there is also a method called content()
1054		this.Content;
1055		// this is the original element which is being applied the tooltipster plugin
1056		this.$el = $(element);
1057		// this will be the element which triggers the appearance of the tooltip on hover/click/custom events.
1058		// it will be the same as this.$el if icons are not used (see in the options), otherwise it will correspond to the created icon
1059		this.$elProxy;
1060		this.elProxyPosition;
1061		this.enabled = true;
1062		this.options = $.extend({}, defaults, options);
1063		this.mouseIsOverProxy = false;
1064		// a unique namespace per instance, for easy selective unbinding
1065		this.namespace = 'tooltipster-'+ Math.round(Math.random()*100000);
1066		// Status (capital S) can be either : appearing, shown, disappearing, hidden
1067		this.Status = 'hidden';
1068		this.timerHide = null;
1069		this.timerShow = null;
1070		// this will be the tooltip element (jQuery wrapped HTML element)
1071		this.$tooltip;
1072		
1073		// for backward compatibility
1074		this.options.iconTheme = this.options.iconTheme.replace('.', '');
1075		this.options.theme = this.options.theme.replace('.', '');
1076		
1077		// launch
1078		
1079		this._init();
1080	}
1081	
1082	Plugin.prototype = {
1083		
1084		_init: function() {
1085			
1086			var self = this;
1087			
1088			// disable the plugin on old browsers (including IE7 and lower)
1089			if (document.querySelector) {
1090				
1091				// note : the content is null (empty) by default and can stay that way if the plugin remains initialized but not fed any content. The tooltip will just not appear.
1092				
1093				// let's save the initial value of the title attribute for later restoration if need be.
1094				var initialTitle = null;
1095				// it will already have been saved in case of multiple tooltips
1096				if (self.$el.data('tooltipster-initialTitle') === undefined) {
1097					
1098					initialTitle = self.$el.attr('title');
1099					
1100					// we do not want initialTitle to have the value "undefined" because of how jQuery's .data() method works
1101					if (initialTitle === undefined) initialTitle = null;
1102					
1103					self.$el.data('tooltipster-initialTitle', initialTitle);
1104				}
1105				
1106				// if content is provided in the options, its has precedence over the title attribute.
1107				// Note : an empty string is considered content, only 'null' represents the absence of content.
1108				// Also, an existing title="" attribute will result in an empty string content
1109				if (self.options.content !== null){
1110					self._content_set(self.options.content);
1111				}
1112				else {
1113					self._content_set(initialTitle);
1114				}
1115				
1116				var c = self.options.functionInit.call(self.$el, self.$el, self.Content);
1117				if(typeof c !== 'undefined') self._content_set(c);
1118				
1119				self.$el
1120					// strip the title off of the element to prevent the default tooltips from popping up
1121					.removeAttr('title')
1122					// to be able to find all instances on the page later (upon window events in particular)
1123					.addClass('tooltipstered');
1124
1125				// detect if we're changing the tooltip origin to an icon
1126				// note about this condition : if the device has touch capability and self.options.iconTouch is false, you'll have no icons event though you may consider your device as a desktop if it also has a mouse. Not sure why someone would have this use case though.
1127				if ((!deviceHasTouchCapability && self.options.iconDesktop) || (deviceHasTouchCapability && self.options.iconTouch)) {
1128					
1129					// TODO : the tooltip should be automatically be given an absolute position to be near the origin. Otherwise, when the origin 
1129is floating or what, it's going to be nowhere near it and disturb the position flow of the page elements. It will imply that the icon also detects when its origin moves, to follow it : not trivial.
1130					// Until it's done, the icon feature does not really make sense since the user still has most of the work to do by himself
1131					
1132					// if the icon provided is in the form of a string
1133					if(typeof self.options.icon === 'string'){
1134						// wrap it in a span with the icon class
1135						self.$elProxy = $('<span class="'+ self.options.iconTheme +'"></span>');
1136						self.$elProxy.text(self.options.icon);
1137					}
1138					// if it is an object (sensible choice)
1139					else {
1140						// (deep) clone the object if iconCloning == true, to make sure every instance has its own proxy. We use the icon without wrapping, no need to. We do not give it a class either, as the user will undoubtedly style the object on his own and since our css properties may conflict with his own
1141						if (self.options.iconCloning) self.$elProxy = self.options.icon.clone(true);
1142						else self.$elProxy = self.options.icon;
1143					}
1144					
1145					self.$elProxy.insertAfter(self.$el);
1146				}
1147				else {
1148					self.$elProxy = self.$el;
1149				}
1150				
1151				// for 'click' and 'hover' triggers : bind on events to open the tooltip. Closing is now handled in _showNow() because of its bindings.
1152				// Notes about touch events :
1153					// - mouseenter, mouseleave and clicks happen even on pure touch devices because they are emulated. deviceIsPureTouch() is a simple attempt to detect them.
1154					// - on hybrid devices, we do not prevent touch gesture from opening tooltips. It would be too complex to differentiate real mouse events from emulated ones.
1155					// - we check deviceIsPureTouch() at each event rather than prior to binding because the situation may change during browsing
1156				if (self.options.trigger == 'hover') {
1157					
1158					// these binding are for mouse interaction only
1159					self.$elProxy
1160						.on('mouseenter.'+ self.namespace, function() {
1161							if (!deviceIsPureTouch() || self.options.touchDevices) {
1162								self.mouseIsOverProxy = true;
1163								self._show();
1164							}
1165						})
1166						.on('mouseleave.'+ self.namespace, function() {
1167							if (!deviceIsPureTouch() || self.options.touchDevices) {
1168								self.mouseIsOverProxy = false;
1169							}
1170						});
1171					
1172					// for touch interaction only
1173					if (deviceHasTouchCapability && self.options.touchDevices) {
1174						
1175						// for touch devices, we immediately display the tooltip because we cannot rely on mouseleave to handle the delay
1176						self.$elProxy.on('touchstart.'+ self.namespace, function() {
1177							self._showNow();
1178						});
1179					}
1180				}
1181				else if (self.options.trigger == 'click') {
1182					
1183					// note : for touch devices, we do not bind on touchstart, we only rely on the emulated clicks (triggered by taps)
1184					self.$elProxy.on('click.'+ self.namespace, function() {
1185						if (!deviceIsPureTouch() || self.options.touchDevices) {
1186							self._show();
1187						}
1188					});
1189				}
1190			}
1191		},
1192		
1193		// this function will schedule the opening of the tooltip after the delay, if there is one
1194		_show: function() {
1195			
1196			var self = this;
1197			
1198			if (self.Status != 'shown' && self.Status != 'appearing') {
1199				
1200				if (self.options.delay) {
1201					self.timerShow = setTimeout(function(){
1202						
1203						// for hover trigger, we check if the mouse is still over the proxy, otherwise we do not show anything
1204						if (self.options.trigger == 'click' || (self.options.trigger == 'hover' && self.mouseIsOverProxy)) {
1205							self._showNow();
1206						}
1207					}, self.options.delay);
1208				}
1209				else self._showNow();
1210			}
1211		},
1212		
1213		// this function will open the tooltip right away
1214		_showNow: function(callback) {
1215			
1216			var self = this;
1217			
1218			// call our constructor custom function before continuing
1219			self.options.functionBefore.call(self.$el, self.$el, function() {
1220				
1221				// continue only if the tooltip is enabled and has any content
1222				if (self.enabled && self.Content !== null) {
1223				
1224					// save the method callback and cancel hide method callbacks
1225					if (callback) self.callbacks.show.push(callback);
1226					self.callbacks.hide = [];
1227					
1228					//get rid of any appearance timer
1229					clearTimeout(self.timerShow);
1230					self.timerShow = null;
1231					clearTimeout(self.timerHide);
1232					self.timerHide = null;
1233					
1234					// if we only want one tooltip open at a time, close all auto-closing tooltips currently open and not already disappearing
1235					if (self.options.onlyOne) {
1236						$('.tooltipstered').not(self.$el).each(function(i,el) {
1237							
1238							var $el = $(el),
1239								nss = $el.data('tooltipster-ns');
1240							
1241							// iterate on all tooltips of the element
1242							$.each(nss, function(i, ns){
1243								var instance = $el.data(ns),
1244									// we have to use the public methods here
1245									s = instance.status(),
1246									ac = instance.option('autoClose');
1247								
1248								if (s !== 'hidden' && s !== 'disappearing' && ac) {
1249									instance.hide();
1250								}
1251							});
1252						});
1253					}
1254					
1255					var finish = function() {
1256						self.Status = 'shown';
1257						
1258						// trigger any show method custom callbacks and reset them
1259						$.each(self.callbacks.show, function(i,c) { c.call(self.$el); });
1260						self.callbacks.show = [];
1261					};
1262					
1263					// if this origin already has its tooltip open
1264					if (self.Status !== 'hidden') {
1265						
1266						// the timer (if any) will start (or restart) right now
1267						var extraTime = 0;
1268						
1269						// if it was disappearing, cancel that
1270						if (self.Status === 'disappearing') {
1271							
1272							self.Status = 'appearing';
1273							
1274							if (supportsTransitions()) {
1275								
1276								self.$tooltip
1277									.clearQueue()
1278									.removeClass('tooltipster-dying')
1279									.addClass('tooltipster-'+ self.options.animation +'-show');
1280								
1281								if (self.options.speed > 0) self.$tooltip.delay(self.options.speed);
1282								
1283								self.$tooltip.queue(finish);
1284							}
1285							else {
1286								// in case the tooltip was currently fading out, bring it back to life
1287								self.$tooltip
1288									.stop()
1289									.fadeIn(finish);
1290							}
1291						}
1292						// if the tooltip is already open, we still need to trigger the method custom callback
1293						else if(self.Status === 'shown') {
1294							finish();
1295						}
1296					}
1297					// if the tooltip isn't already open, open that sucker up!
1298					else {
1299						
1300						self.Status = 'appearing';
1301						
1302						// the timer (if any) will start when the tooltip has fully appeared after its transition
1303						var extraTime = self.options.speed;
1304						
1305						// disable horizontal scrollbar to keep overflowing tooltips from jacking with it and then restore it to its previous value
1306						self.bodyOverflowX = $('body').css('overflow-x');
1307						$('body').css('overflow-x', 'hidden');
1308						
1309						// get some other settings related to building the tooltip
1310						var animation = 'tooltipster-' + self.options.animation,
1311							animationSpeed = '-webkit-transition-duration: '+ self.options.speed +'ms; -webkit-animation-duration: '+ self.options.speed +'ms; -moz-transition-duration: '+ self.options.speed +'ms; -moz-animation-duration: '+ self.options.speed +'ms; -o-transition-duration: '+ self.options.speed +'ms; -o-animation-duration: '+ self.options.speed +'ms; -ms-transition-duration: '+ self.options.speed +'ms; -ms-animation-duration: '+ self.options.speed +'ms; transition-duration: '+ self.options.speed +'ms; animation-duration: '+ self.options.speed +'ms;',
1312							minWidth = self.options.minWidth ? 'min-width:'+ Math.round(self.options.minWidth) +'px;' : '',
1313							maxWidth = self.options.maxWidth ? 'max-width:'+ Math.round(self.options.maxWidth) +'px;' : '',
1314							pointerEvents = self.options.interactive ? 'pointer-events: auto;' : '';
1315						
1316						// build the base of our tooltip
1317						self.$tooltip = $('<div class="tooltipster-base '+ self.options.theme +'" style="'+ minWidth +' '+ maxWidth +' '+ pointerEvents +' '+ animationSpeed +'"><div class="tooltipster-content"></div></div>');
1318						
1319						// only add the animation class if the user has a browser that supports animations
1320						if (supportsTransitions()) self.$tooltip.addClass(animation);
1321						
1322						// insert the content
1323						self._content_insert();
1324						
1325						// attach
1326						self.$tooltip.appendTo('body');
1327						
1328						// do all the crazy calculations and positioning
1329						self.reposition();
1330						
1331						// call our custom callback since the content of the tooltip is now part of the DOM
1332						self.options.functionReady.call(self.$el, self.$el, self.$tooltip);
1333						
1334						// animate in the tooltip
1335						if (supportsTransitions()) {
1336							
1337							self.$tooltip.addClass(animation + '-show');
1338							
1339							if(self.options.speed > 0) self.$tooltip.delay(self.options.speed);
1340							
1341							self.$tooltip.queue(finish);
1342						}
1343						else {
1344							self.$tooltip.css('display', 'none').fadeIn(self.options.speed, finish);
1345						}
1346						
1347						// will check if our tooltip origin is removed while the tooltip is shown
1348						self._interval_set();
1349						
1350						// reposition on scroll (otherwise position:fixed element's tooltips will move away form their origin) and on resize (in case position can/has to be changed)
1351						$(window).on('scroll.'+ self.namespace +' resize.'+ self.namespace, function() {
1352							self.reposition();
1353						});
1354						
1355						// auto-close bindings
1356						if (self.options.autoClose) {
1357							
1358							// in case a listener is already bound for autoclosing (mouse or touch, hover or click), unbind it first
1359							$('body').off('.'+ self.namespace);
1360							
1361							// here we'll have to set different sets of bindings for both touch and mouse
1362							if (self.options.trigger == 'hover') {
1363								
1364								// if the user touches the body, hide
1365								if (deviceHasTouchCapability) {
1366									// timeout 0 : explanation below in click section
1367									setTimeout(function() {
1368										// we don't want to bind on click here because the initial touchstart event has not yet triggered its click event, which is thus about to happen
1369										$('body').on('touchstart.'+ self.namespace, function() {
1370											self.hide();
1371										});
1372									}, 0);
1373								}
1374								
1375								// if we have to allow interaction
1376								if (self.options.interactive) {
1377									
1378									// touch events inside the tooltip must not close it
1379									if (deviceHasTouchCapability) {
1380										self.$tooltip.on('touchstart.'+ self.namespace, function(event) {
1381											event.stopPropagation();
1382										});
1383									}
1384									
1385									// as for mouse interaction, we get rid of the tooltip only after the mouse has spent some time out of it
1386									var tolerance = null;
1387									
1388									self.$elProxy.add(self.$tooltip)
1389										// hide after some time out of the proxy and the tooltip
1390										.on('mouseleave.'+ self.namespace + '-autoClose', function() {
1391											clearTimeout(tolerance);
1392											tolerance = setTimeout(function(){
1393												self.hide();
1394											}, self.options.interactiveTolerance);
1395										})
1396										// suspend timeout when the mouse is over the proxy or the tooltip
1397										.on('mouseenter.'+ self.namespace + '-autoClose', function() {
1398											clearTimeout(tolerance);
1399										});
1400								}
1401								// if this is a non-interactive tooltip, get rid of it if the mouse leaves
1402								else {
1403									self.$elProxy.on('mouseleave.'+ self.namespace + '-autoClose', function() {
1404										self.hide();
1405									});
1406								}
1407								
1408								// close the tooltip when the proxy gets a click (common behavior of native tooltips)
1409								if (self.options.hideOnClick) {
1410									
1411									self.$elProxy.on('click.'+ self.namespace + '-autoClose', function() {
1412										self.hide();
1413									});
1414								}
1415							}
1416							// here we'll set the same bindings for both clicks and touch on the body to hide the tooltip
1417							else if(self.options.trigger == 'click'){
1418								
1419								// use a timeout to prevent immediate closing if the method was called on a click event and if options.delay == 0 (because of bubbling)
1420								setTimeout(function() {
1421									$('body').on('click.'+ self.namespace +' touchstart.'+ self.namespace, function() {
1422										self.hide();
1423									});
1424								}, 0);
1425								
1426								// if interactive, we'll stop the events that were emitted from inside the tooltip to stop autoClosing
1427								if (self.options.interactive) {
1428									
1429									// note : the touch events will just not be used if the plugin is not enabled on touch devices
1430									self.$tooltip.on('click.'+ self.namespace +' touchstart.'+ self.namespace, function(event) {
1431										event.stopPropagation();
1432									});
1433								}
1434							}
1435						}
1436					}
1437					
1438					// if we have a timer set, let the countdown begin
1439					if (self.options.timer > 0) {
1440						
1441						self.timerHide = setTimeout(function() {
1442							self.timerHide = null;
1443							self.hide();
1444						}, self.options.timer + extraTime);
1445					}
1446				}
1447			});
1448		},
1449		
1450		_interval_set: function() {
1451			
1452			var self = this;
1453			
1454			self.checkInterval = setInterval(function() {
1455				
1456				// if the tooltip and/or its interval should be stopped
1457				if (
1458						// if the origin has been removed
1459						$('body').find(self.$el).length === 0
1460						// if the elProxy has been removed
1461					||	$('body').find(self.$elProxy).length === 0
1462						// if the tooltip has been closed
1463					||	self.Status == 'hidden'
1464						// if the tooltip has somehow been removed
1465					||	$('body').find(self.$tooltip).length === 0
1466				) {
1467					// remove the tooltip if it's still here
1468					if (self.Status == 'shown' || self.Status == 'appearing') self.hide();
1469					
1470					// clear this interval as it is no longer necessary
1471					self._interval_cancel();
1472				}
1473				// if everything is alright
1474				else {
1475					// compare the former and current positions of the elProxy to reposition the tooltip if need be
1476					if(self.options.positionTracker){
1477						
1478						var p = self._repositionInfo(self.$elProxy),
1479							identical = false;
1480						
1481						// compare size first (a change requires repositioning too)
1482						if(areEqual(p.dimension, self.elProxyPosition.dimension)){
1483							
1484							// for elements with a fixed position, we track the top and left properties (relative to window)
1485							if(self.$elProxy.css('position') === 'fixed'){
1486								if(areEqual(p.position, self.elProxyPosition.position)) identical = true;
1487							}
1488							// otherwise, track total offset (relative to document)
1489							else {
1490								if(areEqual(p.offset, self.elProxyPosition.offset)) identical = true;
1491							}
1492						}
1493						
1494						if(!identical){
1495							self.reposition();
1496							self.options.positionTrackerCallback.call(self, self.$el);
1497						}
1498					}
1499				}
1500			}, 200);
1501		},
1502		
1503		_interval_cancel: function() {
1504			clearInterval(this.checkInterval);
1505			// clean delete
1506			this.checkInterval = null;
1507		},
1508		
1509		_content_set: function(content) {
1510			// clone if asked. Cloning the object makes sure that each instance has its own version of the content (in case a same object were provided for several instances)
1511			// reminder : typeof null === object
1512			if (typeof content === 'object' && content !== null && this.options.contentCloning) {
1513				content = content.clone(true);
1514			}
1515			this.Content = content;
1516		},
1517		
1518		_content_insert: function() {
1519			
1520			var self = this,
1521				$d = this.$tooltip.find('.tooltipster-content');
1522			
1523			if (typeof self.Content === 'string' && !self.options.contentAsHTML) {
1524				$d.text(self.Content);
1525			}
1526			else {
1527				$d
1528					.empty()
1529					.append(self.Content);
1530			}
1531		},
1532		
1533		_update: function(content) {
1534			
1535			var self = this;
1536			
1537			// change the content
1538			self._content_set(content);
1539			
1540			if (self.Content !== null) {
1541				
1542				// update the tooltip if it is open
1543				if (self.Status !== 'hidden') {
1544					
1545					// reset the content in the tooltip
1546					self._content_insert();
1547					
1548					// reposition and resize the tooltip
1549					self.reposition();
1550					
1551					// if we want to play a little animation showing the content changed
1552					if (self.options.updateAnimation) {
1553						
1554						if (supportsTransitions()) {
1555							
1556							self.$tooltip.css({
1557								'width': '',
1558								'-webkit-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms',
1559								'-moz-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms',
1560								'-o-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms',
1561								'-ms-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms',
1562								'transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms'
1563							}).addClass('tooltipster-content-changing');
1564							
1565							// reset the CSS transitions and finish the change animation
1566							setTimeout(function() {
1567								
1568								if(self.Status != 'hidden'){
1569									
1570									self.$tooltip.removeClass('tooltipster-content-changing');
1571									
1572									// after the changing animation has completed, reset the CSS transitions
1573									setTimeout(function() {
1574										
1575										if(self.Status !== 'hidden'){
1576											self.$tooltip.css({
1577												'-webkit-transition': self.options.speed + 'ms',
1578												'-moz-transition': self.options.speed + 'ms',
1579												'-o-transition': self.options.speed + 'ms',
1580												'-ms-transition': self.options.speed + 'ms',
1581												'transition': self.options.speed + 'ms'
1582											});
1583										}
1584									}, self.options.speed);
1585								}
1586							}, self.options.speed);
1587						}
1588						else {
1589							self.$tooltip.fadeTo(self.options.speed, 0.5, function() {
1590								if(self.Status != 'hidden'){
1591									self.$tooltip.fadeTo(self.options.speed, 1);
1592								}
1593							});
1594						}
1595					}
1596				}
1597			}
1598			else {
1599				self.hide();
1600			}
1601		},
1602		
1603		_repositionInfo: function($el) {
1604			return {
1605				dimension: {
1606					height: $el.outerHeight(false),
1607					width: $el.outerWidth(false)
1608				},
1609				offset: $el.offset(),
1610				position: {
1611					left: parseInt($el.css('left')),
1612					top: parseInt($el.css('top'))
1613				}
1614			};
1615		},
1616		
1617		hide: function(callback) {
1618			
1619			var self = this;
1620			
1621			// save the method custom callback and cancel any show method custom callbacks
1622			if (callback) self.callbacks.hide.push(callback);
1623			self.callbacks.show = [];
1624			
1625			// get rid of any appearance timeout
1626			clearTimeout(self.timerShow);
1627			self.timerShow = null;
1628			clearTimeout(self.timerHide);
1629			self.timerHide = null;
1630			
1631			var finishCallbacks = function() {
1632				// trigger any hide method custom callbacks and reset them
1633				$.each(self.callbacks.hide, function(i,c) { c.call(self.$el); });
1634				self.callbacks.hide = [];
1635			};
1636			
1637			// hide
1638			if (self.Status == 'shown' || self.Status == 'appearing') {
1639				
1640				self.Status = 'disappearing';
1641				
1642				var finish = function() {
1643					
1644					self.Status = 'hidden';
1645					
1646					// detach our content object first, so the next jQuery's remove() call does not unbind its event handlers
1647					if (typeof self.Content == 'object' && self.Content !== null) {
1648						self.Content.detach();
1649					}
1650					
1651					self.$tooltip.remove();
1652					self.$tooltip = null;
1653					
1654					// unbind orientationchange, scroll and resize listeners
1655					$(window).off('.'+ self.namespace);
1656					
1657					$('body')
1658						// unbind any auto-closing click/touch listeners
1659						.off('.'+ self.namespace)
1660						.css('overflow-x', self.bodyOverflowX);
1661					
1662					// unbind any auto-closing click/touch listeners
1663					$('body').off('.'+ self.namespace);
1664					
1665					// unbind any auto-closing hover listeners
1666					self.$elProxy.off('.'+ self.namespace + '-autoClose');
1667					
1668					// call our constructor custom callback function
1669					self.options.functionAfter.call(self.$el, self.$el);
1670					
1671					// call our method custom callbacks functions
1672					finishCallbacks();
1673				};
1674				
1675				if (supportsTransitions()) {
1676					
1677					self.$tooltip
1678						.clearQueue()
1679						.removeClass('tooltipster-' + self.options.animation + '-show')
1680						// for transitions only
1681						.addClass('tooltipster-dying');
1682					
1683					if(self.options.speed > 0) self.$tooltip.delay(self.options.speed);
1684					
1685					self.$tooltip.queue(finish);
1686				}
1687				else {
1688					self.$tooltip
1689						.stop()
1690						.fadeOut(self.options.speed, finish);
1691				}
1692			}
1693			// if the tooltip is already hidden, we still need to trigger the method custom callback
1694			else if(self.Status == 'hidden') {
1695				finishCallbacks();
1696			}
1697			
1698			return self;
1699		},
1700		
1701		// the public show() method is actually an alias for the private showNow() method
1702		show: function(callback) {
1703			this._showNow(callback);
1704			return this;
1705		},
1706		
1707		// 'update' is deprecated in favor of 'content' but is kept for backward compatibility
1708		update: function(c) {
1709			return this.content(c);
1710		},
1711		content: function(c) {
1712			// getter method
1713			if(typeof c === 'undefined'){
1714				return this.Content;
1715			}
1716			// setter method
1717			else {
1718				this._update(c);
1719				return this;
1720			}
1721		},
1722		
1723		reposition: function() {
1724			
1725			var self = this;
1726			
1727			// in case the tooltip has been removed from DOM manually
1728			if ($('body').find(self.$tooltip).length !== 0) {
1729				
1730				// reset width
1731				self.$tooltip.css('width', '');
1732				
1733				// find variables to determine placement
1734				self.elProxyPosition = self._repositionInfo(self.$elProxy);
1735				var arrowReposition = null,
1736					windowWidth = $(window).width(),
1737					// shorthand
1738					proxy = self.elProxyPosition,
1739					tooltipWidth = self.$tooltip.outerWidth(false),
1740					tooltipInnerWidth = self.$tooltip.innerWidth() + 1, // this +1 stops FireFox from sometimes forcing an additional text line
1741					tooltipHeight = self.$tooltip.outerHeight(false);
1742				
1743				// if this is an <area> tag inside a <map>, all hell breaks loose. Recalculate all the measurements based on coordinates
1744				if (self.$elProxy.is('area')) {
1745					var areaShape = self.$elProxy.attr('shape'),
1746						mapName = self.$elProxy.parent().attr('name'),
1747						map = $('img[usemap="#'+ mapName +'"]'),
1748						mapOffsetLeft = map.offset().left,
1749						mapOffsetTop = map.offset().top,
1750						areaMeasurements = self.$elProxy.attr('coords') !== undefined ? self.$elProxy.attr('coords').split(',') : undefined;
1751					
1752					if (areaShape == 'circle') {
1753						var areaLeft = parseInt(areaMeasurements[0]),
1754							areaTop = parseInt(areaMeasurements[1]),
1755							areaWidth = parseInt(areaMeasurements[2]);
1756						proxy.dimension.height = areaWidth * 2;
1757						proxy.dimension.width = areaWidth * 2;
1758						proxy.offset.top = mapOffsetTop + areaTop - areaWidth;
1759						proxy.offset.left = mapOffsetLeft + areaLeft - areaWidth;
1760					}
1761					else if (areaShape == 'rect') {
1762						var areaLeft = parseInt(areaMeasurements[0]),
1763							areaTop = parseInt(areaMeasurements[1]),
1764							areaRight = parseInt(areaMeasurements[2]),
1765							areaBottom = parseInt(areaMeasurements[3]);
1766						proxy.dimension.height = areaBottom - areaTop;
1767						proxy.dimension.width = areaRight - areaLeft;
1768						proxy.offset.top = mapOffsetTop + areaTop;
1769						proxy.offset.left = mapOffsetLeft + areaLeft;
1770					}
1771					else if (areaShape == 'poly') {
1772						var areaXs = [],
1773							areaYs = [],
1774							areaSmallestX = 0,
1775							areaSmallestY = 0,
1776							areaGreatestX = 0,
1777							areaGreatestY = 0,
1778							arrayAlternate = 'even';
1779						
1780						for (var i = 0; i < areaMeasurements.length; i++) {
1781							var areaNumber = parseInt(areaMeasurements[i]);
1782							
1783							if (arrayAlternate == 'even') {
1784								if (areaNumber > areaGreatestX) {
1785									areaGreatestX = areaNumber;
1786									if (i === 0) {
1787										areaSmallestX = areaGreatestX;
1788									}
1789								}
1790								
1791								if (areaNumber < areaSmallestX) {
1792									areaSmallestX = areaNumber;
1793								}
1794								
1795								arrayAlternate = 'odd';
1796							}
1797							else {
1798								if (areaNumber > areaGreatestY) {
1799									areaGreatestY = areaNumber;
1800									if (i == 1) {
1801										areaSmallestY = areaGreatestY;
1802									}
1803								}
1804								
1805								if (areaNumber < areaSmallestY) {
1806									areaSmallestY = areaNumber;
1807								}
1808								
1809								arrayAlternate = 'even';
1810							}
1811						}
1812					
1813						proxy.dimension.height = areaGreatestY - areaSmallestY;
1814						proxy.dimension.width = areaGreatestX - areaSmallestX;
1815						proxy.offset.top = mapOffsetTop + areaSmallestY;
1816						proxy.offset.left = mapOffsetLeft + areaSmallestX;
1817					}
1818					else {
1819						proxy.dimension.height = map.outerHeight(false);
1820						proxy.dimension.width = map.outerWidth(false);
1821						proxy.offset.top = mapOffsetTop;
1822						proxy.offset.left = mapOffsetLeft;
1823					}
1824				}
1825				
1826				// our function and global vars for positioning our tooltip
1827				var myLeft = 0,
1828					myLeftMirror = 0,
1829					myTop = 0,
1830					offsetY = parseInt(self.options.offsetY),
1831					offsetX = parseInt(self.options.offsetX),
1832					// this is the arrow position that will eventually be used. It may differ from the position option if the tooltip cannot be displayed in this position
1833					practicalPosition = self.options.position;
1834				
1835				// a function to detect if the tooltip is going off the screen horizontally. If so, reposition the crap out of it!
1836				function dontGoOffScreenX() {
1837				
1838					var windowLeft = $(window).scrollLeft();
1839					
1840					// if the tooltip goes off the left side of the screen, line it up with the left side of the window
1841					if((myLeft - windowLeft) < 0) {
1842						arrowReposition = myLeft - windowLeft;
1843						myLeft = windowLeft;
1844					}
1845					
1846					// if the tooltip goes off the right of the screen, line it up with the right side of the window
1847					if (((myLeft + tooltipWidth) - windowLeft) > windowWidth) {
1848						arrowReposition = myLeft - ((windowWidth + windowLeft) - tooltipWidth);
1849						myLeft = (windowWidth + windowLeft) - tooltipWidth;
1850					}
1851				}
1852				
1853				// a function to detect if the tooltip is going off the screen vertically. If so, switch to the opposite!
1854				function dontGoOffScreenY(switchTo, switchFrom) {
1855					// if it goes off the top off the page
1856					if(((proxy.offset.top - $(window).scrollTop() - tooltipHeight - offsetY - 12) < 0) && (switchFrom.indexOf('top') > -1)) {
1857						practicalPosition = switchTo;
1858					}
1859					
1860					// if it goes off the bottom of the page
1861					if (((proxy.offset.top + proxy.dimension.height + tooltipHeight + 12 + offsetY) > ($(window).scrollTop() + $(window).height())) && (switchFrom.indexOf('bottom') > -1)) {
1862						practicalPosition = switchTo;
1863						myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12;
1864					}
1865				}
1866				
1867				if(practicalPosition == 'top') {
1868					var leftDifference = (proxy.offset.left + tooltipWidth) - (proxy.offset.left + proxy.dimension.width);
1869					myLeft = (proxy.offset.left + offsetX) - (leftDifference / 2);
1870					myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12;
1871					dontGoOffScreenX();
1872					dontGoOffScreenY('bottom', 'top');
1873				}
1874				
1875				if(practicalPosition == 'top-left') {
1876					myLeft = proxy.offset.left + offsetX;
1877					myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12;
1878					dontGoOffScreenX();
1879					dontGoOffScreenY('bottom-left', 'top-left');
1880				}
1881				
1882				if(practicalPosition == 'top-right') {
1883					myLeft = (proxy.offset.left + proxy.dimension.width + offsetX) - tooltipWidth;
1884					myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12;
1885					dontGoOffScreenX();
1886					dontGoOffScreenY('bottom-right', 'top-right');
1887				}
1888				
1889				if(practicalPosition == 'bottom') {
1890					var leftDifference = (proxy.offset.left + tooltipWidth) - (proxy.offset.left + proxy.dimension.width);
1891					myLeft = proxy.offset.left - (leftDifference / 2) + offsetX;
1892					myTop = (proxy.offset.top + proxy.dimension.height) + offsetY + 12;
1893					dontGoOffScreenX();
1894					dontGoOffScreenY('top', 'bottom');
1895				}
1896				
1897				if(practicalPosition == 'bottom-left') {
1898					myLeft = proxy.offset.left + offsetX;
1899					myTop = (proxy.offset.top + proxy.dimension.height) + offsetY + 12;
1900					dontGoOffScreenX();
1901					dontGoOffScreenY('top-left', 'bottom-left');
1902				}
1903				
1904				if(practicalPosition == 'bottom-right') {
1905					myLeft = (proxy.offset.left + proxy.dimension.width + offsetX) - tooltipWidth;
1906					myTop = (proxy.offset.top + proxy.dimension.height) + offsetY + 12;
1907					dontGoOffScreenX();
1908					dontGoOffScreenY('top-right', 'bottom-right');
1909				}
1910				
1911				if(practicalPosition == 'left') {
1912					myLeft = proxy.offset.left - offsetX - tooltipWidth - 12;
1913					myLeftMirror = proxy.offset.left + offsetX + proxy.dimension.width + 12;
1914					var topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height);
1915					myTop = proxy.offset.top - (topDifference / 2) - offsetY;
1916					
1917					// if the tooltip goes off boths sides of the page
1918					if((myLeft < 0) && ((myLeftMirror + tooltipWidth) > windowWidth)) {
1919						var borderWidth = parseFloat(self.$tooltip.css('border-width')) * 2,
1920							newWidth = (tooltipWidth + myLeft) - borderWidth;
1921						self.$tooltip.css('width', newWidth + 'px');
1922						
1923						tooltipHeight = self.$tooltip.outerHeight(false);
1924						myLeft = proxy.offset.left - offsetX - newWidth - 12 - borderWidth;
1925						topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height);
1926						myTop = proxy.offset.top - (topDifference / 2) - offsetY;
1927					}
1928					
1929					// if it only goes off one side, flip it to the other side
1930					else if(myLeft < 0) {
1931						myLeft = proxy.offset.left + offsetX + proxy.dimension.width + 12;
1932						arrowReposition = 'left';
1933					}
1934				}
1935				
1936				if(practicalPosition == 'right') {
1937					myLeft = proxy.offset.left + offsetX + proxy.dimension.width + 12;
1938					myLeftMirror = proxy.offset.left - offsetX - tooltipWidth - 12;
1939					var topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height);
1940					myTop = proxy.offset.top - (topDifference / 2) - offsetY;
1941					
1942					// if the tooltip goes off boths sides of the page
1943					if(((myLeft + tooltipWidth) > windowWidth) && (myLeftMirror < 0)) {
1944						var borderWidth = parseFloat(self.$tooltip.css('border-width')) * 2,
1945							newWidth = (windowWidth - myLeft) - borderWidth;
1946						self.$tooltip.css('width', newWidth + 'px');
1947						
1948						tooltipHeight = self.$tooltip.outerHeight(false);
1949						topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height);
1950						myTop = proxy.offset.top - (topDifference / 2) - offsetY;
1951					}
1952						
1953					// if it only goes off one side, flip it to the other side
1954					else if((myLeft + tooltipWidth) > windowWidth) {
1955						myLeft = proxy.offset.left - offsetX - tooltipWidth - 12;
1956						arrowReposition = 'right';
1957					}
1958				}
1959				
1960				// if arrow is set true, style it and append it
1961				if (self.options.arrow) {
1962	
1963					var arrowClass = 'tooltipster-arrow-' + practicalPosition;
1964					
1965					// set color of the arrow
1966					if(self.options.arrowColor.length < 1) {
1967						var arrowColor = self.$tooltip.css('background-color');
1968					}
1969					else {
1970						var arrowColor = self.options.arrowColor;
1971					}
1972					
1973					// if the tooltip was going off the page and had to re-adjust, we need to update the arrow's position
1974					if (!arrowReposition) {
1975						arrowReposition = '';
1976					}
1977					else if (arrowReposition == 'left') {
1978						arrowClass = 'tooltipster-arrow-right';
1979						arrowReposition = '';
1980					}
1981					else if (arrowReposition == 'right') {
1982						arrowClass = 'tooltipster-arrow-left';
1983						arrowReposition = '';
1984					}
1985					else {
1986						arrowReposition = 'left:'+ Math.round(arrowReposition) +'px;';
1987					}
1988					
1989					// building the logic to create the border around the arrow of the tooltip
1990					if ((practicalPosition == 'top') || (practicalPosition == 'top-left') || (practicalPosition == 'top-right')) {
1991						var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-bottom-width')),
1992							tooltipBorderColor = self.$tooltip.css('border-bottom-color');
1993					}
1994					else if ((practicalPosition == 'bottom') || (practicalPosition == 'bottom-left') || (practicalPosition == 'bottom-right')) {
1995						var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-top-width')),
1996							tooltipBorderColor = self.$tooltip.css('border-top-color');
1997					}
1998					else if (practicalPosition == 'left') {
1999						var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-right-width')),
2000							tooltipBorderColor = self.$tooltip.css('border-right-color');
2001					}
2002					else if (practicalPosition == 'right') {
2003						var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-left-width')),
2004							tooltipBorderColor = self.$tooltip.css('border-left-color');
2005					}
2006					else {
2007						var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-bottom-width')),
2008							tooltipBorderColor = self.$tooltip.css('border-bottom-color');
2009					}
2010					
2011					if (tooltipBorderWidth > 1) {
2012						tooltipBorderWidth++;
2013					}
2014					
2015					var arrowBorder = '';
2016					if (tooltipBorderWidth !== 0) {
2017						var arrowBorderSize = '',
2018							arrowBorderColor = 'border-color: '+ tooltipBorderColor +';';
2019						if (arrowClass.indexOf('bottom') !== -1) {
2020							arrowBorderSize = 'margin-top: -'+ Math.round(tooltipBorderWidth) +'px;';
2021						}
2022						else if (arrowClass.indexOf('top') !== -1) {
2023							arrowBorderSize = 'margin-bottom: -'+ Math.round(tooltipBorderWidth) +'px;';
2024						}
2025						else if (arrowClass.indexOf('left') !== -1) {
2026							arrowBorderSize = 'margin-right: -'+ Math.round(tooltipBorderWidth) +'px;';
2027						}
2028						else if (arrowClass.indexOf('right') !== -1) {
2029							arrowBorderSize = 'margin-left: -'+ Math.round(tooltipBorderWidth) +'px;';
2030						}
2031						arrowBorder = '<span class="tooltipster-arrow-border" style="'+ arrowBorderSize +' '+ arrowBorderColor +';"></span>';
2032					}
2033					
2034					// if the arrow already exists, remove and replace it
2035					self.$tooltip.find('.tooltipster-arrow').remove();
2036					
2037					// build out the arrow and append it		
2038					var arrowConstruct = '<div class="'+ arrowClass +' tooltipster-arrow" style="'+ arrowReposition +'">'+ arrowBorder +'<span style="border-color:'+ arrowColor +';"></span></div>';
2039					self.$tooltip.append(arrowConstruct);
2040				}
2041				
2042				// position the tooltip
2043				self.$tooltip.css({'top': Math.round(myTop) + 'px', 'left': Math.round(myLeft) + 'px'});
2044			}
2045			
2046			return self;
2047		},
2048		
2049		enable: function() {
2050			this.enabled = true;
2051			return this;
2052		},
2053		
2054		disable: function() {
2055			// hide first, in case the tooltip would not disappear on its own (autoClose false)
2056			this.hide();
2057			this.enabled = false;
2058			return this;
2059		},
2060		
2061		destroy: function() {
2062			
2063			var self = this;
2064			
2065			self.hide();
2066			
2067			// remove the icon, if any
2068			if (self.$el[0] !== self.$elProxy[0]) {
2069				self.$elProxy.remove();
2070			}
2071			
2072			self.$el
2073				.removeData(self.namespace)
2074				.off('.'+ self.namespace);
2075			
2076			var ns = self.$el.data('tooltipster-ns');
2077			
2078			// if there are no more tooltips on this element
2079			if(ns.length === 1){
2080				
2081				// optional restoration of a title attribute
2082				var title = null;
2083				if (self.options.restoration === 'previous'){
2084					title = self.$el.data('tooltipster-initialTitle');
2085				}
2086				else if(self.options.restoration === 'current'){
2087					
2088					// old school technique to stringify when outerHTML is not supported
2089					title =
2090						(typeof self.Content === 'string') ?
2091						self.Content :
2092						$('<div></div>').append(self.Content).html();
2093				}
2094				
2095				if (title) {
2096					self.$el.attr('title', title);
2097				}
2098				
2099				// final cleaning
2100				self.$el
2101					.removeClass('tooltipstered')
2102					.removeData('tooltipster-ns')
2103					.removeData('tooltipster-initialTitle');
2104			}
2105			else {
2106				// remove the instance namespace from the list of namespaces of tooltips present on the element
2107				ns = $.grep(ns, function(el, i){
2108					return el !== self.namespace;
2109				});
2110				self.$el.data('tooltipster-ns', ns);
2111			}
2112			
2113			return self;
2114		},
2115		
2116		elementIcon: function() {
2117			return (this.$el[0] !== this.$elProxy[0]) ? this.$elProxy[0] : undefined;
2118		},
2119		
2120		elementTooltip: function() {
2121			return this.$tooltip ? this.$tooltip[0] : undefined;
2122		},
2123		
2124		// public methods but for internal use only
2125		// getter if val is ommitted, setter otherwise
2126		option: function(o, val) {
2127			if (typeof val == 'undefined') return this.options[o];
2128			else {
2129				this.options[o] = val;
2130				return this;
2131			}
2132		},
2133		status: function() {
2134			return this.Status;
2135		}
2136	};
2137	
2138	$.fn[pluginName] = function () {
2139		
2140		// for using in closures
2141		var args = arguments;
2142		
2143		// if we are not in the context of jQuery wrapped HTML element(s) :
2144		// this happens when calling static methods in the form $.fn.tooltipster('methodName'), or when calling $(sel).tooltipster('methodName or options') where $(sel) does not match anything
2145		if (this.length === 0) {
2146			
2147			// if the first argument is a method name
2148			if (typeof args[0] === 'string') {
2149				
2150				var methodIsStatic = true;
2151				
2152				// list static methods here (usable by calling $.fn.tooltipster('methodName');)
2153				switch (args[0]) {
2154					
2155					case 'setDefaults':
2156						// change default options for all future instances
2157						$.extend(defaults, args[1]);
2158						break;
2159					
2160					default:
2161						methodIsStatic = false;
2162						break;
2163				}
2164				
2165				// $.fn.tooltipster('methodName') calls will return true
2166				if (methodIsStatic) return true;
2167				// $(sel).tooltipster('methodName') calls will return the list of objects event though it's empty because chaining should work on empty lists
2168				else return this;
2169			}
2170			// the first argument is undefined or an object of options : we are initalizing but there is no element matched by selector
2171			else {
2172				// still chainable : same as above
2173				return this;
2174			}
2175		}
2176		// this happens when calling $(sel).tooltipster('methodName or options') where $(sel) matches one or more elements
2177		else {
2178			
2179			// method calls
2180			if (typeof args[0] === 'string') {
2181				
2182				var v = '#*$~&';
2183				
2184				this.each(function() {
2185					
2186					// retrieve the namepaces of the tooltip(s) that exist on that element. We will interact with the first tooltip only.
2187					var ns = $(this).data('tooltipster-ns'),
2188						// self represents the instance of the first tooltipster plugin associated to the current HTML object of the loop
2189						self = ns ? $(this).data(ns[0]) : null;
2190					
2191					// if the current element holds a tooltipster instance
2192					if (self) {
2193						
2194						if (typeof self[args[0]] === 'function') {
2195							// note : args[1] and args[2] may not be defined
2196							var resp = self[args[0]](args[1], args[2]);
2197						}
2198						else {
2199							throw new Error('Unknown method .tooltipster("' + args[0] + '")');
2200						}
2201						
2202						// if the function returned anything other than the instance itself (which implies chaining)
2203						if (resp !== self){
2204							v = resp;
2205							// return false to stop .each iteration on the first element matched by the selector
2206							return false;
2207						}
2208					}
2209					else {
2210						throw new Error('You called Tooltipster\'s "' + args[0] + '" method on an uninitialized element');
2211					}
2212				});
2213				
2214				return (v !== '#*$~&') ? v : this;
2215			}
2216			// first argument is undefined or an object : the tooltip is initializing
2217			else {
2218				
2219				var instances = [],
2220					// is there a defined value for the multiple option in the options object ?
2221					multipleIsSet = args[0] && typeof args[0].multiple !== 'undefined',
2222					// if the multiple option is set to true, or if it's not defined but set to true in the defaults
2223					multiple = (multipleIsSet && args[0].multiple) || (!multipleIsSet && defaults.multiple),
2224					// same for debug
2225					debugIsSet = args[0] && typeof args[0].debug !== 'undefined',
2226					debug = (debugIsSet && args[0].debug) || (!debugIsSet && defaults.debug);
2227				
2228				// initialize a tooltipster instance for each element if it doesn't already have one or if the multiple option is set, and attach the object to it
2229				this.each(function () {
2230					
2231					var go = false,
2232						ns = $(this).data('tooltipster-ns'),
2233						instance = null;
2234					
2235					if (!ns) {
2236						go = true;
2237					}
2238					else if (multiple) {
2239						go = true;
2240					}
2241					else if (debug) {
2242						console.log('Tooltipster: one or more tooltips are already attached to this element: ignoring. Use the "multiple" option to attach more tooltips.');
2243					}
2244					
2245					if (go) {
2246						instance = new Plugin(this, args[0]);
2247						
2248						// save the reference of the new instance
2249						if (!ns) ns = [];
2250						ns.push(instance.namespace);
2251						$(this).data('tooltipster-ns', ns)
2252						
2253						// save the instance itself
2254						$(this).data(instance.namespace, instance);
2255					}
2256					
2257					instances.push(instance);
2258				});
2259				
2260				if (multiple) return instances;
2261				else return this;
2262			}
2263		}
2264	};
2265	
2266	// quick & dirty compare function (not bijective nor multidimensional)
2267	function areEqual(a,b) {
2268		var same = true;
2269		$.each(a, function(i, el){
2270			if(typeof b[i] === 'undefined' || a[i] !== b[i]){
2271				same = false;
2272				return false;
2273			}
2274		});
2275		return same;
2276	}
2277	
2278	// detect if this device can trigger touch events
2279	var deviceHasTouchCapability = !!('ontouchstart' in window);
2280	
2281	// we'll assume the device has no mouse until we detect any mouse movement
2282	var deviceHasMouse = false;
2283	$('body').one('mousemove', function() {
2284		deviceHasMouse = true;
2285	});
2286	
2287	function deviceIsPureTouch() {
2288		return (!deviceHasMouse && deviceHasTouchCapability);
2289	}
2290	
2291	// detecting support for CSS transitions
2292	function supportsTransitions() {
2293		var b = document.body || document.documentElement,
2294			s = b.style,
2295			p = 'transition';
2296		
2297		if(typeof s[p] == 'string') {return true; }
2298
2299		v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'],
2300		p = p.charAt(0).toUpperCase() + p.substr(1);
2301		for(var i=0; i<v.length; i++) {
2302			if(typeof s[v[i] + p] == 'string') { return true; }
2303		}
2304		return false;
2305	}
2306})( jQuery, window, document );
2307
2308(function( $ ) {
2309	'use strict';
2310	var Obj = {
2311		// All pages
2312		'common' : {
2313			init : function() {
2314				// JavaScript to be fired on all pages
2315				$( function() {
2316					Obj.common.voting();
2317				} );
2318			},
2319			finalize : function() {
2320				// JavaScript to be fired on all pages, after page specific JS is fired
2321			},
2322
2323			voting : function() {
2324				// Like
2325				$('a.pakb-like-btn').click(function(){
2326					var response_div = $(this).parent();
2327					$.ajax({
2328						url         : PAKB.base_url,
2329						data        : {'pakb_vote_like':$(this).attr('post_id')},
2330						beforeSend  : function(){
2331						},
2332						success     : function(data){
2333							response_div.html(data).fadeIn(900);
2334						},
2335						complete    : function(){
2336
2337						}
2338					});
2339				});
2340
2341				// Dislike
2342				$('a.pakb-dislike-btn').click(function(){
2343					var response_div = $(this).parent();
2344					$.ajax({
2345						url         : PAKB.base_url,
2346						data        : {'pakb_vote_dislike':$(this).attr('post_id')},
2347						beforeSend  : function(){
2348
2349						},
2350						success     : function(data){
2351							response_div.html(data).fadeIn(900);
2352						},
2353						complete    : function(){
2354
2355						}
2356					});
2357				});
2358
2359				// Autosuggest
2360				//will check if display category is enabled through localize script
2361				if ( PAKB.category ) {
2362					$('#kb-s.autosuggest').autocomplete({
2363						serviceUrl  : PAKB.ajaxurl,
2364						params      : {'action':'search_title'},
2365						minChars    : 1,
2366						maxHeight   : 450,
2367						groupBy     : 'category',
2368						preventBadQueries : false,
2369						onSelect    : function(suggestion) {
2370							window.location = suggestion.url;
2371						}
2372					});
2373				} else {
2374					$('#kb-s.autosuggest').autocomplete({
2375						serviceUrl  : PAKB.ajaxurl,
2376						params      : {'action':'search_title'},
2377						minChars    : 1,
2378						maxHeight   : 450,
2379						preventBadQueries : false,
2380						onSelect    : function(suggestion) {
2381							window.location = suggestion.url;
2382						}
2383					});
2384				}
2385
2386				$('.pakb-tooltip').tooltipster();
2387
2388				// Break header out of container
2389				/*
2390				var scroll_resize = function(){
2391
2392					var headerPos = $('.pakb-header').offset(); // returns position
2393					var windowWidth = jQuery(window).width()
2394					var widthHeader = parseInt($(".pakb-header").css("width"));
2395					//var paddingRight = windowWidth - headerPos.left - widthHeader;
2396
2397					//if ( 767 < windowWidth ) {
2398						$(".pakb-header-wrapper").css( {"width": windowWidth, "margin-left": - headerPos.left, "padding-left": + headerPos.left, "padding-right": + headerPos.left} );
2399					//}
2400					return;
2401				};
2402
2403				$(document).ready(scroll_resize);
2404				$(window).resize(scroll_resize);
2405				*/
2406
2407			} // end of voting
2408
2409		}
2410
2411	};
2412
2413	// The routing fires all common scripts, followed by the page specific scripts.
2414	// Add additional events for more control over timing e.g. a finalize event
2415	var UTIL = {
2416		fire : function( func, funcname, args ) {
2417			var fire;
2418			var namespace = Obj;
2419			funcname      = (funcname === undefined) ? 'init' : funcname;
2420			fire          = func !== '';
2421			fire          = fire && namespace[ func ];
2422			fire          = fire && typeof namespace[ func ][ funcname ] === 'function';
2423
2424			if ( fire ) {
2425				namespace[ func ][ funcname ]( args );
2426			}
2427		},
2428		loadEvents : function() {
2429			// Fire common init JS
2430			UTIL.fire( 'common' );
2431
2432			// Fire page-specific init JS, and then finalize JS
2433			$.each( document.body.className.replace( /-/g, '_' ).split( /\s+/ ), function( i, classnm ) {
2434				UTIL.fire( classnm );
2435				UTIL.fire( classnm, 'finalize' );
2436			} );
2437
2438			// Fire common finalize JS
2439			UTIL.fire( 'common', 'finalize' );
2440		}
2441	};
2442
2443	// Load Events
2444	$( document ).ready( UTIL.loadEvents );
2445
2446})( jQuery ); // Fully reference jQuery after this point.

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.