├── .gitattributes
├── .gitignore
├── CHANGELOG.md
├── .npmignore
├── .travis.yml
├── test
├── MockObservable.js
├── mockDomDriver.js
├── page
│ └── index.html
└── index.js
├── .codeclimate.yml
├── .eslintrc
├── .testem.json
├── examples
├── basic
│ ├── main.js
│ ├── index.html
│ └── index.js
├── quadruple-tap
│ ├── main.js
│ ├── index.html
│ └── index.js
├── recognizeWith
│ ├── main.js
│ ├── index.html
│ └── index.js
├── vertical-pan
│ ├── main.js
│ ├── index.html
│ └── index.js
└── recognizeWith-requireFailure-taps
│ ├── main.js
│ ├── index.html
│ └── index.js
├── src
├── makeHammerDriver.js
├── cycle-hammer.js
├── fromEvent.js
├── hammerDriver.js
└── standardEventTypes.js
├── scripts
├── build-examples.js
├── make-api-doc.js
└── cyclic-docs-template.md.ejs
├── lib
├── makeHammerDriver.js
├── cycle-hammer.js
├── hammerDriver.js
├── fromEvent.js
└── standardEventTypes.js
├── LICENSE
├── README.md
├── doc
└── api.md
├── package.json
└── dist
├── cycle-hammer.min.js
└── cycle-hammer.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | logs
2 | *.log
3 | /node_modules
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # v0.1.1 (2015-11-25)
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | *.sublime-project
3 | *.sublime-workspace
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "4.1"
4 | before_script:
5 | - "export DISPLAY=:99.0"
6 | - "sh -e /etc/init.d/xvfb start"
7 | - sleep 3 # give xvfb some time to start
8 |
--------------------------------------------------------------------------------
/test/MockObservable.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Observable mock
3 | * @author Frederik Krautwald
4 | */
5 |
6 | const MockObservable = {
7 | subscribe: () => {},
8 | }
9 |
10 | export default MockObservable
11 |
--------------------------------------------------------------------------------
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | eslint:
4 | enabled: true
5 | csslint:
6 | enabled: false
7 | ratings:
8 | paths:
9 | - "**.js"
10 | - "**.jsx"
11 | exclude_paths:
12 | - examples/**/*
13 | - doc/*
14 | - scripts/*
15 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint-config-cycle",
3 | "env": {
4 | "es6": true,
5 | "browser": true,
6 | "node": true
7 | },
8 | "ecmaFeatures": {
9 | "modules": true
10 | },
11 | "rules": {
12 | "new-cap": 0
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.testem.json:
--------------------------------------------------------------------------------
1 | {
2 | "framework": "mocha+chai",
3 | "src_files": [
4 | "test/index.js"
5 | ],
6 | "before_tests": "browserify test/index.js -t babelify -o test/bundle.js",
7 | "serve_files": [
8 | "test/bundle.js"
9 | ],
10 | "after_tests": "rm test/bundle.js",
11 | "launch_in_ci": [
12 | "firefox"
13 | ],
14 | "launch_in_dev": [
15 | "chrome"
16 | ],
17 | "ignore_missing_launchers": true
18 | }
19 |
--------------------------------------------------------------------------------
/test/mockDomDriver.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview DOM driver mock
3 | * @author Frederik Krautwald
4 | */
5 |
6 | function makeEvents() {
7 | return () => {
8 | return {}
9 | }
10 | }
11 |
12 | function makeSelect() {
13 | return () => {
14 | return {
15 | select: makeSelect(),
16 | events: makeEvents(),
17 | }
18 | }
19 | }
20 |
21 | function mockDomDriver() {
22 | return {
23 | select: makeSelect(),
24 | }
25 | }
26 |
27 | export default mockDomDriver
28 |
--------------------------------------------------------------------------------
/examples/basic/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Demo main
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | import {run} from '@cycle/core'
8 | import {makeDOMDriver as makeDomDriver} from '@cycle/dom'
9 | import makeHammerDriver from './../../src/makeHammerDriver'
10 | import Demo from './index'
11 |
12 | const main = Demo
13 |
14 | const domDriverFunc = makeDomDriver(`.demo-container`)
15 |
16 | run(main, {
17 | dom: makeHammerDriver(domDriverFunc),
18 | })
19 |
--------------------------------------------------------------------------------
/examples/quadruple-tap/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Demo main
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | import {run} from '@cycle/core'
8 | import {makeDOMDriver as makeDomDriver} from '@cycle/dom'
9 | import makeHammerDriver from './../../src/makeHammerDriver'
10 | import Demo from './index'
11 |
12 | const main = Demo
13 |
14 | const domDriverFunc = makeDomDriver(`.demo-container`)
15 |
16 | run(main, {
17 | dom: makeHammerDriver(domDriverFunc),
18 | })
19 |
--------------------------------------------------------------------------------
/examples/recognizeWith/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Demo main
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | import {run} from '@cycle/core'
8 | import {makeDOMDriver as makeDomDriver} from '@cycle/dom'
9 | import makeHammerDriver from './../../src/makeHammerDriver'
10 | import Demo from './index'
11 |
12 | const main = Demo
13 |
14 | const domDriverFunc = makeDomDriver(`.demo-container`)
15 |
16 | run(main, {
17 | dom: makeHammerDriver(domDriverFunc),
18 | })
19 |
--------------------------------------------------------------------------------
/examples/vertical-pan/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Demo main
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | import {run} from '@cycle/core'
8 | import {makeDOMDriver as makeDomDriver} from '@cycle/dom'
9 | import makeHammerDriver from './../../src/makeHammerDriver'
10 | import Demo from './index'
11 |
12 | const main = Demo
13 |
14 | const domDriverFunc = makeDomDriver(`.demo-container`)
15 |
16 | run(main, {
17 | dom: makeHammerDriver(domDriverFunc),
18 | })
19 |
--------------------------------------------------------------------------------
/examples/recognizeWith-requireFailure-taps/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Demo main
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | import {run} from '@cycle/core'
8 | import {makeDOMDriver as makeDomDriver} from '@cycle/dom'
9 | import makeHammerDriver from './../../src/makeHammerDriver'
10 | import Demo from './index'
11 |
12 | const main = Demo
13 |
14 | const domDriverFunc = makeDomDriver(`.demo-container`)
15 |
16 | run(main, {
17 | dom: makeHammerDriver(domDriverFunc),
18 | })
19 |
--------------------------------------------------------------------------------
/src/makeHammerDriver.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Hammer driver factory
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | import hammerDriver from './hammerDriver'
8 |
9 | function makeHammerDriver(domDriverFunc) {
10 | if (typeof domDriverFunc !== `function`) {
11 | throw new Error(
12 | `First argument given to makeHammerDriver() ` +
13 | `must be a DOM driver function.`
14 | )
15 | }
16 | return hammerDriver.bind({}, domDriverFunc)
17 | }
18 |
19 | export default makeHammerDriver
20 |
--------------------------------------------------------------------------------
/test/page/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/scripts/build-examples.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Build examples
3 | * @author Frederik Krautwald
4 | */
5 |
6 | const fs = require(`fs`)
7 | const path = require(`path`)
8 | const browserify = require(`browserify`)
9 |
10 | const baseDir = `examples${path.sep}`
11 | const exampleDirs = process.argv[2].split(`,`)
12 |
13 | function transpile(exampleDir) {
14 | const dir = baseDir + exampleDir + path.sep
15 | const file = `${dir}main.js`
16 | const outfile = `${dir}bundle.js`
17 | browserify(file)
18 | .transform(`babelify`)
19 | .bundle()
20 | .pipe(fs.createWriteStream(outfile))
21 | }
22 |
23 | exampleDirs.forEach(transpile)
24 |
--------------------------------------------------------------------------------
/scripts/make-api-doc.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | 'use strict';
4 | var markdox = require('markdox');
5 |
6 | function generateDoc(options) {
7 | markdox.process(
8 | options.src,
9 | {output: options.output, template: options.template},
10 | function generationCallback(err/*, output */) {
11 | if (err) {
12 | console.error(err);
13 | } else {
14 | console.log('File `' + options.output + '` generated with success');
15 | }
16 | }
17 | );
18 | }
19 |
20 | generateDoc({
21 | src: [
22 | './src/cycle-hammer.js',
23 | ],
24 | output: './doc/api.md',
25 | template: './scripts/cyclic-docs-template.md.ejs'
26 | });
27 |
--------------------------------------------------------------------------------
/examples/basic/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 | Basic cycle-hammer-driver example
10 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/lib/makeHammerDriver.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Hammer driver factory
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | 'use strict';
8 |
9 | Object.defineProperty(exports, '__esModule', {
10 | value: true
11 | });
12 |
13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14 |
15 | var _hammerDriver = require('./hammerDriver');
16 |
17 | var _hammerDriver2 = _interopRequireDefault(_hammerDriver);
18 |
19 | function makeHammerDriver(domDriverFunc) {
20 | if (typeof domDriverFunc !== 'function') {
21 | throw new Error('First argument given to makeHammerDriver() ' + 'must be a DOM driver function.');
22 | }
23 | return _hammerDriver2['default'].bind({}, domDriverFunc);
24 | }
25 |
26 | exports['default'] = makeHammerDriver;
27 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/examples/vertical-pan/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 | Vertical Pan cycle-hammer-driver example
10 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/examples/quadruple-tap/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 | Quadruple Tap cycle-hammer-driver example
10 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/examples/recognizeWith/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 | RecognizeWith cycle-hammer-driver example
10 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/examples/recognizeWith-requireFailure-taps/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 | RecognizeWith and requireFailure cycle-hammer-driver taps example
10 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Cyclic Materials
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cycle-hammer-driver
2 |
3 | > A Hammer driver for Cycle.js.
4 |
5 | [](https://github.com/cyclejs)
6 |
7 | The driver incorporates the [Hammer.js](https://hammerjs.github.io/)
8 | gesture library.
9 |
10 | [Read the documentation](https://github.com/CyclicMaterials/cycle-hammer-driver/blob/master/doc/api.md)
11 | and check the [examples](https://github.com/CyclicMaterials/cycle-hammer-driver/blob/master/examples).
12 |
13 | ## License
14 |
15 | MIT © [Cyclic Materials](http://github.com/CyclicMaterials)
16 |
17 | - - -
18 |
19 | [](https://travis-ci.org/CyclicMaterials/cycle-hammer-driver)
20 | [](https://codeclimate.com/github/CyclicMaterials/cycle-hammer-driver)
21 | [](https://david-dm.org/CyclicMaterials/cycle-hammer-driver)
22 | [](https://david-dm.org/CyclicMaterials/cycle-hammer-driver#info=devDependencies)
23 |
--------------------------------------------------------------------------------
/doc/api.md:
--------------------------------------------------------------------------------
1 |
2 | # Cyclic Materials Cycle Hammer Driver API
3 |
4 | - [`makeDOMDriver`](#makeDOMDriver)
5 |
6 | Author: Frederik Krautwald
7 |
8 | - - -
9 |
10 | ### `makeDOMDriver(domDriverFunc)`
11 |
12 | A factory for the Hammer driver function. Takes a DOM driver function that
13 | adheres to the interface established by the Cycle.js DOM driver.
14 | The output (source) of this driver mimics the DOM driver as a collection
15 | of Observables queried with: `DOM.select(selector).events(eventType)`.
16 | In addition, when listening for hammer.js `eventTypes`, the `events()`
17 | function allows you to specify an optional callback:
18 | `DOM.select(selector).events(eventType, callback)`.
19 | The `callback` takes two arguments:
20 |
21 | - **manager** `{Object}` The `Hammer.Manager` instance for the element.
22 | - **Hammer** `{Object}` The Hammer API.
23 |
24 | #### Arguments:
25 |
26 | - `domDriverFunc :: Function` the DOM driver function.
27 |
28 | #### Return:
29 |
30 | *(Function)* the Hammer driver function. The function expects an Observable of VTree as input, and outputs the source object for this
31 | driver, containing functions `select()` and `dispose()` that can be used
32 | for debugging and testing.
33 |
34 | - - -
35 |
36 |
--------------------------------------------------------------------------------
/src/cycle-hammer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Hammer driver for Cycle.js
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | import makeHammerDriver from './makeHammerDriver'
8 |
9 | const CycleHammer = {
10 | /**
11 | * A factory for the Hammer driver function. Takes a DOM driver function that
12 | * adheres to the interface established by the Cycle.js DOM driver.
13 | * The output (source) of this driver mimics the DOM driver as a collection
14 | * of Observables queried with: `DOM.select(selector).events(eventType)`.
15 | * In addition, when listening for hammer.js `eventTypes`, the `events()`
16 | * function allows you to specify an optional callback:
17 | * `DOM.select(selector).events(eventType, callback)`.
18 | * The `callback` takes two arguments:
19 | *
20 | * - **manager** `{Object}` The `Hammer.Manager` instance for the element.
21 | * - **Hammer** `{Object}` The Hammer API.
22 | *
23 | * @param {Function} domDriverFunc the DOM driver function.
24 | * @return {Function} the Hammer driver function. The function expects an
25 | * Observable of VTree as input, and outputs the source object for this
26 | * driver, containing functions `select()` and `dispose()` that can be used
27 | * for debugging and testing.
28 | * @function makeDOMDriver
29 | */
30 | makeHammerDriver,
31 | }
32 |
33 | export default CycleHammer
34 |
--------------------------------------------------------------------------------
/examples/basic/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Demo dataflow component
3 | * @author Frederik Krautwald
4 | */
5 |
6 | import {div, h3, h4} from '@cycle/dom'
7 | import {Observable} from 'rx'
8 |
9 | function Demo(sources) {
10 | const intent = ({dom}) => {
11 | const options = (manager, Hammer) => {
12 | // Default pan recognizer.
13 | manager.add(new Hammer.Pan())
14 | // Default tap recognizer.
15 | manager.add(new Hammer.Tap())
16 | // Default press recognizer.
17 | manager.add(new Hammer.Press())
18 | }
19 | return {
20 | events$: Observable.merge(
21 | dom.select(`#MyElement`).events(`panleft`, options),
22 | dom.select(`#MyElement`).events(`panright`),
23 | dom.select(`#MyElement`).events(`tap`),
24 | dom.select(`#MyElement`).events(`press`)
25 | ),
26 | }
27 | }
28 |
29 | const model = (actions) => {
30 | return actions.events$.map(
31 | event => ({event})
32 | ).startWith({event: {type: ``}})
33 | }
34 |
35 | const view = (state$) => state$.map(
36 | state => {
37 | const {type} = state.event
38 | return div([
39 | h3(`Basic cycle-hammer-driver example`),
40 | h4(`Events: panleft panright tap press`),
41 | div(`#MyElement`, `${type} gesture detected`)
42 | ])
43 | }
44 | )
45 |
46 | const actions = intent(sources)
47 | const state$ = model(actions)
48 |
49 | return {
50 | dom: view(state$),
51 | }
52 | }
53 |
54 | export default Demo
55 |
--------------------------------------------------------------------------------
/examples/recognizeWith/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Demo dataflow component
3 | * @author Frederik Krautwald
4 | */
5 |
6 | import {div, h3, h4} from '@cycle/dom'
7 | import {Observable} from 'rx'
8 |
9 | function Demo(sources) {
10 | const intent = ({dom}) => {
11 | const options = (manager, Hammer) => {
12 | // create a pinch and rotate recognizer
13 | // these require two pointers
14 | const pinch = new Hammer.Pinch()
15 | const rotate = new Hammer.Rotate()
16 |
17 | // we want to detect both at the same time
18 | pinch.recognizeWith(rotate)
19 |
20 | // add to the Manager
21 | manager.add([pinch, rotate])
22 | }
23 | return {
24 | event$: Observable.merge(
25 | dom.select(`#MyElement`).events(`pinch`, options),
26 | dom.select(`#MyElement`).events(`rotate`)
27 | ),
28 | }
29 | }
30 |
31 | const model = (actions) => {
32 | return actions.event$.map(
33 | event => ({event})
34 | ).startWith({event: {type: ``}})
35 | }
36 |
37 | const view = (state$) => {
38 | let types = ``
39 | return state$.map(
40 | state => {
41 | const {event} = state
42 | types += `${event.type} `
43 | return div([
44 | h3(`RecognizeWith cycle-hammer-driver example`),
45 | h4(`Events: pinch, rotate`),
46 | div(`#MyElement`, `${types}`),
47 | ])
48 | }
49 | )
50 | }
51 |
52 | const actions = intent(sources)
53 | const state$ = model(actions)
54 |
55 | return {
56 | dom: view(state$),
57 | }
58 | }
59 |
60 | export default Demo
61 |
--------------------------------------------------------------------------------
/examples/quadruple-tap/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Demo dataflow component
3 | * @author Frederik Krautwald
4 | */
5 |
6 | import {div, h3, h4} from '@cycle/dom'
7 | import {Observable} from 'rx'
8 |
9 | function Demo(sources) {
10 | const intent = ({dom}) => {
11 | const options = (manager, Hammer) => {
12 | // Default tap recognizer.
13 | manager.add(new Hammer.Tap())
14 |
15 | // Tap recognizer with four minimal taps.
16 | manager.add(new Hammer.Tap({event: `quadrupletap`, taps: 4}))
17 |
18 | // We want to recognize this simultaneous, so a quadruple tap will be
19 | // detected even while a tap is being recognized.
20 | // The tap event will be emitted on every tap.
21 | manager.get(`quadrupletap`).recognizeWith(`tap`)
22 | }
23 | return {
24 | event$: Observable.merge(
25 | dom.select(`#MyElement`).events(`tap`, options),
26 | dom.select(`#MyElement`).events(`quadrupletap`)
27 | ),
28 | }
29 | }
30 |
31 | const model = (actions) => {
32 | return actions.event$.map(
33 | event => ({event})
34 | ).startWith({event: {type: ``}})
35 | }
36 |
37 | const view = (state$) => {
38 | let types = ``
39 | return state$.map(
40 | state => {
41 | const {event} = state
42 | types += `${event.type} `
43 | return div([
44 | h3(`Quadruple Tap cycle-hammer-driver example`),
45 | h4(`Events: tap, quadrupletap`),
46 | div(`#MyElement`, `${types}`),
47 | ])
48 | }
49 | )
50 | }
51 |
52 | const actions = intent(sources)
53 | const state$ = model(actions)
54 |
55 | return {
56 | dom: view(state$),
57 | }
58 | }
59 |
60 | export default Demo
61 |
--------------------------------------------------------------------------------
/lib/cycle-hammer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Hammer driver for Cycle.js
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | 'use strict';
8 |
9 | Object.defineProperty(exports, '__esModule', {
10 | value: true
11 | });
12 |
13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14 |
15 | var _makeHammerDriver = require('./makeHammerDriver');
16 |
17 | var _makeHammerDriver2 = _interopRequireDefault(_makeHammerDriver);
18 |
19 | var CycleHammer = {
20 | /**
21 | * A factory for the Hammer driver function. Takes a DOM driver function that
22 | * adheres to the interface established by the Cycle.js DOM driver.
23 | * The output (source) of this driver mimics the DOM driver as a collection
24 | * of Observables queried with: `DOM.select(selector).events(eventType)`.
25 | * In addition, when listening for hammer.js `eventTypes`, the `events()`
26 | * function allows you to specify an optional callback:
27 | * `DOM.select(selector).events(eventType, callback)`.
28 | * The `callback` takes two arguments:
29 | *
30 | * - **manager** `{Object}` The `Hammer.Manager` instance for the element.
31 | * - **Hammer** `{Object}` The Hammer API.
32 | *
33 | * @param {Function} domDriverFunc the DOM driver function.
34 | * @return {Function} the Hammer driver function. The function expects an
35 | * Observable of VTree as input, and outputs the source object for this
36 | * driver, containing functions `select()` and `dispose()` that can be used
37 | * for debugging and testing.
38 | * @function makeDOMDriver
39 | */
40 | makeHammerDriver: _makeHammerDriver2['default']
41 | };
42 |
43 | exports['default'] = CycleHammer;
44 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/src/fromEvent.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Observable from Hammer Event
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Frederik Krautwald. All rights reserved.
5 | */
6 |
7 | import {Subject} from 'rx'
8 | import Hammer from 'hammerjs'
9 |
10 | const hammers = {}
11 |
12 | function createListener(
13 | {element, eventType, handler, k, callback = () => {}}
14 | ) {
15 | if (typeof hammers[k] !== `object`) {
16 | hammers[k] = new Hammer.Manager(element)
17 | }
18 | const hammer = hammers[k]
19 | callback(hammer, Hammer)
20 | hammer.on(eventType, handler)
21 | }
22 |
23 | function createEventListener(
24 | {element, eventType, handler, k, callback}
25 | ) {
26 | if (Array.isArray(element)) {
27 | for (let i = 0, len = element.length; i < len; i++) {
28 | createEventListener({
29 | element: element[i],
30 | eventType,
31 | handler,
32 | k,
33 | callback,
34 | })
35 | }
36 | } else if (element) {
37 | createListener({element, eventType, handler, k, callback})
38 | }
39 | }
40 |
41 | const elementEvents = {}
42 |
43 | function fromEvent({element, eventType, k, callback}) {
44 | if (typeof elementEvents[k] !== `object`) {
45 | elementEvents[k] = {}
46 | }
47 | const elementEvent = elementEvents[k]
48 | let event$
49 | if (elementEvent[eventType]) {
50 | event$ = elementEvent[eventType]
51 | } else {
52 | elementEvent[eventType] = new Subject()
53 | event$ = elementEvent[eventType]
54 | createEventListener({
55 | element,
56 | eventType,
57 | handler: (value) => {
58 | //console.log(`handler`, value.type)
59 | event$.onNext(value)
60 | },
61 | k,
62 | callback,
63 | })
64 | }
65 | return event$
66 | }
67 |
68 | export default fromEvent
69 |
--------------------------------------------------------------------------------
/examples/vertical-pan/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Demo dataflow component
3 | * @author Frederik Krautwald
4 | */
5 |
6 | import {div, h3, h4} from '@cycle/dom'
7 | import {Observable} from 'rx'
8 |
9 | function Demo(sources) {
10 | const intent = ({dom}) => {
11 | const options = (manager, Hammer) => {
12 | // Default pan recognizer.
13 | manager.add(new Hammer.Pan())
14 | // Default tap recognizer.
15 | manager.add(new Hammer.Tap())
16 | // Default press recognizer.
17 | manager.add(new Hammer.Press())
18 | // Let the pan gesture support all directions.
19 | // This will block the vertical scrolling on a touch-device
20 | // while on the element.
21 | manager.get(`pan`).set({direction: Hammer.DIRECTION_ALL})
22 | }
23 | return {
24 | events$: Observable
25 | .merge(
26 | dom.select(`#MyElement`).events(`panleft`, options),
27 | dom.select(`#MyElement`).events(`panright`),
28 | dom.select(`#MyElement`).events(`panup`),
29 | dom.select(`#MyElement`).events(`pandown`),
30 | dom.select(`#MyElement`).events(`tap`),
31 | dom.select(`#MyElement`).events(`press`)
32 | ),
33 | }
34 | }
35 |
36 | const model = (actions) => {
37 | return actions.events$.map(
38 | event => ({event})
39 | ).startWith({event: {type: ``}})
40 | }
41 |
42 | const view = (state$) => state$.map(
43 | state => {
44 | const {type} = state.event
45 | return div([
46 | h3(`Vertical Pan cycle-hammer-driver example`),
47 | h4(`Events: panleft panright panup pandown tap press`),
48 | div(`#MyElement`, `${type} gesture detected`),
49 | ])
50 | }
51 | )
52 |
53 | const actions = intent(sources)
54 | const state$ = model(actions)
55 |
56 | return {
57 | dom: view(state$),
58 | }
59 | }
60 |
61 | export default Demo
62 |
--------------------------------------------------------------------------------
/src/hammerDriver.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Hammer driver
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | import {Observable} from 'rx'
8 | import fromEvent from './fromEvent'
9 | import eventTypes from './standardEventTypes'
10 |
11 | function fromHammerEvent(eventType, api, callback) {
12 | return api.observable.flatMapLatest(
13 | element => {
14 | if (!element) {
15 | return Observable.empty()
16 | }
17 | const k = api.namespace.join(``)
18 | return fromEvent({element, eventType, k, callback})
19 | }
20 | ).share()
21 | }
22 |
23 | function makeEventsSelector(api, originalEvents) {
24 | return function events(eventType, ...rest) {
25 | return eventTypes[eventType] ?
26 | originalEvents(eventType, ...rest) :
27 | fromHammerEvent(eventType, api, ...rest)
28 | }
29 | }
30 |
31 | function override(obj, methodName, callback) {
32 | obj[methodName] = callback(obj[methodName])
33 | }
34 |
35 | function selectCallback(originalSelect) {
36 | return function select(...args) {
37 | const api = originalSelect.apply(this, args)
38 | override(api, `select`, selectCallback)
39 | const originalEvents = api.events
40 | api.events = makeEventsSelector(api, originalEvents)
41 | return api
42 | }
43 | }
44 |
45 | function hammerDriver(domDriverFunc, vTree$) {
46 | if (typeof domDriverFunc !== `function`) {
47 | throw new Error(
48 | `First argument given to hammerDriver() must be a DOM driver function.`
49 | )
50 | }
51 | if (!vTree$ || typeof vTree$.subscribe !== `function`) {
52 | throw new Error(
53 | `The Hammer Driver expects a stream of virtual DOM elements as input.`
54 | )
55 | }
56 |
57 | const domDriver = domDriverFunc(vTree$)
58 | override(domDriver, `select`, selectCallback)
59 |
60 | return domDriver
61 | }
62 |
63 | export default hammerDriver
64 |
--------------------------------------------------------------------------------
/examples/recognizeWith-requireFailure-taps/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Demo dataflow component
3 | * @author Frederik Krautwald
4 | */
5 |
6 | import {div, h3, h4} from '@cycle/dom'
7 | import {Observable} from 'rx'
8 |
9 | function Demo(sources) {
10 | const intent = ({dom}) => {
11 | const options = (manager, Hammer) => {
12 | // Tap recognizer with minimal two taps.
13 | manager.add(new Hammer.Tap({event: `doubletap`, taps: 2}))
14 | // Single tap recognizer.
15 | manager.add(new Hammer.Tap({event: `singletap`}))
16 |
17 | // We want to recognize this simultaneous, so a double tap will be
18 | // detected even while a single tap is being recognized.
19 | // The tap event will be emitted on every tap.
20 | manager.get(`doubletap`).recognizeWith(`singletap`)
21 | // We only want to trigger a tap when we haven’t detected a double tap.
22 | manager.get(`singletap`).requireFailure(`doubletap`)
23 | }
24 | return {
25 | event$: Observable.merge(
26 | dom.select(`#MyElement`).events(`singletap`, options),
27 | dom.select(`#MyElement`).events(`doubletap`)
28 | ),
29 | }
30 | }
31 |
32 | const model = (actions) => {
33 | return actions.event$.map(
34 | event => ({event})
35 | ).startWith({event: {type: ``}})
36 | }
37 |
38 | const view = (state$) => {
39 | let types = ``
40 | return state$.map(
41 | state => {
42 | const {event} = state
43 | types += `${event.type} `
44 | return div([
45 | h3(`RecognizeWith and requireFailure cycle-hammer-driver taps example`),
46 | h4(`Events: singletap, doubletap`),
47 | div(`#MyElement`, `${types}`),
48 | ])
49 | }
50 | )
51 | }
52 |
53 | const actions = intent(sources)
54 | const state$ = model(actions)
55 |
56 | return {
57 | dom: view(state$),
58 | }
59 | }
60 |
61 | export default Demo
62 |
--------------------------------------------------------------------------------
/scripts/cyclic-docs-template.md.ejs:
--------------------------------------------------------------------------------
1 | docfiles.forEach(function(doc) { ?>
2 | # Cyclic Materials Cycle Hammer Driver API
3 |
4 | doc.javadoc.forEach(function(comment) { ?>
5 | if (!comment.ignore) { ?>
6 | if (comment.name) { ?>
7 | - [`= comment.name ?>`](#= comment.name ?>)
8 | } ?>
9 | } ?>
10 | }) ?>
11 |
12 | doc.javadoc.forEach(function(comment) { ?>
13 | if (!comment.ignore) { ?>
14 | if (comment.name) { ?>
15 | if (comment.isMethod || comment.isFunction) { ?>
16 | ### `= comment.name ?>(= comment.paramStr ?>)`
17 | } else { ?>
18 | ### `= comment.name ?>`
19 | } ?>
20 | } ?>
21 |
22 | = comment.description ?>
23 |
24 | if (comment.deprecated) { ?>
25 | **Deprecated**
26 | } ?>
27 |
28 | if (comment.author) { ?>
29 | Author: - comment.author ?>
30 | } ?>
31 |
32 | if (comment.version) { ?>
33 | Version: = comment.version ?>
34 | } ?>
35 |
36 | if (comment.see) { ?>
37 | See: = comment.see ?>
38 | } ?>
39 |
40 | if (comment.paramTags.length > 0) { ?>
41 | #### Arguments:
42 | comment.paramTags.forEach(function(paramTag) { ?>
43 | - `= paramTag.name ?> if (paramTag.joinedTypes) { ?> :: = paramTag.joinedTypes.replace('.', '') ?> } ?>` if (paramTag.description) { ?> = paramTag.description ?> } ?> }) ?>
44 | } ?>
45 |
46 | if (comment.returnTags.length > 0) { ?>
47 | #### Return:
48 | comment.returnTags.forEach(function(returnTag) { ?>
49 | *(= returnTag.joinedTypes ?>)* = returnTag.description ?>
50 | }) ?>
51 | } ?>
52 | } ?>
53 |
54 | - - -
55 | }) ?>
56 |
57 | }) ?>
58 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Tests for hammerDriver
3 | * @author Frederik Krautwald
4 | */
5 |
6 | /* eslint max-nested-callbacks: 0, max-len: 0, no-unused-expressions: 0 */
7 | /* global describe, it */
8 |
9 | import chai from 'chai'
10 | import CycleHammer from './../src/cycle-hammer'
11 | import hammerDriver from './../src/hammerDriver'
12 | import mockDomDriver from './mockDomDriver'
13 | import MockObservable from './MockObservable'
14 |
15 | const expect = chai.expect
16 | const {makeHammerDriver} = CycleHammer
17 |
18 | describe(`makeHammerDriver`, () => {
19 | it(`should be a function`, () => {
20 | expect(makeHammerDriver).to.be.a(`function`)
21 | })
22 |
23 | it(`should throw if first argument is not a function`, () => {
24 | expect(makeHammerDriver.bind(null, `not a function`)).to.throw(
25 | /First argument given to makeHammerDriver\(\) must be a DOM driver function/
26 | )
27 | })
28 |
29 | it(`should accept a DOM driver as input`, () => {
30 | expect(makeHammerDriver.bind(null, mockDomDriver)).to.not.throw(Error)
31 | })
32 |
33 | it.skip(`should throw if DOM driver function doesn’t support interface`, () => {
34 | let domDriver = () => {}
35 | expect(makeHammerDriver.bind(null, domDriver)).to.throw(
36 | /DOM driver function must have select\(\) method/
37 | )
38 | })
39 |
40 | it(`should bind the DOM driver function to the hammer driver function`, () => {
41 | const boundHammerDriverName = hammerDriver.bind(null, mockDomDriver).name
42 | expect(makeHammerDriver(mockDomDriver).name).to.equal(boundHammerDriverName)
43 | })
44 | })
45 |
46 | describe(`hammerDriver`, () => {
47 | it(`should be a function`, () => {
48 | expect(hammerDriver).to.be.a(`function`)
49 | })
50 |
51 | it(`should throw if first argument is not a function`, () => {
52 | expect(hammerDriver.bind(null, `not a function`)).to.throw(
53 | / given to hammerDriver\(\) must be a DOM driver function/
54 | )
55 | })
56 |
57 | it(`should throw if second argument is not a subscribable stream of `, () => {
58 | expect(hammerDriver.bind(null, mockDomDriver, {})).to.throw(
59 | /The Hammer Driver expects a stream of virtual DOM elements as input/
60 | )
61 | })
62 |
63 | it(`should return DOM driver’s API`, () => {
64 | const vTree$ = MockObservable
65 | const hammerApi = hammerDriver(mockDomDriver, vTree$)
66 | const domDriverApi = mockDomDriver(vTree$)
67 | expect(hammerApi).to.have.all.keys(domDriverApi)
68 | })
69 | })
70 |
--------------------------------------------------------------------------------
/lib/hammerDriver.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Hammer driver
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | 'use strict';
8 |
9 | Object.defineProperty(exports, '__esModule', {
10 | value: true
11 | });
12 |
13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14 |
15 | var _rx = require('rx');
16 |
17 | var _fromEvent = require('./fromEvent');
18 |
19 | var _fromEvent2 = _interopRequireDefault(_fromEvent);
20 |
21 | var _standardEventTypes = require('./standardEventTypes');
22 |
23 | var _standardEventTypes2 = _interopRequireDefault(_standardEventTypes);
24 |
25 | function fromHammerEvent(eventType, api, callback) {
26 | return api.observable.flatMapLatest(function (element) {
27 | if (!element) {
28 | return _rx.Observable.empty();
29 | }
30 | var k = api.namespace.join('');
31 | return (0, _fromEvent2['default'])({ element: element, eventType: eventType, k: k, callback: callback });
32 | }).share();
33 | }
34 |
35 | function makeEventsSelector(api, originalEvents) {
36 | return function events(eventType) {
37 | for (var _len = arguments.length, rest = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
38 | rest[_key - 1] = arguments[_key];
39 | }
40 |
41 | return _standardEventTypes2['default'][eventType] ? originalEvents.apply(undefined, [eventType].concat(rest)) : fromHammerEvent.apply(undefined, [eventType, api].concat(rest));
42 | };
43 | }
44 |
45 | function override(obj, methodName, callback) {
46 | obj[methodName] = callback(obj[methodName]);
47 | }
48 |
49 | function selectCallback(originalSelect) {
50 | return function select() {
51 | for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
52 | args[_key2] = arguments[_key2];
53 | }
54 |
55 | var api = originalSelect.apply(this, args);
56 | override(api, 'select', selectCallback);
57 | var originalEvents = api.events;
58 | api.events = makeEventsSelector(api, originalEvents);
59 | return api;
60 | };
61 | }
62 |
63 | function hammerDriver(domDriverFunc, vTree$) {
64 | if (typeof domDriverFunc !== 'function') {
65 | throw new Error('First argument given to hammerDriver() must be a DOM driver function.');
66 | }
67 | if (!vTree$ || typeof vTree$.subscribe !== 'function') {
68 | throw new Error('The Hammer Driver expects a stream of virtual DOM elements as input.');
69 | }
70 |
71 | var domDriver = domDriverFunc(vTree$);
72 | override(domDriver, 'select', selectCallback);
73 |
74 | return domDriver;
75 | }
76 |
77 | exports['default'] = hammerDriver;
78 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/lib/fromEvent.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Observable from Hammer Event
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Frederik Krautwald. All rights reserved.
5 | */
6 |
7 | 'use strict';
8 |
9 | Object.defineProperty(exports, '__esModule', {
10 | value: true
11 | });
12 |
13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14 |
15 | var _rx = require('rx');
16 |
17 | var _hammerjs = require('hammerjs');
18 |
19 | var _hammerjs2 = _interopRequireDefault(_hammerjs);
20 |
21 | var hammers = {};
22 |
23 | function createListener(_ref) {
24 | var element = _ref.element;
25 | var eventType = _ref.eventType;
26 | var handler = _ref.handler;
27 | var k = _ref.k;
28 | var _ref$callback = _ref.callback;
29 | var callback = _ref$callback === undefined ? function () {} : _ref$callback;
30 |
31 | if (typeof hammers[k] !== 'object') {
32 | hammers[k] = new _hammerjs2['default'].Manager(element);
33 | }
34 | var hammer = hammers[k];
35 | callback(hammer, _hammerjs2['default']);
36 | hammer.on(eventType, handler);
37 | }
38 |
39 | function createEventListener(_ref2) {
40 | var element = _ref2.element;
41 | var eventType = _ref2.eventType;
42 | var handler = _ref2.handler;
43 | var k = _ref2.k;
44 | var callback = _ref2.callback;
45 |
46 | if (Array.isArray(element)) {
47 | for (var i = 0, len = element.length; i < len; i++) {
48 | createEventListener({
49 | element: element[i],
50 | eventType: eventType,
51 | handler: handler,
52 | k: k,
53 | callback: callback
54 | });
55 | }
56 | } else if (element) {
57 | createListener({ element: element, eventType: eventType, handler: handler, k: k, callback: callback });
58 | }
59 | }
60 |
61 | var elementEvents = {};
62 |
63 | function fromEvent(_ref3) {
64 | var element = _ref3.element;
65 | var eventType = _ref3.eventType;
66 | var k = _ref3.k;
67 | var callback = _ref3.callback;
68 |
69 | if (typeof elementEvents[k] !== 'object') {
70 | elementEvents[k] = {};
71 | }
72 | var elementEvent = elementEvents[k];
73 | var event$ = undefined;
74 | if (elementEvent[eventType]) {
75 | event$ = elementEvent[eventType];
76 | } else {
77 | elementEvent[eventType] = new _rx.Subject();
78 | event$ = elementEvent[eventType];
79 | createEventListener({
80 | element: element,
81 | eventType: eventType,
82 | handler: function handler(value) {
83 | //console.log(`handler`, value.type)
84 | event$.onNext(value);
85 | },
86 | k: k,
87 | callback: callback
88 | });
89 | }
90 | return event$;
91 | }
92 |
93 | exports['default'] = fromEvent;
94 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@cyclic/cycle-hammer-driver",
3 | "version": "0.1.1",
4 | "author": "Frederik Krautwald",
5 | "description": "A Hammer driver for Cycle.js",
6 | "license": "MIT",
7 | "bugs": "https://github.com/CyclicMaterials/cycle-hammer-driver/issues",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/CyclicMaterials/cycle-hammer-driver"
11 | },
12 | "keywords": [
13 | "cyclejs",
14 | "driver",
15 | "hammer",
16 | "hammerjs",
17 | "gesture",
18 | "events",
19 | "dom"
20 | ],
21 | "directories": {
22 | "doc": "./doc",
23 | "lib": "./lib"
24 | },
25 | "files": [
26 | "lib/"
27 | ],
28 | "main": "lib/cycle-hammer.js",
29 | "dependencies": {
30 | "hammerjs": "2.0.4"
31 | },
32 | "devDependencies": {
33 | "@cycle/core": "^6.0.0-rc2",
34 | "@cycle/dom": "^8.0.0-rc2",
35 | "babel": "5.8.29",
36 | "babelify": "6.4.0",
37 | "browserify": "12.0.1",
38 | "browserify-shim": "3.8.11",
39 | "chai": "3.4.1",
40 | "chai-virtual-dom": "1.0.0",
41 | "cli-release": "1.0.3",
42 | "eslint": "1.0.0",
43 | "eslint-config-cycle": "3.1.0",
44 | "eslint-plugin-cycle": "1.0.2",
45 | "eslint-plugin-no-class": "0.1.0",
46 | "markdox": "0.1.10",
47 | "mocha": "2.3.4",
48 | "rx": "4.0.7",
49 | "testem": "0.9.11",
50 | "uglify-js": "2.6.1",
51 | "validate-commit-message": "3.0.1",
52 | "virtual-dom": "2.1.1"
53 | },
54 | "browserify-shim": {
55 | "rx": "global:Rx"
56 | },
57 | "scripts": {
58 | "lint": "eslint src/",
59 | "examples": "node scripts/build-examples.js basic,vertical-pan,recognizeWith,quadruple-tap,recognizeWith-requireFailure-taps",
60 | "test-browser": "testem",
61 | "pretest-browser": "npm run build-test",
62 | "posttest-browser": "npm run clean-test",
63 | "build-test": "browserify test/index.js -t babelify -o test/page/tests-bundle.js",
64 | "clean-test": "rm test/page/tests-bundle.js",
65 | "test-ci": "testem ci",
66 | "test": "npm run lint && npm run test-ci",
67 | "deps": "npm install && validate-commit-msg",
68 | "start": "npm run deps",
69 | "browserify": "browserify src/cycle-hammer.js -t babelify -t browserify-shim --standalone CycleHammer --exclude rx --outfile dist/cycle-hammer.js",
70 | "uglify": "uglifyjs dist/cycle-hammer.js -o dist/cycle-hammer.min.js",
71 | "dist": "npm run browserify && npm run uglify",
72 | "predist": "rm -rf dist/ && mkdir -p dist",
73 | "doc": "node ./scripts/make-api-doc.js",
74 | "predoc": "rm -rf doc/ && mkdir -p doc",
75 | "compile": "babel -d lib/ src/",
76 | "precompile": "rm -rf lib/ && mkdir -p lib",
77 | "prepublish": "npm run compile",
78 | "patch": "git checkout master && release patch && npm publish --access=public",
79 | "minor": "git checkout master && release minor && npm publish --access=public",
80 | "major": "git checkout master && release major && npm publish --access=public"
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/standardEventTypes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Standard Event Types
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | // https://developer.mozilla.org/en-US/docs/Web/Events
8 | const standardEventTypes = {
9 | abort: true,
10 | afterprint: true,
11 | animationend: true,
12 | animationiteration: true,
13 | animationstart: true,
14 | audioprocess: true,
15 | audioend: true,
16 | audiostart: true,
17 | beforeprint: true,
18 | beforeunload: true,
19 | beginEvent: true,
20 | blocked: true,
21 | blur: true,
22 | cached: true,
23 | canplay: true,
24 | canplaythrough: true,
25 | change: true,
26 | chargingchange: true,
27 | chargingtimechange: true,
28 | checking: true,
29 | click: true,
30 | close: true,
31 | complete: true,
32 | compositionend: true,
33 | compositionstart: true,
34 | compositionupdate: true,
35 | contextmenu: true,
36 | copy: true,
37 | cut: true,
38 | dblclick: true,
39 | devicelight: true,
40 | devicemotion: true,
41 | deviceorientation: true,
42 | deviceproximity: true,
43 | dischargingtimechange: true,
44 | DOMActivate: true,
45 | DOMAttributeNameChanged: true,
46 | DOMAttrModified: true,
47 | DOMCharacterDataModified: true,
48 | DOMContentLoaded: true,
49 | DOMElementNameChanged: true,
50 | DOMFocusIn: true,
51 | DOMFocusOut: true,
52 | DOMNodeInserted: true,
53 | DOMNodeInsertedIntoDocument: true,
54 | DOMNodeRemoved: true,
55 | DOMNodeRemovedFromDocument: true,
56 | DOMSubtreeModified: true,
57 | downloading: true,
58 | drag: true,
59 | dragend: true,
60 | dragenter: true,
61 | dragleave: true,
62 | dragover: true,
63 | dragstart: true,
64 | drop: true,
65 | durationchange: true,
66 | emptied: true,
67 | end: true,
68 | ended: true,
69 | endEvent: true,
70 | focus: true,
71 | focusin: true,
72 | focusout: true,
73 | fullscreenchange: true,
74 | fullscreenerror: true,
75 | gamepadconnected: true,
76 | gamepaddisconnected: true,
77 | gotpointercapture: true,
78 | hashchange: true,
79 | lostpointercapture: true,
80 | input: true,
81 | invalid: true,
82 | keydown: true,
83 | keypress: true,
84 | keyup: true,
85 | languagechange: true,
86 | levelchange: true,
87 | load: true,
88 | loadeddata: true,
89 | loadedmetadata: true,
90 | loadend: true,
91 | loadstart: true,
92 | message: true,
93 | mousedown: true,
94 | mouseenter: true,
95 | mouseleave: true,
96 | mousemove: true,
97 | mouseout: true,
98 | mouseover: true,
99 | mouseup: true,
100 | nomatch: true,
101 | notificationclick: true,
102 | noupdate: true,
103 | obsolete: true,
104 | offline: true,
105 | online: true,
106 | open: true,
107 | orientationchange: true,
108 | pagehide: true,
109 | pageshow: true,
110 | paste: true,
111 | pause: true,
112 | pointercancel: true,
113 | pointerdown: true,
114 | pointerenter: true,
115 | pointerleave: true,
116 | pointerlockchange: true,
117 | pointerlockerror: true,
118 | pointermove: true,
119 | pointerout: true,
120 | pointerover: true,
121 | pointerup: true,
122 | play: true,
123 | playing: true,
124 | popstate: true,
125 | progress: true,
126 | push: true,
127 | pushsubscriptionchange: true,
128 | ratechange: true,
129 | readystatechange: true,
130 | repeatEvent: true,
131 | reset: true,
132 | resize: true,
133 | result: true,
134 | scroll: true,
135 | seeked: true,
136 | seeking: true,
137 | select: true,
138 | selectstart: true,
139 | selectionchange: true,
140 | show: true,
141 | soundend: true,
142 | soundstart: true,
143 | speechend: true,
144 | speechstart: true,
145 | stalled: true,
146 | start: true,
147 | storage: true,
148 | submit: true,
149 | success: true,
150 | suspend: true,
151 | SVGAbort: true,
152 | SVGError: true,
153 | SVGLoad: true,
154 | SVGResize: true,
155 | SVGScroll: true,
156 | SVGUnload: true,
157 | SVGZoom: true,
158 | timeout: true,
159 | timeupdate: true,
160 | touchcancel: true,
161 | touchend: true,
162 | touchenter: true,
163 | touchleave: true,
164 | touchmove: true,
165 | touchstart: true,
166 | transitionend: true,
167 | unload: true,
168 | updateready: true,
169 | upgradeneeded: true,
170 | userproximity: true,
171 | versionchange: true,
172 | visibilitychange: true,
173 | volumechange: true,
174 | waiting: true,
175 | wheel: true,
176 | }
177 |
178 | //const hammerEventTable = {
179 | // pan: true,
180 | // panstart: true,
181 | // panmove: true,
182 | // panend: true,
183 | // pancancel: true,
184 | // panleft: true,
185 | // panright: true,
186 | // panup: true,
187 | // pandown: true,
188 | // pinch: true,
189 | // pinchstart: true,
190 | // pinchmove: true,
191 | // pinchend: true,
192 | // pinchcancel: true,
193 | // pinchin: true,
194 | // pinchout: true,
195 | // press: true,
196 | // pressup: true,
197 | // rotate: true,
198 | // rotatestart: true,
199 | // rotatemove: true,
200 | // rotateend: true,
201 | // rotatecancel: true,
202 | // swipe: true,
203 | // swipeleft: true,
204 | // swiperight: true,
205 | // swipeup: true,
206 | // swipedown: true,
207 | // tap: true,
208 | //}
209 |
210 | export default standardEventTypes
211 |
--------------------------------------------------------------------------------
/lib/standardEventTypes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Standard Event Types
3 | * @author Frederik Krautwald
4 | * @copyright 2015 Cyclic Materials. All rights reserved.
5 | */
6 |
7 | // https://developer.mozilla.org/en-US/docs/Web/Events
8 | "use strict";
9 |
10 | Object.defineProperty(exports, "__esModule", {
11 | value: true
12 | });
13 | var standardEventTypes = {
14 | abort: true,
15 | afterprint: true,
16 | animationend: true,
17 | animationiteration: true,
18 | animationstart: true,
19 | audioprocess: true,
20 | audioend: true,
21 | audiostart: true,
22 | beforeprint: true,
23 | beforeunload: true,
24 | beginEvent: true,
25 | blocked: true,
26 | blur: true,
27 | cached: true,
28 | canplay: true,
29 | canplaythrough: true,
30 | change: true,
31 | chargingchange: true,
32 | chargingtimechange: true,
33 | checking: true,
34 | click: true,
35 | close: true,
36 | complete: true,
37 | compositionend: true,
38 | compositionstart: true,
39 | compositionupdate: true,
40 | contextmenu: true,
41 | copy: true,
42 | cut: true,
43 | dblclick: true,
44 | devicelight: true,
45 | devicemotion: true,
46 | deviceorientation: true,
47 | deviceproximity: true,
48 | dischargingtimechange: true,
49 | DOMActivate: true,
50 | DOMAttributeNameChanged: true,
51 | DOMAttrModified: true,
52 | DOMCharacterDataModified: true,
53 | DOMContentLoaded: true,
54 | DOMElementNameChanged: true,
55 | DOMFocusIn: true,
56 | DOMFocusOut: true,
57 | DOMNodeInserted: true,
58 | DOMNodeInsertedIntoDocument: true,
59 | DOMNodeRemoved: true,
60 | DOMNodeRemovedFromDocument: true,
61 | DOMSubtreeModified: true,
62 | downloading: true,
63 | drag: true,
64 | dragend: true,
65 | dragenter: true,
66 | dragleave: true,
67 | dragover: true,
68 | dragstart: true,
69 | drop: true,
70 | durationchange: true,
71 | emptied: true,
72 | end: true,
73 | ended: true,
74 | endEvent: true,
75 | focus: true,
76 | focusin: true,
77 | focusout: true,
78 | fullscreenchange: true,
79 | fullscreenerror: true,
80 | gamepadconnected: true,
81 | gamepaddisconnected: true,
82 | gotpointercapture: true,
83 | hashchange: true,
84 | lostpointercapture: true,
85 | input: true,
86 | invalid: true,
87 | keydown: true,
88 | keypress: true,
89 | keyup: true,
90 | languagechange: true,
91 | levelchange: true,
92 | load: true,
93 | loadeddata: true,
94 | loadedmetadata: true,
95 | loadend: true,
96 | loadstart: true,
97 | message: true,
98 | mousedown: true,
99 | mouseenter: true,
100 | mouseleave: true,
101 | mousemove: true,
102 | mouseout: true,
103 | mouseover: true,
104 | mouseup: true,
105 | nomatch: true,
106 | notificationclick: true,
107 | noupdate: true,
108 | obsolete: true,
109 | offline: true,
110 | online: true,
111 | open: true,
112 | orientationchange: true,
113 | pagehide: true,
114 | pageshow: true,
115 | paste: true,
116 | pause: true,
117 | pointercancel: true,
118 | pointerdown: true,
119 | pointerenter: true,
120 | pointerleave: true,
121 | pointerlockchange: true,
122 | pointerlockerror: true,
123 | pointermove: true,
124 | pointerout: true,
125 | pointerover: true,
126 | pointerup: true,
127 | play: true,
128 | playing: true,
129 | popstate: true,
130 | progress: true,
131 | push: true,
132 | pushsubscriptionchange: true,
133 | ratechange: true,
134 | readystatechange: true,
135 | repeatEvent: true,
136 | reset: true,
137 | resize: true,
138 | result: true,
139 | scroll: true,
140 | seeked: true,
141 | seeking: true,
142 | select: true,
143 | selectstart: true,
144 | selectionchange: true,
145 | show: true,
146 | soundend: true,
147 | soundstart: true,
148 | speechend: true,
149 | speechstart: true,
150 | stalled: true,
151 | start: true,
152 | storage: true,
153 | submit: true,
154 | success: true,
155 | suspend: true,
156 | SVGAbort: true,
157 | SVGError: true,
158 | SVGLoad: true,
159 | SVGResize: true,
160 | SVGScroll: true,
161 | SVGUnload: true,
162 | SVGZoom: true,
163 | timeout: true,
164 | timeupdate: true,
165 | touchcancel: true,
166 | touchend: true,
167 | touchenter: true,
168 | touchleave: true,
169 | touchmove: true,
170 | touchstart: true,
171 | transitionend: true,
172 | unload: true,
173 | updateready: true,
174 | upgradeneeded: true,
175 | userproximity: true,
176 | versionchange: true,
177 | visibilitychange: true,
178 | volumechange: true,
179 | waiting: true,
180 | wheel: true
181 | };
182 |
183 | //const hammerEventTable = {
184 | // pan: true,
185 | // panstart: true,
186 | // panmove: true,
187 | // panend: true,
188 | // pancancel: true,
189 | // panleft: true,
190 | // panright: true,
191 | // panup: true,
192 | // pandown: true,
193 | // pinch: true,
194 | // pinchstart: true,
195 | // pinchmove: true,
196 | // pinchend: true,
197 | // pinchcancel: true,
198 | // pinchin: true,
199 | // pinchout: true,
200 | // press: true,
201 | // pressup: true,
202 | // rotate: true,
203 | // rotatestart: true,
204 | // rotatemove: true,
205 | // rotateend: true,
206 | // rotatecancel: true,
207 | // swipe: true,
208 | // swipeleft: true,
209 | // swiperight: true,
210 | // swipeup: true,
211 | // swipedown: true,
212 | // tap: true,
213 | //}
214 |
215 | exports["default"] = standardEventTypes;
216 | module.exports = exports["default"];
--------------------------------------------------------------------------------
/dist/cycle-hammer.min.js:
--------------------------------------------------------------------------------
1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.CycleHammer=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o-1}function splitStr(str){return str.trim().split(/\s+/g)}function inArray(src,find,findByKey){if(src.indexOf&&!findByKey){return src.indexOf(find)}else{var i=0;while(ib[key]})}}return results}function prefixed(obj,property){var prefix,prop;var camelProp=property[0].toUpperCase()+property.slice(1);var i=0;while(i1&&!session.firstMultiple){session.firstMultiple=simpleCloneInputData(input)}else if(pointersLength===1){session.firstMultiple=false}var firstInput=session.firstInput;var firstMultiple=session.firstMultiple;var offsetCenter=firstMultiple?firstMultiple.center:firstInput.center;var center=input.center=getCenter(pointers);input.timeStamp=now();input.deltaTime=input.timeStamp-firstInput.timeStamp;input.angle=getAngle(offsetCenter,center);input.distance=getDistance(offsetCenter,center);computeDeltaXY(session,input);input.offsetDirection=getDirection(input.deltaX,input.deltaY);input.scale=firstMultiple?getScale(firstMultiple.pointers,pointers):1;input.rotation=firstMultiple?getRotation(firstMultiple.pointers,pointers):0;computeIntervalInputData(session,input);var target=manager.element;if(hasParent(input.srcEvent.target,target)){target=input.srcEvent.target}input.target=target}function computeDeltaXY(session,input){var center=input.center;var offset=session.offsetDelta||{};var prevDelta=session.prevDelta||{};var prevInput=session.prevInput||{};if(input.eventType===INPUT_START||prevInput.eventType===INPUT_END){prevDelta=session.prevDelta={x:prevInput.deltaX||0,y:prevInput.deltaY||0};offset=session.offsetDelta={x:center.x,y:center.y}}input.deltaX=prevDelta.x+(center.x-offset.x);input.deltaY=prevDelta.y+(center.y-offset.y)}function computeIntervalInputData(session,input){var last=session.lastInterval||input,deltaTime=input.timeStamp-last.timeStamp,velocity,velocityX,velocityY,direction;if(input.eventType!=INPUT_CANCEL&&(deltaTime>COMPUTE_INTERVAL||last.velocity===undefined)){var deltaX=last.deltaX-input.deltaX;var deltaY=last.deltaY-input.deltaY;var v=getVelocity(deltaTime,deltaX,deltaY);velocityX=v.x;velocityY=v.y;velocity=abs(v.x)>abs(v.y)?v.x:v.y;direction=getDirection(deltaX,deltaY);session.lastInterval=input}else{velocity=last.velocity;velocityX=last.velocityX;velocityY=last.velocityY;direction=last.direction}input.velocity=velocity;input.velocityX=velocityX;input.velocityY=velocityY;input.direction=direction}function simpleCloneInputData(input){var pointers=[];var i=0;while(i=abs(y)){return x>0?DIRECTION_LEFT:DIRECTION_RIGHT}return y>0?DIRECTION_UP:DIRECTION_DOWN}function getDistance(p1,p2,props){if(!props){props=PROPS_XY}var x=p2[props[0]]-p1[props[0]],y=p2[props[1]]-p1[props[1]];return Math.sqrt(x*x+y*y)}function getAngle(p1,p2,props){if(!props){props=PROPS_XY}var x=p2[props[0]]-p1[props[0]],y=p2[props[1]]-p1[props[1]];return Math.atan2(y,x)*180/Math.PI}function getRotation(start,end){return getAngle(end[1],end[0],PROPS_CLIENT_XY)-getAngle(start[1],start[0],PROPS_CLIENT_XY)}function getScale(start,end){return getDistance(end[0],end[1],PROPS_CLIENT_XY)/getDistance(start[0],start[1],PROPS_CLIENT_XY)}var MOUSE_INPUT_MAP={mousedown:INPUT_START,mousemove:INPUT_MOVE,mouseup:INPUT_END};var MOUSE_ELEMENT_EVENTS="mousedown";var MOUSE_WINDOW_EVENTS="mousemove mouseup";function MouseInput(){this.evEl=MOUSE_ELEMENT_EVENTS;this.evWin=MOUSE_WINDOW_EVENTS;this.allow=true;this.pressed=false;Input.apply(this,arguments)}inherit(MouseInput,Input,{handler:function MEhandler(ev){var eventType=MOUSE_INPUT_MAP[ev.type];if(eventType&INPUT_START&&ev.button===0){this.pressed=true}if(eventType&INPUT_MOVE&&ev.which!==1){eventType=INPUT_END}if(!this.pressed||!this.allow){return}if(eventType&INPUT_END){this.pressed=false}this.callback(this.manager,eventType,{pointers:[ev],changedPointers:[ev],pointerType:INPUT_TYPE_MOUSE,srcEvent:ev})}});var POINTER_INPUT_MAP={pointerdown:INPUT_START,pointermove:INPUT_MOVE,pointerup:INPUT_END,pointercancel:INPUT_CANCEL,pointerout:INPUT_CANCEL};var IE10_POINTER_TYPE_ENUM={2:INPUT_TYPE_TOUCH,3:INPUT_TYPE_PEN,4:INPUT_TYPE_MOUSE,5:INPUT_TYPE_KINECT};var POINTER_ELEMENT_EVENTS="pointerdown";var POINTER_WINDOW_EVENTS="pointermove pointerup pointercancel";if(window.MSPointerEvent){POINTER_ELEMENT_EVENTS="MSPointerDown";POINTER_WINDOW_EVENTS="MSPointerMove MSPointerUp MSPointerCancel"}function PointerEventInput(){this.evEl=POINTER_ELEMENT_EVENTS;this.evWin=POINTER_WINDOW_EVENTS;Input.apply(this,arguments);this.store=this.manager.session.pointerEvents=[]}inherit(PointerEventInput,Input,{handler:function PEhandler(ev){var store=this.store;var removePointer=false;var eventTypeNormalized=ev.type.toLowerCase().replace("ms","");var eventType=POINTER_INPUT_MAP[eventTypeNormalized];var pointerType=IE10_POINTER_TYPE_ENUM[ev.pointerType]||ev.pointerType;var isTouch=pointerType==INPUT_TYPE_TOUCH;var storeIndex=inArray(store,ev.pointerId,"pointerId");if(eventType&INPUT_START&&(ev.button===0||isTouch)){if(storeIndex<0){store.push(ev);storeIndex=store.length-1}}else if(eventType&(INPUT_END|INPUT_CANCEL)){removePointer=true}if(storeIndex<0){return}store[storeIndex]=ev;this.callback(this.manager,eventType,{pointers:store,changedPointers:[ev],pointerType:pointerType,srcEvent:ev});if(removePointer){store.splice(storeIndex,1)}}});var SINGLE_TOUCH_INPUT_MAP={touchstart:INPUT_START,touchmove:INPUT_MOVE,touchend:INPUT_END,touchcancel:INPUT_CANCEL};var SINGLE_TOUCH_TARGET_EVENTS="touchstart";var SINGLE_TOUCH_WINDOW_EVENTS="touchstart touchmove touchend touchcancel";function SingleTouchInput(){this.evTarget=SINGLE_TOUCH_TARGET_EVENTS;this.evWin=SINGLE_TOUCH_WINDOW_EVENTS;this.started=false;Input.apply(this,arguments)}inherit(SingleTouchInput,Input,{handler:function TEhandler(ev){var type=SINGLE_TOUCH_INPUT_MAP[ev.type];if(type===INPUT_START){this.started=true}if(!this.started){return}var touches=normalizeSingleTouches.call(this,ev,type);if(type&(INPUT_END|INPUT_CANCEL)&&touches[0].length-touches[1].length===0){this.started=false}this.callback(this.manager,type,{pointers:touches[0],changedPointers:touches[1],pointerType:INPUT_TYPE_TOUCH,srcEvent:ev})}});function normalizeSingleTouches(ev,type){var all=toArray(ev.touches);var changed=toArray(ev.changedTouches);if(type&(INPUT_END|INPUT_CANCEL)){all=uniqueArray(all.concat(changed),"identifier",true)}return[all,changed]}var TOUCH_INPUT_MAP={touchstart:INPUT_START,touchmove:INPUT_MOVE,touchend:INPUT_END,touchcancel:INPUT_CANCEL};var TOUCH_TARGET_EVENTS="touchstart touchmove touchend touchcancel";function TouchInput(){this.evTarget=TOUCH_TARGET_EVENTS;this.targetIds={};Input.apply(this,arguments)}inherit(TouchInput,Input,{handler:function MTEhandler(ev){var type=TOUCH_INPUT_MAP[ev.type];var touches=getTouches.call(this,ev,type);if(!touches){return}this.callback(this.manager,type,{pointers:touches[0],changedPointers:touches[1],pointerType:INPUT_TYPE_TOUCH,srcEvent:ev})}});function getTouches(ev,type){var allTouches=toArray(ev.touches);var targetIds=this.targetIds;if(type&(INPUT_START|INPUT_MOVE)&&allTouches.length===1){targetIds[allTouches[0].identifier]=true;return[allTouches,allTouches]}var i,targetTouches,changedTouches=toArray(ev.changedTouches),changedTargetTouches=[],target=this.target;targetTouches=allTouches.filter(function(touch){return hasParent(touch.target,target)});if(type===INPUT_START){i=0;while(i-1){this.requireFail.splice(index,1)}return this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(otherRecognizer){return!!this.simultaneous[otherRecognizer.id]},emit:function(input){var self=this;var state=this.state;function emit(withState){self.manager.emit(self.options.event+(withState?stateStr(state):""),input)}if(state=STATE_ENDED){emit(true)}},tryEmit:function(input){if(this.canEmit()){return this.emit(input)}this.state=STATE_FAILED},canEmit:function(){var i=0;while(ioptions.threshold&&direction&options.direction},attrTest:function(input){return AttrRecognizer.prototype.attrTest.call(this,input)&&(this.state&STATE_BEGAN||!(this.state&STATE_BEGAN)&&this.directionTest(input))},emit:function(input){this.pX=input.deltaX;this.pY=input.deltaY;var direction=directionStr(input.direction);if(direction){this.manager.emit(this.options.event+direction,input)}this._super.emit.call(this,input)}});function PinchRecognizer(){AttrRecognizer.apply(this,arguments)}inherit(PinchRecognizer,AttrRecognizer,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[TOUCH_ACTION_NONE]},attrTest:function(input){return this._super.attrTest.call(this,input)&&(Math.abs(input.scale-1)>this.options.threshold||this.state&STATE_BEGAN)},emit:function(input){this._super.emit.call(this,input);if(input.scale!==1){var inOut=input.scale<1?"in":"out";this.manager.emit(this.options.event+inOut,input)}}});function PressRecognizer(){Recognizer.apply(this,arguments);this._timer=null;this._input=null}inherit(PressRecognizer,Recognizer,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[TOUCH_ACTION_AUTO]},process:function(input){var options=this.options;var validPointers=input.pointers.length===options.pointers;var validMovement=input.distanceoptions.time;this._input=input;if(!validMovement||!validPointers||input.eventType&(INPUT_END|INPUT_CANCEL)&&!validTime){this.reset()}else if(input.eventType&INPUT_START){this.reset();this._timer=setTimeoutContext(function(){this.state=STATE_RECOGNIZED;this.tryEmit()},options.time,this)}else if(input.eventType&INPUT_END){return STATE_RECOGNIZED}return STATE_FAILED},reset:function(){clearTimeout(this._timer)},emit:function(input){if(this.state!==STATE_RECOGNIZED){return}if(input&&input.eventType&INPUT_END){this.manager.emit(this.options.event+"up",input)}else{this._input.timeStamp=now();this.manager.emit(this.options.event,this._input)}}});function RotateRecognizer(){AttrRecognizer.apply(this,arguments)}inherit(RotateRecognizer,AttrRecognizer,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[TOUCH_ACTION_NONE]},attrTest:function(input){return this._super.attrTest.call(this,input)&&(Math.abs(input.rotation)>this.options.threshold||this.state&STATE_BEGAN)}});function SwipeRecognizer(){AttrRecognizer.apply(this,arguments)}inherit(SwipeRecognizer,AttrRecognizer,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:DIRECTION_HORIZONTAL|DIRECTION_VERTICAL,pointers:1},getTouchAction:function(){return PanRecognizer.prototype.getTouchAction.call(this)},attrTest:function(input){var direction=this.options.direction;var velocity;if(direction&(DIRECTION_HORIZONTAL|DIRECTION_VERTICAL)){velocity=input.velocity}else if(direction&DIRECTION_HORIZONTAL){velocity=input.velocityX}else if(direction&DIRECTION_VERTICAL){velocity=input.velocityY}return this._super.attrTest.call(this,input)&&direction&input.direction&&input.distance>this.options.threshold&&abs(velocity)>this.options.velocity&&input.eventType&INPUT_END},emit:function(input){var direction=directionStr(input.direction);if(direction){this.manager.emit(this.options.event+direction,input)}this.manager.emit(this.options.event,input)}});function TapRecognizer(){Recognizer.apply(this,arguments);this.pTime=false;this.pCenter=false;this._timer=null;this._input=null;this.count=0}inherit(TapRecognizer,Recognizer,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[TOUCH_ACTION_MANIPULATION]},process:function(input){var options=this.options;var validPointers=input.pointers.length===options.pointers;var validMovement=input.distance1?_len-1:0),_key=1;_key<_len;_key++){rest[_key-1]=arguments[_key]}return _standardEventTypes2["default"][eventType]?originalEvents.apply(undefined,[eventType].concat(rest)):fromHammerEvent.apply(undefined,[eventType,api].concat(rest))}}function override(obj,methodName,callback){obj[methodName]=callback(obj[methodName])}function selectCallback(originalSelect){return function select(){for(var _len2=arguments.length,args=Array(_len2),_key2=0;_key2<_len2;_key2++){args[_key2]=arguments[_key2]}var api=originalSelect.apply(this,args);override(api,"select",selectCallback);var originalEvents=api.events;api.events=makeEventsSelector(api,originalEvents);return api}}function hammerDriver(domDriverFunc,vTree$){if(typeof domDriverFunc!=="function"){throw new Error("First argument given to hammerDriver() must be a DOM driver function.")}if(!vTree$||typeof vTree$.subscribe!=="function"){throw new Error("The Hammer Driver expects a stream of virtual DOM elements as input.")}var domDriver=domDriverFunc(vTree$);override(domDriver,"select",selectCallback);return domDriver}exports["default"]=hammerDriver;module.exports=exports["default"]}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{})},{"./fromEvent":3,"./standardEventTypes":6}],5:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{"default":obj}}var _hammerDriver=require("./hammerDriver");var _hammerDriver2=_interopRequireDefault(_hammerDriver);function makeHammerDriver(domDriverFunc){if(typeof domDriverFunc!=="function"){throw new Error("First argument given to makeHammerDriver() "+"must be a DOM driver function.")}return _hammerDriver2["default"].bind({},domDriverFunc)}exports["default"]=makeHammerDriver;module.exports=exports["default"]},{"./hammerDriver":4}],6:[function(require,module,exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var standardEventTypes={abort:true,afterprint:true,animationend:true,animationiteration:true,animationstart:true,audioprocess:true,audioend:true,audiostart:true,beforeprint:true,beforeunload:true,beginEvent:true,blocked:true,blur:true,cached:true,canplay:true,canplaythrough:true,change:true,chargingchange:true,chargingtimechange:true,checking:true,click:true,close:true,complete:true,compositionend:true,compositionstart:true,compositionupdate:true,contextmenu:true,copy:true,cut:true,dblclick:true,devicelight:true,devicemotion:true,deviceorientation:true,deviceproximity:true,dischargingtimechange:true,DOMActivate:true,DOMAttributeNameChanged:true,DOMAttrModified:true,DOMCharacterDataModified:true,DOMContentLoaded:true,DOMElementNameChanged:true,DOMFocusIn:true,DOMFocusOut:true,DOMNodeInserted:true,DOMNodeInsertedIntoDocument:true,DOMNodeRemoved:true,DOMNodeRemovedFromDocument:true,DOMSubtreeModified:true,downloading:true,drag:true,dragend:true,dragenter:true,dragleave:true,dragover:true,dragstart:true,drop:true,durationchange:true,emptied:true,end:true,ended:true,endEvent:true,focus:true,focusin:true,focusout:true,fullscreenchange:true,fullscreenerror:true,gamepadconnected:true,gamepaddisconnected:true,gotpointercapture:true,hashchange:true,lostpointercapture:true,input:true,invalid:true,keydown:true,keypress:true,keyup:true,languagechange:true,levelchange:true,load:true,loadeddata:true,loadedmetadata:true,loadend:true,loadstart:true,message:true,mousedown:true,mouseenter:true,mouseleave:true,mousemove:true,mouseout:true,mouseover:true,mouseup:true,nomatch:true,notificationclick:true,noupdate:true,obsolete:true,offline:true,online:true,open:true,orientationchange:true,pagehide:true,pageshow:true,paste:true,pause:true,pointercancel:true,pointerdown:true,pointerenter:true,pointerleave:true,pointerlockchange:true,pointerlockerror:true,pointermove:true,pointerout:true,pointerover:true,pointerup:true,play:true,playing:true,popstate:true,progress:true,push:true,pushsubscriptionchange:true,ratechange:true,readystatechange:true,repeatEvent:true,reset:true,resize:true,result:true,scroll:true,seeked:true,seeking:true,select:true,selectstart:true,selectionchange:true,show:true,soundend:true,soundstart:true,speechend:true,speechstart:true,stalled:true,start:true,storage:true,submit:true,success:true,suspend:true,SVGAbort:true,SVGError:true,SVGLoad:true,SVGResize:true,SVGScroll:true,SVGUnload:true,SVGZoom:true,timeout:true,timeupdate:true,touchcancel:true,touchend:true,touchenter:true,touchleave:true,touchmove:true,touchstart:true,transitionend:true,unload:true,updateready:true,upgradeneeded:true,userproximity:true,versionchange:true,visibilitychange:true,volumechange:true,waiting:true,wheel:true};exports["default"]=standardEventTypes;module.exports=exports["default"]},{}]},{},[2])(2)});
--------------------------------------------------------------------------------
/dist/cycle-hammer.js:
--------------------------------------------------------------------------------
1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.CycleHammer = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o -1;
210 | }
211 |
212 | /**
213 | * split string on whitespace
214 | * @param {String} str
215 | * @returns {Array} words
216 | */
217 | function splitStr(str) {
218 | return str.trim().split(/\s+/g);
219 | }
220 |
221 | /**
222 | * find if a array contains the object using indexOf or a simple polyFill
223 | * @param {Array} src
224 | * @param {String} find
225 | * @param {String} [findByKey]
226 | * @return {Boolean|Number} false when not found, or the index
227 | */
228 | function inArray(src, find, findByKey) {
229 | if (src.indexOf && !findByKey) {
230 | return src.indexOf(find);
231 | } else {
232 | var i = 0;
233 | while (i < src.length) {
234 | if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
235 | return i;
236 | }
237 | i++;
238 | }
239 | return -1;
240 | }
241 | }
242 |
243 | /**
244 | * convert array-like objects to real arrays
245 | * @param {Object} obj
246 | * @returns {Array}
247 | */
248 | function toArray(obj) {
249 | return Array.prototype.slice.call(obj, 0);
250 | }
251 |
252 | /**
253 | * unique array with objects based on a key (like 'id') or just by the array's value
254 | * @param {Array} src [{id:1},{id:2},{id:1}]
255 | * @param {String} [key]
256 | * @param {Boolean} [sort=False]
257 | * @returns {Array} [{id:1},{id:2}]
258 | */
259 | function uniqueArray(src, key, sort) {
260 | var results = [];
261 | var values = [];
262 | var i = 0;
263 |
264 | while (i < src.length) {
265 | var val = key ? src[i][key] : src[i];
266 | if (inArray(values, val) < 0) {
267 | results.push(src[i]);
268 | }
269 | values[i] = val;
270 | i++;
271 | }
272 |
273 | if (sort) {
274 | if (!key) {
275 | results = results.sort();
276 | } else {
277 | results = results.sort(function sortUniqueArray(a, b) {
278 | return a[key] > b[key];
279 | });
280 | }
281 | }
282 |
283 | return results;
284 | }
285 |
286 | /**
287 | * get the prefixed property
288 | * @param {Object} obj
289 | * @param {String} property
290 | * @returns {String|Undefined} prefixed
291 | */
292 | function prefixed(obj, property) {
293 | var prefix, prop;
294 | var camelProp = property[0].toUpperCase() + property.slice(1);
295 |
296 | var i = 0;
297 | while (i < VENDOR_PREFIXES.length) {
298 | prefix = VENDOR_PREFIXES[i];
299 | prop = (prefix) ? prefix + camelProp : property;
300 |
301 | if (prop in obj) {
302 | return prop;
303 | }
304 | i++;
305 | }
306 | return undefined;
307 | }
308 |
309 | /**
310 | * get a unique id
311 | * @returns {number} uniqueId
312 | */
313 | var _uniqueId = 1;
314 | function uniqueId() {
315 | return _uniqueId++;
316 | }
317 |
318 | /**
319 | * get the window object of an element
320 | * @param {HTMLElement} element
321 | * @returns {DocumentView|Window}
322 | */
323 | function getWindowForElement(element) {
324 | var doc = element.ownerDocument;
325 | return (doc.defaultView || doc.parentWindow);
326 | }
327 |
328 | var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
329 |
330 | var SUPPORT_TOUCH = ('ontouchstart' in window);
331 | var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined;
332 | var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
333 |
334 | var INPUT_TYPE_TOUCH = 'touch';
335 | var INPUT_TYPE_PEN = 'pen';
336 | var INPUT_TYPE_MOUSE = 'mouse';
337 | var INPUT_TYPE_KINECT = 'kinect';
338 |
339 | var COMPUTE_INTERVAL = 25;
340 |
341 | var INPUT_START = 1;
342 | var INPUT_MOVE = 2;
343 | var INPUT_END = 4;
344 | var INPUT_CANCEL = 8;
345 |
346 | var DIRECTION_NONE = 1;
347 | var DIRECTION_LEFT = 2;
348 | var DIRECTION_RIGHT = 4;
349 | var DIRECTION_UP = 8;
350 | var DIRECTION_DOWN = 16;
351 |
352 | var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
353 | var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
354 | var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
355 |
356 | var PROPS_XY = ['x', 'y'];
357 | var PROPS_CLIENT_XY = ['clientX', 'clientY'];
358 |
359 | /**
360 | * create new input type manager
361 | * @param {Manager} manager
362 | * @param {Function} callback
363 | * @returns {Input}
364 | * @constructor
365 | */
366 | function Input(manager, callback) {
367 | var self = this;
368 | this.manager = manager;
369 | this.callback = callback;
370 | this.element = manager.element;
371 | this.target = manager.options.inputTarget;
372 |
373 | // smaller wrapper around the handler, for the scope and the enabled state of the manager,
374 | // so when disabled the input events are completely bypassed.
375 | this.domHandler = function(ev) {
376 | if (boolOrFn(manager.options.enable, [manager])) {
377 | self.handler(ev);
378 | }
379 | };
380 |
381 | this.init();
382 |
383 | }
384 |
385 | Input.prototype = {
386 | /**
387 | * should handle the inputEvent data and trigger the callback
388 | * @virtual
389 | */
390 | handler: function() { },
391 |
392 | /**
393 | * bind the events
394 | */
395 | init: function() {
396 | this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
397 | this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
398 | this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
399 | },
400 |
401 | /**
402 | * unbind the events
403 | */
404 | destroy: function() {
405 | this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
406 | this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
407 | this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
408 | }
409 | };
410 |
411 | /**
412 | * create new input type manager
413 | * called by the Manager constructor
414 | * @param {Hammer} manager
415 | * @returns {Input}
416 | */
417 | function createInputInstance(manager) {
418 | var Type;
419 | var inputClass = manager.options.inputClass;
420 |
421 | if (inputClass) {
422 | Type = inputClass;
423 | } else if (SUPPORT_POINTER_EVENTS) {
424 | Type = PointerEventInput;
425 | } else if (SUPPORT_ONLY_TOUCH) {
426 | Type = TouchInput;
427 | } else if (!SUPPORT_TOUCH) {
428 | Type = MouseInput;
429 | } else {
430 | Type = TouchMouseInput;
431 | }
432 | return new (Type)(manager, inputHandler);
433 | }
434 |
435 | /**
436 | * handle input events
437 | * @param {Manager} manager
438 | * @param {String} eventType
439 | * @param {Object} input
440 | */
441 | function inputHandler(manager, eventType, input) {
442 | var pointersLen = input.pointers.length;
443 | var changedPointersLen = input.changedPointers.length;
444 | var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
445 | var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));
446 |
447 | input.isFirst = !!isFirst;
448 | input.isFinal = !!isFinal;
449 |
450 | if (isFirst) {
451 | manager.session = {};
452 | }
453 |
454 | // source event is the normalized value of the domEvents
455 | // like 'touchstart, mouseup, pointerdown'
456 | input.eventType = eventType;
457 |
458 | // compute scale, rotation etc
459 | computeInputData(manager, input);
460 |
461 | // emit secret event
462 | manager.emit('hammer.input', input);
463 |
464 | manager.recognize(input);
465 | manager.session.prevInput = input;
466 | }
467 |
468 | /**
469 | * extend the data with some usable properties like scale, rotate, velocity etc
470 | * @param {Object} manager
471 | * @param {Object} input
472 | */
473 | function computeInputData(manager, input) {
474 | var session = manager.session;
475 | var pointers = input.pointers;
476 | var pointersLength = pointers.length;
477 |
478 | // store the first input to calculate the distance and direction
479 | if (!session.firstInput) {
480 | session.firstInput = simpleCloneInputData(input);
481 | }
482 |
483 | // to compute scale and rotation we need to store the multiple touches
484 | if (pointersLength > 1 && !session.firstMultiple) {
485 | session.firstMultiple = simpleCloneInputData(input);
486 | } else if (pointersLength === 1) {
487 | session.firstMultiple = false;
488 | }
489 |
490 | var firstInput = session.firstInput;
491 | var firstMultiple = session.firstMultiple;
492 | var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
493 |
494 | var center = input.center = getCenter(pointers);
495 | input.timeStamp = now();
496 | input.deltaTime = input.timeStamp - firstInput.timeStamp;
497 |
498 | input.angle = getAngle(offsetCenter, center);
499 | input.distance = getDistance(offsetCenter, center);
500 |
501 | computeDeltaXY(session, input);
502 | input.offsetDirection = getDirection(input.deltaX, input.deltaY);
503 |
504 | input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
505 | input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
506 |
507 | computeIntervalInputData(session, input);
508 |
509 | // find the correct target
510 | var target = manager.element;
511 | if (hasParent(input.srcEvent.target, target)) {
512 | target = input.srcEvent.target;
513 | }
514 | input.target = target;
515 | }
516 |
517 | function computeDeltaXY(session, input) {
518 | var center = input.center;
519 | var offset = session.offsetDelta || {};
520 | var prevDelta = session.prevDelta || {};
521 | var prevInput = session.prevInput || {};
522 |
523 | if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
524 | prevDelta = session.prevDelta = {
525 | x: prevInput.deltaX || 0,
526 | y: prevInput.deltaY || 0
527 | };
528 |
529 | offset = session.offsetDelta = {
530 | x: center.x,
531 | y: center.y
532 | };
533 | }
534 |
535 | input.deltaX = prevDelta.x + (center.x - offset.x);
536 | input.deltaY = prevDelta.y + (center.y - offset.y);
537 | }
538 |
539 | /**
540 | * velocity is calculated every x ms
541 | * @param {Object} session
542 | * @param {Object} input
543 | */
544 | function computeIntervalInputData(session, input) {
545 | var last = session.lastInterval || input,
546 | deltaTime = input.timeStamp - last.timeStamp,
547 | velocity, velocityX, velocityY, direction;
548 |
549 | if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
550 | var deltaX = last.deltaX - input.deltaX;
551 | var deltaY = last.deltaY - input.deltaY;
552 |
553 | var v = getVelocity(deltaTime, deltaX, deltaY);
554 | velocityX = v.x;
555 | velocityY = v.y;
556 | velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
557 | direction = getDirection(deltaX, deltaY);
558 |
559 | session.lastInterval = input;
560 | } else {
561 | // use latest velocity info if it doesn't overtake a minimum period
562 | velocity = last.velocity;
563 | velocityX = last.velocityX;
564 | velocityY = last.velocityY;
565 | direction = last.direction;
566 | }
567 |
568 | input.velocity = velocity;
569 | input.velocityX = velocityX;
570 | input.velocityY = velocityY;
571 | input.direction = direction;
572 | }
573 |
574 | /**
575 | * create a simple clone from the input used for storage of firstInput and firstMultiple
576 | * @param {Object} input
577 | * @returns {Object} clonedInputData
578 | */
579 | function simpleCloneInputData(input) {
580 | // make a simple copy of the pointers because we will get a reference if we don't
581 | // we only need clientXY for the calculations
582 | var pointers = [];
583 | var i = 0;
584 | while (i < input.pointers.length) {
585 | pointers[i] = {
586 | clientX: round(input.pointers[i].clientX),
587 | clientY: round(input.pointers[i].clientY)
588 | };
589 | i++;
590 | }
591 |
592 | return {
593 | timeStamp: now(),
594 | pointers: pointers,
595 | center: getCenter(pointers),
596 | deltaX: input.deltaX,
597 | deltaY: input.deltaY
598 | };
599 | }
600 |
601 | /**
602 | * get the center of all the pointers
603 | * @param {Array} pointers
604 | * @return {Object} center contains `x` and `y` properties
605 | */
606 | function getCenter(pointers) {
607 | var pointersLength = pointers.length;
608 |
609 | // no need to loop when only one touch
610 | if (pointersLength === 1) {
611 | return {
612 | x: round(pointers[0].clientX),
613 | y: round(pointers[0].clientY)
614 | };
615 | }
616 |
617 | var x = 0, y = 0, i = 0;
618 | while (i < pointersLength) {
619 | x += pointers[i].clientX;
620 | y += pointers[i].clientY;
621 | i++;
622 | }
623 |
624 | return {
625 | x: round(x / pointersLength),
626 | y: round(y / pointersLength)
627 | };
628 | }
629 |
630 | /**
631 | * calculate the velocity between two points. unit is in px per ms.
632 | * @param {Number} deltaTime
633 | * @param {Number} x
634 | * @param {Number} y
635 | * @return {Object} velocity `x` and `y`
636 | */
637 | function getVelocity(deltaTime, x, y) {
638 | return {
639 | x: x / deltaTime || 0,
640 | y: y / deltaTime || 0
641 | };
642 | }
643 |
644 | /**
645 | * get the direction between two points
646 | * @param {Number} x
647 | * @param {Number} y
648 | * @return {Number} direction
649 | */
650 | function getDirection(x, y) {
651 | if (x === y) {
652 | return DIRECTION_NONE;
653 | }
654 |
655 | if (abs(x) >= abs(y)) {
656 | return x > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
657 | }
658 | return y > 0 ? DIRECTION_UP : DIRECTION_DOWN;
659 | }
660 |
661 | /**
662 | * calculate the absolute distance between two points
663 | * @param {Object} p1 {x, y}
664 | * @param {Object} p2 {x, y}
665 | * @param {Array} [props] containing x and y keys
666 | * @return {Number} distance
667 | */
668 | function getDistance(p1, p2, props) {
669 | if (!props) {
670 | props = PROPS_XY;
671 | }
672 | var x = p2[props[0]] - p1[props[0]],
673 | y = p2[props[1]] - p1[props[1]];
674 |
675 | return Math.sqrt((x * x) + (y * y));
676 | }
677 |
678 | /**
679 | * calculate the angle between two coordinates
680 | * @param {Object} p1
681 | * @param {Object} p2
682 | * @param {Array} [props] containing x and y keys
683 | * @return {Number} angle
684 | */
685 | function getAngle(p1, p2, props) {
686 | if (!props) {
687 | props = PROPS_XY;
688 | }
689 | var x = p2[props[0]] - p1[props[0]],
690 | y = p2[props[1]] - p1[props[1]];
691 | return Math.atan2(y, x) * 180 / Math.PI;
692 | }
693 |
694 | /**
695 | * calculate the rotation degrees between two pointersets
696 | * @param {Array} start array of pointers
697 | * @param {Array} end array of pointers
698 | * @return {Number} rotation
699 | */
700 | function getRotation(start, end) {
701 | return getAngle(end[1], end[0], PROPS_CLIENT_XY) - getAngle(start[1], start[0], PROPS_CLIENT_XY);
702 | }
703 |
704 | /**
705 | * calculate the scale factor between two pointersets
706 | * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
707 | * @param {Array} start array of pointers
708 | * @param {Array} end array of pointers
709 | * @return {Number} scale
710 | */
711 | function getScale(start, end) {
712 | return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
713 | }
714 |
715 | var MOUSE_INPUT_MAP = {
716 | mousedown: INPUT_START,
717 | mousemove: INPUT_MOVE,
718 | mouseup: INPUT_END
719 | };
720 |
721 | var MOUSE_ELEMENT_EVENTS = 'mousedown';
722 | var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
723 |
724 | /**
725 | * Mouse events input
726 | * @constructor
727 | * @extends Input
728 | */
729 | function MouseInput() {
730 | this.evEl = MOUSE_ELEMENT_EVENTS;
731 | this.evWin = MOUSE_WINDOW_EVENTS;
732 |
733 | this.allow = true; // used by Input.TouchMouse to disable mouse events
734 | this.pressed = false; // mousedown state
735 |
736 | Input.apply(this, arguments);
737 | }
738 |
739 | inherit(MouseInput, Input, {
740 | /**
741 | * handle mouse events
742 | * @param {Object} ev
743 | */
744 | handler: function MEhandler(ev) {
745 | var eventType = MOUSE_INPUT_MAP[ev.type];
746 |
747 | // on start we want to have the left mouse button down
748 | if (eventType & INPUT_START && ev.button === 0) {
749 | this.pressed = true;
750 | }
751 |
752 | if (eventType & INPUT_MOVE && ev.which !== 1) {
753 | eventType = INPUT_END;
754 | }
755 |
756 | // mouse must be down, and mouse events are allowed (see the TouchMouse input)
757 | if (!this.pressed || !this.allow) {
758 | return;
759 | }
760 |
761 | if (eventType & INPUT_END) {
762 | this.pressed = false;
763 | }
764 |
765 | this.callback(this.manager, eventType, {
766 | pointers: [ev],
767 | changedPointers: [ev],
768 | pointerType: INPUT_TYPE_MOUSE,
769 | srcEvent: ev
770 | });
771 | }
772 | });
773 |
774 | var POINTER_INPUT_MAP = {
775 | pointerdown: INPUT_START,
776 | pointermove: INPUT_MOVE,
777 | pointerup: INPUT_END,
778 | pointercancel: INPUT_CANCEL,
779 | pointerout: INPUT_CANCEL
780 | };
781 |
782 | // in IE10 the pointer types is defined as an enum
783 | var IE10_POINTER_TYPE_ENUM = {
784 | 2: INPUT_TYPE_TOUCH,
785 | 3: INPUT_TYPE_PEN,
786 | 4: INPUT_TYPE_MOUSE,
787 | 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
788 | };
789 |
790 | var POINTER_ELEMENT_EVENTS = 'pointerdown';
791 | var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
792 |
793 | // IE10 has prefixed support, and case-sensitive
794 | if (window.MSPointerEvent) {
795 | POINTER_ELEMENT_EVENTS = 'MSPointerDown';
796 | POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
797 | }
798 |
799 | /**
800 | * Pointer events input
801 | * @constructor
802 | * @extends Input
803 | */
804 | function PointerEventInput() {
805 | this.evEl = POINTER_ELEMENT_EVENTS;
806 | this.evWin = POINTER_WINDOW_EVENTS;
807 |
808 | Input.apply(this, arguments);
809 |
810 | this.store = (this.manager.session.pointerEvents = []);
811 | }
812 |
813 | inherit(PointerEventInput, Input, {
814 | /**
815 | * handle mouse events
816 | * @param {Object} ev
817 | */
818 | handler: function PEhandler(ev) {
819 | var store = this.store;
820 | var removePointer = false;
821 |
822 | var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
823 | var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
824 | var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
825 |
826 | var isTouch = (pointerType == INPUT_TYPE_TOUCH);
827 |
828 | // get index of the event in the store
829 | var storeIndex = inArray(store, ev.pointerId, 'pointerId');
830 |
831 | // start and mouse must be down
832 | if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
833 | if (storeIndex < 0) {
834 | store.push(ev);
835 | storeIndex = store.length - 1;
836 | }
837 | } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
838 | removePointer = true;
839 | }
840 |
841 | // it not found, so the pointer hasn't been down (so it's probably a hover)
842 | if (storeIndex < 0) {
843 | return;
844 | }
845 |
846 | // update the event in the store
847 | store[storeIndex] = ev;
848 |
849 | this.callback(this.manager, eventType, {
850 | pointers: store,
851 | changedPointers: [ev],
852 | pointerType: pointerType,
853 | srcEvent: ev
854 | });
855 |
856 | if (removePointer) {
857 | // remove from the store
858 | store.splice(storeIndex, 1);
859 | }
860 | }
861 | });
862 |
863 | var SINGLE_TOUCH_INPUT_MAP = {
864 | touchstart: INPUT_START,
865 | touchmove: INPUT_MOVE,
866 | touchend: INPUT_END,
867 | touchcancel: INPUT_CANCEL
868 | };
869 |
870 | var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
871 | var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
872 |
873 | /**
874 | * Touch events input
875 | * @constructor
876 | * @extends Input
877 | */
878 | function SingleTouchInput() {
879 | this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
880 | this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
881 | this.started = false;
882 |
883 | Input.apply(this, arguments);
884 | }
885 |
886 | inherit(SingleTouchInput, Input, {
887 | handler: function TEhandler(ev) {
888 | var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
889 |
890 | // should we handle the touch events?
891 | if (type === INPUT_START) {
892 | this.started = true;
893 | }
894 |
895 | if (!this.started) {
896 | return;
897 | }
898 |
899 | var touches = normalizeSingleTouches.call(this, ev, type);
900 |
901 | // when done, reset the started state
902 | if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
903 | this.started = false;
904 | }
905 |
906 | this.callback(this.manager, type, {
907 | pointers: touches[0],
908 | changedPointers: touches[1],
909 | pointerType: INPUT_TYPE_TOUCH,
910 | srcEvent: ev
911 | });
912 | }
913 | });
914 |
915 | /**
916 | * @this {TouchInput}
917 | * @param {Object} ev
918 | * @param {Number} type flag
919 | * @returns {undefined|Array} [all, changed]
920 | */
921 | function normalizeSingleTouches(ev, type) {
922 | var all = toArray(ev.touches);
923 | var changed = toArray(ev.changedTouches);
924 |
925 | if (type & (INPUT_END | INPUT_CANCEL)) {
926 | all = uniqueArray(all.concat(changed), 'identifier', true);
927 | }
928 |
929 | return [all, changed];
930 | }
931 |
932 | var TOUCH_INPUT_MAP = {
933 | touchstart: INPUT_START,
934 | touchmove: INPUT_MOVE,
935 | touchend: INPUT_END,
936 | touchcancel: INPUT_CANCEL
937 | };
938 |
939 | var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
940 |
941 | /**
942 | * Multi-user touch events input
943 | * @constructor
944 | * @extends Input
945 | */
946 | function TouchInput() {
947 | this.evTarget = TOUCH_TARGET_EVENTS;
948 | this.targetIds = {};
949 |
950 | Input.apply(this, arguments);
951 | }
952 |
953 | inherit(TouchInput, Input, {
954 | handler: function MTEhandler(ev) {
955 | var type = TOUCH_INPUT_MAP[ev.type];
956 | var touches = getTouches.call(this, ev, type);
957 | if (!touches) {
958 | return;
959 | }
960 |
961 | this.callback(this.manager, type, {
962 | pointers: touches[0],
963 | changedPointers: touches[1],
964 | pointerType: INPUT_TYPE_TOUCH,
965 | srcEvent: ev
966 | });
967 | }
968 | });
969 |
970 | /**
971 | * @this {TouchInput}
972 | * @param {Object} ev
973 | * @param {Number} type flag
974 | * @returns {undefined|Array} [all, changed]
975 | */
976 | function getTouches(ev, type) {
977 | var allTouches = toArray(ev.touches);
978 | var targetIds = this.targetIds;
979 |
980 | // when there is only one touch, the process can be simplified
981 | if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
982 | targetIds[allTouches[0].identifier] = true;
983 | return [allTouches, allTouches];
984 | }
985 |
986 | var i,
987 | targetTouches,
988 | changedTouches = toArray(ev.changedTouches),
989 | changedTargetTouches = [],
990 | target = this.target;
991 |
992 | // get target touches from touches
993 | targetTouches = allTouches.filter(function(touch) {
994 | return hasParent(touch.target, target);
995 | });
996 |
997 | // collect touches
998 | if (type === INPUT_START) {
999 | i = 0;
1000 | while (i < targetTouches.length) {
1001 | targetIds[targetTouches[i].identifier] = true;
1002 | i++;
1003 | }
1004 | }
1005 |
1006 | // filter changed touches to only contain touches that exist in the collected target ids
1007 | i = 0;
1008 | while (i < changedTouches.length) {
1009 | if (targetIds[changedTouches[i].identifier]) {
1010 | changedTargetTouches.push(changedTouches[i]);
1011 | }
1012 |
1013 | // cleanup removed touches
1014 | if (type & (INPUT_END | INPUT_CANCEL)) {
1015 | delete targetIds[changedTouches[i].identifier];
1016 | }
1017 | i++;
1018 | }
1019 |
1020 | if (!changedTargetTouches.length) {
1021 | return;
1022 | }
1023 |
1024 | return [
1025 | // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
1026 | uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
1027 | changedTargetTouches
1028 | ];
1029 | }
1030 |
1031 | /**
1032 | * Combined touch and mouse input
1033 | *
1034 | * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
1035 | * This because touch devices also emit mouse events while doing a touch.
1036 | *
1037 | * @constructor
1038 | * @extends Input
1039 | */
1040 | function TouchMouseInput() {
1041 | Input.apply(this, arguments);
1042 |
1043 | var handler = bindFn(this.handler, this);
1044 | this.touch = new TouchInput(this.manager, handler);
1045 | this.mouse = new MouseInput(this.manager, handler);
1046 | }
1047 |
1048 | inherit(TouchMouseInput, Input, {
1049 | /**
1050 | * handle mouse and touch events
1051 | * @param {Hammer} manager
1052 | * @param {String} inputEvent
1053 | * @param {Object} inputData
1054 | */
1055 | handler: function TMEhandler(manager, inputEvent, inputData) {
1056 | var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
1057 | isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
1058 |
1059 | // when we're in a touch event, so block all upcoming mouse events
1060 | // most mobile browser also emit mouseevents, right after touchstart
1061 | if (isTouch) {
1062 | this.mouse.allow = false;
1063 | } else if (isMouse && !this.mouse.allow) {
1064 | return;
1065 | }
1066 |
1067 | // reset the allowMouse when we're done
1068 | if (inputEvent & (INPUT_END | INPUT_CANCEL)) {
1069 | this.mouse.allow = true;
1070 | }
1071 |
1072 | this.callback(manager, inputEvent, inputData);
1073 | },
1074 |
1075 | /**
1076 | * remove the event listeners
1077 | */
1078 | destroy: function destroy() {
1079 | this.touch.destroy();
1080 | this.mouse.destroy();
1081 | }
1082 | });
1083 |
1084 | var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
1085 | var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
1086 |
1087 | // magical touchAction value
1088 | var TOUCH_ACTION_COMPUTE = 'compute';
1089 | var TOUCH_ACTION_AUTO = 'auto';
1090 | var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
1091 | var TOUCH_ACTION_NONE = 'none';
1092 | var TOUCH_ACTION_PAN_X = 'pan-x';
1093 | var TOUCH_ACTION_PAN_Y = 'pan-y';
1094 |
1095 | /**
1096 | * Touch Action
1097 | * sets the touchAction property or uses the js alternative
1098 | * @param {Manager} manager
1099 | * @param {String} value
1100 | * @constructor
1101 | */
1102 | function TouchAction(manager, value) {
1103 | this.manager = manager;
1104 | this.set(value);
1105 | }
1106 |
1107 | TouchAction.prototype = {
1108 | /**
1109 | * set the touchAction value on the element or enable the polyfill
1110 | * @param {String} value
1111 | */
1112 | set: function(value) {
1113 | // find out the touch-action by the event handlers
1114 | if (value == TOUCH_ACTION_COMPUTE) {
1115 | value = this.compute();
1116 | }
1117 |
1118 | if (NATIVE_TOUCH_ACTION) {
1119 | this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
1120 | }
1121 | this.actions = value.toLowerCase().trim();
1122 | },
1123 |
1124 | /**
1125 | * just re-set the touchAction value
1126 | */
1127 | update: function() {
1128 | this.set(this.manager.options.touchAction);
1129 | },
1130 |
1131 | /**
1132 | * compute the value for the touchAction property based on the recognizer's settings
1133 | * @returns {String} value
1134 | */
1135 | compute: function() {
1136 | var actions = [];
1137 | each(this.manager.recognizers, function(recognizer) {
1138 | if (boolOrFn(recognizer.options.enable, [recognizer])) {
1139 | actions = actions.concat(recognizer.getTouchAction());
1140 | }
1141 | });
1142 | return cleanTouchActions(actions.join(' '));
1143 | },
1144 |
1145 | /**
1146 | * this method is called on each input cycle and provides the preventing of the browser behavior
1147 | * @param {Object} input
1148 | */
1149 | preventDefaults: function(input) {
1150 | // not needed with native support for the touchAction property
1151 | if (NATIVE_TOUCH_ACTION) {
1152 | return;
1153 | }
1154 |
1155 | var srcEvent = input.srcEvent;
1156 | var direction = input.offsetDirection;
1157 |
1158 | // if the touch action did prevented once this session
1159 | if (this.manager.session.prevented) {
1160 | srcEvent.preventDefault();
1161 | return;
1162 | }
1163 |
1164 | var actions = this.actions;
1165 | var hasNone = inStr(actions, TOUCH_ACTION_NONE);
1166 | var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
1167 | var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
1168 |
1169 | if (hasNone ||
1170 | (hasPanY && direction & DIRECTION_HORIZONTAL) ||
1171 | (hasPanX && direction & DIRECTION_VERTICAL)) {
1172 | return this.preventSrc(srcEvent);
1173 | }
1174 | },
1175 |
1176 | /**
1177 | * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
1178 | * @param {Object} srcEvent
1179 | */
1180 | preventSrc: function(srcEvent) {
1181 | this.manager.session.prevented = true;
1182 | srcEvent.preventDefault();
1183 | }
1184 | };
1185 |
1186 | /**
1187 | * when the touchActions are collected they are not a valid value, so we need to clean things up. *
1188 | * @param {String} actions
1189 | * @returns {*}
1190 | */
1191 | function cleanTouchActions(actions) {
1192 | // none
1193 | if (inStr(actions, TOUCH_ACTION_NONE)) {
1194 | return TOUCH_ACTION_NONE;
1195 | }
1196 |
1197 | var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
1198 | var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
1199 |
1200 | // pan-x and pan-y can be combined
1201 | if (hasPanX && hasPanY) {
1202 | return TOUCH_ACTION_PAN_X + ' ' + TOUCH_ACTION_PAN_Y;
1203 | }
1204 |
1205 | // pan-x OR pan-y
1206 | if (hasPanX || hasPanY) {
1207 | return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
1208 | }
1209 |
1210 | // manipulation
1211 | if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
1212 | return TOUCH_ACTION_MANIPULATION;
1213 | }
1214 |
1215 | return TOUCH_ACTION_AUTO;
1216 | }
1217 |
1218 | /**
1219 | * Recognizer flow explained; *
1220 | * All recognizers have the initial state of POSSIBLE when a input session starts.
1221 | * The definition of a input session is from the first input until the last input, with all it's movement in it. *
1222 | * Example session for mouse-input: mousedown -> mousemove -> mouseup
1223 | *
1224 | * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
1225 | * which determines with state it should be.
1226 | *
1227 | * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
1228 | * POSSIBLE to give it another change on the next cycle.
1229 | *
1230 | * Possible
1231 | * |
1232 | * +-----+---------------+
1233 | * | |
1234 | * +-----+-----+ |
1235 | * | | |
1236 | * Failed Cancelled |
1237 | * +-------+------+
1238 | * | |
1239 | * Recognized Began
1240 | * |
1241 | * Changed
1242 | * |
1243 | * Ended/Recognized
1244 | */
1245 | var STATE_POSSIBLE = 1;
1246 | var STATE_BEGAN = 2;
1247 | var STATE_CHANGED = 4;
1248 | var STATE_ENDED = 8;
1249 | var STATE_RECOGNIZED = STATE_ENDED;
1250 | var STATE_CANCELLED = 16;
1251 | var STATE_FAILED = 32;
1252 |
1253 | /**
1254 | * Recognizer
1255 | * Every recognizer needs to extend from this class.
1256 | * @constructor
1257 | * @param {Object} options
1258 | */
1259 | function Recognizer(options) {
1260 | this.id = uniqueId();
1261 |
1262 | this.manager = null;
1263 | this.options = merge(options || {}, this.defaults);
1264 |
1265 | // default is enable true
1266 | this.options.enable = ifUndefined(this.options.enable, true);
1267 |
1268 | this.state = STATE_POSSIBLE;
1269 |
1270 | this.simultaneous = {};
1271 | this.requireFail = [];
1272 | }
1273 |
1274 | Recognizer.prototype = {
1275 | /**
1276 | * @virtual
1277 | * @type {Object}
1278 | */
1279 | defaults: {},
1280 |
1281 | /**
1282 | * set options
1283 | * @param {Object} options
1284 | * @return {Recognizer}
1285 | */
1286 | set: function(options) {
1287 | extend(this.options, options);
1288 |
1289 | // also update the touchAction, in case something changed about the directions/enabled state
1290 | this.manager && this.manager.touchAction.update();
1291 | return this;
1292 | },
1293 |
1294 | /**
1295 | * recognize simultaneous with an other recognizer.
1296 | * @param {Recognizer} otherRecognizer
1297 | * @returns {Recognizer} this
1298 | */
1299 | recognizeWith: function(otherRecognizer) {
1300 | if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
1301 | return this;
1302 | }
1303 |
1304 | var simultaneous = this.simultaneous;
1305 | otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1306 | if (!simultaneous[otherRecognizer.id]) {
1307 | simultaneous[otherRecognizer.id] = otherRecognizer;
1308 | otherRecognizer.recognizeWith(this);
1309 | }
1310 | return this;
1311 | },
1312 |
1313 | /**
1314 | * drop the simultaneous link. it doesnt remove the link on the other recognizer.
1315 | * @param {Recognizer} otherRecognizer
1316 | * @returns {Recognizer} this
1317 | */
1318 | dropRecognizeWith: function(otherRecognizer) {
1319 | if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
1320 | return this;
1321 | }
1322 |
1323 | otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1324 | delete this.simultaneous[otherRecognizer.id];
1325 | return this;
1326 | },
1327 |
1328 | /**
1329 | * recognizer can only run when an other is failing
1330 | * @param {Recognizer} otherRecognizer
1331 | * @returns {Recognizer} this
1332 | */
1333 | requireFailure: function(otherRecognizer) {
1334 | if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
1335 | return this;
1336 | }
1337 |
1338 | var requireFail = this.requireFail;
1339 | otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1340 | if (inArray(requireFail, otherRecognizer) === -1) {
1341 | requireFail.push(otherRecognizer);
1342 | otherRecognizer.requireFailure(this);
1343 | }
1344 | return this;
1345 | },
1346 |
1347 | /**
1348 | * drop the requireFailure link. it does not remove the link on the other recognizer.
1349 | * @param {Recognizer} otherRecognizer
1350 | * @returns {Recognizer} this
1351 | */
1352 | dropRequireFailure: function(otherRecognizer) {
1353 | if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
1354 | return this;
1355 | }
1356 |
1357 | otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1358 | var index = inArray(this.requireFail, otherRecognizer);
1359 | if (index > -1) {
1360 | this.requireFail.splice(index, 1);
1361 | }
1362 | return this;
1363 | },
1364 |
1365 | /**
1366 | * has require failures boolean
1367 | * @returns {boolean}
1368 | */
1369 | hasRequireFailures: function() {
1370 | return this.requireFail.length > 0;
1371 | },
1372 |
1373 | /**
1374 | * if the recognizer can recognize simultaneous with an other recognizer
1375 | * @param {Recognizer} otherRecognizer
1376 | * @returns {Boolean}
1377 | */
1378 | canRecognizeWith: function(otherRecognizer) {
1379 | return !!this.simultaneous[otherRecognizer.id];
1380 | },
1381 |
1382 | /**
1383 | * You should use `tryEmit` instead of `emit` directly to check
1384 | * that all the needed recognizers has failed before emitting.
1385 | * @param {Object} input
1386 | */
1387 | emit: function(input) {
1388 | var self = this;
1389 | var state = this.state;
1390 |
1391 | function emit(withState) {
1392 | self.manager.emit(self.options.event + (withState ? stateStr(state) : ''), input);
1393 | }
1394 |
1395 | // 'panstart' and 'panmove'
1396 | if (state < STATE_ENDED) {
1397 | emit(true);
1398 | }
1399 |
1400 | emit(); // simple 'eventName' events
1401 |
1402 | // panend and pancancel
1403 | if (state >= STATE_ENDED) {
1404 | emit(true);
1405 | }
1406 | },
1407 |
1408 | /**
1409 | * Check that all the require failure recognizers has failed,
1410 | * if true, it emits a gesture event,
1411 | * otherwise, setup the state to FAILED.
1412 | * @param {Object} input
1413 | */
1414 | tryEmit: function(input) {
1415 | if (this.canEmit()) {
1416 | return this.emit(input);
1417 | }
1418 | // it's failing anyway
1419 | this.state = STATE_FAILED;
1420 | },
1421 |
1422 | /**
1423 | * can we emit?
1424 | * @returns {boolean}
1425 | */
1426 | canEmit: function() {
1427 | var i = 0;
1428 | while (i < this.requireFail.length) {
1429 | if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
1430 | return false;
1431 | }
1432 | i++;
1433 | }
1434 | return true;
1435 | },
1436 |
1437 | /**
1438 | * update the recognizer
1439 | * @param {Object} inputData
1440 | */
1441 | recognize: function(inputData) {
1442 | // make a new copy of the inputData
1443 | // so we can change the inputData without messing up the other recognizers
1444 | var inputDataClone = extend({}, inputData);
1445 |
1446 | // is is enabled and allow recognizing?
1447 | if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
1448 | this.reset();
1449 | this.state = STATE_FAILED;
1450 | return;
1451 | }
1452 |
1453 | // reset when we've reached the end
1454 | if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
1455 | this.state = STATE_POSSIBLE;
1456 | }
1457 |
1458 | this.state = this.process(inputDataClone);
1459 |
1460 | // the recognizer has recognized a gesture
1461 | // so trigger an event
1462 | if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
1463 | this.tryEmit(inputDataClone);
1464 | }
1465 | },
1466 |
1467 | /**
1468 | * return the state of the recognizer
1469 | * the actual recognizing happens in this method
1470 | * @virtual
1471 | * @param {Object} inputData
1472 | * @returns {Const} STATE
1473 | */
1474 | process: function(inputData) { }, // jshint ignore:line
1475 |
1476 | /**
1477 | * return the preferred touch-action
1478 | * @virtual
1479 | * @returns {Array}
1480 | */
1481 | getTouchAction: function() { },
1482 |
1483 | /**
1484 | * called when the gesture isn't allowed to recognize
1485 | * like when another is being recognized or it is disabled
1486 | * @virtual
1487 | */
1488 | reset: function() { }
1489 | };
1490 |
1491 | /**
1492 | * get a usable string, used as event postfix
1493 | * @param {Const} state
1494 | * @returns {String} state
1495 | */
1496 | function stateStr(state) {
1497 | if (state & STATE_CANCELLED) {
1498 | return 'cancel';
1499 | } else if (state & STATE_ENDED) {
1500 | return 'end';
1501 | } else if (state & STATE_CHANGED) {
1502 | return 'move';
1503 | } else if (state & STATE_BEGAN) {
1504 | return 'start';
1505 | }
1506 | return '';
1507 | }
1508 |
1509 | /**
1510 | * direction cons to string
1511 | * @param {Const} direction
1512 | * @returns {String}
1513 | */
1514 | function directionStr(direction) {
1515 | if (direction == DIRECTION_DOWN) {
1516 | return 'down';
1517 | } else if (direction == DIRECTION_UP) {
1518 | return 'up';
1519 | } else if (direction == DIRECTION_LEFT) {
1520 | return 'left';
1521 | } else if (direction == DIRECTION_RIGHT) {
1522 | return 'right';
1523 | }
1524 | return '';
1525 | }
1526 |
1527 | /**
1528 | * get a recognizer by name if it is bound to a manager
1529 | * @param {Recognizer|String} otherRecognizer
1530 | * @param {Recognizer} recognizer
1531 | * @returns {Recognizer}
1532 | */
1533 | function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
1534 | var manager = recognizer.manager;
1535 | if (manager) {
1536 | return manager.get(otherRecognizer);
1537 | }
1538 | return otherRecognizer;
1539 | }
1540 |
1541 | /**
1542 | * This recognizer is just used as a base for the simple attribute recognizers.
1543 | * @constructor
1544 | * @extends Recognizer
1545 | */
1546 | function AttrRecognizer() {
1547 | Recognizer.apply(this, arguments);
1548 | }
1549 |
1550 | inherit(AttrRecognizer, Recognizer, {
1551 | /**
1552 | * @namespace
1553 | * @memberof AttrRecognizer
1554 | */
1555 | defaults: {
1556 | /**
1557 | * @type {Number}
1558 | * @default 1
1559 | */
1560 | pointers: 1
1561 | },
1562 |
1563 | /**
1564 | * Used to check if it the recognizer receives valid input, like input.distance > 10.
1565 | * @memberof AttrRecognizer
1566 | * @param {Object} input
1567 | * @returns {Boolean} recognized
1568 | */
1569 | attrTest: function(input) {
1570 | var optionPointers = this.options.pointers;
1571 | return optionPointers === 0 || input.pointers.length === optionPointers;
1572 | },
1573 |
1574 | /**
1575 | * Process the input and return the state for the recognizer
1576 | * @memberof AttrRecognizer
1577 | * @param {Object} input
1578 | * @returns {*} State
1579 | */
1580 | process: function(input) {
1581 | var state = this.state;
1582 | var eventType = input.eventType;
1583 |
1584 | var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
1585 | var isValid = this.attrTest(input);
1586 |
1587 | // on cancel input and we've recognized before, return STATE_CANCELLED
1588 | if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
1589 | return state | STATE_CANCELLED;
1590 | } else if (isRecognized || isValid) {
1591 | if (eventType & INPUT_END) {
1592 | return state | STATE_ENDED;
1593 | } else if (!(state & STATE_BEGAN)) {
1594 | return STATE_BEGAN;
1595 | }
1596 | return state | STATE_CHANGED;
1597 | }
1598 | return STATE_FAILED;
1599 | }
1600 | });
1601 |
1602 | /**
1603 | * Pan
1604 | * Recognized when the pointer is down and moved in the allowed direction.
1605 | * @constructor
1606 | * @extends AttrRecognizer
1607 | */
1608 | function PanRecognizer() {
1609 | AttrRecognizer.apply(this, arguments);
1610 |
1611 | this.pX = null;
1612 | this.pY = null;
1613 | }
1614 |
1615 | inherit(PanRecognizer, AttrRecognizer, {
1616 | /**
1617 | * @namespace
1618 | * @memberof PanRecognizer
1619 | */
1620 | defaults: {
1621 | event: 'pan',
1622 | threshold: 10,
1623 | pointers: 1,
1624 | direction: DIRECTION_ALL
1625 | },
1626 |
1627 | getTouchAction: function() {
1628 | var direction = this.options.direction;
1629 | var actions = [];
1630 | if (direction & DIRECTION_HORIZONTAL) {
1631 | actions.push(TOUCH_ACTION_PAN_Y);
1632 | }
1633 | if (direction & DIRECTION_VERTICAL) {
1634 | actions.push(TOUCH_ACTION_PAN_X);
1635 | }
1636 | return actions;
1637 | },
1638 |
1639 | directionTest: function(input) {
1640 | var options = this.options;
1641 | var hasMoved = true;
1642 | var distance = input.distance;
1643 | var direction = input.direction;
1644 | var x = input.deltaX;
1645 | var y = input.deltaY;
1646 |
1647 | // lock to axis?
1648 | if (!(direction & options.direction)) {
1649 | if (options.direction & DIRECTION_HORIZONTAL) {
1650 | direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
1651 | hasMoved = x != this.pX;
1652 | distance = Math.abs(input.deltaX);
1653 | } else {
1654 | direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
1655 | hasMoved = y != this.pY;
1656 | distance = Math.abs(input.deltaY);
1657 | }
1658 | }
1659 | input.direction = direction;
1660 | return hasMoved && distance > options.threshold && direction & options.direction;
1661 | },
1662 |
1663 | attrTest: function(input) {
1664 | return AttrRecognizer.prototype.attrTest.call(this, input) &&
1665 | (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
1666 | },
1667 |
1668 | emit: function(input) {
1669 | this.pX = input.deltaX;
1670 | this.pY = input.deltaY;
1671 |
1672 | var direction = directionStr(input.direction);
1673 | if (direction) {
1674 | this.manager.emit(this.options.event + direction, input);
1675 | }
1676 |
1677 | this._super.emit.call(this, input);
1678 | }
1679 | });
1680 |
1681 | /**
1682 | * Pinch
1683 | * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
1684 | * @constructor
1685 | * @extends AttrRecognizer
1686 | */
1687 | function PinchRecognizer() {
1688 | AttrRecognizer.apply(this, arguments);
1689 | }
1690 |
1691 | inherit(PinchRecognizer, AttrRecognizer, {
1692 | /**
1693 | * @namespace
1694 | * @memberof PinchRecognizer
1695 | */
1696 | defaults: {
1697 | event: 'pinch',
1698 | threshold: 0,
1699 | pointers: 2
1700 | },
1701 |
1702 | getTouchAction: function() {
1703 | return [TOUCH_ACTION_NONE];
1704 | },
1705 |
1706 | attrTest: function(input) {
1707 | return this._super.attrTest.call(this, input) &&
1708 | (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
1709 | },
1710 |
1711 | emit: function(input) {
1712 | this._super.emit.call(this, input);
1713 | if (input.scale !== 1) {
1714 | var inOut = input.scale < 1 ? 'in' : 'out';
1715 | this.manager.emit(this.options.event + inOut, input);
1716 | }
1717 | }
1718 | });
1719 |
1720 | /**
1721 | * Press
1722 | * Recognized when the pointer is down for x ms without any movement.
1723 | * @constructor
1724 | * @extends Recognizer
1725 | */
1726 | function PressRecognizer() {
1727 | Recognizer.apply(this, arguments);
1728 |
1729 | this._timer = null;
1730 | this._input = null;
1731 | }
1732 |
1733 | inherit(PressRecognizer, Recognizer, {
1734 | /**
1735 | * @namespace
1736 | * @memberof PressRecognizer
1737 | */
1738 | defaults: {
1739 | event: 'press',
1740 | pointers: 1,
1741 | time: 500, // minimal time of the pointer to be pressed
1742 | threshold: 5 // a minimal movement is ok, but keep it low
1743 | },
1744 |
1745 | getTouchAction: function() {
1746 | return [TOUCH_ACTION_AUTO];
1747 | },
1748 |
1749 | process: function(input) {
1750 | var options = this.options;
1751 | var validPointers = input.pointers.length === options.pointers;
1752 | var validMovement = input.distance < options.threshold;
1753 | var validTime = input.deltaTime > options.time;
1754 |
1755 | this._input = input;
1756 |
1757 | // we only allow little movement
1758 | // and we've reached an end event, so a tap is possible
1759 | if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
1760 | this.reset();
1761 | } else if (input.eventType & INPUT_START) {
1762 | this.reset();
1763 | this._timer = setTimeoutContext(function() {
1764 | this.state = STATE_RECOGNIZED;
1765 | this.tryEmit();
1766 | }, options.time, this);
1767 | } else if (input.eventType & INPUT_END) {
1768 | return STATE_RECOGNIZED;
1769 | }
1770 | return STATE_FAILED;
1771 | },
1772 |
1773 | reset: function() {
1774 | clearTimeout(this._timer);
1775 | },
1776 |
1777 | emit: function(input) {
1778 | if (this.state !== STATE_RECOGNIZED) {
1779 | return;
1780 | }
1781 |
1782 | if (input && (input.eventType & INPUT_END)) {
1783 | this.manager.emit(this.options.event + 'up', input);
1784 | } else {
1785 | this._input.timeStamp = now();
1786 | this.manager.emit(this.options.event, this._input);
1787 | }
1788 | }
1789 | });
1790 |
1791 | /**
1792 | * Rotate
1793 | * Recognized when two or more pointer are moving in a circular motion.
1794 | * @constructor
1795 | * @extends AttrRecognizer
1796 | */
1797 | function RotateRecognizer() {
1798 | AttrRecognizer.apply(this, arguments);
1799 | }
1800 |
1801 | inherit(RotateRecognizer, AttrRecognizer, {
1802 | /**
1803 | * @namespace
1804 | * @memberof RotateRecognizer
1805 | */
1806 | defaults: {
1807 | event: 'rotate',
1808 | threshold: 0,
1809 | pointers: 2
1810 | },
1811 |
1812 | getTouchAction: function() {
1813 | return [TOUCH_ACTION_NONE];
1814 | },
1815 |
1816 | attrTest: function(input) {
1817 | return this._super.attrTest.call(this, input) &&
1818 | (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
1819 | }
1820 | });
1821 |
1822 | /**
1823 | * Swipe
1824 | * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
1825 | * @constructor
1826 | * @extends AttrRecognizer
1827 | */
1828 | function SwipeRecognizer() {
1829 | AttrRecognizer.apply(this, arguments);
1830 | }
1831 |
1832 | inherit(SwipeRecognizer, AttrRecognizer, {
1833 | /**
1834 | * @namespace
1835 | * @memberof SwipeRecognizer
1836 | */
1837 | defaults: {
1838 | event: 'swipe',
1839 | threshold: 10,
1840 | velocity: 0.65,
1841 | direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
1842 | pointers: 1
1843 | },
1844 |
1845 | getTouchAction: function() {
1846 | return PanRecognizer.prototype.getTouchAction.call(this);
1847 | },
1848 |
1849 | attrTest: function(input) {
1850 | var direction = this.options.direction;
1851 | var velocity;
1852 |
1853 | if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
1854 | velocity = input.velocity;
1855 | } else if (direction & DIRECTION_HORIZONTAL) {
1856 | velocity = input.velocityX;
1857 | } else if (direction & DIRECTION_VERTICAL) {
1858 | velocity = input.velocityY;
1859 | }
1860 |
1861 | return this._super.attrTest.call(this, input) &&
1862 | direction & input.direction &&
1863 | input.distance > this.options.threshold &&
1864 | abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
1865 | },
1866 |
1867 | emit: function(input) {
1868 | var direction = directionStr(input.direction);
1869 | if (direction) {
1870 | this.manager.emit(this.options.event + direction, input);
1871 | }
1872 |
1873 | this.manager.emit(this.options.event, input);
1874 | }
1875 | });
1876 |
1877 | /**
1878 | * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
1879 | * between the given interval and position. The delay option can be used to recognize multi-taps without firing
1880 | * a single tap.
1881 | *
1882 | * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
1883 | * multi-taps being recognized.
1884 | * @constructor
1885 | * @extends Recognizer
1886 | */
1887 | function TapRecognizer() {
1888 | Recognizer.apply(this, arguments);
1889 |
1890 | // previous time and center,
1891 | // used for tap counting
1892 | this.pTime = false;
1893 | this.pCenter = false;
1894 |
1895 | this._timer = null;
1896 | this._input = null;
1897 | this.count = 0;
1898 | }
1899 |
1900 | inherit(TapRecognizer, Recognizer, {
1901 | /**
1902 | * @namespace
1903 | * @memberof PinchRecognizer
1904 | */
1905 | defaults: {
1906 | event: 'tap',
1907 | pointers: 1,
1908 | taps: 1,
1909 | interval: 300, // max time between the multi-tap taps
1910 | time: 250, // max time of the pointer to be down (like finger on the screen)
1911 | threshold: 2, // a minimal movement is ok, but keep it low
1912 | posThreshold: 10 // a multi-tap can be a bit off the initial position
1913 | },
1914 |
1915 | getTouchAction: function() {
1916 | return [TOUCH_ACTION_MANIPULATION];
1917 | },
1918 |
1919 | process: function(input) {
1920 | var options = this.options;
1921 |
1922 | var validPointers = input.pointers.length === options.pointers;
1923 | var validMovement = input.distance < options.threshold;
1924 | var validTouchTime = input.deltaTime < options.time;
1925 |
1926 | this.reset();
1927 |
1928 | if ((input.eventType & INPUT_START) && (this.count === 0)) {
1929 | return this.failTimeout();
1930 | }
1931 |
1932 | // we only allow little movement
1933 | // and we've reached an end event, so a tap is possible
1934 | if (validMovement && validTouchTime && validPointers) {
1935 | if (input.eventType != INPUT_END) {
1936 | return this.failTimeout();
1937 | }
1938 |
1939 | var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
1940 | var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
1941 |
1942 | this.pTime = input.timeStamp;
1943 | this.pCenter = input.center;
1944 |
1945 | if (!validMultiTap || !validInterval) {
1946 | this.count = 1;
1947 | } else {
1948 | this.count += 1;
1949 | }
1950 |
1951 | this._input = input;
1952 |
1953 | // if tap count matches we have recognized it,
1954 | // else it has began recognizing...
1955 | var tapCount = this.count % options.taps;
1956 | if (tapCount === 0) {
1957 | // no failing requirements, immediately trigger the tap event
1958 | // or wait as long as the multitap interval to trigger
1959 | if (!this.hasRequireFailures()) {
1960 | return STATE_RECOGNIZED;
1961 | } else {
1962 | this._timer = setTimeoutContext(function() {
1963 | this.state = STATE_RECOGNIZED;
1964 | this.tryEmit();
1965 | }, options.interval, this);
1966 | return STATE_BEGAN;
1967 | }
1968 | }
1969 | }
1970 | return STATE_FAILED;
1971 | },
1972 |
1973 | failTimeout: function() {
1974 | this._timer = setTimeoutContext(function() {
1975 | this.state = STATE_FAILED;
1976 | }, this.options.interval, this);
1977 | return STATE_FAILED;
1978 | },
1979 |
1980 | reset: function() {
1981 | clearTimeout(this._timer);
1982 | },
1983 |
1984 | emit: function() {
1985 | if (this.state == STATE_RECOGNIZED ) {
1986 | this._input.tapCount = this.count;
1987 | this.manager.emit(this.options.event, this._input);
1988 | }
1989 | }
1990 | });
1991 |
1992 | /**
1993 | * Simple way to create an manager with a default set of recognizers.
1994 | * @param {HTMLElement} element
1995 | * @param {Object} [options]
1996 | * @constructor
1997 | */
1998 | function Hammer(element, options) {
1999 | options = options || {};
2000 | options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
2001 | return new Manager(element, options);
2002 | }
2003 |
2004 | /**
2005 | * @const {string}
2006 | */
2007 | Hammer.VERSION = '2.0.4';
2008 |
2009 | /**
2010 | * default settings
2011 | * @namespace
2012 | */
2013 | Hammer.defaults = {
2014 | /**
2015 | * set if DOM events are being triggered.
2016 | * But this is slower and unused by simple implementations, so disabled by default.
2017 | * @type {Boolean}
2018 | * @default false
2019 | */
2020 | domEvents: false,
2021 |
2022 | /**
2023 | * The value for the touchAction property/fallback.
2024 | * When set to `compute` it will magically set the correct value based on the added recognizers.
2025 | * @type {String}
2026 | * @default compute
2027 | */
2028 | touchAction: TOUCH_ACTION_COMPUTE,
2029 |
2030 | /**
2031 | * @type {Boolean}
2032 | * @default true
2033 | */
2034 | enable: true,
2035 |
2036 | /**
2037 | * EXPERIMENTAL FEATURE -- can be removed/changed
2038 | * Change the parent input target element.
2039 | * If Null, then it is being set the to main element.
2040 | * @type {Null|EventTarget}
2041 | * @default null
2042 | */
2043 | inputTarget: null,
2044 |
2045 | /**
2046 | * force an input class
2047 | * @type {Null|Function}
2048 | * @default null
2049 | */
2050 | inputClass: null,
2051 |
2052 | /**
2053 | * Default recognizer setup when calling `Hammer()`
2054 | * When creating a new Manager these will be skipped.
2055 | * @type {Array}
2056 | */
2057 | preset: [
2058 | // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
2059 | [RotateRecognizer, { enable: false }],
2060 | [PinchRecognizer, { enable: false }, ['rotate']],
2061 | [SwipeRecognizer,{ direction: DIRECTION_HORIZONTAL }],
2062 | [PanRecognizer, { direction: DIRECTION_HORIZONTAL }, ['swipe']],
2063 | [TapRecognizer],
2064 | [TapRecognizer, { event: 'doubletap', taps: 2 }, ['tap']],
2065 | [PressRecognizer]
2066 | ],
2067 |
2068 | /**
2069 | * Some CSS properties can be used to improve the working of Hammer.
2070 | * Add them to this method and they will be set when creating a new Manager.
2071 | * @namespace
2072 | */
2073 | cssProps: {
2074 | /**
2075 | * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
2076 | * @type {String}
2077 | * @default 'none'
2078 | */
2079 | userSelect: 'none',
2080 |
2081 | /**
2082 | * Disable the Windows Phone grippers when pressing an element.
2083 | * @type {String}
2084 | * @default 'none'
2085 | */
2086 | touchSelect: 'none',
2087 |
2088 | /**
2089 | * Disables the default callout shown when you touch and hold a touch target.
2090 | * On iOS, when you touch and hold a touch target such as a link, Safari displays
2091 | * a callout containing information about the link. This property allows you to disable that callout.
2092 | * @type {String}
2093 | * @default 'none'
2094 | */
2095 | touchCallout: 'none',
2096 |
2097 | /**
2098 | * Specifies whether zooming is enabled. Used by IE10>
2099 | * @type {String}
2100 | * @default 'none'
2101 | */
2102 | contentZooming: 'none',
2103 |
2104 | /**
2105 | * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
2106 | * @type {String}
2107 | * @default 'none'
2108 | */
2109 | userDrag: 'none',
2110 |
2111 | /**
2112 | * Overrides the highlight color shown when the user taps a link or a JavaScript
2113 | * clickable element in iOS. This property obeys the alpha value, if specified.
2114 | * @type {String}
2115 | * @default 'rgba(0,0,0,0)'
2116 | */
2117 | tapHighlightColor: 'rgba(0,0,0,0)'
2118 | }
2119 | };
2120 |
2121 | var STOP = 1;
2122 | var FORCED_STOP = 2;
2123 |
2124 | /**
2125 | * Manager
2126 | * @param {HTMLElement} element
2127 | * @param {Object} [options]
2128 | * @constructor
2129 | */
2130 | function Manager(element, options) {
2131 | options = options || {};
2132 |
2133 | this.options = merge(options, Hammer.defaults);
2134 | this.options.inputTarget = this.options.inputTarget || element;
2135 |
2136 | this.handlers = {};
2137 | this.session = {};
2138 | this.recognizers = [];
2139 |
2140 | this.element = element;
2141 | this.input = createInputInstance(this);
2142 | this.touchAction = new TouchAction(this, this.options.touchAction);
2143 |
2144 | toggleCssProps(this, true);
2145 |
2146 | each(options.recognizers, function(item) {
2147 | var recognizer = this.add(new (item[0])(item[1]));
2148 | item[2] && recognizer.recognizeWith(item[2]);
2149 | item[3] && recognizer.requireFailure(item[3]);
2150 | }, this);
2151 | }
2152 |
2153 | Manager.prototype = {
2154 | /**
2155 | * set options
2156 | * @param {Object} options
2157 | * @returns {Manager}
2158 | */
2159 | set: function(options) {
2160 | extend(this.options, options);
2161 |
2162 | // Options that need a little more setup
2163 | if (options.touchAction) {
2164 | this.touchAction.update();
2165 | }
2166 | if (options.inputTarget) {
2167 | // Clean up existing event listeners and reinitialize
2168 | this.input.destroy();
2169 | this.input.target = options.inputTarget;
2170 | this.input.init();
2171 | }
2172 | return this;
2173 | },
2174 |
2175 | /**
2176 | * stop recognizing for this session.
2177 | * This session will be discarded, when a new [input]start event is fired.
2178 | * When forced, the recognizer cycle is stopped immediately.
2179 | * @param {Boolean} [force]
2180 | */
2181 | stop: function(force) {
2182 | this.session.stopped = force ? FORCED_STOP : STOP;
2183 | },
2184 |
2185 | /**
2186 | * run the recognizers!
2187 | * called by the inputHandler function on every movement of the pointers (touches)
2188 | * it walks through all the recognizers and tries to detect the gesture that is being made
2189 | * @param {Object} inputData
2190 | */
2191 | recognize: function(inputData) {
2192 | var session = this.session;
2193 | if (session.stopped) {
2194 | return;
2195 | }
2196 |
2197 | // run the touch-action polyfill
2198 | this.touchAction.preventDefaults(inputData);
2199 |
2200 | var recognizer;
2201 | var recognizers = this.recognizers;
2202 |
2203 | // this holds the recognizer that is being recognized.
2204 | // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
2205 | // if no recognizer is detecting a thing, it is set to `null`
2206 | var curRecognizer = session.curRecognizer;
2207 |
2208 | // reset when the last recognizer is recognized
2209 | // or when we're in a new session
2210 | if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
2211 | curRecognizer = session.curRecognizer = null;
2212 | }
2213 |
2214 | var i = 0;
2215 | while (i < recognizers.length) {
2216 | recognizer = recognizers[i];
2217 |
2218 | // find out if we are allowed try to recognize the input for this one.
2219 | // 1. allow if the session is NOT forced stopped (see the .stop() method)
2220 | // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
2221 | // that is being recognized.
2222 | // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
2223 | // this can be setup with the `recognizeWith()` method on the recognizer.
2224 | if (session.stopped !== FORCED_STOP && ( // 1
2225 | !curRecognizer || recognizer == curRecognizer || // 2
2226 | recognizer.canRecognizeWith(curRecognizer))) { // 3
2227 | recognizer.recognize(inputData);
2228 | } else {
2229 | recognizer.reset();
2230 | }
2231 |
2232 | // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
2233 | // current active recognizer. but only if we don't already have an active recognizer
2234 | if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
2235 | curRecognizer = session.curRecognizer = recognizer;
2236 | }
2237 | i++;
2238 | }
2239 | },
2240 |
2241 | /**
2242 | * get a recognizer by its event name.
2243 | * @param {Recognizer|String} recognizer
2244 | * @returns {Recognizer|Null}
2245 | */
2246 | get: function(recognizer) {
2247 | if (recognizer instanceof Recognizer) {
2248 | return recognizer;
2249 | }
2250 |
2251 | var recognizers = this.recognizers;
2252 | for (var i = 0; i < recognizers.length; i++) {
2253 | if (recognizers[i].options.event == recognizer) {
2254 | return recognizers[i];
2255 | }
2256 | }
2257 | return null;
2258 | },
2259 |
2260 | /**
2261 | * add a recognizer to the manager
2262 | * existing recognizers with the same event name will be removed
2263 | * @param {Recognizer} recognizer
2264 | * @returns {Recognizer|Manager}
2265 | */
2266 | add: function(recognizer) {
2267 | if (invokeArrayArg(recognizer, 'add', this)) {
2268 | return this;
2269 | }
2270 |
2271 | // remove existing
2272 | var existing = this.get(recognizer.options.event);
2273 | if (existing) {
2274 | this.remove(existing);
2275 | }
2276 |
2277 | this.recognizers.push(recognizer);
2278 | recognizer.manager = this;
2279 |
2280 | this.touchAction.update();
2281 | return recognizer;
2282 | },
2283 |
2284 | /**
2285 | * remove a recognizer by name or instance
2286 | * @param {Recognizer|String} recognizer
2287 | * @returns {Manager}
2288 | */
2289 | remove: function(recognizer) {
2290 | if (invokeArrayArg(recognizer, 'remove', this)) {
2291 | return this;
2292 | }
2293 |
2294 | var recognizers = this.recognizers;
2295 | recognizer = this.get(recognizer);
2296 | recognizers.splice(inArray(recognizers, recognizer), 1);
2297 |
2298 | this.touchAction.update();
2299 | return this;
2300 | },
2301 |
2302 | /**
2303 | * bind event
2304 | * @param {String} events
2305 | * @param {Function} handler
2306 | * @returns {EventEmitter} this
2307 | */
2308 | on: function(events, handler) {
2309 | var handlers = this.handlers;
2310 | each(splitStr(events), function(event) {
2311 | handlers[event] = handlers[event] || [];
2312 | handlers[event].push(handler);
2313 | });
2314 | return this;
2315 | },
2316 |
2317 | /**
2318 | * unbind event, leave emit blank to remove all handlers
2319 | * @param {String} events
2320 | * @param {Function} [handler]
2321 | * @returns {EventEmitter} this
2322 | */
2323 | off: function(events, handler) {
2324 | var handlers = this.handlers;
2325 | each(splitStr(events), function(event) {
2326 | if (!handler) {
2327 | delete handlers[event];
2328 | } else {
2329 | handlers[event].splice(inArray(handlers[event], handler), 1);
2330 | }
2331 | });
2332 | return this;
2333 | },
2334 |
2335 | /**
2336 | * emit event to the listeners
2337 | * @param {String} event
2338 | * @param {Object} data
2339 | */
2340 | emit: function(event, data) {
2341 | // we also want to trigger dom events
2342 | if (this.options.domEvents) {
2343 | triggerDomEvent(event, data);
2344 | }
2345 |
2346 | // no handlers, so skip it all
2347 | var handlers = this.handlers[event] && this.handlers[event].slice();
2348 | if (!handlers || !handlers.length) {
2349 | return;
2350 | }
2351 |
2352 | data.type = event;
2353 | data.preventDefault = function() {
2354 | data.srcEvent.preventDefault();
2355 | };
2356 |
2357 | var i = 0;
2358 | while (i < handlers.length) {
2359 | handlers[i](data);
2360 | i++;
2361 | }
2362 | },
2363 |
2364 | /**
2365 | * destroy the manager and unbinds all events
2366 | * it doesn't unbind dom events, that is the user own responsibility
2367 | */
2368 | destroy: function() {
2369 | this.element && toggleCssProps(this, false);
2370 |
2371 | this.handlers = {};
2372 | this.session = {};
2373 | this.input.destroy();
2374 | this.element = null;
2375 | }
2376 | };
2377 |
2378 | /**
2379 | * add/remove the css properties as defined in manager.options.cssProps
2380 | * @param {Manager} manager
2381 | * @param {Boolean} add
2382 | */
2383 | function toggleCssProps(manager, add) {
2384 | var element = manager.element;
2385 | each(manager.options.cssProps, function(value, name) {
2386 | element.style[prefixed(element.style, name)] = add ? value : '';
2387 | });
2388 | }
2389 |
2390 | /**
2391 | * trigger dom event
2392 | * @param {String} event
2393 | * @param {Object} data
2394 | */
2395 | function triggerDomEvent(event, data) {
2396 | var gestureEvent = document.createEvent('Event');
2397 | gestureEvent.initEvent(event, true, true);
2398 | gestureEvent.gesture = data;
2399 | data.target.dispatchEvent(gestureEvent);
2400 | }
2401 |
2402 | extend(Hammer, {
2403 | INPUT_START: INPUT_START,
2404 | INPUT_MOVE: INPUT_MOVE,
2405 | INPUT_END: INPUT_END,
2406 | INPUT_CANCEL: INPUT_CANCEL,
2407 |
2408 | STATE_POSSIBLE: STATE_POSSIBLE,
2409 | STATE_BEGAN: STATE_BEGAN,
2410 | STATE_CHANGED: STATE_CHANGED,
2411 | STATE_ENDED: STATE_ENDED,
2412 | STATE_RECOGNIZED: STATE_RECOGNIZED,
2413 | STATE_CANCELLED: STATE_CANCELLED,
2414 | STATE_FAILED: STATE_FAILED,
2415 |
2416 | DIRECTION_NONE: DIRECTION_NONE,
2417 | DIRECTION_LEFT: DIRECTION_LEFT,
2418 | DIRECTION_RIGHT: DIRECTION_RIGHT,
2419 | DIRECTION_UP: DIRECTION_UP,
2420 | DIRECTION_DOWN: DIRECTION_DOWN,
2421 | DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
2422 | DIRECTION_VERTICAL: DIRECTION_VERTICAL,
2423 | DIRECTION_ALL: DIRECTION_ALL,
2424 |
2425 | Manager: Manager,
2426 | Input: Input,
2427 | TouchAction: TouchAction,
2428 |
2429 | TouchInput: TouchInput,
2430 | MouseInput: MouseInput,
2431 | PointerEventInput: PointerEventInput,
2432 | TouchMouseInput: TouchMouseInput,
2433 | SingleTouchInput: SingleTouchInput,
2434 |
2435 | Recognizer: Recognizer,
2436 | AttrRecognizer: AttrRecognizer,
2437 | Tap: TapRecognizer,
2438 | Pan: PanRecognizer,
2439 | Swipe: SwipeRecognizer,
2440 | Pinch: PinchRecognizer,
2441 | Rotate: RotateRecognizer,
2442 | Press: PressRecognizer,
2443 |
2444 | on: addEventListeners,
2445 | off: removeEventListeners,
2446 | each: each,
2447 | merge: merge,
2448 | extend: extend,
2449 | inherit: inherit,
2450 | bindFn: bindFn,
2451 | prefixed: prefixed
2452 | });
2453 |
2454 | if (typeof define == TYPE_FUNCTION && define.amd) {
2455 | define(function() {
2456 | return Hammer;
2457 | });
2458 | } else if (typeof module != 'undefined' && module.exports) {
2459 | module.exports = Hammer;
2460 | } else {
2461 | window[exportName] = Hammer;
2462 | }
2463 |
2464 | })(window, document, 'Hammer');
2465 |
2466 | },{}],2:[function(require,module,exports){
2467 | /**
2468 | * @fileoverview Hammer driver for Cycle.js
2469 | * @author Frederik Krautwald
2470 | * @copyright 2015 Cyclic Materials. All rights reserved.
2471 | */
2472 |
2473 | 'use strict';
2474 |
2475 | Object.defineProperty(exports, '__esModule', {
2476 | value: true
2477 | });
2478 |
2479 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
2480 |
2481 | var _makeHammerDriver = require('./makeHammerDriver');
2482 |
2483 | var _makeHammerDriver2 = _interopRequireDefault(_makeHammerDriver);
2484 |
2485 | var CycleHammer = {
2486 | /**
2487 | * A factory for the Hammer driver function. Takes a DOM driver function that
2488 | * adheres to the interface established by the Cycle.js DOM driver.
2489 | * The output (source) of this driver mimics the DOM driver as a collection
2490 | * of Observables queried with: `DOM.select(selector).events(eventType)`.
2491 | * In addition, when listening for hammer.js `eventTypes`, the `events()`
2492 | * function allows you to specify an optional callback:
2493 | * `DOM.select(selector).events(eventType, callback)`.
2494 | * The `callback` takes two arguments:
2495 | *
2496 | * - **manager** `{Object}` The `Hammer.Manager` instance for the element.
2497 | * - **Hammer** `{Object}` The Hammer API.
2498 | *
2499 | * @param {Function} domDriverFunc the DOM driver function.
2500 | * @return {Function} the Hammer driver function. The function expects an
2501 | * Observable of VTree as input, and outputs the source object for this
2502 | * driver, containing functions `select()` and `dispose()` that can be used
2503 | * for debugging and testing.
2504 | * @function makeDOMDriver
2505 | */
2506 | makeHammerDriver: _makeHammerDriver2['default']
2507 | };
2508 |
2509 | exports['default'] = CycleHammer;
2510 | module.exports = exports['default'];
2511 |
2512 | },{"./makeHammerDriver":5}],3:[function(require,module,exports){
2513 | (function (global){
2514 | /**
2515 | * @fileoverview Observable from Hammer Event
2516 | * @author Frederik Krautwald
2517 | * @copyright 2015 Frederik Krautwald. All rights reserved.
2518 | */
2519 |
2520 | 'use strict';
2521 |
2522 | Object.defineProperty(exports, '__esModule', {
2523 | value: true
2524 | });
2525 |
2526 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
2527 |
2528 | var _rx = (typeof window !== "undefined" ? window['Rx'] : typeof global !== "undefined" ? global['Rx'] : null);
2529 |
2530 | var _hammerjs = require('hammerjs');
2531 |
2532 | var _hammerjs2 = _interopRequireDefault(_hammerjs);
2533 |
2534 | var hammers = {};
2535 |
2536 | function createListener(_ref) {
2537 | var element = _ref.element;
2538 | var eventType = _ref.eventType;
2539 | var handler = _ref.handler;
2540 | var k = _ref.k;
2541 | var _ref$callback = _ref.callback;
2542 | var callback = _ref$callback === undefined ? function () {} : _ref$callback;
2543 |
2544 | if (typeof hammers[k] !== 'object') {
2545 | hammers[k] = new _hammerjs2['default'].Manager(element);
2546 | }
2547 | var hammer = hammers[k];
2548 | callback(hammer, _hammerjs2['default']);
2549 | hammer.on(eventType, handler);
2550 | }
2551 |
2552 | function createEventListener(_ref2) {
2553 | var element = _ref2.element;
2554 | var eventType = _ref2.eventType;
2555 | var handler = _ref2.handler;
2556 | var k = _ref2.k;
2557 | var callback = _ref2.callback;
2558 |
2559 | if (Array.isArray(element)) {
2560 | for (var i = 0, len = element.length; i < len; i++) {
2561 | createEventListener({
2562 | element: element[i],
2563 | eventType: eventType,
2564 | handler: handler,
2565 | k: k,
2566 | callback: callback
2567 | });
2568 | }
2569 | } else if (element) {
2570 | createListener({ element: element, eventType: eventType, handler: handler, k: k, callback: callback });
2571 | }
2572 | }
2573 |
2574 | var elementEvents = {};
2575 |
2576 | function fromEvent(_ref3) {
2577 | var element = _ref3.element;
2578 | var eventType = _ref3.eventType;
2579 | var k = _ref3.k;
2580 | var callback = _ref3.callback;
2581 |
2582 | if (typeof elementEvents[k] !== 'object') {
2583 | elementEvents[k] = {};
2584 | }
2585 | var elementEvent = elementEvents[k];
2586 | var event$ = undefined;
2587 | if (elementEvent[eventType]) {
2588 | event$ = elementEvent[eventType];
2589 | } else {
2590 | elementEvent[eventType] = new _rx.Subject();
2591 | event$ = elementEvent[eventType];
2592 | createEventListener({
2593 | element: element,
2594 | eventType: eventType,
2595 | handler: function handler(value) {
2596 | //console.log(`handler`, value.type)
2597 | event$.onNext(value);
2598 | },
2599 | k: k,
2600 | callback: callback
2601 | });
2602 | }
2603 | return event$;
2604 | }
2605 |
2606 | exports['default'] = fromEvent;
2607 | module.exports = exports['default'];
2608 |
2609 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2610 | },{"hammerjs":1}],4:[function(require,module,exports){
2611 | (function (global){
2612 | /**
2613 | * @fileoverview Hammer driver
2614 | * @author Frederik Krautwald
2615 | * @copyright 2015 Cyclic Materials. All rights reserved.
2616 | */
2617 |
2618 | 'use strict';
2619 |
2620 | Object.defineProperty(exports, '__esModule', {
2621 | value: true
2622 | });
2623 |
2624 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
2625 |
2626 | var _rx = (typeof window !== "undefined" ? window['Rx'] : typeof global !== "undefined" ? global['Rx'] : null);
2627 |
2628 | var _fromEvent = require('./fromEvent');
2629 |
2630 | var _fromEvent2 = _interopRequireDefault(_fromEvent);
2631 |
2632 | var _standardEventTypes = require('./standardEventTypes');
2633 |
2634 | var _standardEventTypes2 = _interopRequireDefault(_standardEventTypes);
2635 |
2636 | function fromHammerEvent(eventType, api, callback) {
2637 | return api.observable.flatMapLatest(function (element) {
2638 | if (!element) {
2639 | return _rx.Observable.empty();
2640 | }
2641 | var k = api.namespace.join('');
2642 | return (0, _fromEvent2['default'])({ element: element, eventType: eventType, k: k, callback: callback });
2643 | }).share();
2644 | }
2645 |
2646 | function makeEventsSelector(api, originalEvents) {
2647 | return function events(eventType) {
2648 | for (var _len = arguments.length, rest = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
2649 | rest[_key - 1] = arguments[_key];
2650 | }
2651 |
2652 | return _standardEventTypes2['default'][eventType] ? originalEvents.apply(undefined, [eventType].concat(rest)) : fromHammerEvent.apply(undefined, [eventType, api].concat(rest));
2653 | };
2654 | }
2655 |
2656 | function override(obj, methodName, callback) {
2657 | obj[methodName] = callback(obj[methodName]);
2658 | }
2659 |
2660 | function selectCallback(originalSelect) {
2661 | return function select() {
2662 | for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
2663 | args[_key2] = arguments[_key2];
2664 | }
2665 |
2666 | var api = originalSelect.apply(this, args);
2667 | override(api, 'select', selectCallback);
2668 | var originalEvents = api.events;
2669 | api.events = makeEventsSelector(api, originalEvents);
2670 | return api;
2671 | };
2672 | }
2673 |
2674 | function hammerDriver(domDriverFunc, vTree$) {
2675 | if (typeof domDriverFunc !== 'function') {
2676 | throw new Error('First argument given to hammerDriver() must be a DOM driver function.');
2677 | }
2678 | if (!vTree$ || typeof vTree$.subscribe !== 'function') {
2679 | throw new Error('The Hammer Driver expects a stream of virtual DOM elements as input.');
2680 | }
2681 |
2682 | var domDriver = domDriverFunc(vTree$);
2683 | override(domDriver, 'select', selectCallback);
2684 |
2685 | return domDriver;
2686 | }
2687 |
2688 | exports['default'] = hammerDriver;
2689 | module.exports = exports['default'];
2690 |
2691 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2692 | },{"./fromEvent":3,"./standardEventTypes":6}],5:[function(require,module,exports){
2693 | /**
2694 | * @fileoverview Hammer driver factory
2695 | * @author Frederik Krautwald
2696 | * @copyright 2015 Cyclic Materials. All rights reserved.
2697 | */
2698 |
2699 | 'use strict';
2700 |
2701 | Object.defineProperty(exports, '__esModule', {
2702 | value: true
2703 | });
2704 |
2705 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
2706 |
2707 | var _hammerDriver = require('./hammerDriver');
2708 |
2709 | var _hammerDriver2 = _interopRequireDefault(_hammerDriver);
2710 |
2711 | function makeHammerDriver(domDriverFunc) {
2712 | if (typeof domDriverFunc !== 'function') {
2713 | throw new Error('First argument given to makeHammerDriver() ' + 'must be a DOM driver function.');
2714 | }
2715 | return _hammerDriver2['default'].bind({}, domDriverFunc);
2716 | }
2717 |
2718 | exports['default'] = makeHammerDriver;
2719 | module.exports = exports['default'];
2720 |
2721 | },{"./hammerDriver":4}],6:[function(require,module,exports){
2722 | /**
2723 | * @fileoverview Standard Event Types
2724 | * @author Frederik Krautwald
2725 | * @copyright 2015 Cyclic Materials. All rights reserved.
2726 | */
2727 |
2728 | // https://developer.mozilla.org/en-US/docs/Web/Events
2729 | "use strict";
2730 |
2731 | Object.defineProperty(exports, "__esModule", {
2732 | value: true
2733 | });
2734 | var standardEventTypes = {
2735 | abort: true,
2736 | afterprint: true,
2737 | animationend: true,
2738 | animationiteration: true,
2739 | animationstart: true,
2740 | audioprocess: true,
2741 | audioend: true,
2742 | audiostart: true,
2743 | beforeprint: true,
2744 | beforeunload: true,
2745 | beginEvent: true,
2746 | blocked: true,
2747 | blur: true,
2748 | cached: true,
2749 | canplay: true,
2750 | canplaythrough: true,
2751 | change: true,
2752 | chargingchange: true,
2753 | chargingtimechange: true,
2754 | checking: true,
2755 | click: true,
2756 | close: true,
2757 | complete: true,
2758 | compositionend: true,
2759 | compositionstart: true,
2760 | compositionupdate: true,
2761 | contextmenu: true,
2762 | copy: true,
2763 | cut: true,
2764 | dblclick: true,
2765 | devicelight: true,
2766 | devicemotion: true,
2767 | deviceorientation: true,
2768 | deviceproximity: true,
2769 | dischargingtimechange: true,
2770 | DOMActivate: true,
2771 | DOMAttributeNameChanged: true,
2772 | DOMAttrModified: true,
2773 | DOMCharacterDataModified: true,
2774 | DOMContentLoaded: true,
2775 | DOMElementNameChanged: true,
2776 | DOMFocusIn: true,
2777 | DOMFocusOut: true,
2778 | DOMNodeInserted: true,
2779 | DOMNodeInsertedIntoDocument: true,
2780 | DOMNodeRemoved: true,
2781 | DOMNodeRemovedFromDocument: true,
2782 | DOMSubtreeModified: true,
2783 | downloading: true,
2784 | drag: true,
2785 | dragend: true,
2786 | dragenter: true,
2787 | dragleave: true,
2788 | dragover: true,
2789 | dragstart: true,
2790 | drop: true,
2791 | durationchange: true,
2792 | emptied: true,
2793 | end: true,
2794 | ended: true,
2795 | endEvent: true,
2796 | focus: true,
2797 | focusin: true,
2798 | focusout: true,
2799 | fullscreenchange: true,
2800 | fullscreenerror: true,
2801 | gamepadconnected: true,
2802 | gamepaddisconnected: true,
2803 | gotpointercapture: true,
2804 | hashchange: true,
2805 | lostpointercapture: true,
2806 | input: true,
2807 | invalid: true,
2808 | keydown: true,
2809 | keypress: true,
2810 | keyup: true,
2811 | languagechange: true,
2812 | levelchange: true,
2813 | load: true,
2814 | loadeddata: true,
2815 | loadedmetadata: true,
2816 | loadend: true,
2817 | loadstart: true,
2818 | message: true,
2819 | mousedown: true,
2820 | mouseenter: true,
2821 | mouseleave: true,
2822 | mousemove: true,
2823 | mouseout: true,
2824 | mouseover: true,
2825 | mouseup: true,
2826 | nomatch: true,
2827 | notificationclick: true,
2828 | noupdate: true,
2829 | obsolete: true,
2830 | offline: true,
2831 | online: true,
2832 | open: true,
2833 | orientationchange: true,
2834 | pagehide: true,
2835 | pageshow: true,
2836 | paste: true,
2837 | pause: true,
2838 | pointercancel: true,
2839 | pointerdown: true,
2840 | pointerenter: true,
2841 | pointerleave: true,
2842 | pointerlockchange: true,
2843 | pointerlockerror: true,
2844 | pointermove: true,
2845 | pointerout: true,
2846 | pointerover: true,
2847 | pointerup: true,
2848 | play: true,
2849 | playing: true,
2850 | popstate: true,
2851 | progress: true,
2852 | push: true,
2853 | pushsubscriptionchange: true,
2854 | ratechange: true,
2855 | readystatechange: true,
2856 | repeatEvent: true,
2857 | reset: true,
2858 | resize: true,
2859 | result: true,
2860 | scroll: true,
2861 | seeked: true,
2862 | seeking: true,
2863 | select: true,
2864 | selectstart: true,
2865 | selectionchange: true,
2866 | show: true,
2867 | soundend: true,
2868 | soundstart: true,
2869 | speechend: true,
2870 | speechstart: true,
2871 | stalled: true,
2872 | start: true,
2873 | storage: true,
2874 | submit: true,
2875 | success: true,
2876 | suspend: true,
2877 | SVGAbort: true,
2878 | SVGError: true,
2879 | SVGLoad: true,
2880 | SVGResize: true,
2881 | SVGScroll: true,
2882 | SVGUnload: true,
2883 | SVGZoom: true,
2884 | timeout: true,
2885 | timeupdate: true,
2886 | touchcancel: true,
2887 | touchend: true,
2888 | touchenter: true,
2889 | touchleave: true,
2890 | touchmove: true,
2891 | touchstart: true,
2892 | transitionend: true,
2893 | unload: true,
2894 | updateready: true,
2895 | upgradeneeded: true,
2896 | userproximity: true,
2897 | versionchange: true,
2898 | visibilitychange: true,
2899 | volumechange: true,
2900 | waiting: true,
2901 | wheel: true
2902 | };
2903 |
2904 | //const hammerEventTable = {
2905 | // pan: true,
2906 | // panstart: true,
2907 | // panmove: true,
2908 | // panend: true,
2909 | // pancancel: true,
2910 | // panleft: true,
2911 | // panright: true,
2912 | // panup: true,
2913 | // pandown: true,
2914 | // pinch: true,
2915 | // pinchstart: true,
2916 | // pinchmove: true,
2917 | // pinchend: true,
2918 | // pinchcancel: true,
2919 | // pinchin: true,
2920 | // pinchout: true,
2921 | // press: true,
2922 | // pressup: true,
2923 | // rotate: true,
2924 | // rotatestart: true,
2925 | // rotatemove: true,
2926 | // rotateend: true,
2927 | // rotatecancel: true,
2928 | // swipe: true,
2929 | // swipeleft: true,
2930 | // swiperight: true,
2931 | // swipeup: true,
2932 | // swipedown: true,
2933 | // tap: true,
2934 | //}
2935 |
2936 | exports["default"] = standardEventTypes;
2937 | module.exports = exports["default"];
2938 |
2939 | },{}]},{},[2])(2)
2940 | });
--------------------------------------------------------------------------------