PageSourceSearch

https://iot.ru/bitrix/templates/.default/js/libs/jcf.js

js iot.ru collected 2026-10-02 07:11:47 UTC 13,517 bytes, 452 lines download raw bytes

1/*!
2 * JavaScript Custom Forms
3 *
4 * Copyright 2014-2015 PSD2HTML - http://psd2html.com/jcf
5 * Released under the MIT license (LICENSE.txt)
6 *
7 * Version: 1.2.1
8 */
9;(function(root, factory) {
10	'use strict';
11	if (typeof define === 'function' && define.amd) {
12		define(['jquery'], factory);
13	} else if (typeof exports === 'object') {
14		module.exports = factory(require('jquery'));
15	} else {
16		root.jcf = factory(jQuery);
17	}
18}(this, function($) {
19	'use strict';
20
21	// define version
22	var version = '1.2.1';
23
24	// private variables
25	var customInstances = [];
26
27	// default global options
28	var commonOptions = {
29		optionsKey: 'jcf',
30		dataKey: 'jcf-instance',
31		rtlClass: 'jcf-rtl',
32		focusClass: 'jcf-focus',
33		pressedClass: 'jcf-pressed',
34		disabledClass: 'jcf-disabled',
35		hiddenClass: 'jcf-hidden',
36		resetAppearanceClass: 'jcf-reset-appearance',
37		unselectableClass: 'jcf-unselectable'
38	};
39
40	// detect device type
41	var isTouchDevice = ('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch,
42		isWinPhoneDevice = /Windows Phone/.test(navigator.userAgent);
43	commonOptions.isMobileDevice = !!(isTouchDevice || isWinPhoneDevice);
44
45	// create global stylesheet if custom forms are used
46	var createStyleSheet = function() {
47		var styleTag = $('<style>').appendTo('head'),
48			styleSheet = styleTag.prop('sheet') || styleTag.prop('styleSheet');
49
50		// crossbrowser style handling
51		var addCSSRule = function(selector, rules, index) {
52			if (styleSheet.insertRule) {
53				styleSheet.insertRule(selector + '{' + rules + '}', index);
54			} else {
55				styleSheet.addRule(selector, rules, index);
56			}
57		};
58
59		// add special rules
60		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');
61		addCSSRule('.' + commonOptions.rtlClass + ' .' + commonOptions.hiddenClass, 'right:-9999px !important; left: auto !important');
62		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);');
63		addCSSRule('.' + commonOptions.resetAppearanceClass, 'background: none; border: none; -webkit-appearance: none; appearance: none; opacity: 0; filter: alpha(opacity=0);');
64
65		// detect rtl pages
66		var html = $('html'), body = $('body');
67		if (html.css('direction') === 'rtl' || body.css('direction') === 'rtl') {
68			html.addClass(commonOptions.rtlClass);
69		}
70
71		// handle form reset event
72		html.on('reset', function() {
73			setTimeout(function() {
74				api.refreshAll();
75			}, 0);
76		});
77
78		// mark stylesheet as created
79		commonOptions.styleSheetCreated = true;
80	};
81
82	// simplified pointer events handler
83	(function() {
84		var pointerEventsSupported = navigator.pointerEnabled || navigator.msPointerEnabled,
85			touchEventsSupported = ('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch,
86			eventList, eventMap = {}, eventPrefix = 'jcf-';
87
88		// detect events to attach
89		if (pointerEventsSupported) {
90			eventList = {
91				pointerover: navigator.pointerEnabled ? 'pointerover' : 'MSPointerOver',
92				pointerdown: navigator.pointerEnabled ? 'pointerdown' : 'MSPointerDown',
93				pointermove: navigator.pointerEnabled ? 'pointermove' : 'MSPointerMove',
94				pointerup: navigator.pointerEnabled ? 'pointerup' : 'MSPointerUp'
95			};
96		} else {
97			eventList = {
98				pointerover: 'mouseover',
99				pointerdown: 'mousedown' + (touchEventsSupported ? ' touchstart' : ''),
100				pointermove: 'mousemove' + (touchEventsSupported ? ' touchmove' : ''),
101				pointerup: 'mouseup' + (touchEventsSupported ? ' touchend' : '')
102			};
103		}
104
105		// create event map
106		$.each(eventList, function(targetEventName, fakeEventList) {
107			$.each(fakeEventList.split(' '), function(index, fakeEventName) {
108				eventMap[fakeEventName] = targetEventName;
109			});
110		});
111
112		// jQuery event hooks
113		$.each(eventList, function(eventName, eventHandlers) {
114			eventHandlers = eventHandlers.split(' ');
115			$.event.special[eventPrefix + eventName] = {
116				setup: function() {
117					var self = this;
118					$.each(eventHandlers, function(index, fallbackEvent) {
119						if (self.addEventListener) self.addEventListener(fallbackEvent, fixEvent, false);
120						else self['on' + fallbackEvent] = fixEvent;
121					});
122				},
123				teardown: function() {
124					var self = this;
125					$.each(eventHandlers, function(index, fallbackEvent) {
126						if (self.addEventListener) self.removeEventListener(fallbackEvent, fixEvent, false);
127						else self['on' + fallbackEvent] = null;
128					});
129				}
130			};
131		});
132
133		// check that mouse event are not simulated by mobile browsers
134		var lastTouch = null;
135		var mouseEventSimulated = function(e) {
136			var dx = Math.abs(e.pageX - lastTouch.x),
137				dy = Math.abs(e.pageY - lastTouch.y),
138				rangeDistance = 25;
139
140			if (dx <= rangeDistance && dy <= rangeDistance) {
141				return true;
142			}
143		};
144
145		// normalize event
146		var fixEvent = function(e) {
147			var origEvent = e || window.event,
148				touchEventData = null,
149				targetEventName = eventMap[origEvent.type];
150
151			e = $.event.fix(origEvent);
152			e.type = eventPrefix + targetEventName;
153
154			if (origEvent.pointerType) {
155				switch (origEvent.pointerType) {
156					case 2: e.pointerType = 'touch'; break;
157					case 3: e.pointerType = 'pen'; break;
158					case 4: e.pointerType = 'mouse'; break;
159					default: e.pointerType = origEvent.pointerType;
160				}
161			} else {
162				e.pointerType = origEvent.type.substr(0, 5); // "mouse" or "touch" word length
163			}
164
165			if (!e.pageX && !e.pageY) {
166				touchEventData = origEvent.changedTouches ? origEvent.changedTouches[0] : origEvent;
167				e.pageX = touchEventData.pageX;
168				e.pageY = touchEventData.pageY;
169			}
170
171			if (origEvent.type === 'touchend') {
172				lastTouch = { x: e.pageX, y: e.pageY };
173			}
174			if (e.pointerType === 'mouse' && lastTouch && mouseEventSimulated(e)) {
175				return;
176			} else {
177				return ($.event.dispatch || $.event.handle).call(this, e);
178			}
179		};
180	}());
181
182	// custom mousewheel/trackpad handler
183	(function() {
184		var wheelEvents = ('onwheel' in document || document.documentMode >= 9 ? 'wheel' : 'mousewheel DOMMouseScroll').split(' '),
185			shimEventName = 'jcf-mousewheel';
186
187		$.event.special[shimEventName] = {
188			setup: function() {
189				var self = this;
190				$.each(wheelEvents, function(index, fallbackEvent) {
191					if (self.addEventListener) self.addEventListener(fallbackEvent, fixEvent, false);
192					else self['on' + fallbackEvent] = fixEvent;
193				});
194			},
195			teardown: function() {
196				var self = this;
197				$.each(wheelEvents, function(index, fallbackEvent) {
198					if (self.addEventListener) self.removeEventListener(fallbackEvent, fixEvent, false);
199					else self['on' + fallbackEvent] = null;
200				});
201			}
202		};
203
204		var fixEvent = function(e) {
205			var origEvent = e || window.event;
206			e = $.event.fix(origEvent);
207			e.type = shimEventName;
208
209			// old wheel events handler
210			if ('detail'      in origEvent) { e.deltaY = -origEvent.detail;      }
211			if ('wheelDelta'  in origEvent) { e.deltaY = -origEvent.wheelDelta;  }
212			if ('wheelDeltaY' in origEvent) { e.deltaY = -origEvent.wheelDeltaY; }
213			if ('wheelDeltaX' in origEvent) { e.deltaX = -origEvent.wheelDeltaX; }
214
215			// modern wheel event handler
216			if ('deltaY' in origEvent) {
217				e.deltaY = origEvent.deltaY;
218			}
219			if ('deltaX' in origEvent) {
220				e.deltaX = origEvent.deltaX;
221			}
222
223			// handle deltaMode for mouse wheel
224			e.delta = e.deltaY || e.deltaX;
225			if (origEvent.deltaMode === 1) {
226				var lineHeight = 16;
227				e.delta *= lineHeight;
228				e.deltaY *= lineHeight;
229				e.deltaX *= lineHeight;
230			}
231
232			return ($.event.dispatch || $.event.handle).call(this, e);
233		};
234	}());
235
236	// extra module methods
237	var moduleMixin = {
238		// provide function for firing native events
239		fireNativeEvent: function(elements, eventName) {
240			$(elements).each(function() {
241				var element = this, eventObject;
242				if (element.dispatchEvent) {
243					eventObject = document.createEvent('HTMLEvents');
244					eventObject.initEvent(eventName, true, true);
245					element.dispatchEvent(eventObject);
246				} else if (document.createEventObject) {
247					eventObject = document.createEventObject();
248					eventObject.target = element;
249					element.fireEvent('on' + eventName, eventObject);
250				}
251			});
252		},
253		// bind event handlers for module instance (functions beggining with "on")
254		bindHandlers: function() {
255			var self = this;
256			$.each(self, function(propName, propValue) {
257				if (propName.indexOf('on') === 0 && $.isFunction(propValue)) {
258					// dont use $.proxy here because it doesn't create unique handler
259					self[propName] = function() {
260						return propValue.apply(self, arguments);
261					};
262				}
263			});
264		}
265	};
266
267	// public API
268	var api = {
269		version: version,
270		modules: {},
271		getOptions: function() {
272			return $.extend({}, commonOptions);
273		},
274		setOptions: function(moduleName, moduleOptions) {
275			if (arguments.length > 1) {
276				// set module options
277				if (this.modules[moduleName]) {
278					$.extend(this.modules[moduleName].prototype.options, moduleOptions);
279				}
280			} else {
281				// set common options
282				$.extend(commonOptions, moduleName);
283			}
284		},
285		addModule: function(proto) {
286			// proto is factory function
287			if ($.isFunction(proto)) {
288				proto = proto($, window);
289			}
290
291			// add module to list
292			var Module = function(options) {
293				// save instance to collection
294				if (!options.element.data(commonOptions.dataKey)) {
295					options.element.data(commonOptions.dataKey, this);
296				}
297				customInstances.push(this);
298
299				// save options
300				this.options = $.extend({}, commonOptions, this.options, getInlineOptions(options.element), options);
301
302				// bind event handlers to instance
303				this.bindHandlers();
304
305				// call constructor
306				this.init.apply(this, arguments);
307			};
308
309			// parse options from HTML attribute
310			var getInlineOptions = function(element) {
311				var dataOptions = element.data(commonOptions.optionsKey),
312					attrOptions = element.attr(commonOptions.optionsKey);
313
314				if (dataOptions) {
315					return dataOptions;
316				} else if (attrOptions) {
317					try {
318						return $.parseJSON(attrOptions);
319					} catch (e) {
320						// ignore invalid attributes
321					}
322				}
323			};
324
325			// set proto as prototype for new module
326			Module.prototype = proto;
327
328			// add mixin methods to module proto
329			$.extend(proto, moduleMixin);
330			if (proto.plugins) {
331				$.each(proto.plugins, function(pluginName, plugin) {
332					$.extend(plugin.prototype, moduleMixin);
333				});
334			}
335
336			// override destroy method
337			var originalDestroy = Module.prototype.destroy;
338			Module.prototype.destroy = function() {
339				this.options.element.removeData(this.options.dataKey);
340
341				for (var i = customInstances.length - 1; i >= 0; i--) {
342					if (customInstances[i] === this) {
343						customInstances.splice(i, 1);
344						break;
345					}
346				}
347
348				if (originalDestroy) {
349					originalDestroy.apply(this, arguments);
350				}
351			};
352
353			// save module to list
354			this.modules[proto.name] = Module;
355		},
356		getInstance: function(element) {
357			return $(element).data(commonOptions.dataKey);
358		},
359		replace: function(elements, moduleName, customOptions) {
360			var self = this,
361				instance;
362
363			if (!commonOptions.styleSheetCreated) {
364				createStyleSheet();
365			}
366
367			$(elements).each(function() {
368				var moduleOptions,
369					element = $(this);
370
371				instance = element.data(commonOptions.dataKey);
372				if (instance) {
373					instance.refresh();
374				} else {
375					if (!moduleName) {
376						$.each(self.modules, function(currentModuleName, module) {
377							if (module.prototype.matchElement.call(module.prototype, element)) {
378								moduleName = currentModuleName;
379								return false;
380							}
381						});
382					}
383					if (moduleName) {
384						moduleOptions = $.extend({ element: element }, customOptions);
385						instance = new self.modules[moduleName](moduleOptions);
386					}
387				}
388			});
389			return instance;
390		},
391		refresh: function(elements) {
392			$(elements).each(function() {
393				var instance = $(this).data(commonOptions.dataKey);
394				if (instance) {
395					instance.refresh();
396				}
397			});
398		},
399		destroy: function(elements) {
400			$(elements).each(function() {
401				var instance = $(this).data(commonOptions.dataKey);
402				if (instance) {
403					instance.destroy();
404				}
405			});
406		},
407		replaceAll: function(context) {
408			var self = this;
409			$.each(this.modules, function(moduleName, module) {
410				$(module.prototype.selector, context).each(function() {
411					if (this.className.indexOf('jcf-ignore') < 0) {
412						self.replace(this, moduleName);
413					}
414				});
415			});
416		},
417		refreshAll: function(context) {
418			if (context) {
419				$.each(this.modules, function(moduleName, module) {
420					$(module.prototype.selector, context).each(function() {
421						var instance = $(this).data(commonOptions.dataKey);
422						if (instance) {
423							instance.refresh();
424						}
425					});
426				});
427			} else {
428				for (var i = customInstances.length - 1; i >= 0; i--) {
429					customInstances[i].refresh();
430				}
431			}
432		},
433		destroyAll: function(context) {
434			if (context) {
435				$.each(this.modules, function(moduleName, module) {
436					$(module.prototype.selector, context).each(function(index, element) {
437						var instance = $(element).data(commonOptions.dataKey);
438						if (instance) {
439							instance.destroy();
440						}
441					});
442				});
443			} else {
444				while (customInstances.length) {
445					customInstances[0].destroy();
446				}
447			}
448		}
449	};
450
451	return api;
452}));

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.