PageSourceSearch

https://tatum-musik.com/wp-content/themes/lush/js/utilities.js

js tatum-musik.com collected 2026-10-07 15:18:18 UTC 56,585 bytes, 1,707 lines download raw bytes

1/*
2 * JavaScript Custom Forms Module
3 */
4jcf = {
5	// global options
6	modules: {},
7	plugins: {},
8	baseOptions: {
9		unselectableClass:'jcf-unselectable',
10		labelActiveClass:'jcf-label-active',
11		labelDisabledClass:'jcf-label-disabled',
12		classPrefix: 'jcf-class-',
13		hiddenClass:'jcf-hidden',
14		focusClass:'jcf-focus',
15		wrapperTag: 'div'
16	},
17	// replacer function
18	customForms: {
19		setOptions: function(obj) {
20			for(var p in obj) {
21				if(obj.hasOwnProperty(p) && typeof obj[p] === 'object') {
22					jcf.lib.extend(jcf.modules[p].prototype.defaultOptions, obj[p]);
23				}
24			}
25		},
26		replaceAll: function() {
27			for(var k in jcf.modules) {
28				var els = jcf.lib.queryBySelector(jcf.modules[k].prototype.selector);
29				for(var i = 0; i<els.length; i++) {
30					if(els[i].jcf) {
31						// refresh form element state
32						els[i].jcf.refreshState();
33					} else {
34						// replace form element
35						if(!jcf.lib.hasClass(els[i], 'default') && jcf.modules[k].prototype.checkElement(els[i])) {
36							new jcf.modules[k]({
37								replaces:els[i]
38							});
39						}
40					}
41				}
42			}
43		},
44		refreshAll: function() {
45			for(var k in jcf.modules) {
46				var els = jcf.lib.queryBySelector(jcf.modules[k].prototype.selector);
47				for(var i = 0; i<els.length; i++) {
48					if(els[i].jcf) {
49						// refresh form element state
50						els[i].jcf.refreshState();
51					}
52				}
53			}
54		},
55		refreshElement: function(obj) {
56			if(obj && obj.jcf) {
57				obj.jcf.refreshState();
58			}
59		},
60		destroyAll: function() {
61			for(var k in jcf.modules) {
62				var els = jcf.lib.queryBySelector(jcf.modules[k].prototype.selector);
63				for(var i = 0; i<els.length; i++) {
64					if(els[i].jcf) {
65						els[i].jcf.destroy();
66					}
67				}
68			}
69		}
70	},
71	// detect device type
72	isTouchDevice: ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch,
73	isWinPhoneDevice: navigator.msPointerEnabled && /MSIE 10.*Touch/.test(navigator.userAgent),
74	// define base module
75	setBaseModule: function(obj) {
76		jcf.customControl = function(opt){
77			this.options = jcf.lib.extend({}, jcf.baseOptions, this.defaultOptions, opt);
78			this.init();
79		};
80		for(var p in obj) {
81			jcf.customControl.prototype[p] = obj[p];
82		}
83	},
84	// add module to jcf.modules
85	addModule: function(obj) {
86		if(obj.name){
87			// create new module proto class
88			jcf.modules[obj.name] = function(){
89				jcf.modules[obj.name].superclass.constructor.apply(this, arguments);
90			};
91			jcf.lib.inherit(jcf.modules[obj.name], jcf.customControl);
92			for(var p in obj) {
93				jcf.modules[obj.name].prototype[p] = obj[p];
94			}
95			// on create module
96			jcf.modules[obj.name].prototype.onCreateModule();
97			// make callback for exciting modules
98			for(var mod in jcf.modules) {
99				if(jcf.modules[mod] != jcf.modules[obj.name]) {
100					jcf.modules[mod].prototype.onModuleAdded(jcf.modules[obj.name]);
101				}
102			}
103		}
104	},
105	// add plugin to jcf.plugins
106	addPlugin: function(obj) {
107		if(obj && obj.name) {
108			jcf.plugins[obj.name] = function() {
109				this.init.apply(this, arguments);
110			};
111			for(var p in obj) {
112				jcf.plugins[obj.name].prototype[p] = obj[p];
113			}
114		}
115	},
116	// miscellaneous init
117	init: function(){
118		if(navigator.msPointerEnabled) {
119			this.eventPress = 'MSPointerDown';
120			this.eventMove = 'MSPointerMove';
121			this.eventRelease = 'MSPointerUp';
122		} else {
123			this.eventPress = this.isTouchDevice ? 'touchstart' : 'mousedown';
124			this.eventMove = this.isTouchDevice ? 'touchmove' : 'mousemove';
125			this.eventRelease = this.isTouchDevice ? 'touchend' : 'mouseup';
126		}
127
128		// init jcf styles
129		setTimeout(function(){
130			jcf.lib.domReady(function(){
131				jcf.initStyles();
132			});
133		},1);
134		return this;
135	},
136	initStyles: function() {
137		// create <style> element and rules
138		var head = document.getElementsByTagName('head')[0],
139			style = document.createElement('style'),
140			rules = document.createTextNode('.'+jcf.baseOptions.unselectableClass+'{'+
141				'-moz-user-select:none;'+
142				'-webkit-tap-highlight-color:rgba(255,255,255,0);'+
143				'-webkit-user-select:none;'+
144				'user-select:none;'+
145			'}');
146
147		// append style element
148		style.type = 'text/css';
149		if(style.styleSheet) {
150			style.styleSheet.cssText = rules.nodeValue;
151		} else {
152			style.appendChild(rules);
153		}
154		head.appendChild(style);
155	}
156}.init();
157
158/*
159 * Custom Form Control prototype
160 */
161jcf.setBaseModule({
162	init: function(){
163		if(this.options.replaces) {
164			this.realElement = this.options.replaces;
165			this.realElement.jcf = this;
166			this.replaceObject();
167		}
168	},
169	defaultOptions: {
170		// default module options (will be merged with base options)
171	},
172	checkElement: function(el){
173		return true;
173 // additional check for correct form element
174	},
175	replaceObject: function(){
176		this.createWrapper();
177		this.attachEvents();
178		this.fixStyles();
179		this.setupWrapper();
180	},
181	createWrapper: function(){
182		this.fakeElement = jcf.lib.createElement(this.options.wrapperTag);
183		this.labelFor = jcf.lib.getLabelFor(this.realElement);
184		jcf.lib.disableTextSelection(this.fakeElement);
185		jcf.lib.addClass(this.fakeElement, jcf.lib.getAllClasses(this.realElement.className, this.options.classPrefix));
186		jcf.lib.addClass(this.realElement, jcf.baseOptions.hiddenClass);
187	},
188	attachEvents: function(){
189		jcf.lib.event.add(this.realElement, 'focus', this.onFocusHandler, this);
190		jcf.lib.event.add(this.realElement, 'blur', this.onBlurHandler, this);
191		jcf.lib.event.add(this.fakeElement, 'click', this.onFakeClick, this);
192		jcf.lib.event.add(this.fakeElement, jcf.eventPress, this.onFakePressed, this);
193		jcf.lib.event.add(this.fakeElement, jcf.eventRelease, this.onFakeReleased, this);
194
195		if(this.labelFor) {
196			this.labelFor.jcf = this;
197			jcf.lib.event.add(this.labelFor, 'click', this.onFakeClick, this);
198			jcf.lib.event.add(this.labelFor, jcf.eventPress, this.onFakePressed, this);
199			jcf.lib.event.add(this.labelFor, jcf.eventRelease, this.onFakeReleased, this);
200		}
201	},
202	fixStyles: function() {
203		// hide mobile webkit tap effect
204		if(jcf.isTouchDevice) {
205			var tapStyle = 'rgba(255,255,255,0)';
206			this.realElement.style.webkitTapHighlightColor = tapStyle;
207			this.fakeElement.style.webkitTapHighlightColor = tapStyle;
208			if(this.labelFor) {
209				this.labelFor.style.webkitTapHighlightColor = tapStyle;
210			}
211		}
212	},
213	setupWrapper: function(){
214		// implement in subclass
215	},
216	refreshState: function(){
217		// implement in subclass
218	},
219	destroy: function() {
220		if(this.fakeElement && this.fakeElement.parentNode) {
221			this.fakeElement.parentNode.removeChild(this.fakeElement);
222		}
223		jcf.lib.removeClass(this.realElement, jcf.baseOptions.hiddenClass);
224		this.realElement.jcf = null;
225	},
226	onFocus: function(){
227		// emulated focus event
228		jcf.lib.addClass(this.fakeElement,this.options.focusClass);
229	},
230	onBlur: function(cb){
231		// emulated blur event
232		jcf.lib.removeClass(this.fakeElement,this.options.focusClass);
233	},
234	onFocusHandler: function() {
235		// handle focus loses
236		if(this.focused) return;
237		this.focused = true;
238
239		// handle touch devices also
240		if(jcf.isTouchDevice) {
241			if(jcf.focusedInstance && jcf.focusedInstance.realElement != this.realElement) {
242				jcf.focusedInstance.onBlur();
243				jcf.focusedInstance.realElement.blur();
244			}
245			jcf.focusedInstance = this;
246		}
247		this.onFocus.apply(this, arguments);
248	},
249	onBlurHandler: function() {
250		// handle focus loses
251		if(!this.pressedFlag) {
252			this.focused = false;
253			this.onBlur.apply(this, arguments);
254		}
255	},
256	onFakeClick: function(){
257		if(jcf.isTouchDevice) {
258			this.onFocus();
259		} else if(!this.realElement.disabled) {
260			this.realElement.focus();
261		}
262	},
263	onFakePressed: function(e){
264		this.pressedFlag = true;
265	},
266	onFakeReleased: function(){
267		this.pressedFlag = false;
268	},
269	onCreateModule: function(){
270		// implement in subclass
271	},
272	onModuleAdded: function(module) {
273		// implement in subclass
274	},
275	onControlReady: function() {
276		// implement in subclass
277	}
278});
279
280/*
281 * JCF Utility Library
282 */
283jcf.lib = {
284	bind: function(func, scope){
285		return function() {
286			return func.apply(scope, arguments);
287		}
288	},
289	browser: (function() {
290		var ua = navigator.userAgent.toLowerCase(), res = {},
291		match = /(webkit)[ \/]([\w.]+)/.exec(ua) || /(opera)(?:.*version)?[ \/]([\w.]+)/.exec(ua) ||
292				/(msie) ([\w.]+)/.exec(ua) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+))?/.exec(ua) || [];
293		res[match[1]] = true;
294		res.version = match[2] || "0";
295		res.safariMac = ua.indexOf('mac') != -1 && ua.indexOf('safari') != -1;
296		return res;
297	})(),
298	getOffset: function (obj) {
299		if (obj.getBoundingClientRect && !navigator.msPointerEnabled) {
300			var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
301			var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
302			var clientLeft = document.documentElement.clientLeft || document.body.clientLeft || 0;
303			var clientTop = document.documentElement.clientTop || document.body.clientTop || 0;
304			return {
305				top:Math.round(obj.getBoundingClientRect().top + scrollTop - clientTop),
306				left:Math.round(obj.getBoundingClientRect().left + scrollLeft - clientLeft)
307			}
308		} else {
309			var posLeft = 0, posTop = 0;
310			while (obj.offsetParent) {posLeft += obj.offsetLeft; posTop += obj.offsetTop; obj = obj.offsetParent;}
311			return {top:posTop,left:posLeft};
312		}
313	},
314	getScrollTop: function() {
315		return window.pageYOffset || document.documentElement.scrollTop;
316	},
317	getScrollLeft: function() {
318		return window.pageXOffset || document.documentElement.scrollLeft;
319	},
320	getWindowWidth: function(){
321		return document.compatMode=='CSS1Compat' ? document.documentElement.clientWidth : document.body.clientWidth;
322	},
323	getWindowHeight: function(){
324		return document.compatMode=='CSS1Compat' ? document.documentElement.clientHeight : document.body.clientHeight;
325	},
326	getStyle: function(el, prop) {
327		if (document.defaultView && document.defaultView.getComputedStyle) {
328			return document.defaultView.getComputedStyle(el, null)[prop];
329		} else if (el.currentStyle) {
330			return el.currentStyle[prop];
331		} else {
332			return el.style[prop];
333		}
334	},
335	getParent: function(obj, selector) {
336		while(obj.parentNode && obj.parentNode != document.body) {
337			if(obj.parentNode.tagName.toLowerCase() == selector.toLowerCase()) {
338				return obj.parentNode;
339			}
340			obj = obj.parentNode;
341		}
342		return false;
343	},
344	isParent: function(child, parent) {
345		while(child.parentNode) {
346			if(child.parentNode === parent) {
347				return true;
348			}
349			child = child.parentNode;
350		}
351		return false;
352	},
353	getLabelFor: function(object) {
354		var parentLabel = jcf.lib.getParent(object,'label');
355		if(parentLabel) {
356			return parentLabel;
357		} else if(object.id) {
358			return jcf.lib.queryBySelector('label[for="' + object.id + '"]')[0];
359		}
360	},
361	disableTextSelection: function(el){
362		if (typeof el.onselectstart !== 'undefined') {
363			el.onselectstart = function() {return false};
364		} else if(window.opera) {
365			el.setAttribute('unselectable', 'on');
366		} else {
367			jcf.lib.addClass(el, jcf.baseOptions.unselectableClass);
368		}
369	},
370	enableTextSelection: function(el) {
371		if (typeof el.onselectstart !== 'undefined') {
372			el.onselectstart = null;
373		} else if(window.opera) {
374			el.removeAttribute('unselectable');
375		} else {
376			jcf.lib.removeClass(el, jcf.baseOptions.unselectableClass);
377		}
378	},
379	queryBySelector: function(selector, scope){
380		return this.getElementsBySelector(selector, scope);
381	},
382	prevSibling: function(node) {
383		while(node = node.previousSibling) if(node.nodeType == 1) break;
384		return node;
385	},
386	nextSibling: function(node) {
387		while(node = node.nextSibling) if(node.nodeType == 1) break;
388		return node;
389	},
390	fireEvent: function(element,event) {
391		if(element.dispatchEvent){
392			var evt = document.createEvent('HTMLEvents');
393			evt.initEvent(event, true, true );
394			return !element.dispatchEvent(evt);
395		}else if(document.createEventObject){
396			var evt = document.createEventObject();
397			return element.fireEvent('on'+event,evt);
398		}
399	},
400	isParent: function(p, c) {
401		while(c.parentNode) {
402			if(p == c) {
403				return true;
404			}
405			c = c.parentNode;
406		}
407		return false;
408	},
409	inherit: function(Child, Parent) {
410		var F = function() { }
411		F.prototype = Parent.prototype
412		Child.prototype = new F()
413		Child.prototype.constructor = Child
414		Child.superclass = Parent.prototype
415	},
416	extend: function(obj) {
417		for(var i = 1; i < arguments.length; i++) {
418			for(var p in arguments[i]) {
419				if(arguments[i].hasOwnProperty(p)) {
420					obj[p] = arguments[i][p];
421				}
422			}
423		}
424		return obj;
425	},
426	hasClass: function (obj,cname) {
427		return (obj.className ? obj.className.match(new RegExp('(\\s|^)'+cname+'(\\s|$)')) : false);
428	},
429	addClass: function (obj,cname) {
430		if (!this.hasClass(obj,cname)) obj.className += (!obj.className.length || obj.className.charAt(obj.className.length - 1) === ' ' ? '' : ' ') + cname;
431	},
432	removeClass: function (obj,cname) {
433		if (this.hasClass(obj,cname)) obj.className=obj.className.replace(new RegExp('(\\s|^)'+cname+'(\\s|$)'),' ').replace(/\s+$/, '');
434	},
435	toggleClass: function(obj, cname, condition) {
436		if(condition) this.addClass(obj, cname); else this.removeClass(obj, cname);
437	},
438	createElement: function(tagName, options) {
439		var el = document.createElement(tagName);
440		for(var p in options) {
441			if(options.hasOwnProperty(p)) {
442				switch (p) {
443					case 'class': el.className = options[p]; break;
444					case 'html': el.innerHTML = options[p]; break;
445					case 'style': this.setStyles(el, options[p]); break;
446					default: el.setAttribute(p, options[p]);
447				}
448			}
449		}
450		return el;
451	},
452	setStyles: function(el, styles) {
453		for(var p in styles) {
454			if(styles.hasOwnProperty(p)) {
455				switch (p) {
456					case 'float': el.style.cssFloat = styles[p]; break;
457					case 'opacity': el.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity='+styles[p]*100+')'; el.style.opacity = styles[p]; break;
458					default: el.style[p] = (typeof styles[p] === 'undefined' ? 0 : styles[p]) + (typeof styles[p] === 'number' ? 'px' : '');
459				}
460			}
461		}
462		return el;
463	},
464	getInnerWidth: function(el) {
465		return el.offsetWidth - (parseInt(this.getStyle(el,'paddingLeft')) || 0) - (parseInt(this.getStyle(el,'paddingRight')) || 0);
466	},
467	getInnerHeight: function(el) {
468		return el.offsetHeight - (parseInt(this.getStyle(el,'paddingTop')) || 0) - (parseInt(this.getStyle(el,'paddingBottom')) || 0);
469	},
470	getAllClasses: function(cname, prefix, skip) {
471		if(!skip) skip = '';
472		if(!prefix) prefix = '';
473		return cname ? cname.replace(new RegExp('(\\s|^)'+skip+'(\\s|$)'),' ').replace(/[\s]*([\S]+)+[\s]*/gi,prefix+"$1 ") : '';
474	},
475	getElementsBySelector: function(selector, scope) {
476		if(typeof document.querySelectorAll === 'function') {
477			return (scope || document).querySelectorAll(selector);
478		}
479		var selectors = selector.split(',');
480		var resultList = [];
481		for(var s = 0; s < selectors.length; s++) {
482			var currentContext = [scope || document];
483			var tokens = selectors[s].replace(/^\s+/,'').replace(/\s+$/,'').split(' ');
484			for (var i = 0; i < tokens.length; i++) {
485				token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');
486				if (token.indexOf('#') > -1) {
487					var bits = token.split('#'), tagName = bits[0], id = bits[1];
488					var element = document.getElementById(id);
489					if (tagName && element.nodeName.toLowerCase() != tagName) {
490						return [];
491					}
492					currentContext = [element];
493					continue;
494				}
495				if (token.indexOf('.') > -1) {
496					var bits = token.split('.'), tagName = bits[0] || '*', className = bits[1], found = [], foundCount = 0;
497					for (var h = 0; h < currentContext.length; h++) {
498						var elements;
499						if (tagName == '*') {
500							elements = currentContext[h].getElementsByTagName('*');
501						} else {
502							elements = currentContext[h].getElementsByTagName(tagName);
503						}
504						for (var j = 0; j < elements.length; j++) {
505							found[foundCount++] = elements[j];
506						}
507					}
508					currentContext = [];
509					var currentContextIndex = 0;
510					for (var k = 0; k < found.length; k++) {
511						if (found[k].className && found[k].className.match(new RegExp('(\\s|^)'+className+'(\\s|$)'))) {
512							currentContext[currentContextIndex++] = found[k];
513						}
514					}
515					continue;
516				}
517				if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
518					var tagName = RegExp.$1 || '*', attrName = RegExp.$2, attrOperator = RegExp.$3, attrValue = RegExp.$4;
519					if(attrName.toLowerCase() == 'for' && this.browser.msie && this.browser.version < 8) {
520						attrName = 'htmlFor';
521					}
522					var found = [], foundCount = 0;
523					for (var h = 0; h < currentContext.length; h++) {
524						var elements;
525						if (tagName == '*') {
526							elements = currentContext[h].getElementsByTagName('*');
527						} else {
528							elements = currentContext[h].getElementsByTagName(tagName);
529						}
530						for (var j = 0; elements[j]; j++) {
531							found[foundCount++] = elements[j];
532						}
533					}
534					currentContext = [];
535					var currentContextIndex = 0, checkFunction;
536					switch (attrOperator) {
537						case '=': checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue) }; break;
538						case '~': checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('(\\s|^)'+attrValue+'(\\s|$)'))) }; break;
539						case '|': checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))) }; break;
540						case '^': checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0) }; break;
541						case '$': checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length) }; break;
542						case '*': checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1) }; break;
543						default : checkFunction = function(e) { return e.getAttribute(attrName) };
544					}
545					currentContext = [];
546					var currentContextIndex = 0;
547					for (var k = 0; k < found.length; k++) {
548						if (checkFunction(found[k])) {
549							currentContext[currentContextIndex++] = found[k];
550						}
551					}
552					continue;
553				}
554				tagName = token;
555				var found = [], foundCount = 0;
556				for (var h = 0; h < currentContext.length; h++) {
557					var elements = currentContext[h].getElementsByTagName(tagName);
558					for (var j = 0; j < elements.length; j++) {
559						found[foundCount++] = elements[j];
560					}
561				}
562				currentContext = found;
563			}
564			resultList = [].concat(resultList,currentContext);
565		}
566		return resultList;
567	},
568	scrollSize: (function(){
569		var content, hold, sizeBefore, sizeAfter;
570		function buildSizer(){
571			if(hold) removeSizer();
572			content = document.createElement('div');
573			hold = document.createElement('div');
574			hold.style.cssText = 'position:absolute;overflow:hidden;width:100px;height:100px';
575			hold.appendChild(content);
576			document.body.appendChild(hold);
577		}
578		function removeSizer(){
579			document.body.removeChild(hold);
580			hold = null;
581		}
582		function calcSize(vertical) {
583			buildSizer();
584			content.style.cssText = 'height:'+(vertical ? '100%' : '200px');
585			sizeBefore = (vertical ? content.offsetHeight : content.offsetWidth);
586			hold.style.overflow = 'scroll'; content.innerHTML = 1;
587			sizeAfter = (vertical ? content.offsetHeight : content.offsetWidth);
588			if(vertical && hold.clientHeight) sizeAfter = hold.clientHeight;
589			removeSizer();
590			return sizeBefore - sizeAfter;
591		}
592		return {
593			getWidth:function(){
594				return calcSize(false);
595			},
596			getHeight:function(){
597				return calcSize(true)
598			}
599		}
600	}()),
601	domReady: function (handler){
602		var called = false
603		function ready() {
604			if (called) return;
605			called = true;
606			handler();
607		}
608		if (document.addEventListener) {
609			document.addEventListener("DOMContentLoaded", ready, false);
610		} else if (document.attachEvent) {
611			if (document.documentElement.doScroll && window == window.top) {
612				function tryScroll(){
613					if (called) return
614					if (!document.body) return
615					try {
616						document.documentElement.doScroll("left")
617						ready()
618					} catch(e) {
619						setTimeout(tryScroll, 0)
620					}
621				}
622				tryScroll()
623			}
624			document.attachEvent("onreadystatechange", function(){
625				if (document.readyState === "complete") {
626					ready()
627				}
628			})
629		}
630		if (window.addEventListener) window.addEventListener('load', ready, false)
631		else if (window.attachEvent) window.attachEvent('onload', ready)
632	},
633	event: (function(){
634		var guid = 0;
635		function fixEvent(e) {
636			e = e || window.event;
637			if (e.isFixed) {
638				return e;
639			}
640			e.isFixed = true;
641			e.preventDefault = e.preventDefault || function(){this.returnValue = false}
642			e.stopPropagation = e.stopPropagaton || function(){this.cancelBubble = true}
643			if (!e.target) {
644				e.target = e.srcElement
645			}
646			if (!e.relatedTarget && e.fromElement) {
647				e.relatedTarget = e.fromElement == e.target ? e.toElement : e.fromElement;
648			}
649			if (e.pageX == null && e.clientX != null) {
650				var html = document.documentElement, body = document.body;
651				e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0);
652				e.pageY = e.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0);
653			}
654			if (!e.which && e.button) {
655				e.which = e.button & 1 ? 1 : (e.button & 2 ? 3 : (e.button & 4 ? 2 : 0));
656			}
657			if(e.type === "DOMMouseScroll" || e.type === 'mousewheel') {
658				e.mWheelDelta = 0;
659				if (e.wheelDelta) {
660					e.mWheelDelta = e.wheelDelta/120;
661				} else if (e.detail) {
662					e.mWheelDelta = -e.detail/3;
663				}
664			}
665			return e;
666		}
667		function commonHandle(event, customScope) {
668			event = fixEvent(event);
669			var handlers = this.events[event.type];
670			for (var g in handlers) {
671				var handler = handlers[g];
672				var ret = handler.call(customScope || this, event);
673				if (ret === false) {
674					event.preventDefault()
675					event.stopPropagation()
676				}
677			}
678		}
679		var publicAPI = {
680			add: function(elem, type, handler, forcedScope) {
681				if (elem.setInterval && (elem != window && !elem.frameElement)) {
682					elem = window;
683				}
684				if (!handler.guid) {
685					handler.guid = ++guid;
686				}
687				if (!elem.events) {
688					elem.events = {};
689					elem.handle = function(event) {
690						return commonHandle.call(elem, event);
691					}
692				}
693				if (!elem.events[type]) {
694					elem.events[type] = {};
695					if (elem.addEventListener) elem.addEventListener(type, elem.handle, false);
696					else if (elem.attachEvent) elem.attachEvent("on" + type, elem.handle);
697					if(type === 'mousewheel') {
698						publicAPI.add(elem, 'DOMMouseScroll', handler, forcedScope);
699					}
700				}
701				var fakeHandler = jcf.lib.bind(handler, forcedScope);
702				fakeHandler.guid = handler.guid;
703				elem.events[type][handler.guid] = forcedScope ? fakeHandler : handler;
704			},
705			remove: function(elem, type, handler) {
706				var handlers = elem.events && elem.events[type];
707				if (!handlers) return;
708				delete handlers[handler.guid];
709				for(var any in handlers) return;
710				if (elem.removeEventListener) elem.removeEventListener(type, elem.handle, false);
711				else if (elem.detachEvent) elem.detachEvent("on" + type, elem.handle);
712				delete elem.events[type];
713				for (var any in elem.events) return;
714				try {
715					delete elem.handle;
716					delete elem.events;
717				} catch(e) {
718					if(elem.removeAttribute) {
719						elem.removeAttribute("handle");
720						elem.removeAttribute("events");
721					}
722				}
723				if(type === 'mousewheel') {
724					publicAPI.remove(elem, 'DOMMouseScroll', handler);
725				}
726			}
727		}
728		return publicAPI;
729	}())
730}
731
732// custom select module
733jcf.addModule({
734	name:'select',
735	selector:'select',
736	defaultOptions: {
737		useNativeDropOnMobileDevices: true,
738		hideDropOnScroll: true,
739		showNativeDrop: false,
740		handleDropPosition: true,
741		selectDropPosition: 'bottom', // or 'top'
742		wrapperClass:'select-area',
743		focusClass:'select-focus',
744		dropActiveClass:'select-active',
745		selectedClass:'item-selected',
746		currentSelectedClass:'current-selected',
747		disabledClass:'select-disabled',
748		valueSelector:'span.center',
749		optGroupClass:'optgroup',
750		openerSelector:'a.select-opener',
751		selectStructure:'<span class="left"></span><span class="center"></span><a class="select-opener"></a>',
752		wrapperTag: 'span',
753		classPrefix:'select-',
754		dropMaxHeight: 200,
755		dropFlippedClass: 'select-options-flipped',
756		dropHiddenClass:'options-hidden',
757		dropScrollableClass:'options-overflow',
758		dropClass:'select-options',
759		dropClassPrefix:'drop-',
760		dropStructure:'<div class="drop-holder"><div class="drop-list"></div></div>',
761		dropSelector:'div.drop-list'
762	},
763	checkElement: function(el){
764		return (!el.size && !el.multiple);
765	},
766	setupWrapper: function(){
767		jcf.lib.addClass(this.fakeElement, this.options.wrapperClass);
768		this.realElement.parentNode.insertBefore(this.fakeElement, this.realElement);
769		this.fakeElement.innerHTML = this.options.selectStructure;
770		this.fakeElement.style.width = (this.realElement.offsetWidth > 0 ? this.realElement.offsetWidth + 'px' : 'auto');
771
772		// show native drop if specified in options
773		if(jcf.baseOptions.useNativeDropOnMobileDevices && (jcf.isTouchDevice || jcf.isWinPhoneDevice)) {
774			this.options.showNativeDrop = true;
775		}
776		if(this.options.showNativeDrop) {
777			this.fakeElement.appendChild(this.realElement);
778			jcf.lib.removeClass(this.realElement, this.options.hiddenClass);
779			jcf.lib.setStyles(this.realElement, {
780				top:0,
781				left:0,
782				margin:0,
783				padding:0,
784				opacity:0,
785				border:'none',
786				position:'absolute',
787				width: jcf.lib.getInnerWidth(this.fakeElement) - 1,
788				height: jcf.lib.getInnerHeight(this.fakeElement) - 1
789			});
790			jcf.lib.event.add(this.realElement, 'touchstart', function(){
791				this.realElement.title = '';
792			}, this)
793		}
794
795		// create select body
796		this.opener = jcf.lib.queryBySelector(this.options.openerSelector, this.fakeElement)[0];
797		this.valueText = jcf.lib.queryBySelector(this.options.valueSelector, this.fakeElement)[0];
798		jcf.lib.disableTextSelection(this.valueText);
799		this.opener.jcf = this;
800
801		if(!this.options.showNativeDrop) {
802			this.createDropdown();
803			this.refreshState();
804			this.onControlReady(this);
805			this.hideDropdown(true);
806		} else {
807			this.refreshState();
808		}
809		this.addEvents();
810	},
811	addEvents: function(){
812		if(this.options.showNativeDrop) {
813			jcf.lib.event.add(this.realElement, 'click', this.onChange, this);
814		} else {
815			jcf.lib.event.add(this.fakeElement, 'click', this.toggleDropdown, this);
816		}
817		jcf.lib.event.add(this.realElement, 'change', this.onChange, this);
818	},
819	onFakeClick: function() {
820		// do nothing (drop toggles by toggleDropdown method)
821	},
822	onFocus: function(){
823		jcf.modules[this.name].superclass.onFocus.apply(this, arguments);
824		if(!this.options.showNativeDrop) {
825			// Mac Safari Fix
826			if(jcf.lib.browser.safariMac) {
827				this.realElement.setAttribute('size','2');
828			}
829			jcf.lib.event.add(this.realElement, 'keydown', this.onKeyDown, this);
830			if(jcf.activeControl && jcf.activeControl != this) {
831				jcf.activeControl.hideDropdown();
832				jcf.activeControl = this;
833			}
834		}
835	},
836	onBlur: function(){
837		if(!this.options.showNativeDrop) {
838			// Mac Safari Fix
839			if(jcf.lib.browser.safariMac) {
840				this.realElement.removeAttribute('size');
841			}
842			if(!this.isActiveDrop() || !this.isOverDrop()) {
843				jcf.modules[this.name].superclass.onBlur.apply(this);
844				if(jcf.activeControl === this) jcf.activeControl = null;
845				if(!jcf.isTouchDevice) {
846					this.hideDropdown();
847				}
848			}
849			jcf.lib.event.remove(this.realElement, 'keydown', this.onKeyDown);
850		} else {
851			jcf.modules[this.name].superclass.onBlur.apply(this);
852		}
853	},
854	onChange: function() {
855		this.refreshState();
856	},
857	onKeyDown: function(e){
858		this.dropOpened = true;
859		jcf.tmpFlag = true;
860		setTimeout(function(){jcf.tmpFlag = false},100);
861		var context = this;
862		context.keyboardFix = true;
863		setTimeout(function(){
864			context.refreshState();
865		},10);
866		if(e.keyCode == 13) {
867			context.toggleDropdown.apply(context);
868			return false;
869		}
870	},
871	onResizeWindow: function(e){
872		if(this.isActiveDrop()) {
873			this.hideDropdown();
874		}
875	},
876	onScrollWindow: function(e){
877		if(this.options.hideDropOnScroll) {
878			this.hideDropdown();
879		} else if(this.isActiveDrop()) {
880			this.positionDropdown();
881		}
882	},
883	onOptionClick: function(e){
884		var opener = e.target && e.target.tagName && e.target.tagName.toLowerCase() == 'li' ? e.target : jcf.lib.getParent(e.target, 'li');
885		if(opener) {
886			this.dropOpened = true;
887			this.realElement.selectedIndex = parseInt(opener.getAttribute('rel'));
888			if(jcf.isTouchDevice) {
889				this.onFocus();
890			} else {
891				this.realElement.focus();
892			}
893			this.refreshState();
894
895			this.hideDropdown();
896			jcf.lib.fireEvent(this.realElement, 'change');
897			$(e.target).attr('href', $(this.realElement).val());
898		}
899		return false;
900	},
901	onClickOutside: function(e){
902		if(jcf.tmpFlag) {
903			jcf.tmpFlag = false;
904			return;
905		}
906		if(!jcf.lib.isParent(this.fakeElement, e.target) && !jcf.lib.isParent(this.selectDrop, e.target)) {
907			this.hideDropdown();
908		}
909	},
910	onDropHover: function(e){
911		if(!this.keyboardFix) {
912			this.hoverFlag = true;
913			var opener = e.target && e.target.tagName && e.target.tagName.toLowerCase() == 'li' ? e.target : jcf.lib.getParent(e.target, 'li');
914			if(opener) {
915				this.realElement.selectedIndex = parseInt(opener.getAttribute('rel'));
916				this.refreshSelectedClass(parseInt(opener.getAttribute('rel')));
917			}
918		} else {
919			this.keyboardFix = false;
920		}
921	},
922	onDropLeave: function(){
923		this.hoverFlag = false;
924	},
925	isActiveDrop: function(){
926		return !jcf.lib.hasClass(this.selectDrop, this.options.dropHiddenClass);
927	},
928	isOverDrop: function(){
929		return this.hoverFlag;
930	},
931	createDropdown: function(){
932		// remove old dropdown if exists
933		if(this.selectDrop) {
934			this.selectDrop.parentNode.removeChild(this.selectDrop);
935		}
936
937		// create dropdown holder
938		this.selectDrop = document.createElement('div');
939		this.selectDrop.className = this.options.dropClass;
940		this.selectDrop.innerHTML = this.options.dropStructure;
941		jcf.lib.setStyles(this.selectDrop, {position:'absolute'});
942		this.selectList = jcf.lib.queryBySelector(this.options.dropSelector,this.selectDrop)[0];
943		jcf.lib.addClass(this.selectDrop, this.options.dropHiddenClass);
944		document.body.appendChild(this.selectDrop);
945		this.selectDrop.jcf = this;
946		jcf.lib.event.add(this.selectDrop, 'click', this.onOptionClick, this);
947		jcf.lib.event.add(this.selectDrop, 'mouseover', this.onDropHover, this);
948		jcf.lib.event.add(this.selectDrop, 'mouseout', this.onDropLeave, this);
949		this.buildDropdown();
950	},
951	buildDropdown: function() {
952		// build select options / optgroups
953		this.buildDropdownOptions();
954
955		// position and resize dropdown
956		this.positionDropdown();
957
958		// cut dropdown if height exceedes
959		this.buildDropdownScroll();
960	},
961	buildDropdownOptions: function() {
962		this.resStructure = '';
963		this.optNum = 0;
964		for(var i = 0; i < this.realElement.children.length; i++) {
965			this.resStructure += this.buildElement(this.realElement.children[i], i) +'\n';
966		}
967		this.selectList.innerHTML = this.resStructure;
968	},
969	buildDropdownScroll: function() {
970		if(this.options.dropMaxHeight) {
971			if(this.selectDrop.offsetHeight > this.options.dropMaxHeight) {
972				this.selectList.style.height = this.options.dropMaxHeight+'px';
973				this.selectList.style.overflow = 'auto';
974				this.selectList.style.overflowX = 'hidden';
975				jcf.lib.addClass(this.selectDrop, this.options.dropScrollableClass);
976			}
977		}
978		jcf.lib.addClass(this.selectDrop, jcf.lib.getAllClasses(this.realElement.className, this.options.dropClassPrefix, jcf.baseOptions.hiddenClass));
979	},
980	parseOptionTitle: function(optTitle) {
981		return (typeof optTitle === 'string' && /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i.test(optTitle)) ? optTitle : '';
982	},
983	buildElement: function(obj, index){
984		// build option
985		var res = '', optImage;
986		if(obj.tagName.toLowerCase() == 'option') {
987			if(!jcf.lib.prevSibling(obj) || jcf.lib.prevSibling(obj).tagName.toLowerCase() != 'option') {
988				res += '<ul>';
989			}
990
991			optImage = this.parseOptionTitle(obj.title);
992			res += '<li rel="'+(this.optNum++)+'" class="'+(obj.className? obj.className + ' ' : '')+(index % 2 ? 'option-even ' : '')+'jcfcalc"><a href="#">'+(optImage ? '<img src="'+optImage+'" alt="" />
992' : '')+'<span>' + obj.innerHTML + '</span></a></li>';
993			if(!jcf.lib.nextSibling(obj) || jcf.lib.nextSibling(obj).tagName.toLowerCase() != 'option') {
994				res += '</ul>';
995			}
996			return res;
997		}
998		// build option group with options
999		else if(obj.tagName.toLowerCase() == 'optgroup' && obj.label) {
1000			res += '<div class="'+this.options.optGroupClass+'">';
1001			res += '<strong class="jcfcalc"><em>'+(obj.label)+'</em></strong>';
1002			for(var i = 0; i < obj.children.length; i++) {
1003				res += this.buildElement(obj.children[i], i);
1004			}
1005			res += '</div>';
1006			return res;
1007		}
1008	},
1009	positionDropdown: function(){
1010		var ofs = jcf.lib.getOffset(this.fakeElement), selectAreaHeight = this.fakeElement.offsetHeight, selectDropHeight = this.selectDrop.offsetHeight;
1011		var fitInTop = ofs.top - selectDropHeight >= jcf.lib.getScrollTop() && jcf.lib.getScrollTop() + jcf.lib.getWindowHeight() < ofs.top + selectAreaHeight + selectDropHeight;
1012
1013
1014		if((this.options.handleDropPosition && fitInTop) || this.options.selectDropPosition === 'top') {
1015			this.selectDrop.style.top = (ofs.top - selectDropHeight)+'px';
1016			jcf.lib.addClass(this.selectDrop, this.options.dropFlippedClass);
1017		} else {
1018			this.selectDrop.style.top = (ofs.top + selectAreaHeight)+'px';
1019			jcf.lib.removeClass(this.selectDrop, this.options.dropFlippedClass);
1020		}
1021		this.selectDrop.style.left = ofs.left+'px';
1022		this.selectDrop.style.width = this.fakeElement.offsetWidth+'px';
1023	},
1024	showDropdown: function(){
1025		document.body.appendChild(this.selectDrop);
1026		jcf.lib.removeClass(this.selectDrop, this.options.dropHiddenClass);
1027		jcf.lib.addClass(this.fakeElement,this.options.dropActiveClass);
1028		this.positionDropdown();
1029
1030		// highlight current active item
1031		var activeItem = this.getFakeActiveOption();
1032		this.removeClassFromItems(this.options.currentSelectedClass);
1033		jcf.lib.addClass(activeItem, this.options.currentSelectedClass);
1034
1035		// show current dropdown
1036		jcf.lib.event.add(window, 'resize', this.onResizeWindow, this);
1037		jcf.lib.event.add(window, 'scroll', this.onScrollWindow, this);
1038		jcf.lib.event.add(document, jcf.eventPress, this.onClickOutside, this);
1039		this.positionDropdown();
1040	},
1041	hideDropdown: function(partial){
1042		if(this.selectDrop.parentNode) {
1043			if(this.selectDrop.offsetWidth) {
1044				this.selectDrop.parentNode.removeChild(this.selectDrop);
1045			}
1046			if(partial) {
1047				return;
1048			}
1049		}
1050		if(typeof this.origSelectedIndex === 'number') {
1051			this.realElement.selectedIndex = this.origSelectedIndex;
1052		}
1053		jcf.lib.removeClass(this.fakeElement,this.options.dropActiveClass);
1054		jcf.lib.addClass(this.selectDrop, this.options.dropHiddenClass);
1055		jcf.lib.event.remove(window, 'resize', this.onResizeWindow);
1056		jcf.lib.event.remove(window, 'scroll', this.onScrollWindow);
1057		jcf.lib.event.remove(document.documentElement, jcf.eventPress, this.onClickOutside);
1058		if(jcf.isTouchDevice) {
1059			this.onBlur();
1060		}
1061	},
1062	toggleDropdown: function(){
1063		if(!this.realElement.disabled) {
1064			if(jcf.isTouchDevice) {
1065				this.onFocus();
1066			} else {
1067				this.realElement.focus();
1068			}
1069			if(this.isActiveDrop()) {
1070				this.hideDropdown();
1071			} else {
1072				this.showDropdown();
1073			}
1074			this.refreshState();
1075		}
1076	},
1077	scrollToItem: function(){
1078		if(this.isActiveDrop()) {
1079			var dropHeight = this.selectList.offsetHeight;
1080			var offsetTop = this.calcOptionOffset(this.getFakeActiveOption());
1081			var sTop = this.selectList.scrollTop;
1082			var oHeight = this.getFakeActiveOption().offsetHeight;
1083			//offsetTop+=sTop;
1084
1085			if(offsetTop >= sTop + dropHeight) {
1086				this.selectList.scrollTop = offsetTop - dropHeight + oHeight;
1087			} else if(offsetTop < sTop) {
1088				this.selectList.scrollTop = offsetTop;
1089			}
1090		}
1091	},
1092	getFakeActiveOption: function(c) {
1093		return jcf.lib.queryBySelector('li[rel="'+(typeof c === 'number' ? c : this.realElement.selectedIndex) +'"]',this.selectList)[0];
1094	},
1095	calcOptionOffset: function(fake) {
1096		var h = 0;
1097		var els = jcf.lib.queryBySelector('.jcfcalc',this.selectList);
1098		for(var i = 0; i < els.length; i++) {
1099			if(els[i] == fake) break;
1100			h+=els[i].offsetHeight;
1101		}
1102		return h;
1103	},
1104	childrenHasItem: function(hold,item) {
1105		var items = hold.getElementsByTagName('*');
1106		for(i = 0; i < items.length; i++) {
1107			if(items[i] == item) return true;
1108		}
1109		return false;
1110	},
1111	removeClassFromItems: function(className){
1112		var children = jcf.lib.queryBySelector('li',this.selectList);
1113		for(var i = children.length - 1; i >= 0; i--) {
1114			jcf.lib.removeClass(children[i], className);
1115		}
1116	},
1117	setSelectedClass: function(c){
1118		jcf.lib.addClass(this.getFakeActiveOption(c), this.options.selectedClass);
1119	},
1120	refreshSelectedClass: function(c){
1121		if(!this.options.showNativeDrop) {
1122			this.removeClassFromItems(this.options.selectedClass);
1123			this.setSelectedClass(c);
1124		}
1125		if(this.realElement.disabled) {
1126			jcf.lib.addClass(this.fakeElement, this.options.disabledClass);
1127			if(this.labelFor) {
1128				jcf.lib.addClass(this.labelFor, this.options.labelDisabledClass);
1129			}
1130		} else {
1131			jcf.lib.removeClass(this.fakeElement, this.options.disabledClass);
1132			if(this.labelFor) {
1133				jcf.lib.removeClass(this.labelFor, this.options.labelDisabledClass);
1134			}
1135		}
1136	},
1137	refreshSelectedText: function() {
1138		if(!this.dropOpened && this.realElement.title) {
1139			this.valueText.innerHTML = this.realElement.title;
1140		} else {
1141			if(this.realElement.options[this.realElement.selectedIndex].title) {
1142				var optImage = this.parseOptionTitle(this.realElement.options[this.realElement.selectedIndex].title);
1143				this.valueText.innerHTML = (optImage ? '<img src="'+optImage+'" alt="" />' : '') + this.realElement.options[this.realElement.selectedIndex].innerHTML;
1144			} else {
1145				this.valueText.innerHTML = this.realElement.options[this.realElement.selectedIndex].innerHTML;
1146			}
1147		}
1148	},
1149	refreshState: function(){
1150		this.origSelectedIndex = this.realElement.selectedIndex;
1151		this.refreshSelectedClass();
1152		this.refreshSelectedText();
1153		if(!this.options.showNativeDrop) {
1154			this.positionDropdown();
1155			if(this.selectDrop.offsetWidth) {
1156				this.scrollToItem();
1157			}
1158		}
1159	}
1160});
1161
1162
1163/*
1164 * Utility module
1165 */
1166lib = {
1167	hasClass: function(el,cls) {
1168		return el && el.className ? el.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)')) : false;
1169	},
1170	addClass: function(el,cls) {
1171		if (el && !this.hasClass(el,cls)) el.className += " "+cls;
1172	},
1173	removeClass: function(el,cls) {
1174		if (el && this.hasClass(el,cls)) {el.className=el.className.replace(new RegExp('(\\s|^)'+cls+'(\\s|$)'), '');}
1175	},
1176	extend: function(obj) {
1177		for(var i = 1; i < arguments.length; i++) {
1178			for(var p in arguments[i]) {
1179				if(arguments[i].hasOwnProperty(p)) {
1180					obj[p] = arguments[i][p];
1181				}
1182			}
1183		}
1184		return obj;
1185	},
1186	each: function(obj, callback) {
1187		var property, len;
1188		if(typeof obj.length === 'number') {
1189			for(property = 0, len = obj.length; property < len; property++) {
1190				if(callback.call(obj[property], property, obj[property]) === false) {
1191					break;
1192				}
1193			}
1194		} else {
1195			for(property in obj) {
1196				if(obj.hasOwnProperty(property)) {
1197					if(callback.call(obj[property], property, obj[property]) === false) {
1198						break;
1199					}
1200				}
1201			}
1202		}
1203	},
1204	event: (function() {
1205		var fixEvent = function(e) {
1206			e = e || window.event;
1207			if(e.isFixed) return e; else e.isFixed = true;
1208			if(!e.target) e.target = e.srcElement;
1209			e.preventDefault = e.preventDefault || function() {this.returnValue = false;};
1210			e.stopPropagation = e.stopPropagation || function() {this.cancelBubble = true;};
1211			return e;
1212		};
1213		return {
1214			add: function(elem, event, handler) {
1215				if(!elem.events) {
1216					elem.events = {};
1217					elem.handle = function(e) {
1218						var ret, handlers = elem.events[e.type];
1219						e = fixEvent(e);
1220						for(var i = 0, len = handlers.length; i < len; i++) {
1221							if(handlers[i]) {
1222								ret = handlers[i].call(elem, e);
1223								if(ret === false) {
1224									e.preventDefault();
1225									e.stopPropagation();
1226								}
1227							}
1228						}
1229					};
1230				}
1231				if(!elem.events[event]) {
1232					elem.events[event] = [];
1233					if(elem.addEventListener) elem.addEventListener(event, elem.handle, false);
1234					else if(elem.attachEvent) elem.attachEvent('on'+event, elem.handle);
1235				}
1236				elem.events[event].push(handler);
1237			},
1238			remove: function(elem, event, handler) {
1239				var handlers = elem.events[event];
1240				for(var i = handlers.length - 1; i >= 0; i--) {
1241					if(handlers[i] === handler) {
1242						handlers.splice(i,1);
1243					}
1244				}
1245				if(!handlers.length) {
1246					delete elem.events[event];
1247					if(elem.removeEventListener) elem.removeEventListener(event, elem.handle, false);
1248					else if(elem.detachEvent) elem.detachEvent('on'+event, elem.handle);
1249				}
1250			}
1251		};
1252	}()),
1253	queryElementsBySelector: function(selector, scope) {
1254		scope = scope || document;
1255		if(!selector) return [];
1256		if(selector === '>*') return scope.children;
1257		if(typeof document.querySelectorAll === 'function') {
1258			return scope.querySelectorAll(selector);
1259		}
1260		var selectors = selector.split(',');
1261		var resultList = [];
1262		for(var s = 0; s < selectors.length; s++) {
1263			var currentContext = [scope || document];
1264			var tokens = selectors[s].replace(/^\s+/,'').replace(/\s+$/,'').split(' ');
1265			for (var i = 0; i < tokens.length; i++) {
1266				token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');
1267				if (token.indexOf('#') > -1) {
1268					var bits = token.split('#'), tagName = bits[0], id = bits[1];
1269					var element = document.getElementById(id);
1270					if (element && tagName && element.nodeName.toLowerCase() != tagName) {
1271						return [];
1272					}
1273					currentContext = element ? [element] : [];
1274					continue;
1275				}
1276				if (token.indexOf('.') > -1) {
1277					var bits = token.split('.'), tagName = bits[0] || '*', className = bits[1], found = [], foundCount = 0;
1278					for (var h = 0; h < currentContext.length; h++) {
1279						var elements;
1280						if (tagName == '*') {
1281							elements = currentContext[h].getElementsByTagName('*');
1282						} else {
1283							elements = currentContext[h].getElementsByTagName(tagName);
1284						}
1285						for (var j = 0; j < elements.length; j++) {
1286							found[foundCount++] = elements[j];
1287						}
1288					}
1289					currentContext = [];
1290					var currentContextIndex = 0;
1291					for (var k = 0; k < found.length; k++) {
1292						if (found[k].className && found[k].className.match(new RegExp('(\\s|^)'+className+'(\\s|$)'))) {
1293							currentContext[currentContextIndex++] = found[k];
1294						}
1295					}
1296					continue;
1297				}
1298				if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
1299					var tagName = RegExp.$1 || '*', attrName = RegExp.$2, attrOperator = RegExp.$3, attrValue = RegExp.$4;
1300					if(attrName.toLowerCase() == 'for' && this.browser.msie && this.browser.version < 8) {
1301						attrName = 'htmlFor';
1302					}
1303					var found = [], foundCount = 0;
1304					for (var h = 0; h < currentContext.length; h++) {
1305						var elements;
1306						if (tagName == '*') {
1307							elements = currentContext[h].getElementsByTagName('*');
1308						} else {
1309							elements = currentContext[h].getElementsByTagName(tagName);
1310						}
1311						for (var j = 0; elements[j]; j++) {
1312							found[foundCount++] = elements[j];
1313						}
1314					}
1315					currentContext = [];
1316					var currentContextIndex = 0, checkFunction;
1317					switch (attrOperator) {
1318						case '=': checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue) }; break;
1319						case '~': checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('(\\s|^)'+attrValue+'(\\s|$)'))) }; break;
1320						case '|': checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))) }; break;
1321						case '^': checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0) }; break;
1322						case '$': checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length) }; break;
1323						case '*': checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1) }; break;
1324						default : checkFunction = function(e) { return e.getAttribute(attrName) };
1325					}
1326					currentContext = [];
1327					var currentContextIndex = 0;
1328					for (var k = 0; k < found.length; k++) {
1329						if (checkFunction(found[k])) {
1330							currentContext[currentContextIndex++] = found[k];
1331						}
1332					}
1333					continue;
1334				}
1335				tagName = token;
1336				var found = [], foundCount = 0;
1337				for (var h = 0; h < currentContext.length; h++) {
1338					var elements = currentContext[h].getElementsByTagName(tagName);
1339					for (var j = 0; j < elements.length; j++) {
1340						found[foundCount++] = elements[j];
1341					}
1342				}
1343				currentContext = found;
1344			}
1345			resultList = [].concat(resultList,currentContext);
1346		}
1347		return resultList;
1348	},
1349	trim: function (str) {
1350		return str.replace(/^\s+/, '').replace(/\s+$/, '');
1351	},
1352	bind: function(f, scope, forceArgs){
1353		return function() {return f.apply(scope, typeof forceArgs !== 'undefined' ? [forceArgs] : arguments);};
1354	}
1355};
1356
1357/*
1358 * jQuery Accordion plugin
1359 */
1360;(function($){
1361	$.fn.slideAccordion = function(opt){
1362		// default options
1363		var options = $.extend({
1364			addClassBeforeAnimation: false,
1365			activeClass:'active',
1366			opener:'.opener',
1367			slider:'.slide',
1368			animSpeed: 300,
1369			collapsible:true,
1370			event:'click'
1371		},opt);
1372
1373		return this.each(function(){
1374			// options
1375			var accordion = $(this);
1376			var items = accordion.find(':has('+options.slider+')');
1377
1378			items.each(function(){
1379				var item = $(this);
1380				var opener = item.find(options.opener);
1381				var slider = item.find(options.slider);
1382				opener.bind(options.event, function(e){
1383					if(!slider.is(':animated')) {
1384						if(item.hasClass(options.activeClass)) {
1385							if(options.collapsible) {
1386								slider.slideUp(options.animSpeed, function(){
1387									hideSlide(slider);
1388									item.removeClass(options.activeClass);
1389								});
1390							}
1391						} else {
1392							// show active
1393							var levelItems = item.siblings('.'+options.activeClass);
1394							var sliderElements = levelItems.find(options.slider);
1395							item.addClass(options.activeClass);
1396							showSlide(slider).hide().slideDown(options.animSpeed);
1397
1398							// collapse others
1399							sliderElements.slideUp(options.animSpeed, function(){
1400								levelItems.removeClass(options.activeClass);
1401								hideSlide(sliderElements);
1402							});
1403						}
1404					}
1405					e.preventDefault();
1406				});
1407				if(item.hasClass(options.activeClass)) showSlide(slider); else hideSlide(slider);
1408			});
1409		});
1410	};
1411
1412	// accordion slide visibility
1413	var showSlide = function(slide) {
1414		return slide.css({position:'', top: '', left: '', width: '' });
1415	};
1416	var hideSlide = function(slide) {
1417		return slide.show().css({position:'absolute', top: -9999, left: -9999, width: slide.width() });
1418	};
1419}(jQuery));
1420
1421/*
1422 * Popups plugin
1423 */
1424;(function($) {
1425	function ContentPopup(opt) {
1426		this.options = $.extend({
1427			holder: null,
1428			popup: '.popup',
1429			btnOpen: '.open',
1430			btnClose: '.close',
1431			openClass: 'popup-active',
1432			clickEvent: 'click',
1433			mode: 'click',
1434			hideOnClickLink: true,
1435			hideOnClickOutside: true,
1436			delay: 50
1437		}, opt);
1438		if(this.options.holder) {
1439			this.holder = $(this.options.holder);
1440			this.init();
1441		}
1442	}
1443	ContentPopup.prototype = {
1444		init: function() {
1445			this.findElements();
1446			this.attachEvents();
1447		},
1448		findElements: function() {
1449			this.popup = this.holder.find(this.options.popup);
1450			this.btnOpen = this.holder.find(this.options.btnOpen);
1451			this.btnClose = this.holder.find(this.options.btnClose);
1452		},
1453		attachEvents: function() {
1454			// handle popup openers
1455			var self = this;
1456			this.clickMode = isTouchDevice || (self.options.mode === self.options.clickEvent);
1457
1458			if(this.clickMode) {
1459				// handle click mode
1460				this.btnOpen.bind(self.options.clickEvent, function(e) {
1461					if(self.holder.hasClass(self.options.openClass)) {
1462						if(self.options.hideOnClickLink) {
1463							self.hidePopup();
1464						}
1465					} else {
1466						self.showPopup();
1467					}
1468					e.preventDefault();
1469				});
1470
1471				// prepare outside click handler
1472				this.outsideClickHandler = this.bind(this.outsideClickHandler, this);
1473			} else {
1474				// handle hover mode
1475				var timer, delayedFunc = function(func) {
1476					clearTimeout(timer);
1477					timer = setTimeout(function() {
1478						func.call(self);
1479					}, self.options.delay);
1480				};
1481				this.btnOpen.bind('mouseover', function() {
1482					delayedFunc(self.showPopup);
1483				}).bind('mouseout', function() {
1484					delayedFunc(self.hidePopup);
1485				});
1486				this.popup.bind('mouseover', function() {
1487					delayedFunc(self.showPopup);
1488				}).bind('mouseout', function() {
1489					delayedFunc(self.hidePopup);
1490				});
1491			}
1492
1493			// handle close buttons
1494			this.btnClose.bind(self.options.clickEvent, function(e) {
1495				self.hidePopup();
1496				e.preventDefault();
1497			});
1498		},
1499		outsideClickHandler: function(e) {
1500			// hide popup if clicked outside
1501			var currentNode = (e.changedTouches ? e.changedTouches[0] : e).target;
1502			if(!$(currentNode).parents().filter(this.holder).length) {
1503				this.hidePopup();
1504			}
1505		},
1506		showPopup: function() {
1507			// reveal popup
1508			this.holder.addClass(this.options.openClass);
1509			this.popup.css({display:'block'});
1510
1511			// outside click handler
1512			if(this.clickMode && this.options.hideOnClickOutside && !this.outsideHandlerActive) {
1513				this.outsideHandlerActive = true;
1514				$(document).bind('click touchstart', this.outsideClickHandler);
1515			}
1516		},
1517		hidePopup: function() {
1518			// hide popup
1519			this.holder.removeClass(this.options.openClass);
1520			this.popup.css({display:'none'});
1521
1522			// outside click handler
1523			if(this.clickMode && this.options.hideOnClickOutside && this.outsideHandlerActive) {
1524				this.outsideHandlerActive = false;
1525				$(document).unbind('click touchstart', this.outsideClickHandler);
1526			}
1527		},
1528		bind: function(f, scope, forceArgs){
1529			return function() {return f.apply(scope, forceArgs ? [forceArgs] : arguments);};
1530		}
1531	};
1532
1533	// detect touch devices
1534	var isTouchDevice = /MSIE 10.*Touch/.test(navigator.userAgent) || ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;
1535
1536	// jQuery plugin interface
1537	$.fn.contentPopup = function(opt) {
1538		return this.each(function() {
1539			new ContentPopup($.extend(opt, {holder: this}));
1540		});
1541	};
1542}(jQuery));
1543
1544/*
1545 * Convert navigation to select
1546 */
1547;(function($) {
1548	function NavigationSelect(options) {
1549		this.options = $.extend({
1550			list: null,
1551			levelIndentHTML: ' &bull; ',
1552			defaultOptionAttr: 'title',
1553			defaultOptionText: '...',
1554			selectClass: 'nav-select',
1555			activeClass: 'nav-active',
1556			defaultOptionClass: 'opt-default',
1557			hasDropClass: 'opt-sublevel',
1558			levelPrefixClass: 'opt-level-',
1559			useDefaultOption: true
1560		}, options);
1561		if(this.options.list) {
1562			this.createSelect();
1563			this.attachEvents();
1564		}
1565	}
1566	NavigationSelect.prototype = {
1567		createSelect: function() {
1568			var self = this;
1569			this.startIndex = 0;
1570			this.navigation = $(this.options.list);
1571			this.select = $('<select>').addClass(this.options.selectClass);
1572			this.createDefaultOption();
1573			this.createList(this.navigation, 0);
1574			this.select.insertBefore(this.navigation);
1575		},
1576		createDefaultOption: function() {
1577			if(this.options.useDefaultOption) {
1578				var attrText = this.navigation.attr(this.options.defaultOptionAttr);
1579				var defaultOption = $('<option>').addClass(this.options.defaultOptionClass).text(attrText || this.options.defaultOptionText);
1580				this.navigation.removeAttr(this.options.defaultOptionAttr);
1581				this.select.append(defaultOption);
1582				this.startIndex = 1;
1583			}
1584		},
1585		createList: function(list, level) {
1586			var self = this;
1587			list.children().each(function(index, item) {
1588				var listItem = $(this),
1589					listLink = listItem.find('a').eq(0),
1590					listDrop = listItem.find('ul').eq(0),
1591					hasDrop = listDrop.length > 0;
1592
1593				if(listLink.length) {
1594					self.select.append(self.createOption(listLink, hasDrop, level, listLink.hasClass(self.options.activeClass)));
1595				}
1596				if(hasDrop) {
1597					self.createList(listDrop, level + 1);
1598				}
1599			});
1600		},
1601		createOption: function(link, hasDrop, level, selected) {
1602			var optionHTML = this.getLevelIndent(level) + link.html();
1603			return $('<option>').html(optionHTML)
1604				.addClass(this.options.levelPrefixClass + (level + 1))
1605				.toggleClass(this.options.hasDropClass, hasDrop)
1606				.val(link.attr('href')).attr('selected', selected ? 'selected' : false);
1607		},
1608		getLevelIndent: function(level) {
1609			return (new Array(level + 1)).join(this.options.levelIndentHTML);
1610		},
1611		attachEvents: function() {
1612			// redirect on select change
1613			var self = this;
1614			this.select.change(function() {
1615				if(this.selectedIndex >= self.startIndex) {
1616					location.href = this.value;
1617				}
1618			});
1619		}
1620	};
1621
1622	// jquery pluginm interface
1623	$.fn.navigationSelect = function(opt) {
1624		return this.each(function() {
1625			new NavigationSelect($.extend({list: this}, opt));
1626		});
1627	};
1628}(jQuery));
1629
1630/*
1631 * Responsive Layout helper
1632 */
1633
1634ResponsiveHelper = (function($){
1635	// init variables
1636	var handlers = [];
1637	var win = $(window), prevWinWidth;
1638	var scrollBarWidth = 0;
1639
1640	// prepare resize handler
1641	function resizeHandler() {
1642		var winWidth = win.width() + scrollBarWidth;
1643		if(winWidth !== prevWinWidth) {
1644			prevWinWidth = winWidth;
1645
1646			// loop through range groups
1647			$.each(handlers, function(index, rangeObject){
1648				// disable current active area if needed
1649				$.each(rangeObject.data, function(property, item) {
1650					if((winWidth < item.range[0] || winWidth > item.range[1]) && item.currentActive) {
1651						item.currentActive = false;
1652						if(typeof item.disableCallback === 'function') {
1653							item.disableCallback();
1654						}
1655					}
1656				});
1657
1658				// enable areas that match current width
1659				$.each(rangeObject.data, function(property, item) {
1660					if(winWidth >= item.range[0] && winWidth <= item.range[1] && !item.currentActive) {
1661						// make callback
1662						item.currentActive = true;
1663						if(typeof item.enableCallback === 'function') {
1664							item.enableCallback();
1665						}
1666					}
1667				});
1668			});
1669		}
1670	}
1671	win.bind('load', function(){
1672		if( cr_browser == 'Opera' || cr_browser == 'Firefox' ) { 
1673			scrollBarWidth = window.innerWidth - $('body').width();
1674			resizeHandler();
1675		}
1676		win.bind('resize orientationchange', resizeHandler);
1677	});
1678
1679	// range parser
1680	function parseRange(rangeStr) {
1681		var rangeData = rangeStr.split('..');
1682		var x1 = parseInt(rangeData[0], 10) || -Infinity;
1683		var x2 = parseInt(rangeData[1], 10) || Infinity;
1684		return [x1, x2].sort(function(a, b){
1685			return a - b;
1686		});
1687	}
1688
1689	// export public functions
1690	return {
1691		addRange: function(ranges) {
1692			// parse data and add items to collection
1693			var result = {data:{}};
1694			$.each(ranges, function(property, data){
1695				result.data[property] = {
1696					range: parseRange(property),
1697					enableCallback: data.on,
1698					disableCallback: data.off
1699				};
1700			});
1701			handlers.push(result);
1702
1703			// call resizeHandler to recalculate all events
1704			resizeHandler();
1705		}
1706	};
1707}(jQuery));

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.