PageSourceSearch

https://www.cobhamsasuquo.com/wp-content/themes/croma/js/utilities.js

js cobhamsasuquo.com collected 2026-10-03 01:35:23 UTC 65,408 bytes, 1,961 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// placeholder class
1165;(function(){
1166	var placeholderCollection = [];
1167	PlaceholderInput = function() {
1168		this.options = {
1169			element:null,
1170			showUntilTyping:false,
1171			wrapWithElement:false,
1172			getParentByClass:false,
1173			showPasswordBullets:false,
1174			placeholderAttr:'value',
1175			inputFocusClass:'focus',
1176			inputActiveClass:'text-active',
1177			parentFocusClass:'parent-focus',
1178			parentActiveClass:'parent-active',
1179			labelFocusClass:'label-focus',
1180			labelActiveClass:'label-active',
1181			fakeElementClass:'input-placeholder-text'
1182		};
1183		placeholderCollection.push(this);
1184		this.init.apply(this,arguments);
1185	};
1186	PlaceholderInput.refreshAllInputs = function(except) {
1187		for(var i = 0; i < placeholderCollection.length; i++) {
1188			if(except !== placeholderCollection[i]) {
1189				placeholderCollection[i].refreshState();
1190			}
1191		}
1192	};
1193	PlaceholderInput.replaceByOptions = function(opt) {
1194		var inputs = [].concat(
1195			convertToArray(document.querySelectorAll('input.placeholder-input, textarea.placeholder-input'))
1196		);
1197		for(var i = 0; i < inputs.length; i++) {
1198			if(inputs[i].className.indexOf(opt.skipClass) < 0) {
1199				var inputType = getInputType(inputs[i]);
1200				var placeholderValue = inputs[i].getAttribute('placeholder');
1201				if(opt.focusOnly || (opt.clearInputs && (inputType === 'text' || inputType === 'email' || placeholderValue)) ||
1202					(opt.clearTextareas && inputType === 'textarea') ||
1203					(opt.clearPasswords && inputType === 'password')
1204				) {
1205					new PlaceholderInput({
1206						element:inputs[i],
1207						focusOnly: opt.focusOnly,
1208						wrapWithElement:opt.wrapWithElement,
1209						showUntilTyping:opt.showUntilTyping,
1210						getParentByClass:opt.getParentByClass,
1211						showPasswordBullets:opt.showPasswordBullets,
1212						placeholderAttr: placeholderValue ? 'placeholder' : opt.placeholderAttr
1213					});
1214				}
1215			}
1216		}
1217	};
1218	PlaceholderInput.prototype = {
1219		init: function(opt) {
1220			this.setOptions(opt);
1221			if(this.element && this.element.PlaceholderInst) {
1222				this.element.PlaceholderInst.refreshClasses();
1223			} else {
1224				this.element.PlaceholderInst = this;
1225				if(this.elementType !== 'radio' || this.elementType !== 'checkbox' || this.elementType !== 'file') {
1226					this.initElements();
1227					this.attachEvents();
1228					this.refreshClasses();
1229				}
1230			}
1231		},
1232		setOptions: function(opt) {
1233			for(var p in opt) {
1234				if(opt.hasOwnProperty(p)) {
1235					this.options[p] = opt[p];
1236				}
1237			}
1238			if(this.options.element) {
1239				this.element = this.options.element;
1240				this.elementType = getInputType(this.element);
1241				if(this.options.focusOnly) {
1242					this.wrapWithElement = false;
1243				} else {
1244					if(this.elementType === 'password' && this.options.showPasswordBullets) {
1245						this.wrapWithElement = false;
1246					} else {
1247						this.wrapWithElement = this.elementType === 'password' || this.options.showUntilTyping ? true : this.options.wrapWithElement;
1248					}
1249				}
1250				this.setPlaceholderValue(this.options.placeholderAttr);
1251			}
1252		},
1253		setPlaceholderValue: function(attr) {
1254			this.origValue = (attr === 'value' ? this.element.defaultValue : (this.element.getAttribute(attr) || ''));
1255			if(this.options.placeholderAttr !== 'value') {
1256				this.element.removeAttribute(this.options.placeholderAttr);
1257			}
1258		},
1259		initElements: function() {
1260			// create fake element if needed
1261			if(this.wrapWithElement) {
1262				this.fakeElement = document.createElement('span');
1263				this.fakeElement.className = this.options.fakeElementClass;
1264				this.fakeElement.innerHTML += this.origValue;
1265				this.fakeElement.style.color = getStyle(this.element, 'color');
1266				this.fakeElement.style.position = 'absolute';
1267				this.element.parentNode.insertBefore(this.fakeElement, this.element);
1268
1269				if(this.element.value === this.origValue || !this.element.value) {
1270					this.element.value = '';
1271					this.togglePlaceholderText(true);
1272				} else {
1273					this.togglePlaceholderText(false);
1274				}
1275			} else if(!this.element.value && this.origValue.length) {
1276				this.element.value = this.origValue;
1277			}
1278			// get input label
1279			if(this.element.id) {
1280				this.labels = document.getElementsByTagName('label');
1281				for(var i = 0; i < this.labels.length; i++) {
1282					if(this.labels[i].htmlFor === this.element.id) {
1283						this.labelFor = this.labels[i];
1284						break;
1285					}
1286				}
1287			}
1288			// get parent node (or parentNode by className)
1289			this.elementParent = this.element.parentNode;
1290			if(typeof this.options.getParentByClass === 'string') {
1291				var el = this.element;
1292				while(el.parentNode) {
1293					if(hasClass(el.parentNode, this.options.getParentByClass)) {
1294						this.elementParent = el.parentNode;
1295						break;
1296					} else {
1297						el = el.parentNode;
1298					}
1299				}
1300			}
1301		},
1302		attachEvents: function() {
1303			this.element.onfocus = bindScope(this.focusHandler, this);
1304			this.element.onblur = bindScope(this.blurHandler, this);
1305			if(this.options.showUntilTyping) {
1306				this.element.onkeydown = bindScope(this.typingHandler, this);
1307				this.element.onpaste = bindScope(this.typingHandler, this);
1308			}
1309			if(this.wrapWithElement) this.fakeElement.onclick = bindScope(this.focusSetter, this);
1310		},
1311		togglePlaceholderText: function(state) {
1312			if(!this.element.readOnly && !this.options.focusOnly) {
1313				if(this.wrapWithElement) {
1314					this.fakeElement.style.display = state ? '' : 'none';
1315				} else {
1316					this.element.value = state ? this.origValue : '';
1317				}
1318			}
1319		},
1320		focusSetter: function() {
1321			this.element.focus();
1322		},
1323		focusHandler: function() {
1324			clearInterval(this.checkerInterval);
1325			this.checkerInterval = setInterval(bindScope(this.intervalHandler,this), 1);
1326			this.focused = true;
1327			if(!this.element.value.length || this.element.value === this.origValue) {
1328				if(!this.options.showUntilTyping) {
1329					this.togglePlaceholderText(false);
1330				}
1331			}
1332			this.refreshClasses();
1333		},
1334		blurHandler: function() {
1335			clearInterval(this.checkerInterval);
1336			this.focused = false;
1337			if(!this.element.value.length || this.element.value === this.origValue) {
1338				this.togglePlaceholderText(true);
1339			}
1340			this.refreshClasses();
1341			PlaceholderInput.refreshAllInputs(this);
1342		},
1343		typingHandler: function() {
1344			setTimeout(bindScope(function(){
1345				if(this.element.value.length) {
1346					this.togglePlaceholderText(false);
1347					this.refreshClasses();
1348				}
1349			},this), 10);
1350		},
1351		intervalHandler: function() {
1352			if(typeof this.tmpValue === 'undefined') {
1353				this.tmpValue = this.element.value;
1354			}
1355			if(this.tmpValue != this.element.value) {
1356				PlaceholderInput.refreshAllInputs(this);
1357			}
1358		},
1359		refreshState: function() {
1360			if(this.wrapWithElement) {
1361				if(this.element.value.length && this.element.value !== this.origValue) {
1362					this.togglePlaceholderText(false);
1363				} else if(!this.element.value.length) {
1364					this.togglePlaceholderText(true);
1365				}
1366			}
1367			this.refreshClasses();
1368		},
1369		refreshClasses: function() {
1370			this.textActive = this.focused || (this.element.value.length && this.element.value !== this.origValue);
1371			this.setStateClass(this.element, this.options.inputFocusClass,this.focused);
1372			this.setStateClass(this.elementParent, this.options.parentFocusClass,this.focused);
1373			this.setStateClass(this.labelFor, this.options.labelFocusClass,this.focused);
1374			this.setStateClass(this.element, this.options.inputActiveClass, this.textActive);
1375			this.setStateClass(this.elementParent, this.options.parentActiveClass, this.textActive);
1376			this.setStateClass(this.labelFor, this.options.labelActiveClass, this.textActive);
1377		},
1378		setStateClass: function(el,cls,state) {
1379			if(!el) return; else if(state) addClass(el,cls); else removeClass(el,cls);
1380		}
1381	};
1382
1383	// utility functions
1384	function convertToArray(collection) {
1385		var arr = [];
1386		for (var i = 0, ref = arr.length = collection.length; i < ref; i++) {
1387			arr[i] = collection[i];
1388		}
1389		return arr;
1390	}
1391	function getInputType(input) {
1392		return (input.type ? input.type : input.tagName).toLowerCase();
1393	}
1394	function hasClass(el,cls) {
1395		return el.className ? el.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)')) : false;
1396	}
1397	function addClass(el,cls) {
1398		if (!hasClass(el,cls)) el.className += " "+cls;
1399	}
1400	function removeClass(el,cls) {
1401		if (hasClass(el,cls)) {el.className=el.className.replace(new RegExp('(\\s|^)'+cls+'(\\s|$)'), ' ');}
1402	}
1403	function bindScope(f, scope) {
1404		return function() {return f.apply(scope, arguments);};
1405	}
1406	function getStyle(el, prop) {
1407		if (document.defaultView && document.defaultView.getComputedStyle) {
1408			return document.defaultView.getComputedStyle(el, null)[prop];
1409		} else if (el.currentStyle) {
1410			return el.currentStyle[prop];
1411		} else {
1412			return el.style[prop];
1413		}
1414	}
1415}());
1416
1417/*
1418 * Utility module
1419 */
1420lib = {
1421	hasClass: function(el,cls) {
1422		return el && el.className ? el.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)')) : false;
1423	},
1424	addClass: function(el,cls) {
1425		if (el && !this.hasClass(el,cls)) el.className += " "+cls;
1426	},
1427	removeClass: function(el,cls) {
1428		if (el && this.hasClass(el,cls)) {el.className=el.className.replace(new RegExp('(\\s|^)'+cls+'(\\s|$)'), '');}
1429	},
1430	extend: function(obj) {
1431		for(var i = 1; i < arguments.length; i++) {
1432			for(var p in arguments[i]) {
1433				if(arguments[i].hasOwnProperty(p)) {
1434					obj[p] = arguments[i][p];
1435				}
1436			}
1437		}
1438		return obj;
1439	},
1440	each: function(obj, callback) {
1441		var property, len;
1442		if(typeof obj.length === 'number') {
1443			for(property = 0, len = obj.length; property < len; property++) {
1444				if(callback.call(obj[property], property, obj[property]) === false) {
1445					break;
1446				}
1447			}
1448		} else {
1449			for(property in obj) {
1450				if(obj.hasOwnProperty(property)) {
1451					if(callback.call(obj[property], property, obj[property]) === false) {
1452						break;
1453					}
1454				}
1455			}
1456		}
1457	},
1458	event: (function() {
1459		var fixEvent = function(e) {
1460			e = e || window.event;
1461			if(e.isFixed) return e; else e.isFixed = true;
1462			if(!e.target) e.target = e.srcElement;
1463			e.preventDefault = e.preventDefault || function() {this.returnValue = false;};
1464			e.stopPropagation = e.stopPropagation || function() {this.cancelBubble = true;};
1465			return e;
1466		};
1467		return {
1468			add: function(elem, event, handler) {
1469				if(!elem.events) {
1470					elem.events = {};
1471					elem.handle = function(e) {
1472						var ret, handlers = elem.events[e.type];
1473						e = fixEvent(e);
1474						for(var i = 0, len = handlers.length; i < len; i++) {
1475							if(handlers[i]) {
1476								ret = handlers[i].call(elem, e);
1477								if(ret === false) {
1478									e.preventDefault();
1479									e.stopPropagation();
1480								}
1481							}
1482						}
1483					};
1484				}
1485				if(!elem.events[event]) {
1486					elem.events[event] = [];
1487					if(elem.addEventListener) elem.addEventListener(event, elem.handle, false);
1488					else if(elem.attachEvent) elem.attachEvent('on'+event, elem.handle);
1489				}
1490				elem.events[event].push(handler);
1491			},
1492			remove: function(elem, event, handler) {
1493				var handlers = elem.events[event];
1494				for(var i = handlers.length - 1; i >= 0; i--) {
1495					if(handlers[i] === handler) {
1496						handlers.splice(i,1);
1497					}
1498				}
1499				if(!handlers.length) {
1500					delete elem.events[event];
1501					if(elem.removeEventListener) elem.removeEventListener(event, elem.handle, false);
1502					else if(elem.detachEvent) elem.detachEvent('on'+event, elem.handle);
1503				}
1504			}
1505		};
1506	}()),
1507	queryElementsBySelector: function(selector, scope) {
1508		scope = scope || document;
1509		if(!selector) return [];
1510		if(selector === '>*') return scope.children;
1511		if(typeof document.querySelectorAll === 'function') {
1512			return scope.querySelectorAll(selector);
1513		}
1514		var selectors = selector.split(',');
1515		var resultList = [];
1516		for(var s = 0; s < selectors.length; s++) {
1517			var currentContext = [scope || document];
1518			var tokens = selectors[s].replace(/^\s+/,'').replace(/\s+$/,'').split(' ');
1519			for (var i = 0; i < tokens.length; i++) {
1520				token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');
1521				if (token.indexOf('#') > -1) {
1522					var bits = token.split('#'), tagName = bits[0], id = bits[1];
1523					var element = document.getElementById(id);
1524					if (element && tagName && element.nodeName.toLowerCase() != tagName) {
1525						return [];
1526					}
1527					currentContext = element ? [element] : [];
1528					continue;
1529				}
1530				if (token.indexOf('.') > -1) {
1531					var bits = token.split('.'), tagName = bits[0] || '*', className = bits[1], found = [], foundCount = 0;
1532					for (var h = 0; h < currentContext.length; h++) {
1533						var elements;
1534						if (tagName == '*') {
1535							elements = currentContext[h].getElementsByTagName('*');
1536						} else {
1537							elements = currentContext[h].getElementsByTagName(tagName);
1538						}
1539						for (var j = 0; j < elements.length; j++) {
1540							found[foundCount++] = elements[j];
1541						}
1542					}
1543					currentContext = [];
1544					var currentContextIndex = 0;
1545					for (var k = 0; k < found.length; k++) {
1546						if (found[k].className && found[k].className.match(new RegExp('(\\s|^)'+className+'(\\s|$)'))) {
1547							currentContext[currentContextIndex++] = found[k];
1548						}
1549					}
1550					continue;
1551				}
1552				if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
1553					var tagName = RegExp.$1 || '*', attrName = RegExp.$2, attrOperator = RegExp.$3, attrValue = RegExp.$4;
1554					if(attrName.toLowerCase() == 'for' && this.browser.msie && this.browser.version < 8) {
1555						attrName = 'htmlFor';
1556					}
1557					var found = [], foundCount = 0;
1558					for (var h = 0; h < currentContext.length; h++) {
1559						var elements;
1560						if (tagName == '*') {
1561							elements = currentContext[h].getElementsByTagName('*');
1562						} else {
1563							elements = currentContext[h].getElementsByTagName(tagName);
1564						}
1565						for (var j = 0; elements[j]; j++) {
1566							found[foundCount++] = elements[j];
1567						}
1568					}
1569					currentContext = [];
1570					var currentContextIndex = 0, checkFunction;
1571					switch (attrOperator) {
1572						case '=': checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue) }; break;
1573						case '~': checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('(\\s|^)'+attrValue+'(\\s|$)'))) }; break;
1574						case '|': checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))) }; break;
1575						case '^': checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0) }; break;
1576						case '$': checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length) }; break;
1577						case '*': checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1) }; break;
1578						default : checkFunction = function(e) { return e.getAttribute(attrName) };
1579					}
1580					currentContext = [];
1581					var currentContextIndex = 0;
1582					for (var k = 0; k < found.length; k++) {
1583						if (checkFunction(found[k])) {
1584							currentContext[currentContextIndex++] = found[k];
1585						}
1586					}
1587					continue;
1588				}
1589				tagName = token;
1590				var found = [], foundCount = 0;
1591				for (var h = 0; h < currentContext.length; h++) {
1592					var elements = currentContext[h].getElementsByTagName(tagName);
1593					for (var j = 0; j < elements.length; j++) {
1594						found[foundCount++] = elements[j];
1595					}
1596				}
1597				currentContext = found;
1598			}
1599			resultList = [].concat(resultList,currentContext);
1600		}
1601		return resultList;
1602	},
1603	trim: function (str) {
1604		return str.replace(/^\s+/, '').replace(/\s+$/, '');
1605	},
1606	bind: function(f, scope, forceArgs){
1607		return function() {return f.apply(scope, typeof forceArgs !== 'undefined' ? [forceArgs] : arguments);};
1608	}
1609};
1610
1611/*
1612 * jQuery Accordion plugin
1613 */
1614;(function($){
1615	$.fn.slideAccordion = function(opt){
1616		// default options
1617		var options = $.extend({
1618			addClassBeforeAnimation: false,
1619			activeClass:'active',
1620			opener:'.opener',
1621			slider:'.slide',
1622			animSpeed: 300,
1623			collapsible:true,
1624			event:'click'
1625		},opt);
1626
1627		return this.each(function(){
1628			// options
1629			var accordion = $(this);
1630			var items = accordion.find(':has('+options.slider+')');
1631
1632			items.each(function(){
1633				var item = $(this);
1634				var opener = item.find(options.opener);
1635				var slider = item.find(options.slider);
1636				opener.bind(options.event, function(e){
1637					if(!slider.is(':animated')) {
1638						if(item.hasClass(options.activeClass)) {
1639							if(options.collapsible) {
1640								slider.slideUp(options.animSpeed, function(){
1641									hideSlide(slider);
1642									item.removeClass(options.activeClass);
1643								});
1644							}
1645						} else {
1646							// show active
1647							var levelItems = item.siblings('.'+options.activeClass);
1648							var sliderElements = levelItems.find(options.slider);
1649							item.addClass(options.activeClass);
1650							showSlide(slider).hide().slideDown(options.animSpeed);
1651
1652							// collapse others
1653							sliderElements.slideUp(options.animSpeed, function(){
1654								levelItems.removeClass(options.activeClass);
1655								hideSlide(sliderElements);
1656							});
1657						}
1658					}
1659					e.preventDefault();
1660				});
1661				if(item.hasClass(options.activeClass)) showSlide(slider); else hideSlide(slider);
1662			});
1663		});
1664	};
1665
1666	// accordion slide visibility
1667	var showSlide = function(slide) {
1668		return slide.css({position:'', top: '', left: '', width: '' });
1669	};
1670	var hideSlide = function(slide) {
1671		return slide.show().css({position:'absolute', top: -9999, left: -9999, width: slide.width() });
1672	};
1673}(jQuery));
1674
1675/*
1676 * Popups plugin
1677 */
1678;(function($) {
1679	function ContentPopup(opt) {
1680		this.options = $.extend({
1681			holder: null,
1682			popup: '.popup',
1683			btnOpen: '.open',
1684			btnClose: '.close',
1685			openClass: 'popup-active',
1686			clickEvent: 'click',
1687			mode: 'click',
1688			hideOnClickLink: true,
1689			hideOnClickOutside: true,
1690			delay: 50
1691		}, opt);
1692		if(this.options.holder) {
1693			this.holder = $(this.options.holder);
1694			this.init();
1695		}
1696	}
1697	ContentPopup.prototype = {
1698		init: function() {
1699			this.findElements();
1700			this.attachEvents();
1701		},
1702		findElements: function() {
1703			this.popup = this.holder.find(this.options.popup);
1704			this.btnOpen = this.holder.find(this.options.btnOpen);
1705			this.btnClose = this.holder.find(this.options.btnClose);
1706		},
1707		attachEvents: function() {
1708			// handle popup openers
1709			var self = this;
1710			this.clickMode = isTouchDevice || (self.options.mode === self.options.clickEvent);
1711
1712			if(this.clickMode) {
1713				// handle click mode
1714				this.btnOpen.bind(self.options.clickEvent, function(e) {
1715					if(self.holder.hasClass(self.options.openClass)) {
1716						if(self.options.hideOnClickLink) {
1717							self.hidePopup();
1718						}
1719					} else {
1720						self.showPopup();
1721					}
1722					e.preventDefault();
1723				});
1724
1725				// prepare outside click handler
1726				this.outsideClickHandler = this.bind(this.outsideClickHandler, this);
1727			} else {
1728				// handle hover mode
1729				var timer, delayedFunc = function(func) {
1730					clearTimeout(timer);
1731					timer = setTimeout(function() {
1732						func.call(self);
1733					}, self.options.delay);
1734				};
1735				this.btnOpen.bind('mouseover', function() {
1736					delayedFunc(self.showPopup);
1737				}).bind('mouseout', function() {
1738					delayedFunc(self.hidePopup);
1739				});
1740				this.popup.bind('mouseover', function() {
1741					delayedFunc(self.showPopup);
1742				}).bind('mouseout', function() {
1743					delayedFunc(self.hidePopup);
1744				});
1745			}
1746
1747			// handle close buttons
1748			this.btnClose.bind(self.options.clickEvent, function(e) {
1749				self.hidePopup();
1750				e.preventDefault();
1751			});
1752		},
1753		outsideClickHandler: function(e) {
1754			// hide popup if clicked outside
1755			var currentNode = (e.changedTouches ? e.changedTouches[0] : e).target;
1756			if(!$(currentNode).parents().filter(this.holder).length) {
1757				this.hidePopup();
1758			}
1759		},
1760		showPopup: function() {
1761			// reveal popup
1762			this.holder.addClass(this.options.openClass);
1763			this.popup.css({display:'block'});
1764
1765			// outside click handler
1766			if(this.clickMode && this.options.hideOnClickOutside && !this.outsideHandlerActive) {
1767				this.outsideHandlerActive = true;
1768				$(document).bind('click touchstart', this.outsideClickHandler);
1769			}
1770		},
1771		hidePopup: function() {
1772			// hide popup
1773			this.holder.removeClass(this.options.openClass);
1774			this.popup.css({display:'none'});
1775
1776			// outside click handler
1777			if(this.clickMode && this.options.hideOnClickOutside && this.outsideHandlerActive) {
1778				this.outsideHandlerActive = false;
1779				$(document).unbind('click touchstart', this.outsideClickHandler);
1780			}
1781		},
1782		bind: function(f, scope, forceArgs){
1783			return function() {return f.apply(scope, forceArgs ? [forceArgs] : arguments);};
1784		}
1785	};
1786
1787	// detect touch devices
1788	var isTouchDevice = /MSIE 10.*Touch/.test(navigator.userAgent) || ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;
1789
1790	// jQuery plugin interface
1791	$.fn.contentPopup = function(opt) {
1792		return this.each(function() {
1793			new ContentPopup($.extend(opt, {holder: this}));
1794		});
1795	};
1796}(jQuery));
1797
1798/*
1799 * Convert navigation to select
1800 */
1801;(function($) {
1802	function NavigationSelect(options) {
1803		this.options = $.extend({
1804			list: null,
1805			levelIndentHTML: ' &bull; ',
1806			defaultOptionAttr: 'title',
1807			defaultOptionText: '...',
1808			selectClass: 'nav-select',
1809			activeClass: 'nav-active',
1810			defaultOptionClass: 'opt-default',
1811			hasDropClass: 'opt-sublevel',
1812			levelPrefixClass: 'opt-level-',
1813			useDefaultOption: true
1814		}, options);
1815		if(this.options.list) {
1816			this.createSelect();
1817			this.attachEvents();
1818		}
1819	}
1820	NavigationSelect.prototype = {
1821		createSelect: function() {
1822			var self = this;
1823			this.startIndex = 0;
1824			this.navigation = $(this.options.list);
1825			this.select = $('<select>').addClass(this.options.selectClass);
1826			this.createDefaultOption();
1827			this.createList(this.navigation, 0);
1828			this.select.insertBefore(this.navigation);
1829		},
1830		createDefaultOption: function() {
1831			if(this.options.useDefaultOption) {
1832				var attrText = this.navigation.attr(this.options.defaultOptionAttr);
1833				var defaultOption = $('<option>').addClass(this.options.defaultOptionClass).text(attrText || this.options.defaultOptionText);
1834				this.navigation.removeAttr(this.options.defaultOptionAttr);
1835				this.select.append(defaultOption);
1836				this.startIndex = 1;
1837			}
1838		},
1839		createList: function(list, level) {
1840			var self = this;
1841			list.children().each(function(index, item) {
1842				var listItem = $(this),
1843					listLink = listItem.find('a').eq(0),
1844					listDrop = listItem.find('ul').eq(0),
1845					hasDrop = listDrop.length > 0;
1846
1847				if(listLink.length) {
1848					self.select.append(self.createOption(listLink, hasDrop, level, listLink.hasClass(self.options.activeClass)));
1849				}
1850				if(hasDrop) {
1851					self.createList(listDrop, level + 1);
1852				}
1853			});
1854		},
1855		createOption: function(link, hasDrop, level, selected) {
1856			var optionHTML = this.getLevelIndent(level) + link.html();
1857			return $('<option>').html(optionHTML)
1858				.addClass(this.options.levelPrefixClass + (level + 1))
1859				.toggleClass(this.options.hasDropClass, hasDrop)
1860				.val(link.attr('href')).attr('selected', selected ? 'selected' : false);
1861		},
1862		getLevelIndent: function(level) {
1863			return (new Array(level + 1)).join(this.options.levelIndentHTML);
1864		},
1865		attachEvents: function() {
1866			// redirect on select change
1867			var self = this;
1868			this.select.change(function() {
1869				if(this.selectedIndex >= self.startIndex) {
1870					location.href = this.value;
1871				}
1872			});
1873		}
1874	};
1875
1876	// jquery pluginm interface
1877	$.fn.navigationSelect = function(opt) {
1878		return this.each(function() {
1879			new NavigationSelect($.extend({list: this}, opt));
1880		});
1881	};
1882}(jQuery));
1883
1884/*
1885 * Responsive Layout helper
1886 */
1887
1888ResponsiveHelper = (function($){
1889	// init variables
1890	var handlers = [];
1891	var win = $(window), prevWinWidth;
1892	var scrollBarWidth = 0;
1893
1894	// prepare resize handler
1895	function resizeHandler() {
1896		var winWidth = win.width() + scrollBarWidth;
1897		if(winWidth !== prevWinWidth) {
1898			prevWinWidth = winWidth;
1899
1900			// loop through range groups
1901			$.each(handlers, function(index, rangeObject){
1902				// disable current active area if needed
1903				$.each(rangeObject.data, function(property, item) {
1904					if((winWidth < item.range[0] || winWidth > item.range[1]) && item.currentActive) {
1905						item.currentActive = false;
1906						if(typeof item.disableCallback === 'function') {
1907							item.disableCallback();
1908						}
1909					}
1910				});
1911
1912				// enable areas that match current width
1913				$.each(rangeObject.data, function(property, item) {
1914					if(winWidth >= item.range[0] && winWidth <= item.range[1] && !item.currentActive) {
1915						// make callback
1916						item.currentActive = true;
1917						if(typeof item.enableCallback === 'function') {
1918							item.enableCallback();
1919						}
1920					}
1921				});
1922			});
1923		}
1924	}
1925	win.bind('load', function(){
1926		if($.browser.mozilla || $.browser.opera) {
1927			scrollBarWidth = window.innerWidth - $('body').width();
1928			resizeHandler();
1929		}
1930		win.bind('resize orientationchange', resizeHandler);
1931	});
1932
1933	// range parser
1934	function parseRange(rangeStr) {
1935		var rangeData = rangeStr.split('..');
1936		var x1 = parseInt(rangeData[0], 10) || -Infinity;
1937		var x2 = parseInt(rangeData[1], 10) || Infinity;
1938		return [x1, x2].sort(function(a, b){
1939			return a - b;
1940		});
1941	}
1942
1943	// export public functions
1944	return {
1945		addRange: function(ranges) {
1946			// parse data and add items to collection
1947			var result = {data:{}};
1948			$.each(ranges, function(property, data){
1949				result.data[property] = {
1950					range: parseRange(property),
1951					enableCallback: data.on,
1952					disableCallback: data.off
1953				};
1954			});
1955			handlers.push(result);
1956
1957			// call resizeHandler to recalculate all events
1958			resizeHandler();
1959		}
1960	};
1961}(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.