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