├── .github └── CODEOWNERS ├── .gitignore ├── .npmignore ├── LICENSE ├── Makefile ├── README.md ├── bower.json ├── component.json ├── examples ├── focus.html ├── input.html └── layer.html ├── lib └── fastclick.js ├── package.json └── tests ├── 10.html ├── 111.html ├── 160-reduced.html ├── 160.html ├── 176.html ├── 18.html ├── 22.html ├── 226.html ├── 23-reduced.html ├── 23.html ├── 24.html ├── 26.html ├── 27.html ├── 30.html ├── 32.html ├── 36.html ├── 37-reduced.html ├── 37a.html ├── 37b.html ├── 42.html ├── 44.html ├── 45.html ├── 48.html ├── 51-reduced.html ├── 6.html ├── 60.html ├── 62.html ├── 68.html ├── 6b.html ├── 7.html ├── 83-reduced.html ├── 83.html └── 84.html /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Guessed from commit history 2 | * @Financial-Times/apps 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ~$* 2 | .DS_Store 3 | Thumbs.db 4 | Desktop.ini 5 | build 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .npmignore 3 | bower.json 4 | component.json 5 | examples 6 | Makefile 7 | tests 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 The Financial Times Ltd. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash 2 | 3 | QS=compilation_level=SIMPLE_OPTIMIZATIONS&output_format=text 4 | URL=http://closure-compiler.appspot.com/compile 5 | CODE=js_code@lib/fastclick.js 6 | 7 | CHECK=\033[32m✔\033[39m 8 | 9 | build/fastclick.min.js: lib/fastclick.js 10 | @mkdir -p build 11 | @echo -n "Building build/fastclick.min.js... " 12 | @curl --silent --show-error --data-urlencode "${CODE}" --data "${QS}&output_info=compiled_code" ${URL} -o build/fastclick.min.js 13 | @echo -e "${CHECK} Done" 14 | @echo -n "Getting compression stats... " 15 | @echo -e "${CHECK} Done\n\n" "`curl --silent --show-error --data-urlencode "${CODE}" --data "${QS}&output_info=statistics" ${URL}`" 16 | @echo ${STATS} 17 | 18 | test: 19 | jshint -v lib/*.js 20 | 21 | clean: 22 | rm -rf build 23 | 24 | .PHONY: clean test 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FastClick # 2 | 3 | FastClick is a simple, easy-to-use library for eliminating the 300ms delay between a physical tap and the firing of a `click` event on mobile browsers. The aim is to make your application feel less laggy and more responsive while avoiding any interference with your current logic. 4 | 5 | FastClick is developed by [FT Labs](http://labs.ft.com/), part of the Financial Times. 6 | 7 | *Note: As of late 2015 most mobile browsers - notably Chrome and Safari - no longer have a 300ms touch delay, so fastclick offers no benefit on newer browsers, and risks introducing [bugs](https://github.com/ftlabs/fastclick/issues) into your application. Consider carefully whether you really need to use it.* 8 | 9 | [Explication en français](http://maxime.sh/2013/02/supprimer-le-lag-des-clics-sur-mobile-avec-fastclick/). 10 | 11 | [日本語で説明](https://developer.mozilla.org/ja/docs/Mozilla/Firefox_OS/Apps/Tips_and_techniques#Make_events_immediate)。 12 | 13 | ## Why does the delay exist? ## 14 | 15 | According to [Google](https://developers.google.com/mobile/articles/fast_buttons): 16 | 17 | > ...mobile browsers will wait approximately 300ms from the time that you tap the button to fire the click event. The reason for this is that the browser is waiting to see if you are actually performing a double tap. 18 | 19 | ## Compatibility ## 20 | 21 | The library has been deployed as part of the [FT Web App](http://app.ft.com/) and is tried and tested on the following mobile browsers: 22 | 23 | * Mobile Safari on iOS 3 and upwards 24 | * Chrome on iOS 5 and upwards 25 | * Chrome on Android (ICS) 26 | * Opera Mobile 11.5 and upwards 27 | * Android Browser since Android 2 28 | * PlayBook OS 1 and upwards 29 | 30 | ## When it isn't needed ## 31 | 32 | FastClick doesn't attach any listeners on desktop browsers. 33 | 34 | Chrome 32+ on Android with `width=device-width` in the [viewport meta tag](https://developer.mozilla.org/en-US/docs/Mobile/Viewport_meta_tag) doesn't have a 300ms delay, therefore listeners aren't attached. 35 | 36 | ```html 37 | 38 | ``` 39 | 40 | Same goes for Chrome on Android (all versions) with `user-scalable=no` in the viewport meta tag. But be aware that `user-scalable=no` also disables pinch zooming, which may be an accessibility concern. 41 | 42 | For IE11+, you can use `touch-action: manipulation;` to disable double-tap-to-zoom on certain elements (like links and buttons). For IE10 use `-ms-touch-action: manipulation`. 43 | 44 | ## Usage ## 45 | 46 | Include fastclick.js in your JavaScript bundle or add it to your HTML page like this: 47 | 48 | ```html 49 | 50 | ``` 51 | 52 | The script must be loaded prior to instantiating FastClick on any element of the page. 53 | 54 | To instantiate FastClick on the `body`, which is the recommended method of use: 55 | 56 | ```js 57 | if ('addEventListener' in document) { 58 | document.addEventListener('DOMContentLoaded', function() { 59 | FastClick.attach(document.body); 60 | }, false); 61 | } 62 | ``` 63 | 64 | Or, if you're using jQuery: 65 | 66 | ```js 67 | $(function() { 68 | FastClick.attach(document.body); 69 | }); 70 | ``` 71 | 72 | If you're using Browserify or another CommonJS-style module system, the `FastClick.attach` function will be returned when you call `require('fastclick')`. As a result, the easiest way to use FastClick with these loaders is as follows: 73 | 74 | ```js 75 | var attachFastClick = require('fastclick'); 76 | attachFastClick(document.body); 77 | ``` 78 | 79 | ### Minified ### 80 | 81 | Run `make` to build a minified version of FastClick using the Closure Compiler REST API. The minified file is saved to `build/fastclick.min.js` or you can [download a pre-minified version](https://origami-build.ft.com/bundles/js?modules=fastclick). 82 | 83 | Note: the pre-minified version is built using [our build service](http://origami.ft.com/docs/developer-guide/build-service/) which exposes the `FastClick` object through `Origami.fastclick` and will have the Browserify/CommonJS API (see above). 84 | 85 | ```js 86 | var attachFastClick = Origami.fastclick; 87 | attachFastClick(document.body); 88 | ``` 89 | 90 | ### AMD ### 91 | 92 | FastClick has AMD (Asynchronous Module Definition) support. This allows it to be lazy-loaded with an AMD loader, such as [RequireJS](http://requirejs.org/). Note that when using the AMD style require, the full `FastClick` object will be returned, _not_ `FastClick.attach` 93 | 94 | ```js 95 | var FastClick = require('fastclick'); 96 | FastClick.attach(document.body, options); 97 | ``` 98 | 99 | ### Package managers ### 100 | 101 | You can install FastClick using [Component](https://github.com/component/component), [npm](https://npmjs.org/package/fastclick) or [Bower](http://bower.io/). 102 | 103 | For Ruby, there's a third-party gem called [fastclick-rails](http://rubygems.org/gems/fastclick-rails). For .NET there's a [NuGet package](http://nuget.org/packages/FastClick). 104 | 105 | ## Advanced ## 106 | 107 | ### Ignore certain elements with `needsclick` ### 108 | 109 | Sometimes you need FastClick to ignore certain elements. You can do this easily by adding the `needsclick` class. 110 | ```html 111 | Ignored by FastClick 112 | ``` 113 | 114 | #### Use case 1: non-synthetic click required #### 115 | 116 | Internally, FastClick uses `document.createEvent` to fire a synthetic `click` event as soon as `touchend` is fired by the browser. It then suppresses the additional `click` event created by the browser after that. In some cases, the non-synthetic `click` event created by the browser is required, as described in the [triggering focus example](http://ftlabs.github.com/fastclick/examples/focus.html). 117 | 118 | This is where the `needsclick` class comes in. Add the class to any element that requires a non-synthetic click. 119 | 120 | #### Use case 2: Twitter Bootstrap 2.2.2 dropdowns #### 121 | 122 | Another example of when to use the `needsclick` class is with dropdowns in Twitter Bootstrap 2.2.2. Bootstrap add its own `touchstart` listener for dropdowns, so you want to tell FastClick to ignore those. If you don't, touch devices will automatically close the dropdown as soon as it is clicked, because both FastClick and Bootstrap execute the synthetic click, one opens the dropdown, the second closes it immediately after. 123 | 124 | ```html 125 | Dropdown 126 | ``` 127 | 128 | ## Examples ## 129 | 130 | FastClick is designed to cope with many different browser oddities. Here are some examples to illustrate this: 131 | 132 | * [basic use](http://ftlabs.github.com/fastclick/examples/layer.html) showing the increase in perceived responsiveness 133 | * [triggering focus](http://ftlabs.github.com/fastclick/examples/focus.html) on an input element from a `click` handler 134 | * [input element](http://ftlabs.github.com/fastclick/examples/input.html) which never receives clicks but gets fast focus 135 | 136 | ## Tests ## 137 | 138 | There are no automated tests. The files in `tests/` are manual reduced test cases. We've had a think about how best to test these cases, but they tend to be very browser/device specific and sometimes subjective which means it's not so trivial to test. 139 | 140 | ## Credits and collaboration ## 141 | 142 | FastClick is maintained by [Rowan Beentje](http://twitter.com/rowanbeentje), [Matthew Caruana Galizia](http://twitter.com/mcaruanagalizia) and [Matthew Andrews](http://twitter.com/andrewsmatt) at [FT Labs](http://labs.ft.com). All open source code released by FT Labs is licenced under the MIT licence. We welcome comments, feedback and suggestions. Please feel free to raise an issue or pull request. 143 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fastclick", 3 | "license": "MIT", 4 | "main": "lib/fastclick.js", 5 | "ignore": [ 6 | "**/.*", 7 | "component.json", 8 | "package.json", 9 | "Makefile", 10 | "tests", 11 | "examples" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fastclick", 3 | "repo": "ftlabs/fastclick", 4 | "description": "Polyfill to remove click delays on browsers with touch UIs.", 5 | "version": "1.0.3", 6 | "main": "lib/fastclick.js", 7 | "scripts": [ 8 | "lib/fastclick.js" 9 | ], 10 | "ignore": [ 11 | "examples/", 12 | "tests/" 13 | ], 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/focus.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 14 | 26 | 27 | 28 |

FastClick is instantiated on the body element, so all visible elements on this page will receive fast clicks - except one.

29 |

The layers marked A and B both have click handlers that will attempt to trigger focus on the input element programatically. However, on iOS before version 5.0, touch event handlers are not allowed to trigger focus on other elements.

30 |

On earlier versions of iOS, only B will succeed at triggering focus on the input element, because it has a needsclick class which will instruct FastClick not to trigger a programmatic click in the touch event handler and let the system click event go through instead.

31 |
32 | 33 |
A
34 |
B
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/input.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 14 | 15 | 20 | 21 | 22 |

FastClick is instantiated on the body element, but the input element below will not receive fast clicks. Instead focus() will be called on the input element when touchend fires.

23 |

The keyboard will still appear after delay on iOS 4 or earlier, however.

24 |
25 | 26 |
27 |

The same is true for the select element. It should open quickly on iOS > 4.

28 |
29 | 33 |
34 |

The text below is a label for the text input element above. FastClick should automatically resolve the ID in the for attribute and trigger focus on the input element. This doesn't work on iOS 4, however (with or without FastClick).

35 | 36 |

Checkbox labels don't work on iOS 4, but with FastClick, they do!

37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /examples/layer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 14 | 15 | 50 | 51 | 52 |

Layer A responds to click events normally, which on iOS will introduce a 300ms delay.

53 |

Layer B is enhanced with FastClick, and will fire the click handler with no delay.

54 |

The layers will behave normally on platforms that don't support touch events.

55 |

Touch end time:

56 |

Click event time:

57 |

Difference:

58 |
59 |
A
60 |
B
61 |
62 | 63 | 64 | -------------------------------------------------------------------------------- /lib/fastclick.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict'; 3 | 4 | /** 5 | * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs. 6 | * 7 | * @codingstandard ftlabs-jsv2 8 | * @copyright The Financial Times Limited [All Rights Reserved] 9 | * @license MIT License (see LICENSE.txt) 10 | */ 11 | 12 | /*jslint browser:true, node:true*/ 13 | /*global define, Event, Node*/ 14 | 15 | 16 | /** 17 | * Instantiate fast-clicking listeners on the specified layer. 18 | * 19 | * @constructor 20 | * @param {Element} layer The layer to listen on 21 | * @param {Object} [options={}] The options to override the defaults 22 | */ 23 | function FastClick(layer, options) { 24 | var oldOnClick; 25 | 26 | options = options || {}; 27 | 28 | /** 29 | * Whether a click is currently being tracked. 30 | * 31 | * @type boolean 32 | */ 33 | this.trackingClick = false; 34 | 35 | 36 | /** 37 | * Timestamp for when click tracking started. 38 | * 39 | * @type number 40 | */ 41 | this.trackingClickStart = 0; 42 | 43 | 44 | /** 45 | * The element being tracked for a click. 46 | * 47 | * @type EventTarget 48 | */ 49 | this.targetElement = null; 50 | 51 | 52 | /** 53 | * X-coordinate of touch start event. 54 | * 55 | * @type number 56 | */ 57 | this.touchStartX = 0; 58 | 59 | 60 | /** 61 | * Y-coordinate of touch start event. 62 | * 63 | * @type number 64 | */ 65 | this.touchStartY = 0; 66 | 67 | 68 | /** 69 | * ID of the last touch, retrieved from Touch.identifier. 70 | * 71 | * @type number 72 | */ 73 | this.lastTouchIdentifier = 0; 74 | 75 | 76 | /** 77 | * Touchmove boundary, beyond which a click will be cancelled. 78 | * 79 | * @type number 80 | */ 81 | this.touchBoundary = options.touchBoundary || 10; 82 | 83 | 84 | /** 85 | * The FastClick layer. 86 | * 87 | * @type Element 88 | */ 89 | this.layer = layer; 90 | 91 | /** 92 | * The minimum time between tap(touchstart and touchend) events 93 | * 94 | * @type number 95 | */ 96 | this.tapDelay = options.tapDelay || 200; 97 | 98 | /** 99 | * The maximum time for a tap 100 | * 101 | * @type number 102 | */ 103 | this.tapTimeout = options.tapTimeout || 700; 104 | 105 | if (FastClick.notNeeded(layer)) { 106 | return; 107 | } 108 | 109 | // Some old versions of Android don't have Function.prototype.bind 110 | function bind(method, context) { 111 | return function() { return method.apply(context, arguments); }; 112 | } 113 | 114 | 115 | var methods = ['onMouse', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel']; 116 | var context = this; 117 | for (var i = 0, l = methods.length; i < l; i++) { 118 | context[methods[i]] = bind(context[methods[i]], context); 119 | } 120 | 121 | // Set up event handlers as required 122 | if (deviceIsAndroid) { 123 | layer.addEventListener('mouseover', this.onMouse, true); 124 | layer.addEventListener('mousedown', this.onMouse, true); 125 | layer.addEventListener('mouseup', this.onMouse, true); 126 | } 127 | 128 | layer.addEventListener('click', this.onClick, true); 129 | layer.addEventListener('touchstart', this.onTouchStart, false); 130 | layer.addEventListener('touchmove', this.onTouchMove, false); 131 | layer.addEventListener('touchend', this.onTouchEnd, false); 132 | layer.addEventListener('touchcancel', this.onTouchCancel, false); 133 | 134 | // Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2) 135 | // which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick 136 | // layer when they are cancelled. 137 | if (!Event.prototype.stopImmediatePropagation) { 138 | layer.removeEventListener = function(type, callback, capture) { 139 | var rmv = Node.prototype.removeEventListener; 140 | if (type === 'click') { 141 | rmv.call(layer, type, callback.hijacked || callback, capture); 142 | } else { 143 | rmv.call(layer, type, callback, capture); 144 | } 145 | }; 146 | 147 | layer.addEventListener = function(type, callback, capture) { 148 | var adv = Node.prototype.addEventListener; 149 | if (type === 'click') { 150 | adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) { 151 | if (!event.propagationStopped) { 152 | callback(event); 153 | } 154 | }), capture); 155 | } else { 156 | adv.call(layer, type, callback, capture); 157 | } 158 | }; 159 | } 160 | 161 | // If a handler is already declared in the element's onclick attribute, it will be fired before 162 | // FastClick's onClick handler. Fix this by pulling out the user-defined handler function and 163 | // adding it as listener. 164 | if (typeof layer.onclick === 'function') { 165 | 166 | // Android browser on at least 3.2 requires a new reference to the function in layer.onclick 167 | // - the old one won't work if passed to addEventListener directly. 168 | oldOnClick = layer.onclick; 169 | layer.addEventListener('click', function(event) { 170 | oldOnClick(event); 171 | }, false); 172 | layer.onclick = null; 173 | } 174 | } 175 | 176 | /** 177 | * Windows Phone 8.1 fakes user agent string to look like Android and iPhone. 178 | * 179 | * @type boolean 180 | */ 181 | var deviceIsWindowsPhone = navigator.userAgent.indexOf("Windows Phone") >= 0; 182 | 183 | /** 184 | * Android requires exceptions. 185 | * 186 | * @type boolean 187 | */ 188 | var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0 && !deviceIsWindowsPhone; 189 | 190 | 191 | /** 192 | * iOS requires exceptions. 193 | * 194 | * @type boolean 195 | */ 196 | var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent) && !deviceIsWindowsPhone; 197 | 198 | 199 | /** 200 | * iOS 4 requires an exception for select elements. 201 | * 202 | * @type boolean 203 | */ 204 | var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent); 205 | 206 | 207 | /** 208 | * iOS 6.0-7.* requires the target element to be manually derived 209 | * 210 | * @type boolean 211 | */ 212 | var deviceIsIOSWithBadTarget = deviceIsIOS && (/OS [6-7]_\d/).test(navigator.userAgent); 213 | 214 | /** 215 | * BlackBerry requires exceptions. 216 | * 217 | * @type boolean 218 | */ 219 | var deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0; 220 | 221 | /** 222 | * Determine whether a given element requires a native click. 223 | * 224 | * @param {EventTarget|Element} target Target DOM element 225 | * @returns {boolean} Returns true if the element needs a native click 226 | */ 227 | FastClick.prototype.needsClick = function(target) { 228 | switch (target.nodeName.toLowerCase()) { 229 | 230 | // Don't send a synthetic click to disabled inputs (issue #62) 231 | case 'button': 232 | case 'select': 233 | case 'textarea': 234 | if (target.disabled) { 235 | return true; 236 | } 237 | 238 | break; 239 | case 'input': 240 | 241 | // File inputs need real clicks on iOS 6 due to a browser bug (issue #68) 242 | if ((deviceIsIOS && target.type === 'file') || target.disabled) { 243 | return true; 244 | } 245 | 246 | break; 247 | case 'label': 248 | case 'iframe': // iOS8 homescreen apps can prevent events bubbling into frames 249 | case 'video': 250 | return true; 251 | } 252 | 253 | return (/\bneedsclick\b/).test(target.className); 254 | }; 255 | 256 | 257 | /** 258 | * Determine whether a given element requires a call to focus to simulate click into element. 259 | * 260 | * @param {EventTarget|Element} target Target DOM element 261 | * @returns {boolean} Returns true if the element requires a call to focus to simulate native click. 262 | */ 263 | FastClick.prototype.needsFocus = function(target) { 264 | switch (target.nodeName.toLowerCase()) { 265 | case 'textarea': 266 | return true; 267 | case 'select': 268 | return !deviceIsAndroid; 269 | case 'input': 270 | switch (target.type) { 271 | case 'button': 272 | case 'checkbox': 273 | case 'file': 274 | case 'image': 275 | case 'radio': 276 | case 'submit': 277 | return false; 278 | } 279 | 280 | // No point in attempting to focus disabled inputs 281 | return !target.disabled && !target.readOnly; 282 | default: 283 | return (/\bneedsfocus\b/).test(target.className); 284 | } 285 | }; 286 | 287 | 288 | /** 289 | * Send a click event to the specified element. 290 | * 291 | * @param {EventTarget|Element} targetElement 292 | * @param {Event} event 293 | */ 294 | FastClick.prototype.sendClick = function(targetElement, event) { 295 | var clickEvent, touch; 296 | 297 | // On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24) 298 | if (document.activeElement && document.activeElement !== targetElement) { 299 | document.activeElement.blur(); 300 | } 301 | 302 | touch = event.changedTouches[0]; 303 | 304 | // Synthesise a click event, with an extra attribute so it can be tracked 305 | clickEvent = document.createEvent('MouseEvents'); 306 | clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); 307 | clickEvent.forwardedTouchEvent = true; 308 | targetElement.dispatchEvent(clickEvent); 309 | }; 310 | 311 | FastClick.prototype.determineEventType = function(targetElement) { 312 | 313 | //Issue #159: Android Chrome Select Box does not open with a synthetic click event 314 | if (deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') { 315 | return 'mousedown'; 316 | } 317 | 318 | return 'click'; 319 | }; 320 | 321 | 322 | /** 323 | * @param {EventTarget|Element} targetElement 324 | */ 325 | FastClick.prototype.focus = function(targetElement) { 326 | var length; 327 | 328 | // Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724. 329 | if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month' && targetElement.type !== 'email') { 330 | length = targetElement.value.length; 331 | targetElement.setSelectionRange(length, length); 332 | } else { 333 | targetElement.focus(); 334 | } 335 | }; 336 | 337 | 338 | /** 339 | * Check whether the given target element is a child of a scrollable layer and if so, set a flag on it. 340 | * 341 | * @param {EventTarget|Element} targetElement 342 | */ 343 | FastClick.prototype.updateScrollParent = function(targetElement) { 344 | var scrollParent, parentElement; 345 | 346 | scrollParent = targetElement.fastClickScrollParent; 347 | 348 | // Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the 349 | // target element was moved to another parent. 350 | if (!scrollParent || !scrollParent.contains(targetElement)) { 351 | parentElement = targetElement; 352 | do { 353 | if (parentElement.scrollHeight > parentElement.offsetHeight) { 354 | scrollParent = parentElement; 355 | targetElement.fastClickScrollParent = parentElement; 356 | break; 357 | } 358 | 359 | parentElement = parentElement.parentElement; 360 | } while (parentElement); 361 | } 362 | 363 | // Always update the scroll top tracker if possible. 364 | if (scrollParent) { 365 | scrollParent.fastClickLastScrollTop = scrollParent.scrollTop; 366 | } 367 | }; 368 | 369 | 370 | /** 371 | * @param {EventTarget} targetElement 372 | * @returns {Element|EventTarget} 373 | */ 374 | FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) { 375 | 376 | // On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node. 377 | if (eventTarget.nodeType === Node.TEXT_NODE) { 378 | return eventTarget.parentNode; 379 | } 380 | 381 | return eventTarget; 382 | }; 383 | 384 | 385 | /** 386 | * On touch start, record the position and scroll offset. 387 | * 388 | * @param {Event} event 389 | * @returns {boolean} 390 | */ 391 | FastClick.prototype.onTouchStart = function(event) { 392 | var targetElement, touch, selection; 393 | 394 | // Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111). 395 | if (event.targetTouches.length > 1) { 396 | return true; 397 | } 398 | 399 | targetElement = this.getTargetElementFromEventTarget(event.target); 400 | touch = event.targetTouches[0]; 401 | 402 | if (deviceIsIOS) { 403 | 404 | // Only trusted events will deselect text on iOS (issue #49) 405 | selection = window.getSelection(); 406 | if (selection.rangeCount && !selection.isCollapsed) { 407 | return true; 408 | } 409 | 410 | if (!deviceIsIOS4) { 411 | 412 | // Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23): 413 | // when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched 414 | // with the same identifier as the touch event that previously triggered the click that triggered the alert. 415 | // Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an 416 | // immediately preceeding touch event (issue #52), so this fix is unavailable on that platform. 417 | // Issue 120: touch.identifier is 0 when Chrome dev tools 'Emulate touch events' is set with an iOS device UA string, 418 | // which causes all touch events to be ignored. As this block only applies to iOS, and iOS identifiers are always long, 419 | // random integers, it's safe to to continue if the identifier is 0 here. 420 | if (touch.identifier && touch.identifier === this.lastTouchIdentifier) { 421 | event.preventDefault(); 422 | return false; 423 | } 424 | 425 | this.lastTouchIdentifier = touch.identifier; 426 | 427 | // If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and: 428 | // 1) the user does a fling scroll on the scrollable layer 429 | // 2) the user stops the fling scroll with another tap 430 | // then the event.target of the last 'touchend' event will be the element that was under the user's finger 431 | // when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check 432 | // is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42). 433 | this.updateScrollParent(targetElement); 434 | } 435 | } 436 | 437 | this.trackingClick = true; 438 | this.trackingClickStart = event.timeStamp; 439 | this.targetElement = targetElement; 440 | 441 | this.touchStartX = touch.pageX; 442 | this.touchStartY = touch.pageY; 443 | 444 | // Prevent phantom clicks on fast double-tap (issue #36) 445 | if ((event.timeStamp - this.lastClickTime) < this.tapDelay) { 446 | event.preventDefault(); 447 | } 448 | 449 | return true; 450 | }; 451 | 452 | 453 | /** 454 | * Based on a touchmove event object, check whether the touch has moved past a boundary since it started. 455 | * 456 | * @param {Event} event 457 | * @returns {boolean} 458 | */ 459 | FastClick.prototype.touchHasMoved = function(event) { 460 | var touch = event.changedTouches[0], boundary = this.touchBoundary; 461 | 462 | if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) { 463 | return true; 464 | } 465 | 466 | return false; 467 | }; 468 | 469 | 470 | /** 471 | * Update the last position. 472 | * 473 | * @param {Event} event 474 | * @returns {boolean} 475 | */ 476 | FastClick.prototype.onTouchMove = function(event) { 477 | if (!this.trackingClick) { 478 | return true; 479 | } 480 | 481 | // If the touch has moved, cancel the click tracking 482 | if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) { 483 | this.trackingClick = false; 484 | this.targetElement = null; 485 | } 486 | 487 | return true; 488 | }; 489 | 490 | 491 | /** 492 | * Attempt to find the labelled control for the given label element. 493 | * 494 | * @param {EventTarget|HTMLLabelElement} labelElement 495 | * @returns {Element|null} 496 | */ 497 | FastClick.prototype.findControl = function(labelElement) { 498 | 499 | // Fast path for newer browsers supporting the HTML5 control attribute 500 | if (labelElement.control !== undefined) { 501 | return labelElement.control; 502 | } 503 | 504 | // All browsers under test that support touch events also support the HTML5 htmlFor attribute 505 | if (labelElement.htmlFor) { 506 | return document.getElementById(labelElement.htmlFor); 507 | } 508 | 509 | // If no for attribute exists, attempt to retrieve the first labellable descendant element 510 | // the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label 511 | return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea'); 512 | }; 513 | 514 | 515 | /** 516 | * On touch end, determine whether to send a click event at once. 517 | * 518 | * @param {Event} event 519 | * @returns {boolean} 520 | */ 521 | FastClick.prototype.onTouchEnd = function(event) { 522 | var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement; 523 | 524 | if (!this.trackingClick) { 525 | return true; 526 | } 527 | 528 | // Prevent phantom clicks on fast double-tap (issue #36) 529 | if ((event.timeStamp - this.lastClickTime) < this.tapDelay) { 530 | this.cancelNextClick = true; 531 | return true; 532 | } 533 | 534 | if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) { 535 | return true; 536 | } 537 | 538 | // Reset to prevent wrong click cancel on input (issue #156). 539 | this.cancelNextClick = false; 540 | 541 | this.lastClickTime = event.timeStamp; 542 | 543 | trackingClickStart = this.trackingClickStart; 544 | this.trackingClick = false; 545 | this.trackingClickStart = 0; 546 | 547 | // On some iOS devices, the targetElement supplied with the event is invalid if the layer 548 | // is performing a transition or scroll, and has to be re-detected manually. Note that 549 | // for this to function correctly, it must be called *after* the event target is checked! 550 | // See issue #57; also filed as rdar://13048589 . 551 | if (deviceIsIOSWithBadTarget) { 552 | touch = event.changedTouches[0]; 553 | 554 | // In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null 555 | targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement; 556 | targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent; 557 | } 558 | 559 | targetTagName = targetElement.tagName.toLowerCase(); 560 | if (targetTagName === 'label') { 561 | forElement = this.findControl(targetElement); 562 | if (forElement) { 563 | this.focus(targetElement); 564 | if (deviceIsAndroid) { 565 | return false; 566 | } 567 | 568 | targetElement = forElement; 569 | } 570 | } else if (this.needsFocus(targetElement)) { 571 | 572 | // Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through. 573 | // Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37). 574 | if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) { 575 | this.targetElement = null; 576 | return false; 577 | } 578 | 579 | this.focus(targetElement); 580 | this.sendClick(targetElement, event); 581 | 582 | // Select elements need the event to go through on iOS 4, otherwise the selector menu won't open. 583 | // Also this breaks opening selects when VoiceOver is active on iOS6, iOS7 (and possibly others) 584 | if (!deviceIsIOS || targetTagName !== 'select') { 585 | this.targetElement = null; 586 | event.preventDefault(); 587 | } 588 | 589 | return false; 590 | } 591 | 592 | if (deviceIsIOS && !deviceIsIOS4) { 593 | 594 | // Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled 595 | // and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42). 596 | scrollParent = targetElement.fastClickScrollParent; 597 | if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) { 598 | return true; 599 | } 600 | } 601 | 602 | // Prevent the actual click from going though - unless the target node is marked as requiring 603 | // real clicks or if it is in the allowlist in which case only non-programmatic clicks are permitted. 604 | if (!this.needsClick(targetElement)) { 605 | event.preventDefault(); 606 | this.sendClick(targetElement, event); 607 | } 608 | 609 | return false; 610 | }; 611 | 612 | 613 | /** 614 | * On touch cancel, stop tracking the click. 615 | * 616 | * @returns {void} 617 | */ 618 | FastClick.prototype.onTouchCancel = function() { 619 | this.trackingClick = false; 620 | this.targetElement = null; 621 | }; 622 | 623 | 624 | /** 625 | * Determine mouse events which should be permitted. 626 | * 627 | * @param {Event} event 628 | * @returns {boolean} 629 | */ 630 | FastClick.prototype.onMouse = function(event) { 631 | 632 | // If a target element was never set (because a touch event was never fired) allow the event 633 | if (!this.targetElement) { 634 | return true; 635 | } 636 | 637 | if (event.forwardedTouchEvent) { 638 | return true; 639 | } 640 | 641 | // Programmatically generated events targeting a specific element should be permitted 642 | if (!event.cancelable) { 643 | return true; 644 | } 645 | 646 | // Derive and check the target element to see whether the mouse event needs to be permitted; 647 | // unless explicitly enabled, prevent non-touch click events from triggering actions, 648 | // to prevent ghost/doubleclicks. 649 | if (!this.needsClick(this.targetElement) || this.cancelNextClick) { 650 | 651 | // Prevent any user-added listeners declared on FastClick element from being fired. 652 | if (event.stopImmediatePropagation) { 653 | event.stopImmediatePropagation(); 654 | } else { 655 | 656 | // Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2) 657 | event.propagationStopped = true; 658 | } 659 | 660 | // Cancel the event 661 | event.stopPropagation(); 662 | event.preventDefault(); 663 | 664 | return false; 665 | } 666 | 667 | // If the mouse event is permitted, return true for the action to go through. 668 | return true; 669 | }; 670 | 671 | 672 | /** 673 | * On actual clicks, determine whether this is a touch-generated click, a click action occurring 674 | * naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or 675 | * an actual click which should be permitted. 676 | * 677 | * @param {Event} event 678 | * @returns {boolean} 679 | */ 680 | FastClick.prototype.onClick = function(event) { 681 | var permitted; 682 | 683 | // It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early. 684 | if (this.trackingClick) { 685 | this.targetElement = null; 686 | this.trackingClick = false; 687 | return true; 688 | } 689 | 690 | // Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target. 691 | if (event.target.type === 'submit' && event.detail === 0) { 692 | return true; 693 | } 694 | 695 | permitted = this.onMouse(event); 696 | 697 | // Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through. 698 | if (!permitted) { 699 | this.targetElement = null; 700 | } 701 | 702 | // If clicks are permitted, return true for the action to go through. 703 | return permitted; 704 | }; 705 | 706 | 707 | /** 708 | * Remove all FastClick's event listeners. 709 | * 710 | * @returns {void} 711 | */ 712 | FastClick.prototype.destroy = function() { 713 | var layer = this.layer; 714 | 715 | if (deviceIsAndroid) { 716 | layer.removeEventListener('mouseover', this.onMouse, true); 717 | layer.removeEventListener('mousedown', this.onMouse, true); 718 | layer.removeEventListener('mouseup', this.onMouse, true); 719 | } 720 | 721 | layer.removeEventListener('click', this.onClick, true); 722 | layer.removeEventListener('touchstart', this.onTouchStart, false); 723 | layer.removeEventListener('touchmove', this.onTouchMove, false); 724 | layer.removeEventListener('touchend', this.onTouchEnd, false); 725 | layer.removeEventListener('touchcancel', this.onTouchCancel, false); 726 | }; 727 | 728 | 729 | /** 730 | * Check whether FastClick is needed. 731 | * 732 | * @param {Element} layer The layer to listen on 733 | */ 734 | FastClick.notNeeded = function(layer) { 735 | var metaViewport; 736 | var chromeVersion; 737 | var blackberryVersion; 738 | var firefoxVersion; 739 | 740 | // Devices that don't support touch don't need FastClick 741 | if (typeof window.ontouchstart === 'undefined') { 742 | return true; 743 | } 744 | 745 | // Chrome version - zero for other browsers 746 | chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1]; 747 | 748 | if (chromeVersion) { 749 | 750 | if (deviceIsAndroid) { 751 | metaViewport = document.querySelector('meta[name=viewport]'); 752 | 753 | if (metaViewport) { 754 | // Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89) 755 | if (metaViewport.content.indexOf('user-scalable=no') !== -1) { 756 | return true; 757 | } 758 | // Chrome 32 and above with width=device-width or less don't need FastClick 759 | if (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) { 760 | return true; 761 | } 762 | } 763 | 764 | // Chrome desktop doesn't need FastClick (issue #15) 765 | } else { 766 | return true; 767 | } 768 | } 769 | 770 | if (deviceIsBlackBerry10) { 771 | blackberryVersion = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/); 772 | 773 | // BlackBerry 10.3+ does not require Fastclick library. 774 | // https://github.com/ftlabs/fastclick/issues/251 775 | if (blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) { 776 | metaViewport = document.querySelector('meta[name=viewport]'); 777 | 778 | if (metaViewport) { 779 | // user-scalable=no eliminates click delay. 780 | if (metaViewport.content.indexOf('user-scalable=no') !== -1) { 781 | return true; 782 | } 783 | // width=device-width (or less than device-width) eliminates click delay. 784 | if (document.documentElement.scrollWidth <= window.outerWidth) { 785 | return true; 786 | } 787 | } 788 | } 789 | } 790 | 791 | // IE10 with -ms-touch-action: none or manipulation, which disables double-tap-to-zoom (issue #97) 792 | if (layer.style.msTouchAction === 'none' || layer.style.touchAction === 'manipulation') { 793 | return true; 794 | } 795 | 796 | // Firefox version - zero for other browsers 797 | firefoxVersion = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1]; 798 | 799 | if (firefoxVersion >= 27) { 800 | // Firefox 27+ does not have tap delay if the content is not zoomable - https://bugzilla.mozilla.org/show_bug.cgi?id=922896 801 | 802 | metaViewport = document.querySelector('meta[name=viewport]'); 803 | if (metaViewport && (metaViewport.content.indexOf('user-scalable=no') !== -1 || document.documentElement.scrollWidth <= window.outerWidth)) { 804 | return true; 805 | } 806 | } 807 | 808 | // IE11: prefixed -ms-touch-action is no longer supported and it's recomended to use non-prefixed version 809 | // http://msdn.microsoft.com/en-us/library/windows/apps/Hh767313.aspx 810 | if (layer.style.touchAction === 'none' || layer.style.touchAction === 'manipulation') { 811 | return true; 812 | } 813 | 814 | return false; 815 | }; 816 | 817 | 818 | /** 819 | * Factory method for creating a FastClick object 820 | * 821 | * @param {Element} layer The layer to listen on 822 | * @param {Object} [options={}] The options to override the defaults 823 | */ 824 | FastClick.attach = function(layer, options) { 825 | return new FastClick(layer, options); 826 | }; 827 | 828 | 829 | if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { 830 | 831 | // AMD. Register as an anonymous module. 832 | define(function() { 833 | return FastClick; 834 | }); 835 | } else if (typeof module !== 'undefined' && module.exports) { 836 | module.exports = FastClick.attach; 837 | module.exports.FastClick = FastClick; 838 | } else { 839 | window.FastClick = FastClick; 840 | } 841 | }()); 842 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fastclick", 3 | "version": "1.0.6", 4 | "description": "Polyfill to remove click delays on browsers with touch UIs.", 5 | "maintainers": [ 6 | { 7 | "name": "Matthew Caruana Galizia", 8 | "email": "m@m.cg", 9 | "url": "http://m.cg/" 10 | } 11 | ], 12 | "author": { 13 | "name": "Rowan Beentje", 14 | "email": "rowan.beentje@ft.com" 15 | }, 16 | "contributors": [ 17 | { 18 | "name": "Rowan Beentje", 19 | "email": "rowan.beentje@ft.com" 20 | }, 21 | { 22 | "name": "Matthew Caruana Galizia", 23 | "email": "m@m.cg" 24 | } 25 | ], 26 | "main": "lib/fastclick.js", 27 | "repository": { 28 | "type": "git", 29 | "url": "git://github.com/ftlabs/fastclick.git" 30 | }, 31 | "keywords": [ 32 | "fastclick", 33 | "mobile", 34 | "touch", 35 | "tap", 36 | "click", 37 | "delay" 38 | ], 39 | "licenses": [ 40 | { 41 | "type": "MIT", 42 | "url": "http://opensource.org/licenses/MIT" 43 | } 44 | ], 45 | "implements": [ 46 | "CommonJS/Modules/1.0" 47 | ], 48 | "homepage": "https://github.com/ftlabs/fastclick" 49 | } 50 | -------------------------------------------------------------------------------- /tests/10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | #10 10 | 11 | 19 | 20 | 21 | 22 |

23 | 24 |

Now try and select the text in this paragraph.

25 | 26 | -------------------------------------------------------------------------------- /tests/111.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | #111 13 | 14 | 28 | 29 | 30 |

If you attempt a pinch zoom on iOS with both fingers on the same element, pinch zooming should work. If each finger is touching a different element, the pinch zooming should also work.

31 |

Only the red block below has FastClick enabled.

32 |
33 |
34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /tests/160-reduced.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | #160 9 | 50 | 51 | 52 |

Calling elem.setSelectionRange on inputs with type date or time, as well as getting the selectionStart or selectionEnd properties, throws a TypeError.

53 |

Filed as Apple bug #15122724.

54 |
55 |

Test (date):

56 | 57 |

Test (datetime):

58 | 59 |

Test (month):

60 | 61 |

Test (time):

62 | 63 |

Control (text):

64 | 65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /tests/160.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | #160 9 | 10 | 15 | 16 | 17 |

Calling elem.setSelectionRange on inputs with type date or time throws a TypeError.

18 |

Filed as Apple bug #15122724.

19 |
20 |

Test:

21 | 22 |

Control:

23 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/176.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | fastclick 8 | 9 | 41 | 42 | 43 | 44 |
first, dye to blue!
45 | 46 | 47 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /tests/18.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 14 | 15 | 24 | 25 | 26 |

On focusing on the input text element, hitting go in the device keyboard should submit the form. The actual submission will be prevented and instead 'Submit caught' will appear in the console.

27 |
28 |
29 | 30 | 31 |
32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/22.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | #22 10 | 11 | 16 | 17 | 18 | 19 |

On Android 4, single pressing the textarea should produce a cursor. Long-pressing a word should bring up the double arrow indicator for selection. It should be possible to move the indicators.

20 |

Tapping on a word with a squiggly red underline should bring up the spelling suggestion box.

21 | 22 | -------------------------------------------------------------------------------- /tests/226.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | #226 10 | 17 | 18 | 19 | The follow select can be opened with VoiceOver off, but with VoiceOver on it will not open. 20 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/23-reduced.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | #23 10 | 11 | 56 | 57 | 58 |

At the start of this test, i = 0. Tapping the first button will increment i and trigger an alert with the text 'Alert #' + i.

59 |

Tapping on the second button should have absolutely no effect, but in iOS6 it will re-trigger the alert.

60 | 61 |

62 | 63 | 64 | -------------------------------------------------------------------------------- /tests/23.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | #23 10 | 11 | 22 | 23 | 24 |

At the start of this test, i = 0. Tapping the first button will increment i and trigger an alert with the text 'Alert #' + i.

25 |

Tapping on the second button should have absolutely no effect, but in iOS 4-6 it will re-trigger the alert.

26 | 27 |

28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/24.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | 27 | #24 28 | 29 | 30 |
31 | 32 |
33 | 34 | 35 |
36 | 37 | 38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/26.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 43 | #26 44 | 45 | 46 |
47 |
48 |
49 |

Clicks:

50 |
51 | 52 |
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /tests/27.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | #27 14 | 15 | 16 | 30 | 31 | 32 |

Clicking or tapping the div that says 'click me' should not trigger focus on the adjacent input element as or after it slides in.

33 |
34 |
35 |
Click Me
36 |
37 | 41 |
42 | 43 | -------------------------------------------------------------------------------- /tests/30.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | #30 11 | 12 | 17 | 18 | 19 |

FastClick is instantiated on the document body. Tap a label for the associated input control to gain focus. Focus should be equally fast in all tests.

20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 |
30 | 31 |
32 | 33 | -------------------------------------------------------------------------------- /tests/32.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | #32 10 | 11 | 21 | 22 | 23 |
24 |
25 | 26 |
27 | 28 |
29 |
30 | 31 | 32 | Appointment Type * 33 | 34 |   35 | 36 | 44 |
45 |
46 | 47 |
48 |
49 | 50 | 51 | Physician 52 | 53 |   54 | 55 | 63 |
64 |
65 | 66 | 67 | 68 |
69 |
70 | 71 | 72 | Time of Day 73 | 74 |   75 | 76 | 83 |
84 |
85 |
86 |
87 | 88 |
89 | 90 | Find Appointments 91 | 92 | 93 |
94 |
95 |
96 | 97 | -------------------------------------------------------------------------------- /tests/36.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #36 5 | 6 | 7 | 8 | 13 | 14 | 19 | 20 | 21 |

A tap and long hold, then release on input #1 will sometimes trigger focus on #2.

22 |
23 |
24 |

25 |

26 |

27 |

28 |

29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/37-reduced.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | #37-reduced 9 | 14 | 15 | 16 |

On tapping the text input in the iframe and enter text, the entered text will not appear until the text input is tapped again. After that, tapping the text input a third time while it is still focus it will seem to disable text entry completely.

17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/37a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | #37 12 | 13 | 14 | 15 |

On touching/clicking the input field within the iframe, you should be able to input text normally.

16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/37b.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | IFrame Page 17 | 18 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/42.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #42 5 | 6 | 7 | 8 | 9 | 23 | 60 | 61 | 62 | 86 | 87 | 88 |
89 |
90 | 1 91 | 2 92 | 3 93 | 4 94 | 5 95 | 6 96 | 7 97 | 8 98 | 9 99 | 10 100 | 11 101 | 12 102 | 13 103 | 14 104 | 15 105 | 16 106 | 17 107 | 18 108 | 19 109 | 20 110 | 21 111 | 22 112 | 23 113 | 24 114 | 25 115 | 26 116 | 27 117 | 28 118 | 29 119 | 30 120 | 31 121 | 32 122 | 33 123 | 34 124 | 35 125 | 36 126 | 37 127 | 38 128 | 39 129 | 40 130 | 41 131 | 42 132 | 43 133 | 44 134 | 45 135 | 46 136 | 47 137 | 48 138 | 49 139 | 50 140 | 51 141 | 52 142 | 53 143 | 54 144 | 55 145 | 56 146 | 57 147 | 58 148 | 59 149 | 60 150 | 61 151 | 62 152 | 63 153 | 64 154 | 65 155 | 66 156 | 67 157 | 68 158 | 69 159 | 70 160 | 71 161 | 72 162 | 73 163 | 74 164 | 75 165 | 76 166 | 77 167 | 78 168 | 79 169 | 80 170 | 81 171 | 82 172 | 83 173 | 84 174 | 85 175 | 86 176 | 87 177 | 88 178 | 89 179 | 90 180 | 91 181 | 92 182 | 93 183 | 94 184 | 95 185 | 96 186 | 97 187 | 98 188 | 99 189 | 100 190 |
191 | 192 | -------------------------------------------------------------------------------- /tests/44.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #36 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 50 | 51 | 52 |

Tap the map marker.

53 |
54 |
55 | 56 | 57 | -------------------------------------------------------------------------------- /tests/45.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | #45 11 | 12 | 17 | 18 | 19 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum at bibendum urna. Sed pellentesque felis eget massa luctus convallis. Duis posuere imperdiet velit, a vulputate elit pulvinar nec. Quisque eleifend sollicitudin quam, ac sodales turpis tincidunt sed. Donec ac hendrerit dui. Vestibulum vel tortor purus, a tempus purus. Nam dictum urna a lectus dapibus porttitor. Integer lobortis, massa sit amet consequat rhoncus, purus justo lacinia ante, vitae suscipit lectus dui eu augue. Nulla ut imperdiet arcu. Morbi sapien dui, condimentum sed iaculis eu, accumsan pellentesque risus. Ut interdum mollis feugiat.

20 | 21 |

Nullam aliquet adipiscing sagittis. Duis adipiscing pellentesque semper. Maecenas sollicitudin porttitor ipsum, ac blandit sapien tristique eget. Donec sit amet nulla elit. In hac habitasse platea dictumst. Duis cursus mollis nulla, a sagittis lectus convallis vitae. Suspendisse vestibulum arcu sem. Ut eleifend nisi ac sapien iaculis sed tempor felis accumsan. Integer quis sapien massa, sed ullamcorper mi.

22 | 23 |

Aenean rutrum vehicula lobortis. Maecenas eleifend, augue quis elementum tincidunt, metus eros pulvinar odio, eget faucibus erat magna lacinia sapien. Pellentesque ullamcorper dolor ut ipsum fringilla cursus. Integer gravida augue ac elit placerat hendrerit. Sed eget nisl justo, nec bibendum nunc. Aenean non nunc felis. Nullam semper, felis at venenatis bibendum, justo mauris laoreet ipsum, at tristique risus dui id eros. Aliquam erat volutpat.

24 | 25 |

Aliquam nunc enim, cursus id malesuada sed, vestibulum quis libero. Vivamus accumsan lacus sit amet libero tempor laoreet. Donec convallis, enim ac mattis luctus, nunc dolor rutrum neque, non auctor sem est nec lorem. Cras bibendum dui nec ante semper fermentum. Sed sollicitudin porttitor lorem vitae fermentum. Morbi vitae massa et diam gravida consequat. Nulla semper, leo vitae pharetra commodo, justo eros luctus velit, eget molestie neque mi nec turpis.

26 | 27 |

Fusce urna orci, molestie vitae blandit et, pellentesque in ante. Etiam mattis ultricies ligula, et scelerisque diam venenatis id. In dignissim molestie interdum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis vehicula eros non tortor tristique non euismod urna laoreet. Curabitur mauris tellus, dapibus non blandit a, ultrices vitae purus. Morbi at diam lectus. Donec et purus a diam rutrum aliquam nec ac dolor. Donec quis dolor molestie quam lacinia mattis. Sed euismod condimentum quam sit amet accumsan.

28 | 29 |

Etiam accumsan ipsum vel nulla vulputate eleifend. Nullam vestibulum pulvinar consectetur. Aliquam erat volutpat. Curabitur nunc nisl, ultrices posuere accumsan sed, bibendum a nulla. Donec ac justo vitae orci fermentum euismod. Sed elit risus, rhoncus et egestas vitae, feugiat eu sapien. Nam tempus, dolor quis venenatis pellentesque, lacus quam fringilla enim, non tristique dolor nulla vel eros. Quisque luctus, dolor id consectetur pharetra, mauris leo congue felis, at vehicula augue lacus id quam. Donec euismod laoreet hendrerit.

30 | 31 | -------------------------------------------------------------------------------- /tests/48.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #48 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 | 21 | 22 | 42 | 43 | 44 |

The dropdown should stay open after tapping the button once.

45 |
46 |
47 | 48 | 49 | 50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /tests/51-reduced.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | #51-reduced 9 | 15 | 16 | 17 |

Tap the input twice in succession and try to type.

18 | 19 |
20 | 21 | -------------------------------------------------------------------------------- /tests/6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | #6 10 | 11 | 21 | 22 | 23 | 24 |

Open the browser console to see debug info.

25 | 26 |

27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/60.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | #60 11 | 12 | 17 | 18 | 19 |

FastClick is instantiated on the document body. A label element is wrapped around an anchor element. Tapping the anchor element should cause the label's the associated input control to gain focus.

20 |

This works because the CSS rule label > a { pointer-events: none; } is being used.

21 |
22 | 23 |
24 | 25 | -------------------------------------------------------------------------------- /tests/62.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | #62 9 | 10 | 15 | 16 | 17 |

Tapping a disabled checkbox should not change its value.

18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/68.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | #68 10 | 11 | 16 | 17 | 18 |

On iOS, tapping either of the inputs should open the media selection dialog normally.

19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/6b.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 33 | #6b 34 | 44 | 45 | 46 |

This test case is designed for Chrome on Android 4.1 on the Nexus 7.

47 |

Tap the textarea so that it gains focus. The browser should zoom the page. Once that happens the coordinates for every tap will be off until the page is zoomed back to the normal level.

48 |
49 |
 
50 | 51 |
52 | 53 |
54 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sed mauris in nisi dignissim ultricies sit amet id sapien. Curabitur venenatis, justo sed iaculis molestie, velit nisl consectetur metus, at vulputate nulla nisl et urna. Ut et urna a mauris malesuada mollis non vel ante. Nulla volutpat tellus sed elit varius ultricies. Nam euismod pellentesque felis sed adipiscing. Morbi ultricies risus a diam blandit a tincidunt tellus rhoncus. Cras facilisis pulvinar ante vitae pretium. Ut non orci sem. Integer fringilla est in tortor consectetur porta. Mauris ullamcorper neque sed arcu ultrices accumsan. Morbi condimentum metus eu sem volutpat auctor. Nam posuere fermentum est sed aliquet. Maecenas mauris mauris, auctor hendrerit pellentesque eget, fringilla et nibh. Pellentesque euismod urna sed eros feugiat egestas. Pellentesque volutpat viverra sapien, in tincidunt ipsum tempor pharetra. Suspendisse fermentum posuere luctus.

55 |

Duis sed accumsan est. Etiam augue odio, vulputate a sollicitudin et, ornare ultricies massa. Nullam non lectus velit. Morbi consectetur pretium elit sed mollis. Sed id sem risus, vitae dapibus diam. Proin arcu metus, interdum nec pulvinar sed, auctor nec turpis. Aenean tempus, turpis sit amet pulvinar dapibus, erat arcu ornare enim, sit amet ornare lacus enim ut mauris. Pellentesque hendrerit fermentum massa vitae hendrerit. Morbi et velit libero. Nulla a fermentum nibh.

56 |

Aliquam orci turpis, dictum et rhoncus ac, imperdiet in enim. Nullam at nunc neque, a mollis urna. Phasellus gravida metus vitae turpis tempus vitae dictum ante sodales. Etiam lobortis vulputate ipsum, nec tincidunt velit volutpat nec. Pellentesque odio nibh, mattis vitae ultricies a, porta quis sapien. Curabitur rhoncus, erat ac bibendum porta, ante turpis semper nibh, porta dapibus urna ligula eu lorem. Cras lectus mi, volutpat a rhoncus et, faucibus non nibh. Ut non leo vitae tellus malesuada pharetra eget vitae lorem. Maecenas semper laoreet elit, non pulvinar leo mollis at. Mauris at rhoncus augue. Pellentesque ornare sodales nulla vitae pretium. Vivamus tempus suscipit neque vel auctor.

57 |

Maecenas blandit facilisis nulla a dignissim. In sem nulla, tincidunt id congue nec, volutpat a magna. Cras eleifend porta sodales. Suspendisse felis eros, aliquet sed faucibus sed, lacinia pretium magna. Vestibulum consequat neque non dui malesuada tempus. Quisque pharetra tristique elit consectetur tincidunt. Aenean justo ipsum, lacinia vitae fringilla nec, pulvinar at massa. Integer a mauris ligula, in adipiscing nisl. Curabitur urna massa, luctus non ullamcorper ut, auctor ac mauris. Curabitur malesuada sem ut ipsum pellentesque eu consectetur magna egestas. Vestibulum lorem nibh, iaculis id iaculis eget, imperdiet eget lorem. Nunc quis lorem lorem.

58 |

Quisque vel molestie nibh. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec ornare luctus sapien, vel scelerisque augue adipiscing in. Donec faucibus lobortis sollicitudin. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi rutrum sapien ut eros consequat dapibus. Etiam enim ligula, accumsan nec vestibulum sit amet, fermentum scelerisque est. Nunc in tincidunt quam. Praesent vitae sagittis odio. Aliquam malesuada, eros at adipiscing auctor, felis enim elementum magna, eget gravida arcu nisi ac enim. Pellentesque id vehicula velit. Aliquam dignissim, risus a adipiscing dapibus, nunc turpis adipiscing ligula, dictum sagittis augue ipsum non lacus. Curabitur felis elit, ullamcorper et gravida eget, elementum sed mauris. Maecenas luctus interdum molestie.

59 |
60 | 61 |
62 |
63 | 64 | -------------------------------------------------------------------------------- /tests/7.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | #7 10 | 11 | 16 | 17 | 18 |

Click

19 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum at bibendum urna. Sed pellentesque felis eget massa luctus convallis. Duis posuere imperdiet velit, a vulputate elit pulvinar nec. Quisque eleifend sollicitudin quam, ac sodales turpis tincidunt sed. Donec ac hendrerit dui. Vestibulum vel tortor purus, a tempus purus. Nam dictum urna a lectus dapibus porttitor. Integer lobortis, massa sit amet consequat rhoncus, purus justo lacinia ante, vitae suscipit lectus dui eu augue. Nulla ut imperdiet arcu. Morbi sapien dui, condimentum sed iaculis eu, accumsan pellentesque risus. Ut interdum mollis feugiat.

20 | 21 |

Nullam aliquet adipiscing sagittis. Duis adipiscing pellentesque semper. Maecenas sollicitudin porttitor ipsum, ac blandit sapien tristique eget. Donec sit amet nulla elit. In hac habitasse platea dictumst. Duis cursus mollis nulla, a sagittis lectus convallis vitae. Suspendisse vestibulum arcu sem. Ut eleifend nisi ac sapien iaculis sed tempor felis accumsan. Integer quis sapien massa, sed ullamcorper mi.

22 | 23 |

Aenean rutrum vehicula lobortis. Maecenas eleifend, augue quis elementum tincidunt, metus eros pulvinar odio, eget faucibus erat magna lacinia sapien. Pellentesque ullamcorper dolor ut ipsum fringilla cursus. Integer gravida augue ac elit placerat hendrerit. Sed eget nisl justo, nec bibendum nunc. Aenean non nunc felis. Nullam semper, felis at venenatis bibendum, justo mauris laoreet ipsum, at tristique risus dui id eros. Aliquam erat volutpat.

24 | 25 |

Aliquam nunc enim, cursus id malesuada sed, vestibulum quis libero. Vivamus accumsan lacus sit amet libero tempor laoreet. Donec convallis, enim ac mattis luctus, nunc dolor rutrum neque, non auctor sem est nec lorem. Cras bibendum dui nec ante semper fermentum. Sed sollicitudin porttitor lorem vitae fermentum. Morbi vitae massa et diam gravida consequat. Nulla semper, leo vitae pharetra commodo, justo eros luctus velit, eget molestie neque mi nec turpis.

26 | 27 |

Fusce urna orci, molestie vitae blandit et, pellentesque in ante. Etiam mattis ultricies ligula, et scelerisque diam venenatis id. In dignissim molestie interdum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis vehicula eros non tortor tristique non euismod urna laoreet. Curabitur mauris tellus, dapibus non blandit a, ultrices vitae purus. Morbi at diam lectus. Donec et purus a diam rutrum aliquam nec ac dolor. Donec quis dolor molestie quam lacinia mattis. Sed euismod condimentum quam sit amet accumsan.

28 | 29 |

Etiam accumsan ipsum vel nulla vulputate eleifend. Nullam vestibulum pulvinar consectetur. Aliquam erat volutpat. Curabitur nunc nisl, ultrices posuere accumsan sed, bibendum a nulla. Donec ac justo vitae orci fermentum euismod. Sed elit risus, rhoncus et egestas vitae, feugiat eu sapien. Nam tempus, dolor quis venenatis pellentesque, lacus quam fringilla enim, non tristique dolor nulla vel eros. Quisque luctus, dolor id consectetur pharetra, mauris leo congue felis, at vehicula augue lacus id quam. Donec euismod laoreet hendrerit.

30 | 31 |

Phasellus eget sem tellus, id pulvinar nulla. Ut metus metus, mattis a adipiscing eget, elementum sit amet diam. Aliquam augue mi, tristique vel vestibulum eget, volutpat consectetur libero. Proin lacinia molestie tellus, nec tincidunt justo venenatis vitae. Vestibulum laoreet lacus in lacus hendrerit eleifend. Quisque metus sem, consequat scelerisque gravida nec, dapibus et diam. Praesent scelerisque arcu eu dolor lacinia non imperdiet metus pretium. Nunc consequat urna id sem rutrum id ultrices felis lacinia. Morbi varius porta neque at adipiscing. Praesent quis rutrum mi. Aenean a libero erat, quis fermentum velit.

32 | 33 |

Donec quis dui a tortor sagittis faucibus nec nec turpis. Suspendisse dictum adipiscing augue, id sodales lectus rutrum varius. Donec a dolor tellus, non aliquet lacus. Cras tempor scelerisque mattis. Suspendisse potenti. Nam elit nulla, adipiscing eget hendrerit eu, dignissim a ante. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse felis urna, porta non fermentum in, fermentum sed lacus. Morbi ac leo augue. In quis ligula lacus. Duis nunc libero, laoreet eu consequat at, blandit ullamcorper enim.

34 | 35 |

Proin id lacus ac dui lobortis vehicula eu vulputate leo. Sed bibendum tempor luctus. Mauris tincidunt orci viverra lacus varius sodales rutrum ante tempor. Aliquam a ipsum at urna fringilla pulvinar sit amet non neque. Nulla quis aliquam risus. Nunc dui diam, vulputate eu hendrerit malesuada, bibendum fringilla purus. Nunc vitae elit ligula. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

36 | 37 |

Quisque interdum consequat nulla ac facilisis. Sed aliquam egestas risus at laoreet. Aenean a adipiscing enim. Sed varius, metus non ultrices dignissim, justo felis molestie nunc, in porta orci odio et lacus. Donec semper lorem feugiat dui pharetra sit amet faucibus felis pretium. Etiam aliquet convallis nibh, sed viverra dolor tempus id. Fusce eget nunc vitae odio pretium eleifend. Maecenas diam ligula, euismod at rhoncus vel, dictum eget lorem. Maecenas et metus odio, iaculis suscipit nulla.

38 | 39 |

Duis feugiat consectetur quam porttitor sodales. Mauris ornare sem sit amet lorem imperdiet posuere. Integer et consequat ante. Maecenas hendrerit pretium vulputate. Nullam dictum, mi vitae molestie molestie, lectus dolor gravida turpis, vel bibendum nisl eros ut massa. Aliquam egestas velit non arcu volutpat pretium molestie ipsum sollicitudin. Sed fermentum, neque eget lacinia varius, tellus felis ornare nibh, in placerat lectus ligula sed sapien. Nulla tincidunt eleifend leo ut commodo. Integer id ante sit amet nunc scelerisque sodales. Donec tincidunt, sem blandit accumsan venenatis, odio sem sagittis nunc, eget semper mauris diam vitae arcu. Aliquam rutrum ante ut lorem iaculis interdum.

40 | 41 |

Proin consectetur ligula sed enim cursus viverra. Curabitur posuere augue ac enim dictum ullamcorper. Etiam eu quam tellus, id ultrices velit. Duis malesuada pharetra orci eu aliquam. Curabitur interdum adipiscing nibh ut pellentesque. Integer vulputate lorem vitae lacus dictum a laoreet ipsum semper. Etiam eget ante at nunc imperdiet consequat et vitae nisl. Nulla ornare risus ac ante sollicitudin ut egestas libero pellentesque. Ut imperdiet erat a massa pulvinar vel dictum erat interdum. Donec ut orci tempus nibh elementum lobortis id in sapien. Etiam vitae turpis mauris. Nam sit amet ipsum at arcu auctor varius. Suspendisse venenatis nisi at nisl tempus eget pretium massa interdum.

42 | 43 |

Pellentesque dignissim ante elit. Quisque eget justo ante. Quisque semper dictum lorem, eget feugiat lacus tristique vel. Duis metus lacus, malesuada sed viverra ac, mollis nec lacus. Curabitur vitae neque vel mi varius fermentum eget sed tortor. Praesent id nisi vitae purus ultrices viverra. Nulla felis purus, pharetra et semper ac, adipiscing et sapien. Morbi ornare accumsan nulla vel accumsan. Fusce id nisl a risus dignissim scelerisque. 44 | 45 |

Mauris ornare consectetur feugiat. Aliquam eu leo sit amet augue rhoncus lobortis. Vivamus in dui eget risus aliquam fermentum. Nullam egestas enim non odio venenatis commodo. Curabitur sapien enim, pulvinar dignissim scelerisque a, fringilla sed ante. Phasellus venenatis, libero et mollis ornare, tellus eros accumsan quam, lobortis consequat nulla est ac mauris. Ut purus mauris, blandit sit amet semper at, consectetur sit amet enim. Nam rhoncus eros ac enim pretium sit amet porttitor quam aliquam. Donec mollis nibh at nisi accumsan sodales rhoncus purus vulputate. Donec egestas lacinia eros vitae iaculis. Proin at lectus velit. Praesent leo justo, ultrices ut pellentesque ac, porta a neque.

46 | 47 |

Quisque bibendum auctor orci, eu placerat nibh accumsan quis. Phasellus et nisi lorem, et eleifend magna. Quisque nibh eros, volutpat ut congue nec, laoreet sit amet est. Aliquam metus tellus, porta ac tempus nec, consectetur luctus ligula. Quisque dapibus massa quis ligula vestibulum mollis. Pellentesque sit amet molestie est. Nullam eget purus nec ipsum volutpat eleifend eu at justo. Aenean pretium ullamcorper ipsum, fringilla pulvinar ante dignissim id. Fusce viverra, nisl vitae ultricies luctus, lectus magna pulvinar magna, ac fringilla tortor purus vitae lacus. Mauris vestibulum pretium leo, ut rutrum felis ornare ac.

48 | 49 |

Praesent nec dui at turpis pulvinar lacinia. Mauris ut sem justo, at accumsan sapien. Sed vitae ante lectus, in suscipit nisi. In mattis turpis quis arcu dapibus in ornare enim vestibulum. Fusce interdum laoreet nulla, lacinia hendrerit libero eleifend ac. Ut et tellus a ipsum facilisis consectetur. Nulla pretium, nulla sed tristique elementum, arcu quam feugiat nunc, vitae dictum urna magna vitae nibh. Vivamus porta, lectus in ultricies facilisis, felis velit commodo libero, nec tempor urna arcu ac ligula. Nunc gravida, urna ut commodo gravida, mi nisl malesuada diam, aliquam fringilla turpis tellus id nibh. Vestibulum et arcu ut enim elementum imperdiet vel sed mauris. Vivamus euismod elit in purus lobortis tincidunt.

50 | 51 |

Donec facilisis ullamcorper eros id euismod. Cras fermentum augue ac purus dictum sit amet vulputate ipsum lacinia. Donec dignissim diam quis orci semper rhoncus. Integer in nisl leo. Nam a quam sed erat tempus hendrerit quis vel nibh. In hac habitasse platea dictumst. Vivamus eu nunc consectetur sem vestibulum malesuada in sit amet lacus. Proin a nulla sed est varius facilisis sed ut diam. Curabitur cursus faucibus rutrum. Nunc malesuada tempor arcu facilisis posuere. Nullam vitae sem erat. Morbi hendrerit nulla eu justo rutrum porttitor. Quisque congue tincidunt metus in aliquam. Duis non enim non metus rutrum posuere ac sit amet urna.

52 | 53 |

Vestibulum nisi urna, gravida ac porta rutrum, cursus quis magna. Donec condimentum congue convallis. Ut semper pellentesque nibh ac ullamcorper. Nunc rutrum purus ac purus imperdiet gravida tempor nunc lobortis. Duis at diam vitae arcu dignissim scelerisque quis quis elit. Proin adipiscing ipsum id risus pellentesque eu feugiat velit tincidunt. Aliquam feugiat lacus vel ipsum aliquam venenatis. Sed laoreet laoreet molestie. Integer feugiat dictum ipsum, eu dictum elit convallis nec. Nulla aliquet vulputate mattis. Suspendisse quam nulla, ultricies hendrerit pretium euismod, fringilla id felis.

54 | 55 |

Mauris quis posuere eros. Mauris dapibus lacinia interdum. Aenean feugiat eleifend ultricies. Phasellus faucibus, urna non vestibulum lobortis, mi leo pulvinar velit, at placerat arcu tortor a lectus. Sed varius porta enim ut faucibus. Suspendisse sit amet condimentum nunc. Aenean fermentum enim vel augue gravida quis eleifend enim rutrum. Nunc posuere, dolor ac bibendum tempor, sapien elit aliquet nibh, sit amet tincidunt nibh nunc ut libero. Donec elit tortor, pretium et lobortis et, dapibus sed nunc. Sed non velit dui. Proin vestibulum sapien eget neque congue eget elementum diam convallis. Ut erat sapien, gravida vitae rutrum non, aliquet at ipsum. Vestibulum nisi lacus, pharetra cursus dapibus at, volutpat in est. In elit justo, tristique sit amet ullamcorper vitae, fringilla et augue. Nam sit amet aliquam orci.

56 | 57 |

Aenean rutrum malesuada purus. Nullam et tempor magna. In imperdiet tempor magna, in dignissim felis tempus nec. Pellentesque consectetur felis nec eros venenatis nec adipiscing est vehicula. Aliquam volutpat luctus erat, id bibendum sem fermentum elementum. Fusce dignissim nisi a orci porta a pretium erat tincidunt. Curabitur consequat elementum volutpat. Vestibulum aliquet mattis libero vitae tincidunt.

58 | 59 |

Nam est odio, iaculis in semper sit amet, faucibus vitae lorem. Pellentesque ut augue risus, quis sagittis dolor. Vivamus accumsan fermentum libero in adipiscing. Nullam in fringilla lorem. Mauris ac sapien in diam vehicula porta. Cras mauris urna, pretium nec iaculis sodales, sollicitudin vitae odio. Phasellus gravida nunc egestas eros feugiat rhoncus. Vestibulum pretium, ligula at mattis venenatis, odio leo feugiat ante, vitae rutrum nisi ante sit amet nulla. Mauris eget pharetra enim. Praesent venenatis, libero ut imperdiet sollicitudin, neque odio dictum urna, nec gravida nunc ligula euismod mi. Nulla molestie nunc id diam venenatis lobortis. Nulla consequat, justo eget gravida luctus, dolor ipsum faucibus eros, eget eleifend justo nulla vel massa.

60 | 61 |

Sed tempus, odio sed elementum aliquet, eros augue adipiscing nisl, a vehicula lacus dui non elit. In hac habitasse platea dictumst. Duis faucibus adipiscing volutpat. Phasellus justo enim, rutrum adipiscing egestas eu, vulputate ut quam. Duis pharetra erat quis massa ultricies commodo. Integer accumsan pharetra dolor in condimentum. Vestibulum nisl mi, placerat et lacinia ac, convallis ac sapien. Duis luctus leo ligula. Aliquam rhoncus lacus id quam congue malesuada. Suspendisse scelerisque porttitor ultrices. Nam hendrerit luctus augue. Nam sit amet nisl enim, nec fringilla dui. Fusce in purus mauris. Mauris facilisis malesuada neque in porttitor. Nam in ante justo, ultrices pulvinar orci. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

62 | 63 |

Nulla et luctus urna. Fusce rhoncus ipsum ac magna dictum eleifend. Duis pretium orci nec quam lobortis a varius urna fermentum. Donec scelerisque imperdiet mauris, ut fringilla diam commodo in. Fusce tincidunt tincidunt quam, ut rhoncus tellus tincidunt vitae. Mauris interdum iaculis magna et ultricies. Nam blandit diam eu neque fermentum malesuada euismod augue blandit. Fusce a magna et ante posuere viverra non eu sem. Praesent sodales lectus vel dolor convallis ornare. Nunc quam erat, accumsan a mollis sit amet, tincidunt interdum nisl.

64 | 65 |

Praesent pellentesque ultrices nisl, sit amet mattis felis rhoncus in. Nam id urna non dolor molestie viverra non hendrerit tortor. Donec placerat tellus eget diam egestas in aliquam nibh vulputate. Nulla iaculis libero nec erat vehicula luctus malesuada ut arcu. Suspendisse eget ipsum ipsum. Proin augue dui, posuere non auctor sed, convallis eget massa. Praesent tristique, massa in tempor blandit, augue mi volutpat leo, id vestibulum leo erat vitae metus. Etiam tortor mauris, ultrices a tristique eget, semper non dui. Fusce est arcu, egestas nec volutpat a, mollis id eros.

66 | 67 |

Curabitur ut urna felis, vitae egestas eros. Etiam luctus, ante in auctor tincidunt, ipsum nisi sollicitudin ligula, vel tempus ipsum nibh ac velit. Ut commodo purus nec quam aliquet gravida. Phasellus cursus, urna sit amet tincidunt elementum, massa dui venenatis turpis, consectetur eleifend justo lectus suscipit felis. Suspendisse neque nulla, pellentesque volutpat malesuada at, dignissim at augue. Integer in sagittis odio. Fusce mi erat, ultrices quis condimentum eget, rhoncus at enim. Nam porttitor ante sed purus iaculis vel suscipit metus ornare. Aenean enim nulla, rhoncus sed varius ut, pretium eget augue. Cras non laoreet odio. Proin egestas, urna quis ultrices facilisis, nisl velit pulvinar quam, sed varius lacus erat eu nisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In fringilla lobortis ornare.

68 | 69 |

Cras faucibus mollis erat, sed vestibulum metus feugiat in. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed nec cursus tortor. Suspendisse sit amet nunc felis, nec imperdiet neque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla at nisi ut nisl vestibulum volutpat. Donec sit amet sem et ante consectetur bibendum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent varius molestie ligula, quis fringilla felis consectetur sed. Aliquam aliquam accumsan vehicula. Nam nec libero at nisl aliquet iaculis. Vestibulum viverra risus non arcu laoreet scelerisque. Ut sit amet ipsum ac enim varius ultricies.

70 | 71 |

Sed facilisis lobortis urna vitae fringilla. Morbi eu felis tincidunt nisi elementum bibendum sed vel lorem. Phasellus semper eleifend enim, eget tincidunt justo lobortis quis. Maecenas sit amet metus ligula. Sed vehicula nunc et justo commodo commodo. Nullam sodales risus eu est eleifend blandit. Maecenas ultrices interdum sagittis.

72 | 73 |

Etiam ultrices, diam ut sagittis ullamcorper, magna orci tempus augue, a ultrices nisi odio vel quam. Quisque sed purus sit amet erat lacinia placerat. Nunc eu libero felis, non cursus metus. Ut sodales euismod imperdiet. Cras imperdiet nulla nisl. Mauris dignissim adipiscing justo eu venenatis. Etiam pellentesque nibh metus, in porta leo. Nulla at tortor nunc, ut sagittis neque. Vivamus eu augue dui, nec scelerisque sem. Praesent ac felis turpis, id viverra purus.

74 | 75 |

Nulla leo nisl, porttitor bibendum convallis ac, vulputate id nisl. Morbi et dapibus nunc. Aliquam erat volutpat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur aliquet nisi ac nulla scelerisque volutpat. Mauris nec sem id enim imperdiet semper. Suspendisse eget felis mauris, a hendrerit nibh. Cras blandit velit quis lacus aliquet placerat. In hac habitasse platea dictumst. Morbi sollicitudin, magna vitae convallis ultricies, urna metus faucibus nisi, sed placerat turpis lorem nec metus. Duis non risus ac diam tempus ultrices quis sit amet ante. Vivamus condimentum imperdiet turpis et fringilla. Suspendisse arcu enim, pretium id imperdiet eget, lacinia sed ipsum. Mauris pretium rhoncus orci sit amet porttitor.

76 | 77 |

Nulla lorem massa, dapibus a rutrum eget, tempor id diam. Aenean pellentesque dictum risus, eget egestas enim varius a. In interdum faucibus nibh tempor sollicitudin. Phasellus ac metus non odio lacinia ultricies. Cras malesuada pulvinar lorem quis commodo. Fusce massa purus, placerat a fermentum a, commodo vitae magna. Donec sed magna urna. Proin adipiscing molestie lacinia. Integer tellus est, cursus ut rhoncus non, pretium sed neque. Nullam aliquet tempor ligula et scelerisque.

78 | 79 |

Morbi accumsan tellus justo. Donec elementum, turpis luctus malesuada rhoncus, eros justo tempor lectus, viverra vulputate lectus nulla in purus. Sed id porttitor ipsum. Vestibulum rhoncus, lectus sed dapibus porttitor, sapien felis luctus enim, eu tempor ligula felis nec leo. Vestibulum leo quam, fringilla quis blandit eget, convallis eget orci. Cras a mi velit, vitae molestie turpis. Ut nisi est, malesuada faucibus egestas eget, fermentum a mi. Sed porta vehicula sem, at laoreet erat vulputate nec. Sed dapibus tincidunt venenatis. Nulla facilisis consequat ante, a euismod leo interdum vel. Morbi facilisis velit leo, non aliquam neque. Pellentesque vestibulum, sem id auctor euismod, nisl nisl posuere nisi, ut sodales nisl lorem nec mi.

80 | 81 |

Sed libero purus, malesuada vitae accumsan sit amet, dignissim sed justo. Ut varius urna aliquam ante euismod vitae egestas nisi consectetur. Aliquam neque eros, molestie eget rutrum eget, faucibus eget tortor. Nullam porta, tortor eget sagittis interdum, velit lacus varius risus, vitae lobortis purus dui pretium purus. In id mauris neque, vitae tincidunt dui. Ut vel justo nisi, at hendrerit dolor. Aenean ac nibh nec est blandit feugiat. Fusce lorem leo, vehicula in tristique vitae, consectetur nec nulla.

82 | 83 |

Vivamus felis lorem, laoreet vel mattis eget, aliquet eu neque. Morbi sed tortor sit amet nunc ornare elementum. Nunc arcu quam, fringilla eget tincidunt sit amet, gravida suscipit metus. Suspendisse venenatis erat vitae massa posuere lobortis. Nullam a mattis nisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam at rutrum lacus. Morbi id tellus mi, a venenatis nibh. Sed egestas, lectus vitae scelerisque euismod, velit dui malesuada ligula, et laoreet urna lectus quis tellus. Morbi diam urna, molestie in auctor quis, dapibus id massa. Praesent consequat, quam vel mollis tempus, nulla orci vehicula mi, non pharetra sapien elit ut magna. Etiam mi magna, porta quis hendrerit vitae, convallis bibendum risus. Integer quis nulla velit. Duis consectetur consectetur turpis. Pellentesque a porttitor eros. Quisque blandit sem eget odio varius pellentesque.

84 | 85 |

Ut gravida ultrices nulla, non congue nisi gravida ut. Donec neque dolor, pharetra nec elementum laoreet, dictum sit amet tellus. Nulla id blandit mi. Nullam ipsum justo, pellentesque a hendrerit ac, cursus ac arcu. Proin feugiat tempus adipiscing. Aliquam erat volutpat. Suspendisse mauris neque, aliquet a tempor lacinia, pretium eget mauris.

86 | 87 |

Vivamus facilisis erat vel sem tempor tincidunt. Fusce tortor enim, tempus eu fermentum vitae, ultrices sollicitudin diam. Phasellus luctus interdum tempus. Sed facilisis laoreet quam ac luctus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris arcu mauris, vestibulum vel condimentum eget, faucibus vel magna. Curabitur posuere vestibulum tortor. Vivamus quis mollis turpis. Donec congue, enim in interdum tincidunt, quam enim varius enim, eu aliquet sapien orci quis nulla. Nulla aliquam libero convallis urna interdum scelerisque a in massa. Nunc volutpat, nulla non tincidunt lacinia, nibh turpis congue arcu, et ornare lectus ligula at risus. Etiam adipiscing, nisl nec tempor convallis, elit erat sollicitudin mi, eget adipiscing erat eros nec nulla. Praesent lorem felis, pretium a pretium eu, varius sit amet nibh.

88 | 89 |

Morbi in tellus quis sapien condimentum pretium nec quis tellus. Duis at turpis mi. Donec ornare feugiat tortor consequat ultricies. Quisque iaculis, dui bibendum volutpat gravida, nibh velit tincidunt justo, ornare imperdiet libero nunc sed elit. Vivamus dapibus nunc nec purus scelerisque id rhoncus mauris laoreet. Donec ac diam non mauris tincidunt pharetra at vitae ante. Aliquam erat volutpat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

90 | 91 |

Ut et lectus justo. Nunc rhoncus, justo nec porta varius, enim elit molestie tortor, in sagittis ipsum diam at tellus. Suspendisse sit amet lorem diam, vel venenatis orci. Nulla pharetra condimentum blandit. Donec rutrum vestibulum mauris. Nunc sit amet nibh id orci convallis ornare sit amet id leo. Sed eros nulla, malesuada nec mattis commodo, rhoncus ut urna. Mauris justo leo, dignissim non sodales ac, ullamcorper mollis felis. Sed turpis erat, dapibus sit amet gravida quis, ultricies tincidunt ligula. Praesent vitae massa non urna tempor commodo. Quisque eget iaculis magna. Fusce ut ligula eget libero luctus fermentum dapibus vitae nisi.

92 | 93 |

Quisque ultricies suscipit lorem et blandit. Quisque elit sem, suscipit eu lacinia nec, mollis in nulla. Curabitur auctor ipsum turpis, a tempor neque. Sed at justo ac turpis venenatis lacinia. Sed rhoncus, nibh eu porta tincidunt, odio nulla condimentum est, eget adipiscing turpis felis sed mauris. Fusce tincidunt nisl eget purus viverra vel congue nunc tristique. Duis at ornare risus. Proin pharetra lobortis turpis quis vulputate. Suspendisse potenti. Proin non neque augue. Suspendisse eu luctus ipsum. Vivamus viverra pellentesque quam a fringilla. Vivamus bibendum, urna sed scelerisque scelerisque, sapien velit blandit ipsum, sed feugiat elit enim vel quam. Phasellus eleifend commodo elit, et blandit eros faucibus nec.

94 | 95 |

Sed viverra magna eu enim euismod sagittis. Cras urna est, adipiscing sed feugiat quis, auctor in sapien. Mauris id magna tincidunt nisl imperdiet viverra. Quisque at suscipit lectus. Nam et cursus augue. Phasellus id dolor lacus, non vestibulum purus. Ut feugiat ante at velit euismod vel lacinia magna iaculis. Nulla sit amet nibh diam. Proin consequat feugiat sollicitudin. Nam urna neque, mattis non tincidunt et, elementum vel nisi. Curabitur sit amet justo id magna porta pharetra eget a libero. Morbi sollicitudin, dolor a laoreet venenatis, augue sem sollicitudin purus, eu iaculis odio elit nec sem. Mauris laoreet est nec lectus vulputate euismod. Vestibulum accumsan faucibus tortor non semper. Nunc ullamcorper eros vitae leo fermentum et ullamcorper magna tincidunt.

96 | 97 |

Sed molestie luctus elit at cursus. Mauris eget massa dolor, ac hendrerit ante. Nam vulputate consectetur blandit. Praesent porttitor suscipit diam, in volutpat magna rhoncus tempus. Vestibulum ac diam et mi adipiscing tempus. Aenean et tempus tortor. Mauris non erat et elit venenatis congue a id lorem. Integer leo tortor, vehicula id fringilla eget, volutpat ut eros. Mauris in augue eget felis rutrum congue.

98 | 99 |

In aliquet nisl vel libero molestie sed iaculis metus sollicitudin. Nam suscipit augue laoreet lectus vulputate a dictum tellus tristique. Cras vitae magna ac tortor scelerisque ultrices eget pulvinar ligula. Aenean viverra imperdiet ipsum vitae pulvinar. Morbi eu ante nec lorem euismod scelerisque. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc et elit metus, at ornare risus. Cras sit amet ligula scelerisque arcu viverra ultricies sed iaculis nunc. Nulla sodales sem ut magna semper tincidunt. Morbi aliquam scelerisque arcu, at ultricies quam adipiscing non. Phasellus eu pretium magna. Aliquam ut sem sit amet dolor rutrum feugiat. Nullam vehicula ultrices mattis. Phasellus dapibus tristique bibendum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum euismod imperdiet malesuada.

100 | 101 |

Donec tincidunt scelerisque elit, vitae convallis nisl viverra a. Sed a vehicula nisl. Nullam et ipsum sed ligula posuere consequat. Suspendisse id tellus velit. Quisque nec mi urna. Nulla neque mauris, bibendum a faucibus at, tincidunt at erat. Nulla diam mi, luctus eget adipiscing sagittis, commodo in tellus. Donec ante massa, vestibulum quis hendrerit eget, sagittis in augue. Ut vehicula, risus vulputate aliquet lobortis, lectus enim tincidunt risus, quis porttitor magna sem vel lacus. Curabitur ornare scelerisque libero, adipiscing pulvinar libero accumsan et. Duis rutrum dignissim orci quis tincidunt. Maecenas scelerisque, sapien porttitor consequat auctor, felis lacus adipiscing odio, sit amet lacinia ipsum nulla eget tellus.

102 | 103 |

Curabitur sollicitudin nisl quis odio euismod mollis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla facilisi. Nulla facilisi. Aenean convallis vulputate leo, vel interdum orci placerat eu. Vestibulum hendrerit pretium ipsum, eu aliquet nisl accumsan condimentum. Duis elementum porttitor consequat. Morbi imperdiet vehicula massa, id pellentesque ligula venenatis vel. Donec non felis suscipit sem ornare mollis. Nulla elit quam, posuere vel tincidunt vitae, porttitor quis felis.

104 | 105 |

Nam tempus lectus a est ornare ac aliquet felis placerat. Ut vel dolor ut turpis auctor imperdiet id non velit. Vestibulum sodales commodo dui. Aenean posuere dolor nec lorem malesuada ut ornare quam feugiat. Donec ut neque nec odio ullamcorper vestibulum. Nulla pulvinar leo consectetur ante ullamcorper pellentesque. Sed sed porttitor lacus. Pellentesque a nisl ut tortor sollicitudin dictum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam in ligula leo. Vivamus vel quam velit, laoreet dictum quam. Praesent congue, diam nec volutpat pharetra, nulla erat consequat lorem, quis condimentum risus nisl sit amet tellus. Sed ullamcorper, risus a consectetur dignissim, ligula augue pharetra nulla, eget feugiat metus lacus quis lectus. Praesent malesuada dictum nulla, nec malesuada erat ullamcorper vel.

106 | 107 |

Morbi suscipit facilisis leo, vitae eleifend nunc placerat sit amet. Suspendisse elit sem, bibendum vitae hendrerit nec, dictum sed sapien. Praesent fermentum mollis dapibus. Donec tempus risus ac odio dictum vel ultrices eros convallis. Aliquam a ipsum id lacus mollis dapibus. Quisque at felis purus, id tristique erat. In vel nisi at mi adipiscing tempor. Ut rhoncus semper ultricies. Sed ut urna quam, mollis cursus nisl.

108 | 109 |

Praesent nec diam a mauris pellentesque mollis. Integer tempor metus nec enim ultricies vehicula. Maecenas luctus tincidunt dui, quis feugiat ipsum lacinia a. Morbi non nulla sit amet mi accumsan venenatis sed ut elit. Aenean interdum est vitae justo sollicitudin sed dignissim lectus iaculis. Integer magna lacus, sollicitudin eu porta eget, condimentum id mauris. Praesent id facilisis lacus. Donec interdum nunc nulla. Cras sit amet purus est. Ut mauris elit, hendrerit nec vehicula nec, rhoncus ut lorem.

110 | 111 |

Etiam in tristique nisl. Nam sed vehicula dui. Vestibulum in purus ultrices nisl iaculis pretium. In vitae purus a lectus elementum sodales quis nec leo. Aliquam faucibus imperdiet tortor viverra iaculis. Mauris eu ipsum non turpis sollicitudin pretium sit amet vel dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;

112 | 113 |

Vestibulum et arcu magna, a tristique risus. Donec luctus erat eget magna sodales rutrum. Praesent justo nunc, commodo eu pretium eget, consequat id augue. Cras sed blandit elit. Integer id eros nec diam facilisis dapibus. Aenean scelerisque sodales dolor sit amet posuere. Donec viverra nibh ut lorem egestas eget dignissim nunc consequat. Curabitur facilisis, lectus ac varius vestibulum, tortor dui tincidunt lectus, id elementum augue lacus ut dui.

114 | 115 |

Nam viverra ante nec eros ullamcorper egestas. Mauris porta scelerisque leo in ullamcorper. Ut sit amet egestas augue. Sed at massa turpis. Mauris non tortor quis lorem vehicula interdum. Morbi tortor mauris, tristique quis rutrum ac, suscipit quis metus. Duis ante turpis, malesuada in posuere ut, cursus et massa. Curabitur mi erat, tincidunt laoreet molestie non, sollicitudin in libero. Curabitur at dui nunc. Donec consequat aliquet tristique.

116 | 117 |

Proin quis blandit magna. In consectetur vehicula ante, nec sodales elit hendrerit quis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas eleifend fermentum egestas. Quisque semper ornare blandit. Aliquam malesuada convallis placerat. Nam lobortis, sapien in pulvinar egestas, orci ante fermentum felis, et lobortis mauris justo condimentum odio. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec tristique, quam sodales auctor venenatis, sapien nisi aliquet dolor, eu feugiat tortor massa non nisl. Quisque interdum lacus ac massa consectetur interdum.

118 | 119 | -------------------------------------------------------------------------------- /tests/83-reduced.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Fastclick test 5 | 6 | 9 | 36 | 37 | 38 |
39 | Test button 40 |
41 | 42 | -------------------------------------------------------------------------------- /tests/83.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Fastclick test 6 | 7 | 8 | 13 | 65 | 66 | 67 |
68 | Test button 69 |
70 | 71 | -------------------------------------------------------------------------------- /tests/84.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | #84 9 | 10 | 15 | 16 | 17 |

Tapping the following read-only input field should show the alert message.

18 | 19 | 20 | 21 | --------------------------------------------------------------------------------