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.