1// http://cpojer.net/PowerTools/#select=Mobile/Swipe 2// packager build Mobile/Swipe 3/* 4--- 5 6name: Element.defineCustomEvent 7 8description: Allows to create custom events based on other custom events. 9 10authors: Christoph Pojer (@cpojer) 11 12license: MIT-style license. 13 14requires: [Core/Element.Event] 15 16provides: Element.defineCustomEvent 17 18... 19*/ 20 21(function(){ 22 23[Element, Window, Document].invoke('implement', {hasEvent: function(event){ 24 var events = this.retrieve('events'), 25 list = (events && events[event]) ? events[event].values : null; 26 if (list){ 27 var i = list.length; 28 while (i--) if (i in list){ 29 return true; 30 } 31 } 32 return false; 33}}); 34 35var wrap = function(custom, method, extended){ 36 method = custom[method]; 37 extended = custom[extended]; 38 39 return function(fn, name){ 40 if (extended && !this.hasEvent(name)) extended.call(this, fn, name); 41 if (method) method.call(this, fn, name); 42 }; 43}; 44 45var inherit = function(custom, base, method){ 46 return function(fn, name){ 47 base[method].call(this, fn, name); 48 custom[method].call(this, fn, name); 49 }; 50}; 51 52var events = Element.Events; 53 54Element.defineCustomEvent = function(name, custom){ 55 var base = events[custom.base]; 56 57 custom.onAdd = wrap(custom, 'onAdd', 'onSetup'); 58 custom.onRemove = wrap(custom, 'onRemove', 'onTeardown'); 59 60 events[name] = base ? Object.append({}, custom, { 61 62 base: base.base, 63 64 condition: function(event, name){ 65 return (!base.condition || base.condition.call(this, event, name)) && 66 (!custom.condition || custom.condition.call(this, event, name)); 67 }, 68 69 onAdd: inherit(custom, base, 'onAdd'), 70 onRemove: inherit(custom, base, 'onRemove') 71 72 }) : custom; 73 74 return this; 75}; 76 77Element.enableCustomEvents = function(){ 78 Object.each(events, function(event, name){ 79 if (event.onEnable) event.onEnable.call(event, name); 80 }); 81}; 82 83Element.disableCustomEvents = function(){ 84 Object.each(events, function(event, name){ 85 if (event.onDisable) event.onDisable.call(event, name); 86 }); 87}; 88 89})(); 90 91 92/* 93--- 94 95name: Browser.Features.Touch 96 97description: Checks whether the used Browser has touch events 98 99authors: Christoph Pojer (@cpojer) 100 101license: MIT-style license. 102 103requires: [Core/Browser] 104 105provides: Browser.Features.Touch 106 107... 108*/ 109 110Browser.Features.Touch = (function(){ 111 try { 112 document.createEvent('TouchEvent').initTouchEvent('touchstart'); 113 return true; 114 } catch (exception){} 115 116 return false; 117})(); 118 119// Android doesn't have a touch delay and dispatchEvent does not fire the handler 120Browser.Features.iOSTouch = (function(){ 121 var name = 'cantouch', // Name does not matter 122 html = document.html, 123 hasTouch = false; 124 125 if (!html.addEventListener) return false; 126 127 var handler = function(){ 128 html.removeEventListener(name, handler, true); 129 hasTouch = true; 130 }; 131 132 try { 133 html.addEventListener(name, handler, true); 134 var event = document.createEvent('TouchEvent'); 135 event.initTouchEvent(name); 136 html.dispatchEvent(event); 137 return hasTouch; 138 } catch (exception){} 139 140 handler(); // Remove listener 141 return false; 142})(); 143 144 145/* 146--- 147 148name: Swipe 149 150description: Provides a custom swipe event for touch devices 151 152authors: Christopher Beloch (@C_BHole), Christoph Pojer (@cpojer), Ian Collins (@3n) 153 154license: MIT-style license. 155 156requires: [Core/Element.Event, Custom-Event/Element.defineCustomEvent, Browser.Features.Touch] 157 158provides: Swipe 159 160... 161*/ 162 163(function(){ 164 165var name = 'swipe', 166 distanceKey = name + ':distance', 167 cancelKey = name + ':cancelVertical', 168 dflt = 50; 169 170var start = {}, disabled, active; 171 172var clean = function(){ 173 active = false; 174}; 175 176var events = { 177 178 touchstart: function(event){ 179 if (event.touches.length > 1) return; 180 181 var touch = event.touches[0]; 182 active = true; 183 start = {x: touch.pageX, y: touch.pageY}; 184 }, 185 186 touchmove: function(event){ 187 if (disabled || !active) return; 188 189 var touch = event.changedTouches[0], 190 end = {x: touch.pageX, y: touch.pageY}; 191 if (this.retrieve(cancelKey) && Math.abs(start.y - end.y) > 10){ 192 active = false; 193 return; 194 } 195 196 var distance = this.retrieve(distanceKey, dflt), 197 delta = end.x - start.x, 198 isLeftSwipe = delta < -distance, 199 isRightSwipe = delta > distance; 200 201 if (!isRightSwipe && !isLeftSwipe) 202 return; 203 204 event.preventDefault(); 205 active = false;
206 event.direction = (isLeftSwipe ? 'left' : 'right'); 207 event.start = start; 208 event.end = end; 209 210 this.fireEvent(name, event); 211 }, 212 213 touchend: clean, 214 touchcancel: clean 215 216}; 217 218Element.defineCustomEvent(name, { 219 220 onSetup: function(){ 221 this.addEvents(events); 222 }, 223 224 onTeardown: function(){ 225 this.removeEvents(events); 226 }, 227 228 onEnable: function(){ 229 disabled = false; 230 }, 231 232 onDisable: function(){ 233 disabled = true; 234 clean(); 235 } 236 237}); 238 239})();
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.