1/*! 2--- 3 4name: Browser.Mobile 5 6description: Provides useful information about the browser environment 7 8authors: Christoph Pojer (@cpojer) 9 10license: MIT-style license. 11 12requires: [Core/Browser] 13 14provides: Browser.Mobile 15 16... 17*/ 18 19(function(){ 20Browser.Device = { 21 name: 'other' 22}; 23 24if (Browser.Platform.ios){ 25 var device = navigator.userAgent.toLowerCase().match(/(ip(ad|od|hone))/)[0]; 26 27 Browser.Device[device] = true; 28 Browser.Device.name = device; 29} 30 31if (this.devicePixelRatio == 2) 32 Browser.hasHighResolution = true; 33 34Browser.isMobile = !['mac', 'linux', 'win'].contains(Browser.Platform.name); 35 36}).call(this); 37 38 39/* 40--- 41 42name: Element.defineCustomEvent 43 44description: Allows to create custom events based on other custom events. 45 46authors: Christoph Pojer (@cpojer) 47 48license: MIT-style license. 49 50requires: [Core/Element.Event] 51 52provides: Element.defineCustomEvent 53 54... 55*/ 56 57(function(){ 58 59[Element, Window, Document].invoke('implement', {hasEvent: function(event){ 60 var events = this.retrieve('events'), 61 list = (events && events[event]) ? events[event].values : null; 62 if (list){ 63 var i = list.length; 64 while (i--) if (i in list){ 65 return true; 66 } 67 } 68 return false; 69}}); 70 71var wrap = function(custom, method, extended){ 72 method = custom[method]; 73 extended = custom[extended]; 74 75 return function(fn, name){ 76 if (extended && !this.hasEvent(name)) extended.call(this, fn, name); 77 if (method) method.call(this, fn, name); 78 }; 79}; 80 81var inherit = function(custom, base, method){ 82 return function(fn, name){ 83 base[method].call(this, fn, name); 84 custom[method].call(this, fn, name); 85 }; 86}; 87 88var events = Element.Events; 89 90Element.defineCustomEvent = function(name, custom){ 91 var base = events[custom.base]; 92 93 custom.onAdd = wrap(custom, 'onAdd', 'onSetup'); 94 custom.onRemove = wrap(custom, 'onRemove', 'onTeardown'); 95 96 events[name] = base ? Object.append({}, custom, { 97 98 base: base.base, 99 100 condition: function(event, name){ 101 return (!base.condition || base.condition.call(this, event, name)) && 102 (!custom.condition || custom.condition.call(this, event, name)); 103 }, 104 105 onAdd: inherit(custom, base, 'onAdd'), 106 onRemove: inherit(custom, base, 'onRemove') 107 108 }) : custom; 109 110 return this; 111}; 112 113Element.enableCustomEvents = function(){ 114 Object.each(events, function(event, name){ 115 if (event.onEnable) event.onEnable.call(event, name); 116 }); 117}; 118 119Element.disableCustomEvents = function(){ 120 Object.each(events, function(event, name){ 121 if (event.onDisable) event.onDisable.call(event, name); 122 }); 123}; 124 125})(); 126 127 128/* 129--- 130 131name: Browser.Features.Touch 132 133description: Checks whether the used Browser has touch events 134 135authors: Christoph Pojer (@cpojer) 136 137license: MIT-style license. 138 139requires: [Core/Browser] 140 141provides: Browser.Features.Touch 142 143... 144*/ 145 146Browser.Features.Touch = (function(){ 147 try { 148 document.createEvent('TouchEvent').initTouchEvent('touchstart'); 149 return true; 150 } catch (exception){} 151 152 return false; 153})(); 154 155// Android doesn't have a touch delay and dispatchEvent does not fire the handler 156Browser.Features.iOSTouch = (function(){ 157 var name = 'cantouch', // Name does not matter 158 html = document.html, 159 hasTouch = false; 160 161 if (!html.addEventListener) return false; 162 163 var handler = function(){ 164 html.removeEventListener(name, handler, true); 165 hasTouch = true; 166 }; 167 168 try { 169 html.addEventListener(name, handler, true); 170 var event = document.createEvent('TouchEvent'); 171 event.initTouchEvent(name); 172 html.dispatchEvent(event); 173 return hasTouch; 174 } catch (exception){} 175 176 handler(); // Remove listener 177 return false; 178})(); 179 180 181/* 182--- 183 184name: Touch 185 186description: Provides a custom touch event on mobile devices 187 188authors: Christoph Pojer (@cpojer) 189 190license: MIT-style license. 191 192requires: [Core/Element.Event, Custom-Event/Element.defineCustomEvent, Browser.Features.Touch] 193 194provides: Touch 195 196... 197*/ 198 199(function(){ 200 201var preventDefault = function(event){ 202 if (!event.target || event.target.tagName.toLowerCase() != 'select') 203 event.preventDefault(); 204}; 205 206var disabled; 207 208Element.defineCustomEvent('touch', { 209 210 base: 'touchend', 211 212 condition: function(event){ 213 if (disabled || event.targetTouches.length != 0) return false;
214 215 var touch = event.changedTouches[0], 216 target = document.elementFromPoint(touch.clientX, touch.clientY); 217 218 do { 219 if (target == this) return true; 220 } while (target && (target = target.parentNode)); 221 222 return false; 223 }, 224 225 onSetup: function(){ 226 this.addEvent('touchstart', preventDefault); 227 }, 228 229 onTeardown: function(){ 230 this.removeEvent('touchstart', preventDefault); 231 }, 232 233 onEnable: function(){ 234 disabled = false; 235 }, 236 237 onDisable: function(){ 238 disabled = true; 239 } 240 241}); 242 243})(); 244 245 246/* 247--- 248 249name: Click 250 251description: Provides a replacement for click events on mobile devices 252 253authors: Christoph Pojer (@cpojer) 254 255license: MIT-style license. 256 257requires: [Touch] 258 259provides: Click 260 261... 262*/ 263 264if (Browser.Features.iOSTouch) (function(){ 265 266var name = 'click'; 267delete Element.NativeEvents[name]; 268 269Element.defineCustomEvent(name, { 270 271 base: 'touchend' 272 273}); 274 275})(); 276 277 278/* 279--- 280 281name: Pinch 282 283description: Provides a custom pinch event for touch devices 284 285authors: Christopher Beloch (@C_BHole), Christoph Pojer (@cpojer) 286 287license: MIT-style license. 288 289requires: [Core/Element.Event, Custom-Event/Element.defineCustomEvent, Browser.Features.Touch] 290 291provides: Pinch 292 293... 294*/ 295 296if (Browser.Features.Touch) (function(){ 297 298var name = 'pinch', 299 thresholdKey = name + ':threshold', 300 disabled, active; 301 302var events = { 303 304 touchstart: function(event){ 305 if (event.targetTouches.length == 2) active = true; 306 }, 307 308 touchmove: function(event){ 309 if (disabled || !active) return; 310 311 event.preventDefault(); 312 313 var threshold = this.retrieve(thresholdKey, 0.5); 314 if (event.scale < (1 + threshold) && event.scale > (1 - threshold)) return; 315 316 active = false; 317 event.pinch = (event.scale > 1) ? 'in' : 'out'; 318 this.fireEvent(name, event); 319 } 320 321}; 322 323Element.defineCustomEvent(name, { 324 325 onSetup: function(){ 326 this.addEvents(events); 327 }, 328 329 onTeardown: function(){ 330 this.removeEvents(events); 331 }, 332 333 onEnable: function(){ 334 disabled = false; 335 }, 336 337 onDisable: function(){ 338 disabled = true; 339 } 340 341}); 342 343})(); 344 345 346/* 347--- 348 349name: Swipe 350 351description: Provides a custom swipe event for touch devices 352 353authors: Christopher Beloch (@C_BHole), Christoph Pojer (@cpojer), Ian Collins (@3n) 354 355license: MIT-style license. 356 357requires: [Core/Element.Event, Custom-Event/Element.defineCustomEvent, Browser.Features.Touch] 358 359provides: Swipe 360 361... 362*/ 363 364(function(){ 365 366var name = 'swipe', 367 distanceKey = name + ':distance', 368 cancelKey = name + ':cancelVertical', 369 dflt = 50; 370 371var start = {}, disabled, active; 372 373var clean = function(){ 374 active = false; 375}; 376 377var events = { 378 379 touchstart: function(event){ 380 if (event.touches.length > 1) return; 381 382 var touch = event.touches[0]; 383 active = true; 384 start = {x: touch.pageX, y: touch.pageY}; 385 }, 386 387 touchmove: function(event){ 388 if (disabled || !active) return; 389 390 var touch = event.changedTouches[0], 391 end = {x: touch.pageX, y: touch.pageY}; 392 if (this.retrieve(cancelKey) && Math.abs(start.y - end.y) > 10){ 393 active = false; 394 return; 395 } 396 397 var distance = this.retrieve(distanceKey, dflt), 398 delta = end.x - start.x, 399 isLeftSwipe = delta < -distance, 400 isRightSwipe = delta > distance; 401 402 if (!isRightSwipe && !isLeftSwipe) 403 return; 404 405 event.preventDefault(); 406 active = false; 407 event.direction = (isLeftSwipe ? 'left' : 'right'); 408 event.start = start; 409 event.end = end; 410 411 this.fireEvent(name, event); 412 }, 413 414 touchend: clean, 415 touchcancel: clean 416 417}; 418 419Element.defineCustomEvent(name, { 420 421 onSetup: function(){ 422 this.addEvents(events); 423 }, 424 425 onTeardown: function(){ 426 this.removeEvents(events); 427 }, 428 429 onEnable: function(){ 430 disabled = false; 431 }, 432 433 onDisable: function(){ 434 disabled = true; 435 clean(); 436 } 437 438}); 439 440})(); 441 442 443/* 444--- 445 446name: Touchhold 447 448description: Provides a custom touchhold event for touch devices 449 450authors: Christoph Pojer (@cpojer) 451 452license: MIT-style license. 453 454requires: [Core/Element.Event, Custom-Event/Element.defineCustomEvent, Browser.Features.Touch] 455 456provides: Touchhold 457 458... 459*/ 460 461(function(){ 462 463var name = 'touchhold', 464 delayKey = name + ':delay', 465 disabled, timer; 466 467var clear = function(e){ 468 clearTimeout(timer); 469}; 470 471var events = { 472 473 touchstart: function(event){ 474 if (event.touches.length > 1){ 475 clear(); 476 return; 477 } 478 479 timer = (function(){ 480 this.fireEvent(name, event); 481 }).delay(this.retrieve(delayKey) || 750, this); 482 }, 483 484 touchmove: clear, 485 touchcancel: clear, 486 touchend: clear 487 488}; 489 490Element.defineCustomEvent(name, { 491 492 onSetup: function(){ 493 this.addEvents(events); 494 }, 495 496 onTeardown: function(){ 497 this.removeEvents(events); 498 }, 499 500 onEnable: function(){ 501 disabled = false;
502 }, 503 504 onDisable: function(){ 505 disabled = true; 506 clear(); 507 } 508 509}); 510 511})(); 512
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.