1/** 2 * jQuery 2.0+ REQUIRED 3 * ============================================== 4 * iOS9 'click', 'mousedown' and 'mouseup' fix 5 * --------------------------------------------- 6 * Include this script in your poject to fix 'click', 'mousedown' and 'mouseup' event 7 * handling for $(window), $(document), $('body') and $('html'). By default iOS9 Safari is 8 * suppressing those events in some situations and without some magic they can't be rely on. 9 * This fix is blocking native event handlers from firing 10 * (in some rare cases event will reach it's destination) 11 * and it handles native event handlers basing on 'touchstart' and 'touchend' event. 12 * --------------------------------------------- 13 * Use at your own risk 14 */ 15 16$(document).ready(function(){ 17 18 /** Device is not iOS. There's no need to hack the planet. */ 19 if( typeof navigator.userAgent == 'undefined' || ! navigator.userAgent.match(/(iPad|iPhone|iPod)/i) ){ 20 return; 21 } 22 23 var EVENT_NAMESPACE = 'IOS9FIX'; 24 var MAX_DOM_DEPTH = 100; 25 26 /** 27 * Suppress event for $object. 28 * @param $object 29 * @param eventType 30 */ 31 var blockEventFor = function($object, eventType) { 32 var eventQueue, eventRepo = new Array(); 33 34 if($._data($object.get(0),"events") !== undefined){ 35 eventQueue = $._data($object.get(0),"events")[eventType]; 36 } 37 38 if(eventQueue !== undefined) { 39 for(var i = 0; i < eventQueue.length; i++) { 40 eventRepo.push({ 41 handler: eventQueue[i].handler, 42 selector: eventQueue[i].selector, 43 namespace: eventQueue[i].namespace 44 }); 45 } 46 47 $object.off(eventType); 48 } 49 50 $object.on(eventType + '.' + EVENT_NAMESPACE, '*', function(event){ 51 event.stopImmediatePropagation(); 52 }); 53 54 for(var i = 0; i < eventRepo.length; i++) { 55 56 var _eventType = eventRepo[i].namespace 57 ? eventType + '.' + eventRepo[i].namespace 58 : eventType; 59 60 $object.on(_eventType, eventRepo[i].selector, eventRepo[i].handler); 61 } 62 }; 63 64 /** 65 * EXECUTE MOCKED-EVENT HANDLERS 66 * @param object $object 67 * @param string mockedEventType 68 * @param object originalEvent 69 */ 70 var executeMockedEventHandlers = function($object, mockedEventType, originalEvent){ 71 /** Let's say touch is mouse left button (by default touch event has .which === 0) */ 72 originalEvent.which = 1; 73 74 var mockedEventQueue, $target = $(originalEvent.target); 75 76 if($._data($object.get(0), "events") !== undefined){ 77 mockedEventQueue = $._data($object.get(0), "events")[mockedEventType]; 78 } 79 80 /** No event-handlers for event of such type */ 81 if(mockedEventQueue === undefined){ 82 return false; 83 } 84 85 /** Traverse DOM from 'target' to 'base' and execute mockedEventHandlers for all matched elements */ 86 for(var preventEndlessLoop = 0; preventEndlessLoop < MAX_DOM_DEPTH; preventEndlessLoop++){ 87 88 /** END THE LOOP */ 89 if($target.length == 0){ 90 break; 91 } 92 93 /** EXECUTE MOCKED EVENT HANDLERS */ 94 for(var i = 0; i < mockedEventQueue.length; i++){ 95 96 // Skip eventHandler used to block originalEvent for mockedEvent 97 if(mockedEventQueue[i].namespace === EVENT_NAMESPACE){ 98 continue; 99 } 100 101 if(mockedEventQueue[i].selector === undefined){ 102 // Skip $object level eventHandlers until current DOM level is $object level 103 if( ! $target.is($object[0])) { 104 continue; 105 } 106 } else { 107 // Skip eventHandlers not meant for current DOM level 108 if( ! $target.is(mockedEventQueue[i].selector)){ 109 continue; 110 } 111 } 112 113 // Execute handler for current DOM level 114 if(mockedEventQueue[i].handler.call($target[0], originalEvent) === false){ 115 originalEvent.stopImmediatePropagation(); 116 } 117 118 // Check for stopImmediatePropagation() */ 119 if(originalEvent.isImmediatePropagationStopped()){ 120 break; 121 } 122 } 123 124 if(originalEvent.isPropagationStopped()){ 125 break; 126 } 127 128 /** Go to parent level */ 129 $target = $target.parent(); 130 } 131 }; 132 133 134 135 /***************************** 136 * INITIALIZATION 137 ****************************/ 138 139 /** 140 * Go through objects and suppress all selected events. 141 */ 142 $.each([$(document), $(window), $('body'), $('html')], function(objectIndex, $object){ 143 $.each(['mousedown', 'click', 'mouseup'], function(eventIndex, eventType){ 144 blockEventFor($object, eventType); 145 });
146 }); 147 148 149 /** 150 * MOCK MOUSEDOWN EVENT 151 */ 152 153 /** 154 * Init MouseDown-Mock for Dom $object 155 * @param $object 156 */ 157 var initMouseDownMock = function($object) { 158 $object.on('touchstart', function (event) { 159 executeMockedEventHandlers($object, 'mousedown', event); 160 }); 161 }; 162 163 /** 164 * Init MouseDown-Mock for objects... 165 */ 166 $.each([$(document), $(window), $('body'), $('html')], function(objectIndex, $object){ 167 initMouseDownMock($object); 168 }); 169 170 171 /** 172 * MOCK MOUSEUP EVENT 173 */ 174 175 /** 176 * Init MouseUp-Mock for Dom $object 177 * @param $object 178 */ 179 var initMouseUpMock = function($object) { 180 $object.on('touchend', function (event) { 181 executeMockedEventHandlers($object, 'mouseup', event); 182 }); 183 }; 184 185 /** 186 * Init MouseUp-Mock for objects... 187 */ 188 $.each([$(document), $(window), $('body'), $('html')], function(objectIndex, $object){ 189 initMouseUpMock($object); 190 }); 191 192 193 /** 194 * MOCK CLICK EVENT 195 */ 196 197 /** 198 * Init Click-Mock for Dom $object 199 * @param $object 200 */ 201 var initClickMock = function($object) { 202 var clickCancelationTimer, isClick, cursorX, cursorY, target; 203 204 $object.on('touchstart', function(event){ 205 isClick = true; 206 207 cursorX = event.originalEvent.touches[0].pageX; 208 cursorY = event.originalEvent.touches[0].pageY; 209 target = event.target; 210 211 /** Click Timeout */ 212 clickCancelationTimer = setTimeout(function(){ 213 isClick = false; 214 }, 300); 215 }); 216 217 /** moved more than 10 px away from starting position */ 218 $object.on('touchmove', function(event){ 219 if(Math.abs(cursorX - event.originalEvent.touches[0].pageX) > 10 || Math.abs(cursorY - event.originalEvent.touches[0].pageY) > 10){ 220 isClick = false; 221 } 222 }); 223 224 $object.on('touchend', function(event){ 225 clearTimeout(clickCancelationTimer); 226 227 if(isClick){ 228 executeMockedEventHandlers($object, 'click', event); 229 } 230 }); 231 }; 232 233 /** 234 * Init Click-Mock for objects... 235 */ 236 $.each([$(document), $(window), $('body'), $('html')], function(objectIndex, $object){ 237 initClickMock($object); 238 }); 239 240 241}); 242
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.