PageSourceSearch

https://www.architect-design.ru/bitrix/cache/js/s1/architect/page_…e3c663f53f1cc9d5ce1e0_v1.js?179024896444929

js architect-design.ru collected 2026-10-02 12:22:45 UTC 44,929 bytes, 1,457 lines download raw bytes

1
2; /* Start:"a:4:{s:4:"full";s:26:"/js/jcf.js?151707261813686";s:6:"source";s:10:"/js/jcf.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
3/*!
4 * JavaScript Custom Forms
5 *
6 * Copyright 2014-2016 PSD2HTML - http://psd2html.com/jcf
7 * Released under the MIT license (LICENSE.txt)
8 *
9 * Version: 1.2.3
10 */
11;(function(root, factory) {
12	'use strict';
13	if (typeof define === 'function' && define.amd) {
14		define(['jquery'], factory);
15	} else if (typeof exports === 'object') {
16		module.exports = factory(require('jquery'));
17	} else {
18		root.jcf = factory(jQuery);
19	}
20}(this, function($) {
21	'use strict';
22
23	// define version
24	var version = '1.2.3';
25
26	// private variables
27	var customInstances = [];
28
29	// default global options
30	var commonOptions = {
31		optionsKey: 'jcf',
32		dataKey: 'jcf-instance',
33		rtlClass: 'jcf-rtl',
34		focusClass: 'jcf-focus',
35		pressedClass: 'jcf-pressed',
36		disabledClass: 'jcf-disabled',
37		hiddenClass: 'jcf-hidden',
38		resetAppearanceClass: 'jcf-reset-appearance',
39		unselectableClass: 'jcf-unselectable'
40	};
41
42	// detect device type
43	var isTouchDevice = ('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch,
44		isWinPhoneDevice = /Windows Phone/.test(navigator.userAgent);
45	commonOptions.isMobileDevice = !!(isTouchDevice || isWinPhoneDevice);
46
47	// create global stylesheet if custom forms are used
48	var createStyleSheet = function() {
49		var styleTag = $('<style>').appendTo('head'),
50			styleSheet = styleTag.prop('sheet') || styleTag.prop('styleSheet');
51
52		// crossbrowser style handling
53		var addCSSRule = function(selector, rules, index) {
54			index = index || 0;
55			if (styleSheet.insertRule) {
56				styleSheet.insertRule(selector + '{' + rules + '}', index);
57			} else {
58				styleSheet.addRule(selector, rules, index);
59			}
60		};
61
62		// add special rules
63		addCSSRule('.' + commonOptions.hiddenClass, 'position:absolute !important;left:-9999px !important;height:1px !important;width:1px !important;margin:0 !important;border-width:0 !important;-webkit-appearance:none;-moz-appearance:none;appearance:none');
64		addCSSRule('.' + commonOptions.rtlClass + ' .' + commonOptions.hiddenClass, 'right:-9999px !important; left: auto !important');
65		addCSSRule('.' + commonOptions.unselectableClass, '-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-tap-highlight-color: rgba(0,0,0,0);');
66		addCSSRule('.' + commonOptions.resetAppearanceClass, 'background: none; border: none; -webkit-appearance: none; appearance: none; opacity: 0; filter: alpha(opacity=0);');
67
68		// detect rtl pages
69		var html = $('html'), body = $('body');
70		if (html.css('direction') === 'rtl' || body.css('direction') === 'rtl') {
71			html.addClass(commonOptions.rtlClass);
72		}
73
74		// handle form reset event
75		html.on('reset', function() {
76			setTimeout(function() {
77				api.refreshAll();
78			}, 0);
79		});
80
81		// mark stylesheet as created
82		commonOptions.styleSheetCreated = true;
83	};
84
85	// simplified pointer events handler
86	(function() {
87		var pointerEventsSupported = navigator.pointerEnabled || navigator.msPointerEnabled,
88			touchEventsSupported = ('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch,
89			eventList, eventMap = {}, eventPrefix = 'jcf-';
90
91		// detect events to attach
92		if (pointerEventsSupported) {
93			eventList = {
94				pointerover: navigator.pointerEnabled ? 'pointerover' : 'MSPointerOver',
95				pointerdown: navigator.pointerEnabled ? 'pointerdown' : 'MSPointerDown',
96				pointermove: navigator.pointerEnabled ? 'pointermove' : 'MSPointerMove',
97				pointerup: navigator.pointerEnabled ? 'pointerup' : 'MSPointerUp'
98			};
99		} else {
100			eventList = {
101				pointerover: 'mouseover',
102				pointerdown: 'mousedown' + (touchEventsSupported ? ' touchstart' : ''),
103				pointermove: 'mousemove' + (touchEventsSupported ? ' touchmove' : ''),
104				pointerup: 'mouseup' + (touchEventsSupported ? ' touchend' : '')
105			};
106		}
107
108		// create event map
109		$.each(eventList, function(targetEventName, fakeEventList) {
110			$.each(fakeEventList.split(' '), function(index, fakeEventName) {
111				eventMap[fakeEventName] = targetEventName;
112			});
113		});
114
115		// jQuery event hooks
116		$.each(eventList, function(eventName, eventHandlers) {
117			eventHandlers = eventHandlers.split(' ');
118			$.event.special[eventPrefix + eventName] = {
119				setup: function() {
120					var self = this;
121					$.each(eventHandlers, function(index, fallbackEvent) {
122						if (self.addEventListener) self.addEventListener(fallbackEvent, fixEvent, false);
123						else self['on' + fallbackEvent] = fixEvent;
124					});
125				},
126				teardown: function() {
127					var self = this;
128					$.each(eventHandlers, function(index, fallbackEvent) {
129						if (self.addEventListener) self.removeEventListener(fallbackEvent, fixEvent, false);
130						else self['on' + fallbackEvent] = null;
131					});
132				}
133			};
134		});
135
136		// check that mouse event are not simulated by mobile browsers
137		var lastTouch = null;
138		var mouseEventSimulated = function(e) {
139			var dx = Math.abs(e.pageX - lastTouch.x),
140				dy = Math.abs(e.pageY - lastTouch.y),
141				rangeDistance = 25;
142
143			if (dx <= rangeDistance && dy <= rangeDistance) {
144				return true;
145			}
146		};
147
148		// normalize event
149		var fixEvent = function(e) {
150			var origEvent = e || window.event,
151				touchEventData = null,
152				targetEventName = eventMap[origEvent.type];
153
154			e = $.event.fix(origEvent);
155			e.type = eventPrefix + targetEventName;
156
157			if (origEvent.pointerType) {
158				switch (origEvent.pointerType) {
159					case 2: e.pointerType = 'touch'; break;
160					case 3: e.pointerType = 'pen'; break;
161					case 4: e.pointerType = 'mouse'; break;
162					default: e.pointerType = origEvent.pointerType;
163				}
164			} else {
165				e.pointerType = origEvent.type.substr(0, 5); // "mouse" or "touch" word length
166			}
167
168			if (!e.pageX && !e.pageY) {
169				touchEventData = origEvent.changedTouches ? origEvent.changedTouches[0] : origEvent;
170				e.pageX = touchEventData.pageX;
171				e.pageY = touchEventData.pageY;
172			}
173
174			if (origEvent.type === 'touchend') {
175				lastTouch = { x: e.pageX, y: e.pageY };
176			}
177			if (e.pointerType === 'mouse' && lastTouch && mouseEventSimulated(e)) {
178				return;
179			} else {
180				return ($.event.dispatch || $.event.handle).call(this, e);
181			}
182		};
183	}());
184
185	// custom mousewheel/trackpad handler
186	(function() {
187		var wheelEvents = ('onwheel' in document || document.documentMode >= 9 ? 'wheel' : 'mousewheel DOMMouseScroll').split(' '),
188			shimEventName = 'jcf-mousewheel';
189
190		$.event.special[shimEventName] = {
191			setup: function() {
192				var self = this;
193				$.each(wheelEvents, function(index, fallbackEvent) {
194					if (self.addEventListener) self.addEventListener(fallbackEvent, fixEvent, false);
195					else self['on' + fallbackEvent] = fixEvent;
196				});
197			},
198			teardown: function() {
199				var self = this;
200				$.each(wheelEvents, function(index, fallbackEvent) {
201					if (self.addEventListener) self.removeEventListener(fallbackEvent, fixEvent, false);
202					else self['on' + fallbackEvent] = null;
203				});
204			}
205		};
206
207		var fixEvent = function(e) {
208			var origEvent = e || window.event;
209			e = $.event.fix(origEvent);
210			e.type = shimEventName;
211
212			// old wheel events handler
213			if ('detail'      in origEvent) { e.deltaY = -origEvent.detail;      }
214			if ('wheelDelta'  in origEvent) { e.deltaY = -origEvent.wheelDelta;  }
215			if ('wheelDeltaY' in origEvent) { e.deltaY = -origEvent.wheelDeltaY; }
216			if ('wheelDeltaX' in origEvent) { e.deltaX = -origEvent.wheelDeltaX; }
217
218			// modern wheel event handler
219			if ('deltaY' in origEvent) {
220				e.deltaY = origEvent.deltaY;
221			}
222			if ('deltaX' in origEvent) {
223				e.deltaX = origEvent.deltaX;
224			}
225
226			// handle deltaMode for mouse wheel
227			e.delta = e.deltaY || e.deltaX;
228			if (origEvent.deltaMode === 1) {
229				var lineHeight = 16;
230				e.delta *= lineHeight;
231				e.deltaY *= lineHeight;
232				e.deltaX *= lineHeight;
233			}
234
235			return ($.event.dispatch || $.event.handle).call(this, e);
236		};
237	}());
238
239	// extra module methods
240	var moduleMixin = {
241		// provide function for firing native events
242		fireNativeEvent: function(elements, eventName) {
243			$(elements).each(function() {
244				var element = this, eventObject;
245				if (element.dispatchEvent) {
246					eventObject = document.createEvent('HTMLEvents');
247					eventObject.initEvent(eventName, true, true);
248					element.dispatchEvent(eventObject);
249				} else if (document.createEventObject) {
250					eventObject = document.createEventObject();
251					eventObject.target = element;
252					element.fireEvent('on' + eventName, eventObject);
253				}
254			});
255		},
256		// bind event handlers for module instance (functions beggining with "on")
257		bindHandlers: function() {
258			var self = this;
259			$.each(self, function(propName, propValue) {
260				if (propName.indexOf('on') === 0 && $.isFunction(propValue)) {
261					// dont use $.proxy here because it doesn't create unique handler
262					self[propName] = function() {
263						return propValue.apply(self, arguments);
264					};
265				}
266			});
267		}
268	};
269
270	// public API
271	var api = {
272		version: version,
273		modules: {},
274		getOptions: function() {
275			return $.extend({}, commonOptions);
276		},
277		setOptions: function(moduleName, moduleOptions) {
278			if (arguments.length > 1) {
279				// set module options
280				if (this.modules[moduleName]) {
281					$.extend(this.modules[moduleName].prototype.options, moduleOptions);
282				}
283			} else {
284				// set common options
285				$.extend(commonOptions, moduleName);
286			}
287		},
288		addModule: function(proto) {
289			// proto is factory function
290			if ($.isFunction(proto)) {
291				proto = proto($, window);
292			}
293
294			// add module to list
295			var Module = function(options) {
296				// save instance to collection
297				if (!options.element.data(commonOptions.dataKey)) {
298					options.element.data(commonOptions.dataKey, this);
299				}
300				customInstances.push(this);
301
302				// save options
303				this.options = $.extend({}, commonOptions, this.options, getInlineOptions(options.element), options);
304
305				// bind event handlers to instance
306				this.bindHandlers();
307
308				// call constructor
309				this.init.apply(this, arguments);
310			};
311
312			// parse options from HTML attribute
313			var getInlineOptions = function(element) {
314				var dataOptions = element.data(commonOptions.optionsKey),
315					attrOptions = element.attr(commonOptions.optionsKey);
316
317				if (dataOptions) {
318					return dataOptions;
319				} else if (attrOptions) {
320					try {
321						return $.parseJSON(attrOptions);
322					} catch (e) {
323						// ignore invalid attributes
324					}
325				}
326			};
327
328			// set proto as prototype for new module
329			Module.prototype = proto;
330
331			// add mixin methods to module proto
332			$.extend(proto, moduleMixin);
333			if (proto.plugins) {
334				$.each(proto.plugins, function(pluginName, plugin) {
335					$.extend(plugin.prototype, moduleMixin);
336				});
337			}
338
339			// override destroy method
340			var originalDestroy = Module.prototype.destroy;
341			Module.prototype.destroy = function() {
342				this.options.element.removeData(this.options.dataKey);
343
344				for (var i = customInstances.length - 1; i >= 0; i--) {
345					if (customInstances[i] === this) {
346						customInstances.splice(i, 1);
347						break;
348					}
349				}
350
351				if (originalDestroy) {
352					originalDestroy.apply(this, arguments);
353				}
354			};
355
356			// save module to list
357			this.modules[proto.name] = Module;
358		},
359		getInstance: function(element) {
360			return $(element).data(commonOptions.dataKey);
361		},
362		replace: function(elements, moduleName, customOptions) {
363			var self = this,
364				instance;
365
366			if (!commonOptions.styleSheetCreated) {
367				createStyleSheet();
368			}
369
370			$(elements).each(function() {
371				var moduleOptions,
372					element = $(this);
373
374				instance = element.data(commonOptions.dataKey);
375				if (instance) {
376					instance.refresh();
377				} else {
378					if (!moduleName) {
379						$.each(self.modules, function(currentModuleName, module) {
380							if (module.prototype.matchElement.call(module.prototype, element)) {
381								moduleName = currentModuleName;
382								return false;
383							}
384						});
385					}
386					if (moduleName) {
387						moduleOptions = $.extend({ element: element }, customOptions);
388						instance = new self.modules[moduleName](moduleOptions);
389					}
390				}
391			});
392			return instance;
393		},
394		refresh: function(elements) {
395			$(elements).each(function() {
396				var instance = $(this).data(commonOptions.dataKey);
397				if (instance) {
398					instance.refresh();
399				}
400			});
401		},
402		destroy: function(elements) {
403			$(elements).each(function() {
404				var instance = $(this).data(commonOptions.dataKey);
405				if (instance) {
406					instance.destroy();
407				}
408			});
409		},
410		replaceAll: function(context) {
411			var self = this;
412			$.each(this.modules, function(moduleName, module) {
413				$(module.prototype.selector, context).each(function() {
414					if (this.className.indexOf('jcf-ignore') < 0) {
415						self.replace(this, moduleName);
416					}
417				});
418			});
419		},
420		refreshAll: function(context) {
421			if (context) {
422				$.each(this.modules, function(moduleName, module) {
423					$(module.prototype.selector, context).each(function() {
424						var instance = $(this).data(commonOptions.dataKey);
425						if (instance) {
426							instance.refresh();
427						}
428					});
429				});
430			} else {
431				for (var i = customInstances.length - 1; i >= 0; i--) {
432					customInstances[i].refresh();
433				}
434			}
435		},
436		destroyAll: function(context) {
437			if (context) {
438				$.each(this.modules, function(moduleName, module) {
439					$(module.prototype.selector, context).each(function(index, element) {
440						var instance = $(element).data(commonOptions.dataKey);
441						if (instance) {
442							instance.destroy();
443						}
444					});
445				});
446			} else {
447				while (customInstances.length) {
448					customInstances[0].destroy();
449				}
450			}
451		}
452	};
453
454	// we need to make JCF available globally if we're in AMD environment
455	if (typeof define === 'function' && define.amd) {
456		window.jcf = api;
457	}
458
459	return api;
460}));
461
462/* End */
463;
464; /* Start:"a:4:{s:4:"full";s:33:"/js/jcf.select.js?173657735230423";s:6:"source";s:17:"/js/jcf.select.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
465/*!
466 * JavaScript Custom Forms : Select Module
467 *
468 * Copyright 2014-2016 PSD2HTML - http://psd2html.com/jcf
469 * Released under the MIT license (LICENSE.txt)
470 *
471 * Version: 1.2.3
472 */
473
474(function(jcf) {
475
476jcf.addModule(function($, window) {
477	'use strict';
478
479	var module = {
480		name: 'Select',
481		selector: 'select',
482		options: {
483			element: null,
484			multipleCompactStyle: false
485		},
486		plugins: {
487			ListBox: ListBox,
488			ComboBox: ComboBox,
489			SelectList: SelectList
490		},
491		matchElement: function(element) {
492			return element.is('select');
493		},
494		init: function() {
495			this.element = $(this.options.element);
496			this.createInstance();
497		},
498		isListBox: function() {
499			return this.element.is('[size]:not([jcf-size]), [multiple]');
500		},
501		createInstance: function() {
502			if (this.instance) {
503				this.instance.destroy();
504			}
505
506			if (this.isListBox() && !this.options.multipleCompactStyle && this.options.isMobileDevice && this.options.wrapNativeOnMobile) {
507				this.options.multipleCompactStyle = true;
508			}
509
510			// workaround for iOS issue with multiple selects and autoselection of first option 
511			if (this.options.isMobileDevice && this.options.multipleCompactStyle && this.options.wrapNativeOnMobile && !this.element.children('optgroup:first-child').length) {
512				$('<optgroup disabled hidden></optgroup>').prependTo(this.element);
513			}
514
515			if (this.isListBox() && !this.options.multipleCompactStyle) {
516				this.instance = new ListBox(this.options);
517			} else {
518				this.instance = new ComboBox(this.options);
519			}
520		},
521		refresh: function() {
522			var typeMismatch = (this.isListBox() && this.instance instanceof ComboBox) ||
523								(!this.isListBox() && this.instance instanceof ListBox);
524
525			if (typeMismatch) {
526				this.createInstance();
527			} else {
528				this.instance.refresh();
529			}
530		},
531		destroy: function() {
532			this.instance.destroy();
533		}
534	};
535
536	// combobox module
537	function ComboBox(options) {
538		this.options = $.extend({
539			wrapNative: true,
540			wrapNativeOnMobile: true,
541			fakeDropInBody: true,
542			useCustomScroll: true,
543			flipDropToFit: true,
544			maxVisibleItems: 10,
545			fakeAreaStructure: '<span class="jcf-select"><span class="jcf-select-text"></span><span class="jcf-select-opener"></span></span>',
546			fakeDropStructure: '<div class="jcf-select-drop"><div class="jcf-select-drop-content"></div></div>',
547			optionClassPrefix: 'jcf-option-',
548			selectClassPrefix: 'jcf-select-',
549			dropContentSelector: '.jcf-select-drop-content',
550			selectTextSelector: '.jcf-select-text',
551			dropActiveClass: 'jcf-drop-active',
552			flipDropClass: 'jcf-drop-flipped'
553		}, options);
554		this.init();
555	}
556	$.extend(ComboBox.prototype, {
557		init: function() {
558			this.initStructure();
559			this.bindHandlers();
560			this.attachEvents();
561			this.refresh();
562		},
563		initStructure: function() {
564			// prepare structure
565			this.win = $(window);
566			this.doc = $(document);
567			this.realElement = $(this.options.element);
568			this.fakeElement = $(this.options.fakeAreaStructure).insertAfter(this.realElement);
569			this.selectTextContainer = this.fakeElement.find(this.options.selectTextSelector);
570			this.selectText = $('<span></span>').appendTo(this.selectTextContainer);
571			makeUnselectable(this.fakeElement);
572
573			// copy classes from original select
574			this.fakeElement.addClass(getPrefixedClasses(this.realElement.prop('className'), this.options.selectClassPrefix));
575
576			// handle compact multiple style
577			if (this.realElement.prop('multiple')) {
578				this.fakeElement.addClass('jcf-compact-multiple');
579			}
580
581			// detect device type and dropdown behavior
582			if (this.options.isMobileDevice && this.options.wrapNativeOnMobile && !this.options.wrapNative) {
583				this.options.wrapNative = true;
584			}
585
586			if (this.options.wrapNative) {
587				// wrap native select inside fake block
588				this.realElement.prependTo(this.fakeElement).css({
589					position: 'absolute',
590					height: '100%',
591					width: '100%'
592				}).addClass(this.options.resetAppearanceClass);
593			} else {
594				// just hide native select
595				this.realElement.addClass(this.options.hiddenClass);
596				this.fakeElement.attr('title', this.realElement.attr('title'));
597				this.fakeDropTarget = this.options.fakeDropInBody ? $('body') : this.fakeElement;
598			}
599		},
600		attachEvents: function() {
601			// delayed refresh handler
602			var self = this;
603			this.delayedRefresh = function() {
604				setTimeout(function() {
605					self.refresh();
606					if (self.list) {
607						self.list.refresh();
608						self.list.scrollToActiveOption();
609					}
610				}, 1);
611			};
612
613			// native dropdown event handlers
614			if (this.options.wrapNative) {
615				this.realElement.on({
616					focus: this.onFocus,
617					change: this.onChange,
618					click: this.onChange,
619					keydown: this.delayedRefresh
620				});
621			} else {
622				// custom dropdown event handlers
623				this.realElement.on({
624					focus: this.onFocus,
625					change: this.onChange,
626					keydown: this.onKeyDown
627				});
628				this.fakeElement.on({
629					'jcf-pointerdown': this.onSelectAreaPress
630				});
631			}
632		},
633		onKeyDown: function(e) {
634			if (e.which === 13) {
635				this.toggleDropdown();
636			} else if (this.dropActive) {
637				this.delayedRefresh();
638			}
639		},
640		onChange: function() {
641			this.refresh();
642		},
643		onFocus: function() {
644			if (!this.pressedFlag || !this.focusedFlag) {
645				this.fakeElement.addClass(this.options.focusClass);
646				this.realElement.on('blur', this.onBlur);
647				this.toggleListMode(true);
648				this.focusedFlag = true;
649			}
650		},
651		onBlur: function() {
652			if (!this.pressedFlag) {
653				this.fakeElement.removeClass(this.options.focusClass);
654				this.realElement.off('blur', this.onBlur);
655				this.toggleListMode(false);
656				this.focusedFlag = false;
657			}
658		},
659		onResize: function() {
660			if (this.dropActive) {
661				this.hideDropdown();
662			}
663		},
664		onSelectDropPress: function() {
665			this.pressedFlag = true;
666		},
667		onSelectDropRelease: function(e, pointerEvent) {
668			this.pressedFlag = false;
669			if (pointerEvent.pointerType === 'mouse') {
670				this.realElement.focus();
671			}
672		},
673		onSelectAreaPress: function(e) {
674			// skip click if drop inside fake element or real select is disabled
675			var dropClickedInsideFakeElement = !this.options.fakeDropInBody && $(e.target).closest(this.dropdown).length;
676			if (dropClickedInsideFakeElement || e.button > 1 || this.realElement.is(':disabled')) {
677				return;
678			}
679
680			// toggle dropdown visibility
681			this.selectOpenedByEvent = e.pointerType;
682			this.toggleDropdown();
683
684			// misc handlers
685			if (!this.focusedFlag) {
686				if (e.pointerType === 'mouse') {
687					this.realElement.focus();
688				} else {
689					this.onFocus(e);
690				}
691			}
692			this.pressedFlag = true;
693			this.fakeElement.addClass(this.options.pressedClass);
694			this.doc.on('jcf-pointerup', this.onSelectAreaRelease);
695		},
696		onSelectAreaRelease: function(e) {
697			if (this.focusedFlag && e.pointerType === 'mouse') {
698				this.realElement.focus();
699			}
700			this.pressedFlag = false;
701			this.fakeElement.removeClass(this.options.pressedClass);
702			this.doc.off('jcf-pointerup', this.onSelectAreaRelease);
703		},
704		onOutsideClick: function(e) {
705			var target = $(e.target),
706				clickedInsideSelect = target.closest(this.fakeElement).length || target.closest(this.dropdown).length;
707
708			if (!clickedInsideSelect) {
709				this.hideDropdown();
710			}
711		},
712		onSelect: function() {
713			this.refresh();
714
715			if (this.realElement.prop('multiple')) {
716				this.repositionDropdown();
717			} else {
718				this.hideDropdown();
719			}
720
721			this.fireNativeEvent(this.realElement, 'change');
722		},
723		toggleListMode: function(state) {
724			if (!this.options.wrapNative) {
725				if (state) {
726					// temporary change select to list to avoid appearing of native dropdown
727					this.realElement.attr({
728						size: 4,
729						'jcf-size': ''
730					});
731				} else {
732					// restore select from list mode to dropdown select
733					if (!this.options.wrapNative) {
734						this.realElement.removeAttr('size jcf-size');
735					}
736				}
737			}
738		},
739		createDropdown: function() {
740			// destroy previous dropdown if needed
741			if (this.dropdown) {
742				this.list.destroy();
743				this.dropdown.remove();
744			}
745
746			// create new drop container
747			this.dropdown = $(this.options.fakeDropStructure).appendTo(this.fakeDropTarget);
748			this.dropdown.addClass(getPrefixedClasses(this.realElement.prop('className'), this.options.selectClassPrefix));
749			makeUnselectable(this.dropdown);
750
751			// handle compact multiple style
752			if (this.realElement.prop('multiple')) {
753				this.dropdown.addClass('jcf-compact-multiple');
754			}
755
756			// set initial styles for dropdown in body
757			if (this.options.fakeDropInBody) {
758				this.dropdown.css({
759					position: 'absolute',
760					top: -9999
761				});
762			}
763
764			// create new select list instance
765			this.list = new SelectList({
766				useHoverClass: true,
767				handleResize: false,
768				alwaysPreventMouseWheel: true,
769				maxVisibleItems: this.options.maxVisibleItems,
770				useCustomScroll: this.options.useCustomScroll,
771				holder: this.dropdown.find(this.options.dropContentSelector),
772				multipleSelectWithoutKey: this.realElement.prop('multiple'),
773				element: this.realElement
774			});
775			$(this.list).on({
776				select: this.onSelect,
777				press: this.onSelectDropPress,
778				release: this.onSelectDropRelease
779			});
780		},
781		repositionDropdown: function() {
782			var selectOffset = this.fakeElement.offset(),
783				fakeElementBounds = this.fakeElement[0].getBoundingClientRect(),
784				selectWidth = fakeElementBounds.width || fakeElementBounds.right - fakeElementBounds.left,
785				selectHeight = this.fakeElement.outerHeight(),
786				dropHeight = this.dropdown.css('width', selectWidth).outerHeight(),
787				winScrollTop = this.win.scrollTop(),
788				winHeight = this.win.height(),
789				calcTop, calcLeft, bodyOffset, needFlipDrop = false;
790
791			// check flip drop position
792			if (selectOffset.top + selectHeight + dropHeight > winScrollTop + winHeight && selectOffset.top - dropHeight > winScrollTop) {
793				needFlipDrop = true;
794			}
795
796			if (this.options.fakeDropInBody) {
797				bodyOffset = this.fakeDropTarget.css('position') !== 'static' ? this.fakeDropTarget.offset().top : 0;
798				if (this.options.flipDropToFit && needFlipDrop) {
799					// calculate flipped dropdown position
800					calcLeft = selectOffset.left;
801					calcTop = selectOffset.top - dropHeight - bodyOffset;
802				} else {
803					// calculate default drop position
804					calcLeft = selectOffset.left;
805					calcTop = selectOffset.top + selectHeight - bodyOffset;
806				}
807
808				// update drop styles
809				this.dropdown.css({
810					width: selectWidth,
811					left: calcLeft,
812					top: calcTop
813				});
814			}
815
816			// refresh flipped class
817			this.dropdown.add(this.fakeElement).toggleClass(this.options.flipDropClass, this.options.flipDropToFit && needFlipDrop);
818		},
819		showDropdown: function() {
820			// do not show empty custom dropdown
821			if (!this.realElement.prop('options').length) {
822				return;
823			}
824
825			// create options list if not created
826			if (!this.dropdown) {
827				this.createDropdown();
828			}
829
830			// show dropdown
831			this.dropActive = true;
832			this.dropdown.appendTo(this.fakeDropTarget);
833			this.fakeElement.addClass(this.options.dropActiveClass);
834			this.refreshSelectedText();
835			this.repositionDropdown();
836			this.list.setScrollTop(this.savedScrollTop);
837			this.list.refresh();
838
839			// add temporary event handlers
840			this.win.on('resize', this.onResize);
841			this.doc.on('jcf-pointerdown', this.onOutsideClick);
842		},
843		hideDropdown: function() {
844			if (this.dropdown) {
845				this.savedScrollTop = this.list.getScrollTop();
846				this.fakeElement.removeClass(this.options.dropActiveClass + ' ' + this.options.flipDropClass);
847				this.dropdown.removeClass(this.options.flipDropClass).detach();
848				this.doc.off('jcf-pointerdown', this.onOutsideClick);
849				this.win.off('resize', this.onResize);
850				this.dropActive = false;
851				if (this.selectOpenedByEvent === 'touch') {
852					this.onBlur();
853				}
854			}
855		},
856		toggleDropdown: function() {
857			if (this.dropActive) {
858				this.hideDropdown();
859			} else {
860				this.showDropdown();
861			}
862		},
863		refreshSelectedText: function() {
864			// redraw selected area
865			var selectedIndex = this.realElement.prop('selectedIndex'),
866				selectedOption = this.realElement.prop('options')[selectedIndex],
867				selectedOptionImage = selectedOption ? selectedOption.getAttribute('data-image') : null,
868				selectedOptionText = '',
869				selectedOptionClasses,
870				self = this;
871
872			if (this.realElement.prop('multiple')) {
873				$.each(this.realElement.prop('options'), function(index, option) {
874					if (option.selected) {
875						selectedOptionText += (selectedOptionText ? ', ' : '') + option.innerHTML;
876					}
877				});
878				if (!selectedOptionText) {
879					selectedOptionText = self.realElement.attr('placeholder') || '';
880				}
881				this.selectText.removeAttr('class').html(selectedOptionText);
882			} else if (!selectedOption) {
883				if (this.selectImage) {
884					this.selectImage.hide();
885				}
886				this.selectText.removeAttr('class').empty();
887			} else if (this.currentSelectedText !== selectedOption.innerHTML || this.currentSelectedImage !== selectedOptionImage) {
888				selectedOptionClasses = getPrefixedClasses(selectedOption.className, this.options.optionClassPrefix);
889				this.selectText.attr('class', selectedOptionClasses).html(selectedOption.innerHTML);
890
891				if (selectedOptionImage) {
892					if (!this.selectImage) {
893						this.selectImage = $('<img>').prependTo(this.selectTextContainer).hide();
894					}
895					this.selectImage.attr('src', selectedOptionImage).show();
896				} else if (this.selectImage) {
897					this.selectImage.hide();
898				}
899
900				this.currentSelectedText = selectedOption.innerHTML;
901				this.currentSelectedImage = selectedOptionImage;
902			}
903		},
904		refresh: function() {
905			// refresh fake select visibility
906			if (this.realElement.prop('style').display === 'none') {
907				this.fakeElement.hide();
908			} else {
909				this.fakeElement.show();
910			}
911
912			// refresh selected text
913			this.refreshSelectedText();
914
915			// handle disabled state
916			this.fakeElement.toggleClass(this.options.disabledClass, this.realElement.is(':disabled'));
917		},
918		destroy: function() {
919			// restore structure
920			if (this.options.wrapNative) {
921				this.realElement.insertBefore(this.fakeElement).css({
922					position: '',
923					height: '',
924					width: ''
925				}).removeClass(this.options.resetAppearanceClass);
926			} else {
927				this.realElement.removeClass(this.options.hiddenClass);
928				if (this.realElement.is('[jcf-size]')) {
929					this.realElement.removeAttr('size jcf-size');
930				}
931			}
932
933			// removing element will also remove its event handlers
934			this.fakeElement.remove();
935
936			// remove other event handlers
937			this.doc.off('jcf-pointerup', this.onSelectAreaRelease);
938			this.realElement.off({
939				focus: this.onFocus
940			});
941		}
942	});
943
944	// listbox module
945	function ListBox(options) {
946		this.options = $.extend({
947			wrapNative: true,
948			useCustomScroll: true,
949			fakeStructure: '<span class="jcf-list-box"><span class="jcf-list-wrapper"></span></span>',
950			selectClassPrefix: 'jcf-select-',
951			listHolder: '.jcf-list-wrapper'
952		}, options);
953		this.init();
954	}
955	$.extend(ListBox.prototype, {
956		init: function() {
957			this.bindHandlers();
958			this.initStructure();
959			this.attachEvents();
960		},
961		initStructure: function() {
962			this.realElement = $(this.options.element);
963			this.fakeElement = $(this.options.fakeStructure).insertAfter(this.realElement);
964			this.listHolder = this.fakeElement.find(this.options.listHolder);
965			makeUnselectable(this.fakeElement);
966
967			// copy classes from original select
968			this.fakeElement.addClass(getPrefixedClasses(this.realElement.prop('className'), this.options.selectClassPrefix));
969			this.realElement.addClass(this.options.hiddenClass);
970
971			this.list = new SelectList({
972				useCustomScroll: this.options.useCustomScroll,
973				holder: this.listHolder,
974				selectOnClick: false,
975				element: this.realElement
976			});
977		},
978		attachEvents: function() {
979			// delayed refresh handler
980			var self = this;
981			this.delayedRefresh = function(e) {
982				if (e && (e.which === 16 || e.ctrlKey || e.metaKey || e.altKey)) {
983					// ignore modifier keys
984					return;
985				} else {
986					clearTimeout(self.refreshTimer);
987					self.refreshTimer = setTimeout(function() {
988						self.refresh();
989						self.list.scrollToActiveOption();
990					}, 1);
991				}
992			};
993
994			// other event handlers
995			this.realElement.on({
996				focus: this.onFocus,
997				click: this.delayedRefresh,
998				keydown: this.delayedRefresh
999			});
1000
1001			// select list event handlers
1002			$(this.list).on({
1003				select: this.onSelect,
1004				press: this.onFakeOptionsPress,
1005				release: this.onFakeOptionsRelease
1006			});
1007		},
1008		onFakeOptionsPress: function(e, pointerEvent) {
1009			this.pressedFlag = true;
1010			if (pointerEvent.pointerType === 'mouse') {
1011				this.realElement.focus();
1012			}
1013		},
1014		onFakeOptionsRelease: function(e, pointerEvent) {
1015			this.pressedFlag = false;
1016			if (pointerEvent.pointerType === 'mouse') {
1017				this.realElement.focus();
1018			}
1019		},
1020		onSelect: function() {
1021			this.fireNativeEvent(this.realElement, 'change');
1022			this.fireNativeEvent(this.realElement, 'click');
1023		},
1024		onFocus: function() {
1025			if (!this.pressedFlag || !this.focusedFlag) {
1026				this.fakeElement.addClass(this.options.focusClass);
1027				this.realElement.on('blur', this.onBlur);
1028				this.focusedFlag = true;
1029			}
1030		},
1031		onBlur: function() {
1032			if (!this.pressedFlag) {
1033				this.fakeElement.removeClass(this.options.focusClass);
1034				this.realElement.off('blur', this.onBlur);
1035				this.focusedFlag = false;
1036			}
1037		},
1038		refresh: function() {
1039			this.fakeElement.toggleClass(this.options.disabledClass, this.realElement.is(':disabled'));
1040			this.list.refresh();
1041		},
1042		destroy: function() {
1043			this.list.destroy();
1044			this.realElement.insertBefore(this.fakeElement).removeClass(this.options.hiddenClass);
1045			this.fakeElement.remove();
1046		}
1047	});
1048
1049	// options list module
1050	function SelectList(options) {
1051		this.options = $.extend({
1052			holder: null,
1053			maxVisibleItems: 10,
1054			selectOnClick: true,
1055			useHoverClass: false,
1056			useCustomScroll: false,
1057			handleResize: true,
1058			multipleSelectWithoutKey: false,
1059			alwaysPreventMouseWheel: false,
1060			indexAttribute: 'data-index',
1061			cloneClassPrefix: 'jcf-option-',
1062			containerStructure: '<span class="jcf-list"><span class="jcf-list-content"></span></span>',
1063			containerSelector: '.jcf-list-content',
1064			captionClass: 'jcf-optgroup-caption',
1065			disabledClass: 'jcf-disabled',
1066			optionClass: 'jcf-option',
1067			groupClass: 'jcf-optgroup',
1068			hoverClass: 'jcf-hover',
1069			selectedClass: 'jcf-selected',
1070			scrollClass: 'jcf-scroll-active'
1071		}, options);
1072		this.init();
1073	}
1074	$.extend(SelectList.prototype, {
1075		init: function() {
1076			this.initStructure();
1077			this.refreshSelectedClass();
1078			this.attachEvents();
1079		},
1080		initStructure: function() {
1081			this.element = $(this.options.element);
1082			this.indexSelector = '[' + this.options.indexAttribute + ']';
1083			this.container = $(this.options.containerStructure).appendTo(this.options.holder);
1084			this.listHolder = this.container.find(this.options.containerSelector);
1085			this.lastClickedIndex = this.element.prop('selectedIndex');
1086			this.rebuildList();
1087
1088			// save current selection in multiple select
1089			if (this.element.prop('multiple')) {
1090				this.previousSelection = this.getSelectedOptionsIndexes();
1091			}
1092		},
1093		attachEvents: function() {
1094			this.bindHandlers();
1095			this.listHolder.on('jcf-pointerdown', this.indexSelector, this.onItemPress);
1096			this.listHolder.on('jcf-pointerdown', this.onPress);
1097
1098			if (this.options.useHoverClass) {
1099				this.listHolder.on('jcf-pointerover', this.indexSelector, this.onHoverItem);
1100			}
1101		},
1102		onPress: function(e) {
1103			$(this).trigger('press', e);
1104			this.listHolder.on('jcf-pointerup', this.onRelease);
1105		},
1106		onRelease: function(e) {
1107			$(this).trigger('release', e);
1108			this.listHolder.off('jcf-pointerup', this.onRelease);
1109		},
1110		onHoverItem: function(e) {
1111			var hoverIndex = parseFloat(e.currentTarget.getAttribute(this.options.indexAttribute));
1112			this.fakeOptions.removeClass(this.options.hoverClass).eq(hoverIndex).addClass(this.options.hoverClass);
1113		},
1114		onItemPress: function(e) {
1115			if (e.pointerType === 'touch' || this.options.selectOnClick) {
1116				// select option after "click"
1117				this.tmpListOffsetTop = this.list.offset().top;
1118				this.listHolder.on('jcf-pointerup', this.indexSelector, this.onItemRelease);
1119			} else {
1120				// select option immediately
1121				this.onSelectItem(e);
1122			}
1123		},
1124		onItemRelease: function(e) {
1125			// remove event handlers and temporary data
1126			this.listHolder.off('jcf-pointerup', this.indexSelector, this.onItemRelease);
1127
1128			// simulate item selection
1129			if (this.tmpListOffsetTop === this.list.offset().top) {
1130				this.listHolder.on('click', this.indexSelector, { savedPointerType: e.pointerType }, this.onSelectItem);
1131			}
1132			delete this.tmpListOffsetTop;
1133		},
1134		onSelectItem: function(e) {
1135			var clickedIndex = parseFloat(e.currentTarget.getAttribute(this.options.indexAttribute)),
1136				pointerType = e.data && e.data.savedPointerType || e.pointerType || 'mouse',
1137				range;
1138
1139			// remove click event handler
1140			this.listHolder.off('click', this.indexSelector, this.onSelectItem);
1141
1142			// ignore clicks on disabled options
1143			if (e.button > 1 || this.realOptions[clickedIndex].disabled) {
1144				return;
1145			}
1146
1147			if (this.element.prop('multiple')) {
1148				if (e.metaKey || e.ctrlKey || pointerType === 'touch' || this.options.multipleSelectWithoutKey) {
1149					// if CTRL/CMD pressed or touch devices - toggle selected option
1150					this.realOptions[clickedIndex].selected = !this.realOptions[clickedIndex].selected;
1151				} else if (e.shiftKey) {
1152					// if SHIFT pressed - update selection
1153					range = [this.lastClickedIndex, clickedIndex].sort(function(a, b) {
1154						return a - b;
1155					});
1156					this.realOptions.each(function(index, option) {
1157						option.selected = (index >= range[0] && index <= range[1]);
1158					});
1159				} else {
1160					// set single selected index
1161					this.element.prop('selectedIndex', clickedIndex);
1162				}
1163			} else {
1164				this.element.prop('selectedIndex', clickedIndex);
1165			}
1166
1167			// save last clicked option
1168			if (!e.shiftKey) {
1169				this.lastClickedIndex = clickedIndex;
1170			}
1171
1172			// refresh classes
1173			this.refreshSelectedClass();
1174
1175			// scroll to active item in desktop browsers
1176			if (pointerType === 'mouse') {
1177				this.scrollToActiveOption();
1178			}
1179
1180			// make callback when item selected
1181			$(this).trigger('select');
1182		},
1183		rebuildList: function() {
1184			// rebuild options
1185			var self = this,
1186				rootElement = this.element[0];
1187
1188			// recursively create fake options
1189			this.storedSelectHTML = rootElement.innerHTML;
1190			this.optionIndex = 0;
1191			this.list = $(this.createOptionsList(rootElement));
1192			this.listHolder.empty().append(this.list);
1193			this.realOptions = this.element.find('option');
1194			this.fakeOptions = this.list.find(this.indexSelector);
1195			this.fakeListItems = this.list.find('.' + this.options.captionClass + ',' + this.indexSelector);
1196			delete this.optionIndex;
1197
1198			// detect max visible items
1199			var maxCount = this.options.maxVisibleItems,
1200				sizeValue = this.element.prop('size');
1201			if (sizeValue > 1 && !this.element.is('[jcf-size]')) {
1202				maxCount = sizeValue;
1203			}
1204
1205			// handle scrollbar
1206			var needScrollBar = this.fakeOptions.length > maxCount;
1207			this.container.toggleClass(this.options.scrollClass, needScrollBar);
1208			if (needScrollBar) {
1209				// change max-height
1210				this.listHolder.css({
1211					maxHeight: this.getOverflowHeight(maxCount),
1212					overflow: 'auto'
1213				});
1214
1215				if (this.options.useCustomScroll && jcf.modules.Scrollable) {
1216					// add custom scrollbar if specified in options
1217					jcf.replace(this.listHolder, 'Scrollable', {
1218						handleResize: this.options.handleResize,
1219						alwaysPreventMouseWheel: this.options.alwaysPreventMouseWheel
1220					});
1221					return;
1222				}
1223			}
1224
1225			// disable edge wheel scrolling
1226			if (this.options.alwaysPreventMouseWheel) {
1227				this.preventWheelHandler = function(e) {
1228					var currentScrollTop = self.listHolder.scrollTop(),
1229						maxScrollTop = self.listHolder.prop('scrollHeight') - self.listHolder.innerHe
1229ight();
1230
1231					// check edge cases
1232					if ((currentScrollTop <= 0 && e.deltaY < 0) || (currentScrollTop >= maxScrollTop && e.deltaY > 0)) {
1233						e.preventDefault();
1234					}
1235				};
1236				this.listHolder.on('jcf-mousewheel', this.preventWheelHandler);
1237			}
1238		},
1239		refreshSelectedClass: function() {
1240			var self = this,
1241				selectedItem,
1242				isMultiple = this.element.prop('multiple'),
1243				selectedIndex = this.element.prop('selectedIndex');
1244
1245			if (isMultiple) {
1246				this.realOptions.each(function(index, option) {
1247					self.fakeOptions.eq(index).toggleClass(self.options.selectedClass, !!option.selected);
1248				});
1249			} else {
1250				this.fakeOptions.removeClass(this.options.selectedClass + ' ' + this.options.hoverClass);
1251				selectedItem = this.fakeOptions.eq(selectedIndex).addClass(this.options.selectedClass);
1252				if (this.options.useHoverClass) {
1253					selectedItem.addClass(this.options.hoverClass);
1254				}
1255			}
1256		},
1257		scrollToActiveOption: function() {
1258			// scroll to target option
1259			var targetOffset = this.getActiveOptionOffset();
1260			if (typeof targetOffset === 'number') {
1261				this.listHolder.prop('scrollTop', targetOffset);
1262			}
1263		},
1264		getSelectedOptionsIndexes: function() {
1265			var selection = [];
1266			this.realOptions.each(function(index, option) {
1267				if (option.selected) {
1268					selection.push(index);
1269				}
1270			});
1271			return selection;
1272		},
1273		getChangedSelectedIndex: function() {
1274			var selectedIndex = this.element.prop('selectedIndex'),
1275				self = this,
1276				found = false,
1277				targetIndex = null;
1278
1279			if (this.element.prop('multiple')) {
1280				// multiple selects handling
1281				this.currentSelection = this.getSelectedOptionsIndexes();
1282				$.each(this.currentSelection, function(index, optionIndex) {
1283					if (!found && self.previousSelection.indexOf(optionIndex) < 0) {
1284						if (index === 0) {
1285							found = true;
1286						}
1287						targetIndex = optionIndex;
1288					}
1289				});
1290				this.previousSelection = this.currentSelection;
1291				return targetIndex;
1292			} else {
1293				// single choice selects handling
1294				return selectedIndex;
1295			}
1296		},
1297		getActiveOptionOffset: function() {
1298			// calc values
1299			var currentIndex = this.getChangedSelectedIndex();
1300
1301			// selection was not changed
1302			if (currentIndex === null) {
1303				return;
1304			}
1305
1306			// find option and scroll to it if needed
1307			var dropHeight = this.listHolder.height(),
1308				dropScrollTop = this.listHolder.prop('scrollTop'),
1309				fakeOption = this.fakeOptions.eq(currentIndex),
1310				fakeOptionOffset = fakeOption.offset().top - this.list.offset().top,
1311				fakeOptionHeight = fakeOption.innerHeight();
1312
1313			// scroll list
1314			if (fakeOptionOffset + fakeOptionHeight >= dropScrollTop + dropHeight) {
1315				// scroll down (always scroll to option)
1316				return fakeOptionOffset - dropHeight + fakeOptionHeight;
1317			} else if (fakeOptionOffset < dropScrollTop) {
1318				// scroll up to option
1319				return fakeOptionOffset;
1320			}
1321		},
1322		getOverflowHeight: function(sizeValue) {
1323			var item = this.fakeListItems.eq(sizeValue - 1),
1324				listOffset = this.list.offset().top,
1325				itemOffset = item.offset().top,
1326				itemHeight = item.innerHeight();
1327
1328			return itemOffset + itemHeight - listOffset;
1329		},
1330		getScrollTop: function() {
1331			return this.listHolder.scrollTop();
1332		},
1333		setScrollTop: function(value) {
1334			this.listHolder.scrollTop(value);
1335		},
1336		createOption: function(option) {
1337			var newOption = document.createElement('span');
1338			newOption.className = this.options.optionClass;
1339			newOption.innerHTML = option.innerHTML;
1340			newOption.setAttribute(this.options.indexAttribute, this.optionIndex++);
1341
1342			var optionImage, optionImageSrc = option.getAttribute('data-image');
1343			if (optionImageSrc) {
1344				optionImage = document.createElement('img');
1345				optionImage.src = optionImageSrc;
1346				newOption.insertBefore(optionImage, newOption.childNodes[0]);
1347			}
1348			if (option.disabled) {
1349				newOption.className += ' ' + this.options.disabledClass;
1350			}
1351			if (option.className) {
1352				newOption.className += ' ' + getPrefixedClasses(option.className, this.options.cloneClassPrefix);
1353			}
1354			return newOption;
1355		},
1356		createOptGroup: function(optgroup) {
1357			var optGroupContainer = document.createElement('span'),
1358				optGroupName = optgroup.getAttribute('label'),
1359				optGroupCaption, optGroupList;
1360
1361			// create caption
1362			optGroupCaption = document.createElement('span');
1363			optGroupCaption.className = this.options.captionClass;
1364			optGroupCaption.innerHTML = optGroupName;
1365			optGroupContainer.appendChild(optGroupCaption);
1366
1367			// create list of options
1368			if (optgroup.children.length) {
1369				optGroupList = this.createOptionsList(optgroup);
1370				optGroupContainer.appendChild(optGroupList);
1371			}
1372
1373			optGroupContainer.className = this.options.groupClass;
1374			return optGroupContainer;
1375		},
1376		createOptionContainer: function() {
1377			var optionContainer = document.createElement('li');
1378			return optionContainer;
1379		},
1380		createOptionsList: function(container) {
1381			var self = this,
1382				list = document.createElement('ul');
1383
1384			$.each(container.children, function(index, currentNode) {
1385				var item = self.createOptionContainer(currentNode),
1386					newNode;
1387
1388				switch (currentNode.tagName.toLowerCase()) {
1389					case 'option': newNode = self.createOption(currentNode); break;
1390					case 'optgroup': newNode = self.createOptGroup(currentNode); break;
1391				}
1392				list.appendChild(item).appendChild(newNode);
1393			});
1394			return list;
1395		},
1396		refresh: function() {
1397			// check for select innerHTML changes
1398			if (this.storedSelectHTML !== this.element.prop('innerHTML')) {
1399				this.rebuildList();
1400			}
1401
1402			// refresh custom scrollbar
1403			var scrollInstance = jcf.getInstance(this.listHolder);
1404			if (scrollInstance) {
1405				scrollInstance.refresh();
1406			}
1407
1408			// refresh selectes classes
1409			this.refreshSelectedClass();
1410		},
1411		destroy: function() {
1412			this.listHolder.off('jcf-mousewheel', this.preventWheelHandler);
1413			this.listHolder.off('jcf-pointerdown', this.indexSelector, this.onSelectItem);
1414			this.listHolder.off('jcf-pointerover', this.indexSelector, this.onHoverItem);
1415			this.listHolder.off('jcf-pointerdown', this.onPress);
1416		}
1417	});
1418
1419	// helper functions
1420	var getPrefixedClasses = function(className, prefixToAdd) {
1421		return className ? className.replace(/[\s]*([\S]+)+[\s]*/gi, prefixToAdd + '$1 ') : '';
1422	};
1423	var makeUnselectable = (function() {
1424		var unselectableClass = jcf.getOptions().unselectableClass;
1425		function preventHandler(e) {
1426			e.preventDefault();
1427		}
1428		return function(node) {
1429			node.addClass(unselectableClass).on('selectstart', preventHandler);
1430		};
1431	}());
1432
1433	return module;
1434});
1435
1436}(jcf));
1437
1438/* End */
1439;
1440; /* Start:"a:4:{s:4:"full";s:27:"/js/select.js?1736859260257";s:6:"source";s:13:"/js/select.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/
1441$(document).ready(function () {
1442		$('.modal-wrap').find('select').each(function () {
1443				$(this).attr('data-jcf', '{"wrapNative": true}')
1444		});
1445
1446		jcf.setOptions('Select', {
1447				wrapNative: false,
1448				wrapNativeOnMobile: true
1449		});
1450
1451		jcf.replaceAll();
1452});
1453
1454/* End */
1455;; /* /js/jcf.js?151707261813686*/
1456; /* /js/jcf.select.js?173657735230423*/
1457; /* /js/select.js?1736859260257*/

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.