1/* 2 * JavaScript Custom Forms Module 3 */ 4jcf = { 5 // global options 6 modules: {}, 7 plugins: {}, 8 baseOptions: { 9 unselectableClass:'jcf-unselectable', 10 labelActiveClass:'jcf-label-active', 11 labelDisabledClass:'jcf-label-disabled', 12 classPrefix: 'jcf-class-', 13 hiddenClass:'jcf-hidden', 14 focusClass:'jcf-focus', 15 wrapperTag: 'div' 16 }, 17 // replacer function 18 customForms: { 19 setOptions: function(obj) { 20 for(var p in obj) { 21 if(obj.hasOwnProperty(p) && typeof obj[p] === 'object') { 22 jcf.lib.extend(jcf.modules[p].prototype.defaultOptions, obj[p]); 23 } 24 } 25 }, 26 replaceAll: function(context) { 27 for(var k in jcf.modules) { 28 var els = jcf.lib.queryBySelector(jcf.modules[k].prototype.selector, context); 29 for(var i = 0; i<els.length; i++) { 30 if(els[i].jcf) { 31 // refresh form element state 32 els[i].jcf.refreshState(); 33 } else { 34 // replace form element 35 if(!jcf.lib.hasClass(els[i], 'default') && jcf.modules[k].prototype.checkElement(els[i])) { 36 new jcf.modules[k]({ 37 replaces:els[i] 38 }); 39 } 40 } 41 } 42 } 43 }, 44 refreshAll: function(context) { 45 for(var k in jcf.modules) { 46 var els = jcf.lib.queryBySelector(jcf.modules[k].prototype.selector, context); 47 for(var i = 0; i<els.length; i++) { 48 if(els[i].jcf) { 49 // refresh form element state 50 els[i].jcf.refreshState(); 51 } 52 } 53 } 54 }, 55 refreshElement: function(obj) { 56 if(obj && obj.jcf) { 57 obj.jcf.refreshState(); 58 } 59 }, 60 destroyAll: function() { 61 for(var k in jcf.modules) { 62 var els = jcf.lib.queryBySelector(jcf.modules[k].prototype.selector); 63 for(var i = 0; i<els.length; i++) { 64 if(els[i].jcf) { 65 els[i].jcf.destroy(); 66 } 67 } 68 } 69 } 70 }, 71 // detect device type 72 isTouchDevice: ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch, 73 isWinPhoneDevice: navigator.msPointerEnabled && /MSIE 10.*Touch/.test(navigator.userAgent), 74 // define base module 75 setBaseModule: function(obj) { 76 jcf.customControl = function(opt){ 77 this.options = jcf.lib.extend({}, jcf.baseOptions, this.defaultOptions, opt); 78 this.init(); 79 }; 80 for(var p in obj) { 81 jcf.customControl.prototype[p] = obj[p]; 82 } 83 }, 84 // add module to jcf.modules 85 addModule: function(obj) { 86 if(obj.name){ 87 // create new module proto class 88 jcf.modules[obj.name] = function(){ 89 jcf.modules[obj.name].superclass.constructor.apply(this, arguments); 90 } 91 jcf.lib.inherit(jcf.modules[obj.name], jcf.customControl); 92 for(var p in obj) { 93 jcf.modules[obj.name].prototype[p] = obj[p] 94 } 95 // on create module 96 jcf.modules[obj.name].prototype.onCreateModule(); 97 // make callback for exciting modules 98 for(var mod in jcf.modules) { 99 if(jcf.modules[mod] != jcf.modules[obj.name]) { 100 jcf.modules[mod].prototype.onModuleAdded(jcf.modules[obj.name]); 101 } 102 } 103 } 104 }, 105 // add plugin to jcf.plugins 106 addPlugin: function(obj) { 107 if(obj && obj.name) { 108 jcf.plugins[obj.name] = function() { 109 this.init.apply(this, arguments); 110 } 111 for(var p in obj) { 112 jcf.plugins[obj.name].prototype[p] = obj[p]; 113 } 114 } 115 }, 116 // miscellaneous init 117 init: function(){ 118 if(navigator.pointerEnabled) { 119 this.eventPress = 'pointerdown'; 120 this.eventMove = 'pointermove'; 121 this.eventRelease = 'pointerup'; 122 } else if(navigator.msPointerEnabled) { 123 this.eventPress = 'MSPointerDown'; 124 this.eventMove = 'MSPointerMove'; 125 this.eventRelease = 'MSPointerUp'; 126 } else { 127 this.eventPress = this.isTouchDevice ? 'touchstart' : 'mousedown'; 128 this.eventMove = this.isTouchDevice ? 'touchmove' : 'mousemove'; 129 this.eventRelease = this.isTouchDevice ? 'touchend' : 'mouseup'; 130 } 131 132 setTimeout(function(){ 133 jcf.lib.domReady(function(){ 134 jcf.initStyles(); 135 }); 136 },1); 137 return this; 138 }, 139 initStyles: function() { 140 // create <style> element and rules 141 var head = document.getElementsByTagName('head')[0], 142 style = document.createElement('style'), 143 rules = document.createTextNode('.'+jcf.baseOptions.unselectableClass+'{'+ 144 '-moz-user-select:none;'+ 145 '-webkit-tap-highlight-color:rgba(255,255,255,0);'+ 146 '-webkit-user-select:none;'+ 147 'user-select:none;'+ 148 '}'); 149 150 // append style element 151 style.type = 'text/css'; 152 if(style.styleSheet) { 153 style.styleSheet.cssText = rules.nodeValue; 154 } else { 155 style.appendChild(rules); 156 } 157 head.appendChild(style); 158 } 159}.init(); 160 161/* 162 * Custom Form Control prototype 163 */ 164jcf.setBaseModule({ 165 init: function(){ 166 if(this.options.replaces) { 167 this.realElement = this.options.replaces; 168 this.realElement.jcf = this; 169 this.replaceObject(); 170 } 171 }, 172 defaultOptions: { 173 // default module options (will be merged with base options) 174 }, 175 checkElement: function(el){ 176 return true;
176 // additional check for correct form element 177 }, 178 replaceObject: function(){ 179 this.createWrapper(); 180 this.attachEvents(); 181 this.fixStyles(); 182 this.setupWrapper(); 183 }, 184 createWrapper: function(){ 185 this.fakeElement = jcf.lib.createElement(this.options.wrapperTag); 186 this.labelFor = jcf.lib.getLabelFor(this.realElement); 187 jcf.lib.disableTextSelection(this.fakeElement); 188 jcf.lib.addClass(this.fakeElement, jcf.lib.getAllClasses(this.realElement.className, this.options.classPrefix)); 189 jcf.lib.addClass(this.realElement, jcf.baseOptions.hiddenClass); 190 }, 191 attachEvents: function(){ 192 jcf.lib.event.add(this.realElement, 'focus', this.onFocusHandler, this); 193 jcf.lib.event.add(this.realElement, 'blur', this.onBlurHandler, this); 194 jcf.lib.event.add(this.fakeElement, 'click', this.onFakeClick, this); 195 jcf.lib.event.add(this.fakeElement, jcf.eventPress, this.onFakePressed, this); 196 jcf.lib.event.add(this.fakeElement, jcf.eventRelease, this.onFakeReleased, this); 197 198 if(this.labelFor) { 199 this.labelFor.jcf = this; 200 jcf.lib.event.add(this.labelFor, 'click', this.onFakeClick, this); 201 jcf.lib.event.add(this.labelFor, jcf.eventPress, this.onFakePressed, this); 202 jcf.lib.event.add(this.labelFor, jcf.eventRelease, this.onFakeReleased, this); 203 } 204 }, 205 fixStyles: function() { 206 // hide mobile webkit tap effect 207 if(jcf.isTouchDevice) { 208 var tapStyle = 'rgba(255,255,255,0)'; 209 this.realElement.style.webkitTapHighlightColor = tapStyle; 210 this.fakeElement.style.webkitTapHighlightColor = tapStyle; 211 if(this.labelFor) { 212 this.labelFor.style.webkitTapHighlightColor = tapStyle; 213 } 214 } 215 }, 216 setupWrapper: function(){ 217 // implement in subclass 218 }, 219 refreshState: function(){ 220 // implement in subclass 221 }, 222 destroy: function() { 223 if(this.fakeElement && this.fakeElement.parentNode) { 224 this.fakeElement.parentNode.insertBefore(this.realElement, this.fakeElement); 225 this.fakeElement.parentNode.removeChild(this.fakeElement); 226 } 227 jcf.lib.removeClass(this.realElement, jcf.baseOptions.hiddenClass); 228 this.realElement.jcf = null; 229 }, 230 onFocus: function(){ 231 // emulated focus event 232 jcf.lib.addClass(this.fakeElement,this.options.focusClass); 233 }, 234 onBlur: function(cb){ 235 // emulated blur event 236 jcf.lib.removeClass(this.fakeElement,this.options.focusClass); 237 }, 238 onFocusHandler: function() { 239 // handle focus loses 240 if(this.focused) return; 241 this.focused = true; 242 243 // handle touch devices also 244 if(jcf.isTouchDevice) { 245 if(jcf.focusedInstance && jcf.focusedInstance.realElement != this.realElement) { 246 jcf.focusedInstance.onBlur(); 247 jcf.focusedInstance.realElement.blur(); 248 } 249 jcf.focusedInstance = this; 250 } 251 this.onFocus.apply(this, arguments); 252 }, 253 onBlurHandler: function() { 254 // handle focus loses 255 if(!this.pressedFlag) { 256 this.focused = false; 257 this.onBlur.apply(this, arguments); 258 } 259 }, 260 onFakeClick: function(){ 261 if(jcf.isTouchDevice) { 262 this.onFocus(); 263 } else if(!this.realElement.disabled) { 264 this.realElement.focus(); 265 } 266 }, 267 onFakePressed: function(e){ 268 this.pressedFlag = true; 269 }, 270 onFakeReleased: function(){ 271 this.pressedFlag = false; 272 }, 273 onCreateModule: function(){ 274 // implement in subclass 275 }, 276 onModuleAdded: function(module) { 277 // implement in subclass 278 }, 279 onControlReady: function() { 280 // implement in subclass 281 } 282}); 283 284/* 285 * JCF Utility Library 286 */ 287jcf.lib = { 288 bind: function(func, scope){ 289 return function() { 290 return func.apply(scope, arguments); 291 }; 292 }, 293 browser: (function() { 294 var ua = navigator.userAgent.toLowerCase(), res = {}, 295 match = /(webkit)[ \/]([\w.]+)/.exec(ua) || /(opera)(?:.*version)?[ \/]([\w.]+)/.exec(ua) || 296 /(msie) ([\w.]+)/.exec(ua) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+))?/.exec(ua) || []; 297 res[match[1]] = true; 298 res.version = match[2] || "0"; 299 res.safariMac = ua.indexOf('mac') != -1 && ua.indexOf('safari') != -1; 300 return res; 301 })(), 302 getOffset: function (obj) { 303 if (obj.getBoundingClientRect && !jcf.isWinPhoneDevice) { 304 var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft; 305 var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; 306 var clientLeft = document.documentElement.clientLeft || document.body.clientLeft || 0; 307 var clientTop = document.documentElement.clientTop || document.body.clientTop || 0; 308 return { 309 top:Math.round(obj.getBoundingClientRect().top + scrollTop - clientTop), 310 left:Math.round(obj.getBoundingClientRect().left + scrollLeft - clientLeft) 311 }; 312 } else { 313 var posLeft = 0, posTop = 0; 314 while (obj.offsetParent) {posLeft += obj.offsetLeft; posTop += obj.offsetTop; obj = obj.offsetParent;}
315 return {top:posTop,left:posLeft}; 316 } 317 }, 318 getScrollTop: function() { 319 return window.pageYOffset || document.documentElement.scrollTop; 320 }, 321 getScrollLeft: function() { 322 return window.pageXOffset || document.documentElement.scrollLeft; 323 }, 324 getWindowWidth: function(){ 325 return document.compatMode=='CSS1Compat' ? document.documentElement.clientWidth : document.body.clientWidth; 326 }, 327 getWindowHeight: function(){ 328 return document.compatMode=='CSS1Compat' ? document.documentElement.clientHeight : document.body.clientHeight; 329 }, 330 getStyle: function(el, prop) { 331 if (document.defaultView && document.defaultView.getComputedStyle) { 332 return document.defaultView.getComputedStyle(el, null)[prop]; 333 } else if (el.currentStyle) { 334 return el.currentStyle[prop]; 335 } else { 336 return el.style[prop]; 337 } 338 }, 339 getParent: function(obj, selector) { 340 while(obj.parentNode && obj.parentNode != document.body) { 341 if(obj.parentNode.tagName.toLowerCase() == selector.toLowerCase()) { 342 return obj.parentNode; 343 } 344 obj = obj.parentNode; 345 } 346 return false; 347 }, 348 isParent: function(parent, child) { 349 while(child.parentNode) { 350 if(child.parentNode === parent) { 351 return true; 352 } 353 child = child.parentNode; 354 } 355 return false; 356 }, 357 getLabelFor: function(object) { 358 var parentLabel = jcf.lib.getParent(object,'label'); 359 if(parentLabel) { 360 return parentLabel; 361 } else if(object.id) { 362 return jcf.lib.queryBySelector('label[for="' + object.id + '"]')[0]; 363 } 364 }, 365 disableTextSelection: function(el){ 366 if (typeof el.onselectstart !== 'undefined') { 367 el.onselectstart = function() {return false;}; 368 } else if(window.opera) { 369 el.setAttribute('unselectable', 'on'); 370 } else { 371 jcf.lib.addClass(el, jcf.baseOptions.unselectableClass); 372 } 373 }, 374 enableTextSelection: function(el) { 375 if (typeof el.onselectstart !== 'undefined') { 376 el.onselectstart = null; 377 } else if(window.opera) { 378 el.removeAttribute('unselectable'); 379 } else { 380 jcf.lib.removeClass(el, jcf.baseOptions.unselectableClass); 381 } 382 }, 383 queryBySelector: function(selector, scope){ 384 if(typeof scope === 'string') { 385 var result = []; 386 var holders = this.getElementsBySelector(scope); 387 for (var i = 0, contextNodes; i < holders.length; i++) { 388 contextNodes = Array.prototype.slice.call(this.getElementsBySelector(selector, holders[i])); 389 result = result.concat(contextNodes); 390 } 391 return result; 392 } else { 393 return this.getElementsBySelector(selector, scope); 394 } 395 }, 396 prevSibling: function(node) { 397 while(node = node.previousSibling) if(node.nodeType == 1) break; 398 return node; 399 }, 400 nextSibling: function(node) { 401 while(node = node.nextSibling) if(node.nodeType == 1) break; 402 return node; 403 }, 404 fireEvent: function(element,event) { 405 if(element.dispatchEvent){ 406 var evt = document.createEvent('HTMLEvents'); 407 evt.initEvent(event, true, true ); 408 return !element.dispatchEvent(evt); 409 }else if(document.createEventObject){ 410 var evt = document.createEventObject(); 411 return element.fireEvent('on'+event,evt); 412 } 413 }, 414 inherit: function(Child, Parent) { 415 var F = function() { } 416 F.prototype = Parent.prototype 417 Child.prototype = new F() 418 Child.prototype.constructor = Child 419 Child.superclass = Parent.prototype 420 }, 421 extend: function(obj) { 422 for(var i = 1; i < arguments.length; i++) { 423 for(var p in arguments[i]) { 424 if(arguments[i].hasOwnProperty(p)) { 425 obj[p] = arguments[i][p]; 426 } 427 } 428 } 429 return obj; 430 }, 431 hasClass: function (obj,cname) { 432 return (obj.className ? obj.className.match(new RegExp('(\\s|^)'+cname+'(\\s|$)')) : false); 433 }, 434 addClass: function (obj,cname) { 435 if (!this.hasClass(obj,cname)) obj.className += (!obj.className.length || obj.className.charAt(obj.className.length - 1) === ' ' ? '' : ' ') + cname; 436 }, 437 removeClass: function (obj,cname) { 438 if (this.hasClass(obj,cname)) obj.className=obj.className.replace(new RegExp('(\\s|^)'+cname+'(\\s|$)'),' ').replace(/\s+$/, ''); 439 }, 440 toggleClass: function(obj, cname, condition) { 441 if(condition) this.addClass(obj, cname); else this.removeClass(obj, cname); 442 }, 443 createElement: function(tagName, options) { 444 var el = document.createElement(tagName); 445 for(var p in options) { 446 if(options.hasOwnProperty(p)) { 447 switch (p) { 448 case 'class': el.className = options[p]; break; 449 case 'html': el.innerHTML = options[p]; break; 450 case 'style': this.setStyles(el, options[p]); break; 451 default: el.setAttribute(p, options[p]); 452 } 453 } 454 } 455 return el; 456 }, 457 setStyles: function(el, styles) { 458 for(var p in styles) { 459 if(styles.hasOwnProperty(p)) { 460 switch (p) { 461 case 'float': el.style.cssFloat = styles[p]; break; 462 case 'opacity': el.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity='+styles[p]*100+')'; el.style.opacity = styles[p]; break; 463 default: el.style[p] = (typeof styles[p] === 'undefined' ? 0 : styles[p]) + (typeof styles[p] === 'number' ? 'px' : ''); 464 } 465 } 466 } 467 return el; 468 }, 469 getInnerWidth: function(el) { 470 return el.offsetWidth - (parseInt(this.getStyle(el,'paddingLeft')) || 0) - (parseInt(this.getStyle(el,'paddingRight')) || 0); 471 }, 472 getInnerHeight: function(el) { 473 return el.offsetHeight - (parseInt(this.getStyle(el,'paddingTop')) || 0) - (parseInt(this.getStyle(el,'paddingBottom')) || 0); 474 }, 475 getAllClasses: function(cname, prefix, skip) { 476 if(!skip) skip = ''; 477 if(!prefix) prefix = ''; 478 return cname ? cname.replace(new RegExp('(\\s|^)'+skip+'(\\s|$)'),' ').replace(/[\s]*([\S]+)+[\s]*/gi,prefix+"$1 ") : ''; 479 }, 480 getElementsBySelector: function(selector, scope) { 481 if(typeof document.querySelectorAll === 'function') { 482 return (scope || document).querySelectorAll(selector); 483 } 484 var selectors = selector.split(','); 485 var resultList = []; 486 for(var s = 0; s < selectors.length; s++) { 487 var currentContext = [scope || document]; 488 var tokens = selectors[s].replace(/^\s+/,'').replace(/\s+$/,'').split(' '); 489 for (var i = 0; i < tokens.length; i++) { 490 token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,''); 491 if (token.indexOf('#') > -1) { 492 var bits = token.split('#'), tagName = bits[0], id = bits[1]; 493 var element = document.getElementById(id); 494 if (tagName && element.nodeName.toLowerCase() != tagName) { 495 return []; 496 } 497 currentContext = [element]; 498 continue; 499 } 500 if (token.indexOf('.') > -1) { 501 var bits = token.split('.'), tagName = bits[0] || '*', className = bits[1], found = [], foundCount = 0; 502 for (var h = 0; h < currentContext.length; h++) { 503 var elements; 504 if (tagName == '*') { 505 elements = currentContext[h].getElementsByTagName('*'); 506 } else { 507 elements = currentContext[h].getElementsByTagName(tagName); 508 } 509 for (var j = 0; j < elements.length; j++) { 510 found[foundCount++] = elements[j]; 511 } 512 } 513 currentContext = []; 514 var currentContextIndex = 0; 515 for (var k = 0; k < found.length; k++) { 516 if (found[k].className && found[k].className.match(new RegExp('(\\s|^)'+className+'(\\s|$)'))) { 517 currentContext[currentContextIndex++] = found[k]; 518 } 519 } 520 continue; 521 } 522 if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) { 523 var tagName = RegExp.$1 || '*', attrName = RegExp.$2, attrOperator = RegExp.$3, attrValue = RegExp.$4; 524 if(attrName.toLowerCase() == 'for' && this.browser.msie && this.browser.version < 8) { 525 attrName = 'htmlFor'; 526 } 527 var found = [], foundCount = 0; 528 for (var h = 0; h < currentContext.length; h++) { 529 var elements; 530 if (tagName == '*') { 531 elements = currentContext[h].getElementsByTagName('*'); 532 } else { 533 elements = currentContext[h].getElementsByTagName(tagName); 534 } 535 for (var j = 0; elements[j]; j++) { 536 found[foundCount++] = elements[j]; 537 } 538 } 539 currentContext = []; 540 var currentContextIndex = 0, checkFunction; 541 switch (attrOperator) { 542 case '=': checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue) }; break; 543 case '~': checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('(\\s|^)'+attrValue+'(\\s|$)'))) }; break; 544 case '|': checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))) }; break; 545 case '^': checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0) }; break; 546 case '$': checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length) }; break; 547 case '*': checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1) }; break; 548 default : checkFunction = function(e) { return e.getAttribute(attrName) }; 549 } 550 currentContext = []; 551 var currentContextIndex = 0; 552 for (var k = 0; k < found.length; k++) { 553 if (checkFunction(found[k])) { 554 currentContext[currentContextIndex++] = found[k]; 555 } 556 } 557 continue; 558 } 559 tagName = token; 560 var found = [], foundCount = 0; 561 for (var h = 0; h < currentContext.length; h++) { 562 var elements = currentContext[h].getElementsByTagName(tagName); 563 for (var j = 0; j < elements.length; j++) { 564 found[foundCount++] = elements[j]; 565 } 566 } 567 currentContext = found; 568 } 569 resultList = [].concat(resultList,currentContext); 570 } 571 return resultList; 572 }, 573 scrollSize: (function(){ 574 var content, hold, sizeBefore, sizeAfter; 575 function buildSizer(){ 576 if(hold) removeSizer(); 577 content = document.createElement('div'); 578 hold = document.createElement('div'); 579 hold.style.cssText = 'position:absolute;overflow:hidden;width:100px;height:100px'; 580 hold.appendChild(content); 581 document.body.appendChild(hold); 582 } 583 function removeSizer(){ 584 document.body.removeChild(hold); 585 hold = null; 586 } 587 function calcSize(vertical) { 588 buildSizer(); 589 content.style.cssText = 'height:'+(vertical ? '100%' : '200px'); 590 sizeBefore = (vertical ? content.offsetHeight : content.offsetWidth);
591 hold.style.overflow = 'scroll'; content.innerHTML = 1; 592 sizeAfter = (vertical ? content.offsetHeight : content.offsetWidth); 593 if(vertical && hold.clientHeight) sizeAfter = hold.clientHeight; 594 removeSizer(); 595 return sizeBefore - sizeAfter; 596 } 597 return { 598 getWidth:function(){ 599 return calcSize(false); 600 }, 601 getHeight:function(){ 602 return calcSize(true) 603 } 604 } 605 }()), 606 domReady: function (handler){ 607 var called = false 608 function ready() { 609 if (called) return; 610 called = true; 611 handler(); 612 } 613 if (document.addEventListener) { 614 document.addEventListener("DOMContentLoaded", ready, false); 615 } else if (document.attachEvent) { 616 if (document.documentElement.doScroll && window == window.top) { 617 function tryScroll(){ 618 if (called) return 619 if (!document.body) return 620 try { 621 document.documentElement.doScroll("left") 622 ready() 623 } catch(e) { 624 setTimeout(tryScroll, 0) 625 } 626 } 627 tryScroll() 628 } 629 document.attachEvent("onreadystatechange", function(){ 630 if (document.readyState === "complete") { 631 ready() 632 } 633 }) 634 } 635 if (window.addEventListener) window.addEventListener('load', ready, false) 636 else if (window.attachEvent) window.attachEvent('onload', ready) 637 }, 638 event: (function(){ 639 var guid = 0; 640 function fixEvent(e) { 641 e = e || window.event; 642 if (e.isFixed) { 643 return e; 644 } 645 e.isFixed = true; 646 e.preventDefault = e.preventDefault || function(){this.returnValue = false} 647 e.stopPropagation = e.stopPropagation || function(){this.cancelBubble = true} 648 if (!e.target) { 649 e.target = e.srcElement 650 } 651 if (!e.relatedTarget && e.fromElement) { 652 e.relatedTarget = e.fromElement == e.target ? e.toElement : e.fromElement; 653 } 654 if (e.pageX == null && e.clientX != null) { 655 var html = document.documentElement, body = document.body; 656 e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0); 657 e.pageY = e.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0); 658 } 659 if (!e.which && e.button) { 660 e.which = e.button & 1 ? 1 : (e.button & 2 ? 3 : (e.button & 4 ? 2 : 0)); 661 } 662 if(e.type === "DOMMouseScroll" || e.type === 'mousewheel') { 663 e.mWheelDelta = 0; 664 if (e.wheelDelta) { 665 e.mWheelDelta = e.wheelDelta/120; 666 } else if (e.detail) { 667 e.mWheelDelta = -e.detail/3; 668 } 669 } 670 return e; 671 } 672 function commonHandle(event, customScope) { 673 event = fixEvent(event); 674 var handlers = this.events[event.type]; 675 for (var g in handlers) { 676 var handler = handlers[g]; 677 var ret = handler.call(customScope || this, event); 678 if (ret === false) { 679 event.preventDefault() 680 event.stopPropagation() 681 } 682 } 683 } 684 var publicAPI = { 685 add: function(elem, type, handler, forcedScope) { 686 if (elem.setInterval && (elem != window && !elem.frameElement)) { 687 elem = window; 688 } 689 if (!handler.guid) { 690 handler.guid = ++guid; 691 } 692 if (!elem.events) { 693 elem.events = {}; 694 elem.handle = function(event) { 695 return commonHandle.call(elem, event); 696 } 697 } 698 if (!elem.events[type]) { 699 elem.events[type] = {}; 700 if (elem.addEventListener) elem.addEventListener(type, elem.handle, false); 701 else if (elem.attachEvent) elem.attachEvent("on" + type, elem.handle); 702 if(type === 'mousewheel') { 703 publicAPI.add(elem, 'DOMMouseScroll', handler, forcedScope); 704 } 705 } 706 var fakeHandler = jcf.lib.bind(handler, forcedScope); 707 fakeHandler.guid = handler.guid; 708 elem.events[type][handler.guid] = forcedScope ? fakeHandler : handler; 709 }, 710 remove: function(elem, type, handler) { 711 var handlers = elem.events && elem.events[type]; 712 if (!handlers) return; 713 delete handlers[handler.guid]; 714 for(var any in handlers) return; 715 if (elem.removeEventListener) elem.removeEventListener(type, elem.handle, false); 716 else if (elem.detachEvent) elem.detachEvent("on" + type, elem.handle); 717 delete elem.events[type]; 718 for (var any in elem.events) return; 719 try { 720 delete elem.handle; 721 delete elem.events; 722 } catch(e) { 723 if(elem.removeAttribute) { 724 elem.removeAttribute("handle"); 725 elem.removeAttribute("events"); 726 } 727 } 728 if(type === 'mousewheel') { 729 publicAPI.remove(elem, 'DOMMouseScroll', handler); 730 } 731 } 732 } 733 return publicAPI; 734 }()) 735}
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.