Commit c2a3891c authored by nextime's avatar nextime

Readd hammer.js

parent d6121f4a
......@@ -2,13 +2,13 @@
<? if($GUIDEBUG) { ?>
<!-- JavaScript plugins (requires jQuery) -->
<script src="/resources/js/jquery-1.10.2.min.js"></script>
<script src="/resources/jquery-color/jquery.color.min.js"></script>
<script src="/resources/hammer.js/dist/hammer.min.js"></script>
<script src="/resources/jquery-color/jquery.color.js"></script>
<script src="/resources/hammer.js/hammer.min.js"></script>
<script src="/resources/hammer.js/plugins/hammer.fakemultitouch.js"></script>
<!--[if !IE]> -->
<script src="/resources/js/starthammer.js"></script>
<script src="<?=$BASEGUIPATH;?>/js/starthammer.js"></script>
<!-- <![endif]-->
<script src="/resources/hammer.js/dist/jquery.hammer.min.js"></script>
<script src="/resources/hammer.js/plugins/jquery.hammer.js/jquery.hammer.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/resources/bootstrap/js/bootstrap.min.js"></script>
<!-- Optionally enable responsive features in IE8 -->
......
{
"json": "bower.json"
}
\ No newline at end of file
# ide
.idea
.iml
# node
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
npm-debug.log
node_modules
\ No newline at end of file
[submodule "plugins/jquery.hammer.js"]
path = plugins/jquery.hammer.js
url = git://github.com/EightMedia/jquery.hammer.js.git
language: node_js
node_js:
- "0.10"
before_script:
- npm install -g grunt-cli
script:
- grunt test-travis
\ No newline at end of file
# Contributing to Hammer.js
Looking to contribute something to Hammer.js? **Here's how you can help.**
## Reporting issues
We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems that can be fixed within the Hammer.js. Please read the following guidelines before opening any issue.
1. **Search for existing issues.** We get a lot of duplicate issues, and you'd help us out a lot by first checking if someone else has reported the same issue. Moreover, the issue may have already been resolved with a fix available. Also take a look if your problem is explained at the Wiki.
2. **Create an isolated and reproducible test case.** Be sure the problem exists in Hammer's code with a reduced test case that should be included in each bug report.
3. **Include a live example.** Make use of jsFiddle or jsBin to share your isolated test cases.
4. **Share as much information as possible.** Include operating system and version, browser and version, version of Hammer.js, customized or vanilla build, etc. where appropriate. Also include steps to reproduce the bug.
## Pull requests
- Changes must be done in `/src` files, never just the compiled files
- Try not to pollute your pull request with unintended changes--keep them simple and small
- Try to share which browsers your code has been tested in before submitting a pull request
- Try and write tests for your code, these can be found in `/tests`
\ No newline at end of file
module.exports = (grunt) ->
grunt.initConfig
pkg: grunt.file.readJSON 'package.json'
# meta options
meta:
banner: '
/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n
* <%= pkg.homepage %>\n
*\n
* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %> <<%= pkg.author.email %>>;\n
* Licensed under the <%= _.pluck(pkg.licenses, "type").join(", ") %> license */\n\n'
# concat src files
concat:
options:
separator: '\n\n'
dist:
options:
banner: '<%= meta.banner %>'
src: [
'src/intro.js'
'src/core.js'
'src/setup.js'
'src/utils.js'
'src/instance.js'
'src/event.js'
'src/pointerevent.js'
'src/detection.js'
'src/gestures/*.js'
'src/outro.js']
dest: 'hammer.js'
# minify the sourcecode
uglify:
options:
report: 'gzip'
sourceMap: 'hammer.min.map'
banner: '<%= meta.banner %>'
dist:
files:
'hammer.min.js': ['hammer.js']
# check for optimisations and errors
jshint:
options:
curly: true
expr: true
newcap: true
quotmark: 'single'
regexdash: true
trailing: true
undef: true
unused: true
maxerr: 100
eqnull: true
sub: false
browser: true
node: true
strict: true
laxcomma: true
globals:
define: false
dist:
src: ['hammer.js']
# watch for changes
watch:
scripts:
files: ['src/**/*.js']
tasks: ['concat']
options:
interrupt: true
# simple node server
connect:
server:
options:
directory: "."
hostname: "0.0.0.0"
# tests
qunit:
all: ['tests/**/*.html']
# saucelabs tests
'saucelabs-qunit':
all:
options:
username: 'hammerjs-ci'
key: '2ede6d02-65b3-4ba9-aec8-44a787af0c81'
build: process.env.TRAVIS_JOB_ID || 'dev'
concurrency: 3
urls: [
'http://0.0.0.0:8000/tests/utils.html',
'http://0.0.0.0:8000/tests/mouseevents.html',
'http://0.0.0.0:8000/tests/mousetouchevents.html',
'http://0.0.0.0:8000/tests/touchevents.html',
'http://0.0.0.0:8000/tests/pointerevents_mouse.html',
'http://0.0.0.0:8000/tests/pointerevents_touch.html'
]
browsers: [
{ browserName: 'chrome' }
{ browserName: 'firefox' }
{ browserName: 'internet explorer', platform: 'Windows 7', version: '9' }
{ browserName: 'internet explorer', platform: 'Windows 8', version: '10'}
]
# Load tasks
grunt.loadNpmTasks 'grunt-contrib-concat'
grunt.loadNpmTasks 'grunt-contrib-uglify'
grunt.loadNpmTasks 'grunt-contrib-watch'
grunt.loadNpmTasks 'grunt-contrib-jshint'
grunt.loadNpmTasks 'grunt-contrib-connect'
grunt.loadNpmTasks 'grunt-contrib-qunit'
grunt.loadNpmTasks 'grunt-saucelabs'
# Default task(s).
grunt.registerTask 'default', ['connect','watch']
grunt.registerTask 'build', ['concat','uglify','test']
grunt.registerTask 'test', ['jshint','qunit']
grunt.registerTask 'test-travis', ['build','jshint']
Copyright (C) 2013 by Jorik Tangelder (Eight Media)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
\ No newline at end of file
# Hammer.js
[![Build Status](https://travis-ci.org/EightMedia/hammer.js.png)](https://travis-ci.org/EightMedia/hammer.js/)
[![Selenium Test Status](https://saucelabs.com/buildstatus/hammerjs-ci)](https://saucelabs.com/u/hammerjs-ci)
### A javascript library for multi-touch gestures
> I told you, homeboy /
> You *CAN* touch this /
> Yeah, that's how we living and you know /
> You *CAN* touch this
[__Looking for the jQuery plugin? It has his own repository now.__](https://github.com/EightMedia/jquery.hammer.js)
## Features
- Detects Tap, DoubleTap, Swipe, Drag, Pinch, and Rotate gestures
- DOM Events
- Debug plugins
- Custom gestures
- Chainable instance methods
- AMD support (RequireJS)
- Unit tests
- Option to disable mouse support, so only for touch and pen input.
- Sourcemaps
- [jQuery plugin available here](https://github.com/EightMedia/jquery.hammer.js)
## Getting Started
See the [Wiki on GitHub](https://github.com/EightMedia/hammer.js/wiki) for documentation.
## Contributing
In lieu of a formal styleguide, take care to maintain the existing coding style.
Add unit tests for any new or changed functionality. Lint and test your code using grunt.
Please don't commit the dist versions with your changes, only the changed source files.
## Further notes
Created by [Jorik Tangelder](http://twitter.com/jorikdelaporik) and developed at [Eight Media](http://www.eight.nl/) in Arnhem, the Netherlands.
It's recommend to listen to [this loop](http://soundcloud.com/eightmedia/hammerhammerhammer) while using hammer.js.
{
"name": "hammerjs",
"version": "1.0.6",
"main": ["hammer.js"],
"ignore": [
"tests",
"component.json",
"package.json",
"examples",
"src"
]
}
{
"name": "hammerjs",
"version": "1.0.6",
"main": "hammer.js",
"scripts": [
"hammer.js"
]
}
The demos are for illustration purposes only, and not production ready. Hammer.js is not a component library.
// google analytics
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-30289566-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
\ No newline at end of file
/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
* Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load
*/
;
window.Modernizr = (function( window, document, undefined ) {
var version = '2.6.2',
Modernizr = {},
enableClasses = true,
docElement = document.documentElement,
mod = 'modernizr',
modElem = document.createElement(mod),
mStyle = modElem.style,
inputElem = document.createElement('input') ,
smile = ':)',
toString = {}.toString,
prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
omPrefixes = 'Webkit Moz O ms',
cssomPrefixes = omPrefixes.split(' '),
domPrefixes = omPrefixes.toLowerCase().split(' '),
ns = {'svg': 'http://www.w3.org/2000/svg'},
tests = {},
inputs = {},
attrs = {},
classes = [],
slice = classes.slice,
featureName,
injectElementWithStyles = function( rule, callback, nodes, testnames ) {
var style, ret, node, docOverflow,
div = document.createElement('div'),
body = document.body,
fakeBody = body || document.createElement('body');
if ( parseInt(nodes, 10) ) {
while ( nodes-- ) {
node = document.createElement('div');
node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
div.appendChild(node);
}
}
style = ['&#173;','<style id="s', mod, '">', rule, '</style>'].join('');
div.id = mod;
(body ? div : fakeBody).innerHTML += style;
fakeBody.appendChild(div);
if ( !body ) {
fakeBody.style.background = '';
fakeBody.style.overflow = 'hidden';
docOverflow = docElement.style.overflow;
docElement.style.overflow = 'hidden';
docElement.appendChild(fakeBody);
}
ret = callback(div, rule);
if ( !body ) {
fakeBody.parentNode.removeChild(fakeBody);
docElement.style.overflow = docOverflow;
} else {
div.parentNode.removeChild(div);
}
return !!ret;
},
isEventSupported = (function() {
var TAGNAMES = {
'select': 'input', 'change': 'input',
'submit': 'form', 'reset': 'form',
'error': 'img', 'load': 'img', 'abort': 'img'
};
function isEventSupported( eventName, element ) {
element = element || document.createElement(TAGNAMES[eventName] || 'div');
eventName = 'on' + eventName;
var isSupported = eventName in element;
if ( !isSupported ) {
if ( !element.setAttribute ) {
element = document.createElement('div');
}
if ( element.setAttribute && element.removeAttribute ) {
element.setAttribute(eventName, '');
isSupported = is(element[eventName], 'function');
if ( !is(element[eventName], 'undefined') ) {
element[eventName] = undefined;
}
element.removeAttribute(eventName);
}
}
element = null;
return isSupported;
}
return isEventSupported;
})(),
_hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;
if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
hasOwnProp = function (object, property) {
return _hasOwnProperty.call(object, property);
};
}
else {
hasOwnProp = function (object, property) {
return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
};
}
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) {
var target = this;
if (typeof target != "function") {
throw new TypeError();
}
var args = slice.call(arguments, 1),
bound = function () {
if (this instanceof bound) {
var F = function(){};
F.prototype = target.prototype;
var self = new F();
var result = target.apply(
self,
args.concat(slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return self;
} else {
return target.apply(
that,
args.concat(slice.call(arguments))
);
}
};
return bound;
};
}
function setCss( str ) {
mStyle.cssText = str;
}
function setCssAll( str1, str2 ) {
return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
}
function is( obj, type ) {
return typeof obj === type;
}
function contains( str, substr ) {
return !!~('' + str).indexOf(substr);
}
function testProps( props, prefixed ) {
for ( var i in props ) {
var prop = props[i];
if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
return prefixed == 'pfx' ? prop : true;
}
}
return false;
}
function testDOMProps( props, obj, elem ) {
for ( var i in props ) {
var item = obj[props[i]];
if ( item !== undefined) {
if (elem === false) return props[i];
if (is(item, 'function')){
return item.bind(elem || obj);
}
return item;
}
}
return false;
}
function testPropsAll( prop, prefixed, elem ) {
var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
if(is(prefixed, "string") || is(prefixed, "undefined")) {
return testProps(props, prefixed);
} else {
props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
return testDOMProps(props, prefixed, elem);
}
} tests['flexbox'] = function() {
return testPropsAll('flexWrap');
}; tests['canvas'] = function() {
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
};
tests['canvastext'] = function() {
return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
};
tests['webgl'] = function() {
return !!window.WebGLRenderingContext;
};
tests['touch'] = function() {
var bool;
if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
bool = true;
} else {
injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
bool = node.offsetTop === 9;
});
}
return bool;
};
tests['geolocation'] = function() {
return 'geolocation' in navigator;
};
tests['postmessage'] = function() {
return !!window.postMessage;
};
tests['websqldatabase'] = function() {
return !!window.openDatabase;
};
tests['indexedDB'] = function() {
return !!testPropsAll("indexedDB", window);
};
tests['hashchange'] = function() {
return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
};
tests['history'] = function() {
return !!(window.history && history.pushState);
};
tests['draganddrop'] = function() {
var div = document.createElement('div');
return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
};
tests['websockets'] = function() {
return 'WebSocket' in window || 'MozWebSocket' in window;
};
tests['rgba'] = function() {
setCss('background-color:rgba(150,255,150,.5)');
return contains(mStyle.backgroundColor, 'rgba');
};
tests['hsla'] = function() {
setCss('background-color:hsla(120,40%,100%,.5)');
return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
};
tests['multiplebgs'] = function() {
setCss('background:url(https://),url(https://),red url(https://)');
return (/(url\s*\(.*?){3}/).test(mStyle.background);
}; tests['backgroundsize'] = function() {
return testPropsAll('backgroundSize');
};
tests['borderimage'] = function() {
return testPropsAll('borderImage');
};
tests['borderradius'] = function() {
return testPropsAll('borderRadius');
};
tests['boxshadow'] = function() {
return testPropsAll('boxShadow');
};
tests['textshadow'] = function() {
return document.createElement('div').style.textShadow === '';
};
tests['opacity'] = function() {
setCssAll('opacity:.55');
return (/^0.55$/).test(mStyle.opacity);
};
tests['cssanimations'] = function() {
return testPropsAll('animationName');
};
tests['csscolumns'] = function() {
return testPropsAll('columnCount');
};
tests['cssgradients'] = function() {
var str1 = 'background-image:',
str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
str3 = 'linear-gradient(left top,#9f9, white);';
setCss(
(str1 + '-webkit- '.split(' ').join(str2 + str1) +
prefixes.join(str3 + str1)).slice(0, -str1.length)
);
return contains(mStyle.backgroundImage, 'gradient');
};
tests['cssreflections'] = function() {
return testPropsAll('boxReflect');
};
tests['csstransforms'] = function() {
return !!testPropsAll('transform');
};
tests['csstransforms3d'] = function() {
var ret = !!testPropsAll('perspective');
if ( ret && 'webkitPerspective' in docElement.style ) {
injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
ret = node.offsetLeft === 9 && node.offsetHeight === 3;
});
}
return ret;
};
tests['csstransitions'] = function() {
return testPropsAll('transition');
};
tests['fontface'] = function() {
var bool;
injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) {
var style = document.getElementById('smodernizr'),
sheet = style.sheet || style.styleSheet,
cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
});
return bool;
};
tests['generatedcontent'] = function() {
var bool;
injectElementWithStyles(['#',mod,'{font:0/0 a}#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) {
bool = node.offsetHeight >= 3;
});
return bool;
};
tests['video'] = function() {
var elem = document.createElement('video'),
bool = false;
try {
if ( bool = !!elem.canPlayType ) {
bool = new Boolean(bool);
bool.ogg = elem.canPlayType('video/ogg; codecs="theora"') .replace(/^no$/,'');
bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');
bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,'');
}
} catch(e) { }
return bool;
};
tests['audio'] = function() {
var elem = document.createElement('audio'),
bool = false;
try {
if ( bool = !!elem.canPlayType ) {
bool = new Boolean(bool);
bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
bool.mp3 = elem.canPlayType('audio/mpeg;') .replace(/^no$/,'');
bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,'');
bool.m4a = ( elem.canPlayType('audio/x-m4a;') ||
elem.canPlayType('audio/aac;')) .replace(/^no$/,'');
}
} catch(e) { }
return bool;
};
tests['localstorage'] = function() {
try {
localStorage.setItem(mod, mod);
localStorage.removeItem(mod);
return true;
} catch(e) {
return false;
}
};
tests['sessionstorage'] = function() {
try {
sessionStorage.setItem(mod, mod);
sessionStorage.removeItem(mod);
return true;
} catch(e) {
return false;
}
};
tests['webworkers'] = function() {
return !!window.Worker;
};
tests['applicationcache'] = function() {
return !!window.applicationCache;
};
tests['svg'] = function() {
return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
};
tests['inlinesvg'] = function() {
var div = document.createElement('div');
div.innerHTML = '<svg/>';
return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
};
tests['smil'] = function() {
return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
};
tests['svgclippaths'] = function() {
return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
};
function webforms() {
Modernizr['input'] = (function( props ) {
for ( var i = 0, len = props.length; i < len; i++ ) {
attrs[ props[i] ] = !!(props[i] in inputElem);
}
if (attrs.list){
attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
}
return attrs;
})('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
Modernizr['inputtypes'] = (function(props) {
for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
inputElem.setAttribute('type', inputElemType = props[i]);
bool = inputElem.type !== 'text';
if ( bool ) {
inputElem.value = smile;
inputElem.style.cssText = 'position:absolute;visibility:hidden;';
if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {
docElement.appendChild(inputElem);
defaultView = document.defaultView;
bool = defaultView.getComputedStyle &&
defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
(inputElem.offsetHeight !== 0);
docElement.removeChild(inputElem);
} else if ( /^(search|tel)$/.test(inputElemType) ){
} else if ( /^(url|email)$/.test(inputElemType) ) {
bool = inputElem.checkValidity && inputElem.checkValidity() === false;
} else {
bool = inputElem.value != smile;
}
}
inputs[ props[i] ] = !!bool;
}
return inputs;
})('search tel url email datetime date month week time datetime-local number range color'.split(' '));
}
for ( var feature in tests ) {
if ( hasOwnProp(tests, feature) ) {
featureName = feature.toLowerCase();
Modernizr[featureName] = tests[feature]();
classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
}
}
Modernizr.input || webforms();
Modernizr.addTest = function ( feature, test ) {
if ( typeof feature == 'object' ) {
for ( var key in feature ) {
if ( hasOwnProp( feature, key ) ) {
Modernizr.addTest( key, feature[ key ] );
}
}
} else {
feature = feature.toLowerCase();
if ( Modernizr[feature] !== undefined ) {
return Modernizr;
}
test = typeof test == 'function' ? test() : test;
if (typeof enableClasses !== "undefined" && enableClasses) {
docElement.className += ' ' + (test ? '' : 'no-') + feature;
}
Modernizr[feature] = test;
}
return Modernizr;
};
setCss('');
modElem = inputElem = null;
;(function(window, document) {
var options = window.html5 || {};
var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
var supportsHtml5Styles;
var expando = '_html5shiv';
var expanID = 0;
var expandoData = {};
var supportsUnknownElements;
(function() {
try {
var a = document.createElement('a');
a.innerHTML = '<xyz></xyz>';
supportsHtml5Styles = ('hidden' in a);
supportsUnknownElements = a.childNodes.length == 1 || (function() {
(document.createElement)('a');
var frag = document.createDocumentFragment();
return (
typeof frag.cloneNode == 'undefined' ||
typeof frag.createDocumentFragment == 'undefined' ||
typeof frag.createElement == 'undefined'
);
}());
} catch(e) {
supportsHtml5Styles = true;
supportsUnknownElements = true;
}
}()); function addStyleSheet(ownerDocument, cssText) {
var p = ownerDocument.createElement('p'),
parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
p.innerHTML = 'x<style>' + cssText + '</style>';
return parent.insertBefore(p.lastChild, parent.firstChild);
}
function getElements() {
var elements = html5.elements;
return typeof elements == 'string' ? elements.split(' ') : elements;
}
function getExpandoData(ownerDocument) {
var data = expandoData[ownerDocument[expando]];
if (!data) {
data = {};
expanID++;
ownerDocument[expando] = expanID;
expandoData[expanID] = data;
}
return data;
}
function createElement(nodeName, ownerDocument, data){
if (!ownerDocument) {
ownerDocument = document;
}
if(supportsUnknownElements){
return ownerDocument.createElement(nodeName);
}
if (!data) {
data = getExpandoData(ownerDocument);
}
var node;
if (data.cache[nodeName]) {
node = data.cache[nodeName].cloneNode();
} else if (saveClones.test(nodeName)) {
node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
} else {
node = data.createElem(nodeName);
}
return node.canHaveChildren && !reSkip.test(nodeName) ? data.frag.appendChild(node) : node;
}
function createDocumentFragment(ownerDocument, data){
if (!ownerDocument) {
ownerDocument = document;
}
if(supportsUnknownElements){
return ownerDocument.createDocumentFragment();
}
data = data || getExpandoData(ownerDocument);
var clone = data.frag.cloneNode(),
i = 0,
elems = getElements(),
l = elems.length;
for(;i<l;i++){
clone.createElement(elems[i]);
}
return clone;
}
function shivMethods(ownerDocument, data) {
if (!data.cache) {
data.cache = {};
data.createElem = ownerDocument.createElement;
data.createFrag = ownerDocument.createDocumentFragment;
data.frag = data.createFrag();
}
ownerDocument.createElement = function(nodeName) {
if (!html5.shivMethods) {
return data.createElem(nodeName);
}
return createElement(nodeName, ownerDocument, data);
};
ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
'var n=f.cloneNode(),c=n.createElement;' +
'h.shivMethods&&(' +
getElements().join().replace(/\w+/g, function(nodeName) {
data.createElem(nodeName);
data.frag.createElement(nodeName);
return 'c("' + nodeName + '")';
}) +
');return n}'
)(html5, data.frag);
} function shivDocument(ownerDocument) {
if (!ownerDocument) {
ownerDocument = document;
}
var data = getExpandoData(ownerDocument);
if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
data.hasCSS = !!addStyleSheet(ownerDocument,
'article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}' +
'mark{background:#FF0;color:#000}'
);
}
if (!supportsUnknownElements) {
shivMethods(ownerDocument, data);
}
return ownerDocument;
} var html5 = {
'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video',
'shivCSS': (options.shivCSS !== false),
'supportsUnknownElements': supportsUnknownElements,
'shivMethods': (options.shivMethods !== false),
'type': 'default',
'shivDocument': shivDocument,
createElement: createElement,
createDocumentFragment: createDocumentFragment
}; window.html5 = html5;
shivDocument(document);
}(this, document));
Modernizr._version = version;
Modernizr._prefixes = prefixes;
Modernizr._domPrefixes = domPrefixes;
Modernizr._cssomPrefixes = cssomPrefixes;
Modernizr.hasEvent = isEventSupported;
Modernizr.testProp = function(prop){
return testProps([prop]);
};
Modernizr.testAllProps = testPropsAll;
Modernizr.testStyles = injectElementWithStyles;
Modernizr.prefixed = function(prop, obj, elem){
if(!obj) {
return testPropsAll(prop, 'pfx');
} else {
return testPropsAll(prop, obj, elem);
}
};
docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') +
(enableClasses ? ' js ' + classes.join(' ') : '');
return Modernizr;
})(this, this.document);
/*yepnope1.5.4|WTFPL*/
(function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f<d;f++)g=a[f].split("="),(e=z[g.shift()])&&(c=e(c,g));for(f=0;f<b;f++)c=x[f](c);return c}function g(a,e,f,g,h){var i=b(a),j=i.autoCallback;i.url.split(".").pop().split("?").shift(),i.bypass||(e&&(e=d(e)?e:e[a]||e[g]||e[a.split("/").pop().split("?")[0]]),i.instead?i.instead(a,e,f,g,h):(y[i.url]?i.noexec=!0:y[i.url]=1,f.load(i.url,i.forceCSS||!i.forceJS&&"css"==i.url.split(".").pop().split("?").shift()?"c":c,i.noexec,i.attrs,i.timeout),(d(e)||d(j))&&f.load(function(){k(),e&&e(i.origUrl,h,g),j&&j(i.origUrl,h,g),y[i.url]=2})))}function h(a,b){function c(a,c){if(a){if(e(a))c||(j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}),g(a,j,b,0,h);else if(Object(a)===a)for(n in m=function(){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b}(),a)a.hasOwnProperty(n)&&(!c&&!--m&&(d(j)?j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}:j[n]=function(a){return function(){var b=[].slice.call(arguments);a&&a.apply(this,b),l()}}(k[n])),g(a[n],j,b,n,h))}else!c&&l()}var h=!!a.test,i=a.load||a.both,j=a.callback||f,k=j,l=a.complete||f,m,n;c(h?a.yep:a.nope,!!i),i&&c(i)}var i,j,l=this.yepnope.loader;if(e(a))g(a,0,l,0);else if(w(a))for(i=0;i<a.length;i++)j=a[i],e(j)?g(j,0,l,0):w(j)?B(j):Object(j)===j&&h(j,l);else Object(a)===a&&h(a,l)},B.addPrefix=function(a,b){z[a]=b},B.addFilter=function(a){x.push(a)},B.errorTimeout=1e4,null==b.readyState&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",A=function(){b.removeEventListener("DOMContentLoaded",A,0),b.readyState="complete"},0)),a.yepnope=k(),a.yepnope.executeStack=h,a.yepnope.injectJs=function(a,c,d,e,i,j){var k=b.createElement("script"),l,o,e=e||B.errorTimeout;k.src=a;for(o in d)k.setAttribute(o,d[o]);c=j?h:c||f,k.onreadystatechange=k.onload=function(){!l&&g(k.readyState)&&(l=1,c(),k.onload=k.onreadystatechange=null)},m(function(){l||(l=1,c(1))},e),i?k.onload():n.parentNode.insertBefore(k,n)},a.yepnope.injectCss=function(a,c,d,e,g,i){var e=b.createElement("link"),j,c=i?h:c||f;e.href=a,e.rel="stylesheet",e.type="text/css";for(j in d)e.setAttribute(j,d[j]);g||(n.parentNode.insertBefore(e,n),m(c,0))}})(this,document);
Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0));};
;
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<title>Hammer.js</title>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css" rel="stylesheet">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<style>
@keyframes highlight {
0%{ background: rgba(255, 240, 140, 1); }
100%{ background: rgba(255, 240, 140, 0); }
}
@-moz-keyframes highlight{
0%{ background: rgba(255, 240, 140, 1); }
100%{ background: rgba(255, 240, 140, 0); }
}
@-webkit-keyframes highlight{
0%{ background: rgba(255, 240, 140, 1); }
100%{ background: rgba(255, 240, 140, 0); }
}
body { padding: 0; }
#container {
padding: 20px;
}
.highlight {
background: #fff68d;
}
.hero-unit {
padding: 0;
}
#toucharea {
padding: 30px;
}
</style>
</head>
<body>
<div id="container">
<div class="hero-unit">
<div id="toucharea">
<h1>Touch me</h1>
<p>The tap event will be fired. Notice in the sourcecode that event delegation is also supported.<br>
In the console you can see the event data.</p>
<h4>List items with stopPropagation</h4>
<ul id="items">
<li>List item 1</li>
<li>List item 2</li>
<li>List item 3</li>
<li>List item 4</li>
<li>List item 5</li>
</ul>
<p>
<a href="#" id="add-list-item" class="btn btn-success">Add list item</a>
</p>
</div>
</div>
</div>
<script src="../hammer.js"></script>
<script>
function highlight(el) {
setTimeout(function() {
el.className = el.className.replace("highlight", "");
}, 100);
el.className = el.className + " highlight";
}
var hammertime = Hammer(document.getElementById("toucharea"));
console.log(hammertime);
// the whole area
hammertime.on("tap swipeleft drag", function(ev) {
if(window.console) { console.log(ev); }
highlight(this);
});
// on elements in the toucharea, with a stopPropagation
hammertime.on("tap swipe", function(ev) {
if(window.console) { console.log('nested', ev); }
highlight(this);
ev.stopPropagation();
});
</script>
<script src="assets/js/ga.js"></script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<title>Hammer.js</title>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css" rel="stylesheet">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<style>
html, body, #carousel, #carousel ul, #carousel li {
min-height: 100%;
height: 100%;
padding: 0;
margin: 0;
position: relative;
}
#debug {
position: fixed;
background: #fff;
padding: 5px;
color: #000;
top: 0;
left: 0;
z-index: 1337;
}
#carousel {
background: silver;
overflow: hidden;
width:100%;
-webkit-backface-visibility: hidden;
-webkit-transform: translate3d(0,0,0) scale3d(1,1,1);
-webkit-transform-style: preserve-3d;
}
#carousel ul.animate {
-webkit-transition: all .3s;
-moz-transition: all .3s;
-o-transition: all .3s;
transition: all .3s;
}
#carousel ul {
transform: translate3d(0%,0,0) scale3d(1,1,1);
-o-transform: translate3d(0%,0,0) scale3d(1,1,1);
-ms-transform: translate3d(0%,0,0) scale3d(1,1,1);
-moz-transform: translate3d(0%,0,0) scale3d(1,1,1);
-webkit-transform: translate3d(0%,0,0) scale3d(1,1,1);
overflow: hidden;
-webkit-backface-visibility: hidden;
-webkit-transform-style: preserve-3d;
}
#carousel ul {
-webkit-box-shadow: 0 0 20px rgba(0,0,0,.2);
box-shadow: 0 0 20px rgba(0,0,0,.2);
position: relative;
}
#carousel li {
float: left;
overflow: hidden;
-webkit-transform-style: preserve-3d;
-webkit-transform: translate3d(0,0,0);
}
#carousel li h2 {
color: #fff;
font-size: 30px;
text-align: center;
position: absolute;
top: 40%;
left: 0;
width: 100%;
text-shadow: -1px -1px 0 rgba(0,0,0,.2);
}
#carousel li.pane1 { background: #42d692; }
#carousel li.pane2 { background: #4986e7; }
#carousel li.pane3 { background: #d06b64; }
#carousel li.pane4 { background: #cd74e6; }
#carousel li.pane5 { background: #9fe1e7; }
</style>
</head>
<body>
<!--<div id="debug">Log</div>-->
<div id="carousel">
<ul>
<li class="pane1"><h2>Swipe...</h2></li>
<li class="pane2"><h2>...or drag...</h2></li>
<li class="pane3"><h2>...or swipe...</h2></li>
<li class="pane4"><h2>..or drag...</h2></li>
<li class="pane5"><h2>Dit is het einde!</h2></li>
</ul>
</div>
<!-- jQuery is just for the demo! Hammer.js works without jQuery :-) -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="assets/js/modernizr.js"></script>
<script src="../hammer.js"></script>
<script>
var debug_el = $("#debug");
function debug(text) {
debug_el.text(text);
}
/**
* requestAnimationFrame and cancel polyfill
*/
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame =
window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
/**
* super simple carousel
* animation between panes happens with css transitions
*/
function Carousel(element)
{
var self = this;
element = $(element);
var container = $(">ul", element);
var panes = $(">ul>li", element);
var pane_width = 0;
var pane_count = panes.length;
var current_pane = 0;
/**
* initial
*/
this.init = function() {
setPaneDimensions();
$(window).on("load resize orientationchange", function() {
setPaneDimensions();
//updateOffset();
})
};
/**
* set the pane dimensions and scale the container
*/
function setPaneDimensions() {
pane_width = element.width();
panes.each(function() {
$(this).width(pane_width);
});
container.width(pane_width*pane_count);
};
/**
* show pane by index
*/
this.showPane = function(index, animate) {
// between the bounds
index = Math.max(0, Math.min(index, pane_count-1));
current_pane = index;
var offset = -((100/pane_count)*current_pane);
setContainerOffset(offset, animate);
};
function setContainerOffset(percent, animate) {
container.removeClass("animate");
if(animate) {
container.addClass("animate");
}
if(Modernizr.csstransforms3d) {
container.css("transform", "translate3d("+ percent +"%,0,0) scale3d(1,1,1)");
}
else if(Modernizr.csstransforms) {
container.css("transform", "translate("+ percent +"%,0)");
}
else {
var px = ((pane_width*pane_count) / 100) * percent;
container.css("left", px+"px");
}
}
this.next = function() { return this.showPane(current_pane+1, true); };
this.prev = function() { return this.showPane(current_pane-1, true); };
function handleHammer(ev) {
console.log(ev);
// disable browser scrolling
ev.gesture.preventDefault();
switch(ev.type) {
case 'dragright':
case 'dragleft':
// stick to the finger
var pane_offset = -(100/pane_count)*current_pane;
var drag_offset = ((100/pane_width)*ev.gesture.deltaX) / pane_count;
// slow down at the first and last pane
if((current_pane == 0 && ev.gesture.direction == "right") ||
(current_pane == pane_count-1 && ev.gesture.direction == "left")) {
drag_offset *= .4;
}
setContainerOffset(drag_offset + pane_offset);
break;
case 'swipeleft':
self.next();
ev.gesture.stopDetect();
break;
case 'swiperight':
self.prev();
ev.gesture.stopDetect();
break;
case 'release':
// more then 50% moved, navigate
if(Math.abs(ev.gesture.deltaX) > pane_width/2) {
if(ev.gesture.direction == 'right') {
self.prev();
} else {
self.next();
}
}
else {
self.showPane(current_pane, true);
}
break;
}
}
var hammertime = new Hammer(element[0], { drag_lock_to_axis: true });
element.on("release dragleft dragright swipeleft swiperight", handleHammer);
}
var carousel = new Carousel("#carousel");
carousel.init();
</script>
<script src="assets/js/ga.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Hammer.js</title>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css" rel="stylesheet">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<style>
h1 {
margin: 30px;
text-align: center;
}
.drag {
position: absolute;
left: 100px;
top: 100px;
background: #9fe1e7;
border-radius: 50px;
width: 100px;
height: 100px;
}
.drag1 { background: #42d692; }
.drag2 { background: #4986e7; }
.drag3 { background: #d06b64; }
.drag4 { background: #cd74e6; }
.drag5 { background: #9fe1e7; }
</style>
</head>
<body>
<h1>Drag the balls!</h1>
<div class="drag drag1"></div>
<div class="drag drag2"></div>
<div class="drag drag3"></div>
<div class="drag drag4"></div>
<div class="drag drag5"></div>
<!-- jQuery is just for the demo! Hammer.js works without jQuery :-) -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="assets/js/modernizr.js"></script>
<script src="../hammer.js"></script>
<script>
var hammertime = new Hammer($(".drag")[0], { drag_max_touches:0});
$(".drag")
.on("touch drag", function(ev) {
var touches = ev.gesture.touches;
ev.gesture.preventDefault();
for(var t=0,len=touches.length; t<len; t++) {
var target = $(touches[t].target);
target.css({
zIndex: 1337,
left: touches[t].pageX-50,
top: touches[t].pageY-50
});
}
});
</script>
<script src="assets/js/ga.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Hammer.js</title>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css" rel="stylesheet">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<style>
body {
padding: 15px;
}
.container { position: relative; }
.hitarea {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,.05);
text-align: center;
border: dashed 3px red;
}
.log li {
display: inline-block;
width: 49%;
overflow: hidden;
}
@media screen and (min-width: 640px) {
.log li { width: 30%; }
}
.properties li { white-space: nowrap; }
.properties span { margin-left: 5px; }
.log li.active { background: lightgreen; }
.log li.property-gesture {
position: fixed;
right: 0;
top: 0;
background: lightgreen;
padding: 1px 4px;
width: auto;
}
</style>
</head>
<body>
<p class="alert"><strong>Press shift on your desktop for multitouch.</strong></p>
<p>
<label class="checkbox">
<input type="checkbox" checked id="prevent-default"> block browser behavior (preventDefault)
</label>
</p>
<div class="container">
<div class="log well well-small">
<h4>Events</h4>
<ul class="unstyled events" id="events-list">
<li>touch</li>
<li>release</li>
<li>hold</li>
<li>tap</li>
<li>doubletap</li>
<li>dragstart</li>
<li>drag</li>
<li>dragend</li>
<li>dragleft</li>
<li>dragright</li>
<li>dragup</li>
<li>dragdown</li>
<li>swipe</li>
<li>swipeleft</li>
<li>swiperight</li>
<li>swipeup</li>
<li>swipedown</li>
<li>transformstart</li>
<li>transform</li>
<li>transformend</li>
<li>rotate</li>
<li>rotateleft</li>
<li>rotateright</li>
<li>pinch</li>
<li>pinchin</li>
<li>pinchout</li>
</ul>
<h4>EventData</h4>
<ul class="unstyled properties">
<li class="property-gesture"><strong>gesture</strong> <span id="log-prop-gesture"></span></li>
<li><strong>touches</strong> <span id="log-prop-touches"></span></li>
<li><strong>pointerType</strong> <span id="log-prop-pointerType"></span></li>
<li><strong>center</strong> <span id="log-prop-center"></span></li>
<li><strong>angle</strong> <span id="log-prop-angle"></span>&deg;</li>
<li><strong>direction</strong> <span id="log-prop-direction"></span></li>
<li><strong>distance</strong> <span id="log-prop-distance"></span>px</li>
<li><strong>deltaTime</strong> <span id="log-prop-deltaTime"></span>ms</li>
<li><strong>deltaX</strong> <span id="log-prop-deltaX"></span>px</li>
<li><strong>deltaY</strong> <span id="log-prop-deltaY"></span>px</li>
<li><strong>velocityX</strong> <span id="log-prop-velocityX"></span></li>
<li><strong>velocityY</strong> <span id="log-prop-velocityY"></span></li>
<li><strong>scale</strong> <span id="log-prop-scale"></span></li>
<li><strong>rotation</strong> <span id="log-prop-rotation"></span>&deg;</li>
<li><strong>target</strong> <span id="log-prop-target"></span></li>
</ul>
</div>
<div id="hitarea" class="hitarea"></div>
</div>
<!-- jQuery is just for the demo! Hammer.js works without jQuery :-) -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="../hammer.js"></script>
<script src="../plugins/hammer.fakemultitouch.js"></script>
<script src="../plugins/hammer.showtouches.js"></script>
<!--[if !IE]> -->
<script>
Hammer.plugins.showTouches();
</script>
<!-- <![endif]-->
<script>
Hammer.plugins.fakeMultitouch();
function getEl(id) {
return document.getElementById(id);
}
var log_elements = {};
var prevent_scroll_drag = true;
$("#prevent-default").click(function() {
hammertime.options.prevent_default = this.checked;
});
function getLogElement(type, name) {
var el = log_elements[type + name];
if(!el) {
return log_elements[type + name] = getEl("log-"+ type +"-"+ name);
}
return el;
}
// log properties
var properties = ['gesture','center','deltaTime','angle','direction',
'distance','deltaX','deltaY','velocityX','velocityY', 'pointerType',
'scale','rotation','touches','target'];
function logEvent(ev) {
if(!ev.gesture) {
return;
}
// add to the large event log at the bottom of the page
var log = [this.id, ev.type];
//event_log.innerHTML = log.join(" - ") +"\n" + event_log.innerHTML;
// highlight gesture
var event_el = getLogElement('gesture', ev.type);
event_el.className = "active";
for(var i= 0,len=properties.length; i<len; i++) {
var prop = properties[i];
var value = ev.gesture[prop];
switch(prop) {
case 'center':
value = value.pageX +"x"+ value.pageY;
break;
case 'gesture':
value = ev.type;
break;
case 'target':
value = ev.gesture.target.tagName;
break;
case 'touches':
value = ev.gesture.touches.length;
break;
}
getLogElement('prop', prop).innerHTML = value;
}
}
// get all the events
var all_events = [];
$("#events-list li").each(function() {
var li = $(this);
var type = li.text();
li.attr("id", "log-gesture-"+type);
all_events.push(type);
});
// start!
var hammertime = Hammer(getEl('hitarea'), {
prevent_default: true,
no_mouseevents: true
})
.on(all_events.join(" "), logEvent);
</script>
<script src="assets/js/ga.js" async></script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<title>Hammer.js</title>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css" rel="stylesheet">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<style>
body {
padding: 0;
overflow: hidden;
}
#pinchzoom {
-webkit-transform: translate3d(0,0,0);
overflow: hidden;
}
</style>
</head>
<body>
<div id="pinchzoom">
<div>
<img id="rect" src="assets/img/monalisa.jpg" width="2835" height="4289" ondragstart="return false" alt="" />
</div>
</div>
<!-- jQuery is just for the demo! Hammer.js works without jQuery :-) -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="../hammer.js"></script>
<script src="../plugins/hammer.fakemultitouch.js"></script>
<script src="../plugins/hammer.showtouches.js"></script>
<!--[if !IE]> -->
<script>
// show touches doesnt work well in older IE versions due lack of support of
// the pointer-event css property
if(!Hammer.HAS_TOUCHEVENTS && !Hammer.HAS_POINTEREVENTS) {
Hammer.plugins.showTouches();
}
</script>
<!-- <![endif]-->
<script>
if(!Hammer.HAS_TOUCHEVENTS && !Hammer.HAS_POINTEREVENTS) {
Hammer.plugins.fakeMultitouch();
}
var hammertime = Hammer(document.getElementById('pinchzoom'), {
transform_always_block: true,
transform_min_scale: 1,
drag_block_horizontal: true,
drag_block_vertical: true,
drag_min_distance: 0
});
var rect = document.getElementById('rect');
var posX=0, posY=0,
scale=1, last_scale,
rotation= 1, last_rotation;
hammertime.on('touch drag transform', function(ev) {
switch(ev.type) {
case 'touch':
last_scale = scale;
last_rotation = rotation;
break;
case 'drag':
posX = ev.gesture.deltaX;
posY = ev.gesture.deltaY;
break;
case 'transform':
rotation = last_rotation + ev.gesture.rotation;
scale = Math.max(1, Math.min(last_scale * ev.gesture.scale, 10));
break;
}
// transform!
var transform =
"translate3d("+posX+"px,"+posY+"px, 0) " +
"scale3d("+scale+","+scale+", 0) " +
"rotate("+rotation+"deg) ";
rect.style.transform = transform;
rect.style.oTransform = transform;
rect.style.msTransform = transform;
rect.style.mozTransform = transform;
rect.style.webkitTransform = transform;
});
</script>
<script src="assets/js/ga.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Hammer.js</title>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css" rel="stylesheet">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<style>
body { padding: 0; }
/* pull down is a translate3d y position */
#container {
position: relative;
padding: 20px;
-webkit-transition: -webkit-transform 0ms;
transform: translate3d(0,0,0) scale3d(1,1,1);
-o-transform: translate3d(0,0,0) scale3d(1,1,1);
-ms-transform: translate3d(0,0,0) scale3d(1,1,1);
-moz-transform: translate3d(0,0,0) scale3d(1,1,1);
-webkit-transform: translate3d(0,0,0) scale3d(1,1,1);
-webkit-backface-visibility: hidden;
}
/* slide up with small animation */
#container.pullrefresh-slideup,
#container.pullrefresh-loading {
-o-transition: -o-transform .3s;
-ms-transition: -ms-transform .3s;
-moz-transition: -moz-transform .3s;
-webkit-transition: -webkit-transform .3s;
}
/* place the pullrefresh box above the container */
#pullrefresh {
display: block;
overflow: hidden;
position: absolute;
top: -490px;
left: 0;
width: 100%;
height: 490px;
background: #ccc;
box-shadow: 0 -5px 10px #bbb inset;
}
#pullrefresh .message {
position: absolute;
left: 0;
bottom: 20px;
right: 0;
color: #777;
text-align: center;
text-shadow: 1px 1px 0 #dfdfdf;
font-weight: bold;
}
/* change message with css */
#pullrefresh .message span:after { content: "Pull to refresh..."; }
.pullrefresh-breakpoint #pullrefresh .message span:after { content: "Release to refresh..."; }
.pullrefresh-loading #pullrefresh .message span:after { content: "Loading new image..."; }
/* icon */
#pullrefresh .icon {
position: absolute;
left: 20px;
}
/* arrow icon */
#pullrefresh .icon.arrow {
background: url(assets/img/arrow.png) no-repeat;
width: 71px;
height: 28px;
bottom: 10px;
transform: rotate(90deg);
transition: transform .3s;
-o-transform: rotate(90deg);
-o-transition: -o-transform .3s;
-ms-transform: rotate(90deg);
-ms-transition: -ms-transform .3s;
-moz-transform: rotate(90deg);
-moz-transition: -moz-transform .3s;
-webkit-transform: rotate(90deg);
-webkit-transition: -webkit-transform .3s;
-webkit-backface-visibility: hidden;
}
#pullrefresh .icon.arrow.arrow-up {
transform: rotate(-90deg);
-o-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-webkit-transform: rotate(-90deg);
}
/* spinner icon */
/* rotate spinner with css animation */
@keyframes rotate{ 0%{ transform: rotate(0deg); } 100%{ transform: rotate(360deg); } }
@-o-keyframes rotate{ 0%{ -o-transform: rotate(0deg); } 100%{ -o-transform: rotate(360deg); } }
@-ms-keyframes rotate{ 0%{ -ms-transform: rotate(0deg); } 100%{ -ms-transform: rotate(360deg); } }
@-moz-keyframes rotate{ 0%{ -moz-transform: rotate(0deg); } 100%{ -moz-transform: rotate(360deg); } }
@-webkit-keyframes rotate{ 0%{ -webkit-transform: rotate(0deg); } 100%{ -webkit-transform: rotate(360deg); } }
#pullrefresh .icon.loading {
background: url(assets/img/spinner.png) no-repeat;
width: 19px;
height: 19px;
background-size: 100%;
bottom: 0;
animation: rotate 1s linear infinite;
-o-animation: rotate 1s linear infinite;
-ms-animation: rotate 1s linear infinite;
-moz-animation: rotate 1s linear infinite;
-webkit-animation: rotate 1s linear infinite;
}
</style>
</head>
<body>
<div id="container">
<div id="pullrefresh">
<div class="message">
<div id="pullrefresh-icon" class="icon arrow arrow-down"></div>
<span></span>
</div>
</div>
<div id="content">
<h4>Pull-to-Refresh <small>random images</small></h4>
<p>
<img id="random-image" class="img-rounded" src="http://lorempixel.com/800/600/">
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent at erat felis. Donec ornare ligula non nibh vulputate sollicitudin. Cras sodales eros a velit pulvinar vehicula. In sed lorem lectus, vel dapibus nulla. Mauris lacus massa, volutpat vel suscipit at, lacinia condimentum libero. Praesent nec metus ligula. Morbi porttitor rhoncus mattis.
</p>
<p>
Donec adipiscing porttitor risus, vel commodo ante tincidunt vitae. Fusce lacinia augue non sapien volutpat facilisis. Integer varius faucibus metus, sit amet viverra justo venenatis id. Nam ornare rhoncus tempus. Nulla eleifend, mauris quis auctor bibendum, mi purus interdum sapien, id fringilla nunc mi ut tortor. Sed pretium egestas augue, eget volutpat ipsum egestas nec. Aliquam a elementum justo. Suspendisse tempus, nisi id tincidunt vulputate, nunc sem scelerisque risus, molestie facilisis lacus velit et nunc. Phasellus sed convallis libero. Phasellus sit amet neque non arcu pellentesque laoreet id sed ligula. Donec gravida laoreet condimentum. Ut ornare dignissim tempus. Mauris aliquet tincidunt turpis, quis pulvinar nisl pulvinar id. Sed in gravida ligula.
</p>
<p>
Ut molestie, lectus vel pharetra pharetra, nunc libero interdum ligula, eget vulputate purus nulla sit amet turpis. Aliquam volutpat porttitor erat ac volutpat. Donec ligula elit, tincidunt non congue id, iaculis feugiat sem. Phasellus vestibulum mi id enim interdum imperdiet. Ut dolor ante, tempus sit amet ornare a, faucibus sed massa. Curabitur adipiscing, mauris eget vestibulum lacinia, nisl lorem viverra velit, vitae facilisis urna erat et est. Pellentesque fringilla metus libero, at accumsan nisl. Etiam nisl lorem, placerat ut tristique vel, luctus id nulla. Sed vel nunc ut justo volutpat eleifend ac nec risus. Praesent at viverra tellus. Maecenas semper pellentesque quam, et bibendum nisl eleifend sit amet. Donec sed elit eget magna dictum dignissim.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent at erat felis. Donec ornare ligula non nibh vulputate sollicitudin. Cras sodales eros a velit pulvinar vehicula. In sed lorem lectus, vel dapibus nulla. Mauris lacus massa, volutpat vel suscipit at, lacinia condimentum libero. Praesent nec metus ligula. Morbi porttitor rhoncus mattis.
</p>
<p>
Donec adipiscing porttitor risus, vel commodo ante tincidunt vitae. Fusce lacinia augue non sapien volutpat facilisis. Integer varius faucibus metus, sit amet viverra justo venenatis id. Nam ornare rhoncus tempus. Nulla eleifend, mauris quis auctor bibendum, mi purus interdum sapien, id fringilla nunc mi ut tortor. Sed pretium egestas augue, eget volutpat ipsum egestas nec. Aliquam a elementum justo. Suspendisse tempus, nisi id tincidunt vulputate, nunc sem scelerisque risus, molestie facilisis lacus velit et nunc. Phasellus sed convallis libero. Phasellus sit amet neque non arcu pellentesque laoreet id sed ligula. Donec gravida laoreet condimentum. Ut ornare dignissim tempus. Mauris aliquet tincidunt turpis, quis pulvinar nisl pulvinar id. Sed in gravida ligula.
</p>
<p>
Ut molestie, lectus vel pharetra pharetra, nunc libero interdum ligula, eget vulputate purus nulla sit amet turpis. Aliquam volutpat porttitor erat ac volutpat. Donec ligula elit, tincidunt non congue id, iaculis feugiat sem. Phasellus vestibulum mi id enim interdum imperdiet. Ut dolor ante, tempus sit amet ornare a, faucibus sed massa. Curabitur adipiscing, mauris eget vestibulum lacinia, nisl lorem viverra velit, vitae facilisis urna erat et est. Pellentesque fringilla metus libero, at accumsan nisl. Etiam nisl lorem, placerat ut tristique vel, luctus id nulla. Sed vel nunc ut justo volutpat eleifend ac nec risus. Praesent at viverra tellus. Maecenas semper pellentesque quam, et bibendum nisl eleifend sit amet. Donec sed elit eget magna dictum dignissim.
</p>
</div>
</div>
<script src="../hammer.js"></script>
<script src="assets/js/modernizr.js"></script>
<script>
/**
* requestAnimationFrame and cancel polyfill
*/
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame =
window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
/**
* pull to refresh
* @type {*}
*/
var PullToRefresh = (function() {
function Main(container, slidebox, slidebox_icon, handler) {
var self = this;
this.breakpoint = 80;
this.container = container;
this.slidebox = slidebox;
this.slidebox_icon = slidebox_icon;
this.handler = handler;
this._slidedown_height = 0;
this._anim = null;
this._dragged_down = false;
this.hammertime = Hammer(this.container)
.on("touch dragdown release", function(ev) {
self.handleHammer(ev);
});
};
/**
* Handle HammerJS callback
* @param ev
*/
Main.prototype.handleHammer = function(ev) {
var self = this;
switch(ev.type) {
// reset element on start
case 'touch':
this.hide();
break;
// on release we check how far we dragged
case 'release':
if(!this._dragged_down) {
return;
}
// cancel animation
cancelAnimationFrame(this._anim);
// over the breakpoint, trigger the callback
if(ev.gesture.deltaY >= this.breakpoint) {
container_el.className = 'pullrefresh-loading';
pullrefresh_icon_el.className = 'icon loading';
this.setHeight(60);
this.handler.call(this);
}
// just hide it
else {
pullrefresh_el.className = 'slideup';
container_el.className = 'pullrefresh-slideup';
this.hide();
}
break;
// when we dragdown
case 'dragdown':
this._dragged_down = true;
// if we are not at the top move down
var scrollY = window.scrollY;
if(scrollY > 5) {
return;
} else if(scrollY !== 0) {
window.scrollTo(0,0);
}
// no requestAnimationFrame instance is running, start one
if(!this._anim) {
this.updateHeight();
}
// stop browser scrolling
ev.gesture.preventDefault();
// update slidedown height
// it will be updated when requestAnimationFrame is called
this._slidedown_height = ev.gesture.deltaY * 0.4;
break;
}
};
/**
* when we set the height, we just change the container y
* @param {Number} height
*/
Main.prototype.setHeight = function(height) {
if(Modernizr.csstransforms3d) {
this.container.style.transform = 'translate3d(0,'+height+'px,0) ';
this.container.style.oTransform = 'translate3d(0,'+height+'px,0)';
this.container.style.msTransform = 'translate3d(0,'+height+'px,0)';
this.container.style.mozTransform = 'translate3d(0,'+height+'px,0)';
this.container.style.webkitTransform = 'translate3d(0,'+height+'px,0) scale3d(1,1,1)';
}
else if(Modernizr.csstransforms) {
this.container.style.transform = 'translate(0,'+height+'px) ';
this.container.style.oTransform = 'translate(0,'+height+'px)';
this.container.style.msTransform = 'translate(0,'+height+'px)';
this.container.style.mozTransform = 'translate(0,'+height+'px)';
this.container.style.webkitTransform = 'translate(0,'+height+'px)';
}
else {
this.container.style.top = height+"px";
}
};
/**
* hide the pullrefresh message and reset the vars
*/
Main.prototype.hide = function() {
container_el.className = '';
this._slidedown_height = 0;
this.setHeight(0);
cancelAnimationFrame(this._anim);
this._anim = null;
this._dragged_down = false;
};
/**
* hide the pullrefresh message and reset the vars
*/
Main.prototype.slideUp = function() {
var self = this;
cancelAnimationFrame(this._anim);
pullrefresh_el.className = 'slideup';
container_el.className = 'pullrefresh-slideup';
this.setHeight(0);
setTimeout(function() {
self.hide();
}, 500);
};
/**
* update the height of the slidedown message
*/
Main.prototype.updateHeight = function() {
var self = this;
this.setHeight(this._slidedown_height);
if(this._slidedown_height >= this.breakpoint){
this.slidebox.className = 'breakpoint';
this.slidebox_icon.className = 'icon arrow arrow-up';
}
else {
this.slidebox.className = '';
this.slidebox_icon.className = 'icon arrow';
}
this._anim = requestAnimationFrame(function() {
self.updateHeight();
});
};
return Main;
})();
function getEl(id) {
return document.getElementById(id);
}
var container_el = getEl('container');
var pullrefresh_el = getEl('pullrefresh');
var pullrefresh_icon_el = getEl('pullrefresh-icon');
var image_el = getEl('random-image');
var refresh = new PullToRefresh(container_el, pullrefresh_el, pullrefresh_icon_el);
// update image onrefresh
refresh.handler = function() {
var self = this;
// a small timeout to demo the loading state
setTimeout(function() {
var preload = new Image();
preload.onload = function() {
image_el.src = this.src;
self.slideUp();
};
preload.src = 'http://lorempixel.com/800/600/?'+ (new Date().getTime());
}, 1000);
};
</script>
<script src="assets/js/ga.js"></script>
</body>
</html>
\ No newline at end of file
/*! Hammer.JS - v1.0.6 - 2014-01-02
* http://eightmedia.github.com/hammer.js
*
* Copyright (c) 2014 Jorik Tangelder <j.tangelder@gmail.com>;
* Licensed under the MIT license */
(function(window, undefined) {
'use strict';
/**
* Hammer
* use this to create instances
* @param {HTMLElement} element
* @param {Object} options
* @returns {Hammer.Instance}
* @constructor
*/
var Hammer = function(element, options) {
return new Hammer.Instance(element, options || {});
};
// default settings
Hammer.defaults = {
// add styles and attributes to the element to prevent the browser from doing
// its native behavior. this doesnt prevent the scrolling, but cancels
// the contextmenu, tap highlighting etc
// set to false to disable this
stop_browser_behavior: {
// this also triggers onselectstart=false for IE
userSelect : 'none',
// this makes the element blocking in IE10 >, you could experiment with the value
// see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241
touchAction : 'none',
touchCallout : 'none',
contentZooming : 'none',
userDrag : 'none',
tapHighlightColor: 'rgba(0,0,0,0)'
}
//
// more settings are defined per gesture at gestures.js
//
};
// detect touchevents
Hammer.HAS_POINTEREVENTS = window.navigator.pointerEnabled || window.navigator.msPointerEnabled;
Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window);
// dont use mouseevents on mobile devices
Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android|silk/i;
Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && window.navigator.userAgent.match(Hammer.MOBILE_REGEX);
// eventtypes per touchevent (start, move, end)
// are filled by Hammer.event.determineEventTypes on setup
Hammer.EVENT_TYPES = {};
// direction defines
Hammer.DIRECTION_DOWN = 'down';
Hammer.DIRECTION_LEFT = 'left';
Hammer.DIRECTION_UP = 'up';
Hammer.DIRECTION_RIGHT = 'right';
// pointer type
Hammer.POINTER_MOUSE = 'mouse';
Hammer.POINTER_TOUCH = 'touch';
Hammer.POINTER_PEN = 'pen';
// touch event defines
Hammer.EVENT_START = 'start';
Hammer.EVENT_MOVE = 'move';
Hammer.EVENT_END = 'end';
// hammer document where the base events are added at
Hammer.DOCUMENT = window.document;
// plugins and gestures namespaces
Hammer.plugins = Hammer.plugins || {};
Hammer.gestures = Hammer.gestures || {};
// if the window events are set...
Hammer.READY = false;
/**
* setup events to detect gestures on the document
*/
function setup() {
if(Hammer.READY) {
return;
}
// find what eventtypes we add listeners to
Hammer.event.determineEventTypes();
// Register all gestures inside Hammer.gestures
Hammer.utils.each(Hammer.gestures, function(gesture){
Hammer.detection.register(gesture);
});
// Add touch events on the document
Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect);
Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect);
// Hammer is ready...!
Hammer.READY = true;
}
Hammer.utils = {
/**
* extend method,
* also used for cloning when dest is an empty object
* @param {Object} dest
* @param {Object} src
* @parm {Boolean} merge do a merge
* @returns {Object} dest
*/
extend: function extend(dest, src, merge) {
for(var key in src) {
if(dest[key] !== undefined && merge) {
continue;
}
dest[key] = src[key];
}
return dest;
},
/**
* for each
* @param obj
* @param iterator
*/
each: function(obj, iterator, context) {
var i, length;
// native forEach on arrays
if ('forEach' in obj) {
obj.forEach(iterator, context);
}
// arrays
else if(obj.length !== undefined) {
for (i = 0, length = obj.length; i < length; i++) {
if (iterator.call(context, obj[i], i, obj) === false) {
return;
}
}
}
// objects
else {
for (i in obj) {
if (obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj) === false) {
return;
}
}
}
},
/**
* find if a node is in the given parent
* used for event delegation tricks
* @param {HTMLElement} node
* @param {HTMLElement} parent
* @returns {boolean} has_parent
*/
hasParent: function(node, parent) {
while(node) {
if(node == parent) {
return true;
}
node = node.parentNode;
}
return false;
},
/**
* get the center of all the touches
* @param {Array} touches
* @returns {Object} center
*/
getCenter: function getCenter(touches) {
var valuesX = [], valuesY = [];
Hammer.utils.each(touches, function(touch) {
// I prefer clientX because it ignore the scrolling position
valuesX.push(typeof touch.clientX !== 'undefined' ? touch.clientX : touch.pageX );
valuesY.push(typeof touch.clientY !== 'undefined' ? touch.clientY : touch.pageY );
});
return {
pageX: ((Math.min.apply(Math, valuesX) + Math.max.apply(Math, valuesX)) / 2),
pageY: ((Math.min.apply(Math, valuesY) + Math.max.apply(Math, valuesY)) / 2)
};
},
/**
* calculate the velocity between two points
* @param {Number} delta_time
* @param {Number} delta_x
* @param {Number} delta_y
* @returns {Object} velocity
*/
getVelocity: function getVelocity(delta_time, delta_x, delta_y) {
return {
x: Math.abs(delta_x / delta_time) || 0,
y: Math.abs(delta_y / delta_time) || 0
};
},
/**
* calculate the angle between two coordinates
* @param {Touch} touch1
* @param {Touch} touch2
* @returns {Number} angle
*/
getAngle: function getAngle(touch1, touch2) {
var y = touch2.pageY - touch1.pageY,
x = touch2.pageX - touch1.pageX;
return Math.atan2(y, x) * 180 / Math.PI;
},
/**
* angle to direction define
* @param {Touch} touch1
* @param {Touch} touch2
* @returns {String} direction constant, like Hammer.DIRECTION_LEFT
*/
getDirection: function getDirection(touch1, touch2) {
var x = Math.abs(touch1.pageX - touch2.pageX),
y = Math.abs(touch1.pageY - touch2.pageY);
if(x >= y) {
return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT;
}
else {
return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN;
}
},
/**
* calculate the distance between two touches
* @param {Touch} touch1
* @param {Touch} touch2
* @returns {Number} distance
*/
getDistance: function getDistance(touch1, touch2) {
var x = touch2.pageX - touch1.pageX,
y = touch2.pageY - touch1.pageY;
return Math.sqrt((x * x) + (y * y));
},
/**
* calculate the scale factor between two touchLists (fingers)
* no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
* @param {Array} start
* @param {Array} end
* @returns {Number} scale
*/
getScale: function getScale(start, end) {
// need two fingers...
if(start.length >= 2 && end.length >= 2) {
return this.getDistance(end[0], end[1]) /
this.getDistance(start[0], start[1]);
}
return 1;
},
/**
* calculate the rotation degrees between two touchLists (fingers)
* @param {Array} start
* @param {Array} end
* @returns {Number} rotation
*/
getRotation: function getRotation(start, end) {
// need two fingers
if(start.length >= 2 && end.length >= 2) {
return this.getAngle(end[1], end[0]) -
this.getAngle(start[1], start[0]);
}
return 0;
},
/**
* boolean if the direction is vertical
* @param {String} direction
* @returns {Boolean} is_vertical
*/
isVertical: function isVertical(direction) {
return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN);
},
/**
* stop browser default behavior with css props
* @param {HtmlElement} element
* @param {Object} css_props
*/
stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) {
if(!css_props || !element || !element.style) {
return;
}
// with css properties for modern browsers
Hammer.utils.each(['webkit', 'khtml', 'moz', 'Moz', 'ms', 'o', ''], function(vendor) {
Hammer.utils.each(css_props, function(prop) {
// vender prefix at the property
if(vendor) {
prop = vendor + prop.substring(0, 1).toUpperCase() + prop.substring(1);
}
// set the style
if(prop in element.style) {
element.style[prop] = prop;
}
});
});
// also the disable onselectstart
if(css_props.userSelect == 'none') {
element.onselectstart = function() {
return false;
};
}
// and disable ondragstart
if(css_props.userDrag == 'none') {
element.ondragstart = function() {
return false;
};
}
}
};
/**
* create new hammer instance
* all methods should return the instance itself, so it is chainable.
* @param {HTMLElement} element
* @param {Object} [options={}]
* @returns {Hammer.Instance}
* @constructor
*/
Hammer.Instance = function(element, options) {
var self = this;
// setup HammerJS window events and register all gestures
// this also sets up the default options
setup();
this.element = element;
// start/stop detection option
this.enabled = true;
// merge options
this.options = Hammer.utils.extend(
Hammer.utils.extend({}, Hammer.defaults),
options || {});
// add some css to the element to prevent the browser from doing its native behavoir
if(this.options.stop_browser_behavior) {
Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior);
}
// start detection on touchstart
Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) {
if(self.enabled) {
Hammer.detection.startDetect(self, ev);
}
});
// return instance
return this;
};
Hammer.Instance.prototype = {
/**
* bind events to the instance
* @param {String} gesture
* @param {Function} handler
* @returns {Hammer.Instance}
*/
on: function onEvent(gesture, handler) {
var gestures = gesture.split(' ');
Hammer.utils.each(gestures, function(gesture) {
this.element.addEventListener(gesture, handler, false);
}, this);
return this;
},
/**
* unbind events to the instance
* @param {String} gesture
* @param {Function} handler
* @returns {Hammer.Instance}
*/
off: function offEvent(gesture, handler) {
var gestures = gesture.split(' ');
Hammer.utils.each(gestures, function(gesture) {
this.element.removeEventListener(gesture, handler, false);
}, this);
return this;
},
/**
* trigger gesture event
* @param {String} gesture
* @param {Object} [eventData]
* @returns {Hammer.Instance}
*/
trigger: function triggerEvent(gesture, eventData) {
// optional
if(!eventData) {
eventData = {};
}
// create DOM event
var event = Hammer.DOCUMENT.createEvent('Event');
event.initEvent(gesture, true, true);
event.gesture = eventData;
// trigger on the target if it is in the instance element,
// this is for event delegation tricks
var element = this.element;
if(Hammer.utils.hasParent(eventData.target, element)) {
element = eventData.target;
}
element.dispatchEvent(event);
return this;
},
/**
* enable of disable hammer.js detection
* @param {Boolean} state
* @returns {Hammer.Instance}
*/
enable: function enable(state) {
this.enabled = state;
return this;
}
};
/**
* this holds the last move event,
* used to fix empty touchend issue
* see the onTouch event for an explanation
* @type {Object}
*/
var last_move_event = null;
/**
* when the mouse is hold down, this is true
* @type {Boolean}
*/
var enable_detect = false;
/**
* when touch events have been fired, this is true
* @type {Boolean}
*/
var touch_triggered = false;
Hammer.event = {
/**
* simple addEventListener
* @param {HTMLElement} element
* @param {String} type
* @param {Function} handler
*/
bindDom: function(element, type, handler) {
var types = type.split(' ');
Hammer.utils.each(types, function(type){
element.addEventListener(type, handler, false);
});
},
/**
* touch events with mouse fallback
* @param {HTMLElement} element
* @param {String} eventType like Hammer.EVENT_MOVE
* @param {Function} handler
*/
onTouch: function onTouch(element, eventType, handler) {
var self = this;
this.bindDom(element, Hammer.EVENT_TYPES[eventType], function bindDomOnTouch(ev) {
var sourceEventType = ev.type.toLowerCase();
// onmouseup, but when touchend has been fired we do nothing.
// this is for touchdevices which also fire a mouseup on touchend
if(sourceEventType.match(/mouse/) && touch_triggered) {
return;
}
// mousebutton must be down or a touch event
else if(sourceEventType.match(/touch/) || // touch events are always on screen
sourceEventType.match(/pointerdown/) || // pointerevents touch
(sourceEventType.match(/mouse/) && ev.which === 1) // mouse is pressed
) {
enable_detect = true;
}
// mouse isn't pressed
else if(sourceEventType.match(/mouse/) && !ev.which) {
enable_detect = false;
}
// we are in a touch event, set the touch triggered bool to true,
// this for the conflicts that may occur on ios and android
if(sourceEventType.match(/touch|pointer/)) {
touch_triggered = true;
}
// count the total touches on the screen
var count_touches = 0;
// when touch has been triggered in this detection session
// and we are now handling a mouse event, we stop that to prevent conflicts
if(enable_detect) {
// update pointerevent
if(Hammer.HAS_POINTEREVENTS && eventType != Hammer.EVENT_END) {
count_touches = Hammer.PointerEvent.updatePointer(eventType, ev);
}
// touch
else if(sourceEventType.match(/touch/)) {
count_touches = ev.touches.length;
}
// mouse
else if(!touch_triggered) {
count_touches = sourceEventType.match(/up/) ? 0 : 1;
}
// if we are in a end event, but when we remove one touch and
// we still have enough, set eventType to move
if(count_touches > 0 && eventType == Hammer.EVENT_END) {
eventType = Hammer.EVENT_MOVE;
}
// no touches, force the end event
else if(!count_touches) {
eventType = Hammer.EVENT_END;
}
// store the last move event
if(count_touches || last_move_event === null) {
last_move_event = ev;
}
// trigger the handler
handler.call(Hammer.detection, self.collectEventData(element, eventType, self.getTouchList(last_move_event, eventType), ev));
// remove pointerevent from list
if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) {
count_touches = Hammer.PointerEvent.updatePointer(eventType, ev);
}
}
// on the end we reset everything
if(!count_touches) {
last_move_event = null;
enable_detect = false;
touch_triggered = false;
Hammer.PointerEvent.reset();
}
});
},
/**
* we have different events for each device/browser
* determine what we need and set them in the Hammer.EVENT_TYPES constant
*/
determineEventTypes: function determineEventTypes() {
// determine the eventtype we want to set
var types;
// pointerEvents magic
if(Hammer.HAS_POINTEREVENTS) {
types = Hammer.PointerEvent.getEvents();
}
// on Android, iOS, blackberry, windows mobile we dont want any mouseevents
else if(Hammer.NO_MOUSEEVENTS) {
types = [
'touchstart',
'touchmove',
'touchend touchcancel'];
}
// for non pointer events browsers and mixed browsers,
// like chrome on windows8 touch laptop
else {
types = [
'touchstart mousedown',
'touchmove mousemove',
'touchend touchcancel mouseup'];
}
Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0];
Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1];
Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2];
},
/**
* create touchlist depending on the event
* @param {Object} ev
* @param {String} eventType used by the fakemultitouch plugin
*/
getTouchList: function getTouchList(ev/*, eventType*/) {
// get the fake pointerEvent touchlist
if(Hammer.HAS_POINTEREVENTS) {
return Hammer.PointerEvent.getTouchList();
}
// get the touchlist
else if(ev.touches) {
return ev.touches;
}
// make fake touchlist from mouse position
else {
ev.identifier = 1;
return [ev];
}
},
/**
* collect event data for Hammer js
* @param {HTMLElement} element
* @param {String} eventType like Hammer.EVENT_MOVE
* @param {Object} eventData
*/
collectEventData: function collectEventData(element, eventType, touches, ev) {
// find out pointerType
var pointerType = Hammer.POINTER_TOUCH;
if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) {
pointerType = Hammer.POINTER_MOUSE;
}
return {
center : Hammer.utils.getCenter(touches),
timeStamp : new Date().getTime(),
target : ev.target,
touches : touches,
eventType : eventType,
pointerType: pointerType,
srcEvent : ev,
/**
* prevent the browser default actions
* mostly used to disable scrolling of the browser
*/
preventDefault: function() {
if(this.srcEvent.preventManipulation) {
this.srcEvent.preventManipulation();
}
if(this.srcEvent.preventDefault) {
this.srcEvent.preventDefault();
}
},
/**
* stop bubbling the event up to its parents
*/
stopPropagation: function() {
this.srcEvent.stopPropagation();
},
/**
* immediately stop gesture detection
* might be useful after a swipe was detected
* @return {*}
*/
stopDetect: function() {
return Hammer.detection.stopDetect();
}
};
}
};
Hammer.PointerEvent = {
/**
* holds all pointers
* @type {Object}
*/
pointers: {},
/**
* get a list of pointers
* @returns {Array} touchlist
*/
getTouchList: function() {
var self = this;
var touchlist = [];
// we can use forEach since pointerEvents only is in IE10
Hammer.utils.each(self.pointers, function(pointer){
touchlist.push(pointer);
});
return touchlist;
},
/**
* update the position of a pointer
* @param {String} type Hammer.EVENT_END
* @param {Object} pointerEvent
*/
updatePointer: function(type, pointerEvent) {
if(type == Hammer.EVENT_END) {
this.pointers = {};
}
else {
pointerEvent.identifier = pointerEvent.pointerId;
this.pointers[pointerEvent.pointerId] = pointerEvent;
}
return Object.keys(this.pointers).length;
},
/**
* check if ev matches pointertype
* @param {String} pointerType Hammer.POINTER_MOUSE
* @param {PointerEvent} ev
*/
matchType: function(pointerType, ev) {
if(!ev.pointerType) {
return false;
}
var pt = ev.pointerType,
types = {};
types[Hammer.POINTER_MOUSE] = (pt === ev.MSPOINTER_TYPE_MOUSE || pt === Hammer.POINTER_MOUSE);
types[Hammer.POINTER_TOUCH] = (pt === ev.MSPOINTER_TYPE_TOUCH || pt === Hammer.POINTER_TOUCH);
types[Hammer.POINTER_PEN] = (pt === ev.MSPOINTER_TYPE_PEN || pt === Hammer.POINTER_PEN);
return types[pointerType];
},
/**
* get events
*/
getEvents: function() {
return [
'pointerdown MSPointerDown',
'pointermove MSPointerMove',
'pointerup pointercancel MSPointerUp MSPointerCancel'
];
},
/**
* reset the list
*/
reset: function() {
this.pointers = {};
}
};
Hammer.detection = {
// contains all registred Hammer.gestures in the correct order
gestures: [],
// data of the current Hammer.gesture detection session
current : null,
// the previous Hammer.gesture session data
// is a full clone of the previous gesture.current object
previous: null,
// when this becomes true, no gestures are fired
stopped : false,
/**
* start Hammer.gesture detection
* @param {Hammer.Instance} inst
* @param {Object} eventData
*/
startDetect: function startDetect(inst, eventData) {
// already busy with a Hammer.gesture detection on an element
if(this.current) {
return;
}
this.stopped = false;
this.current = {
inst : inst, // reference to HammerInstance we're working for
startEvent: Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc
lastEvent : false, // last eventData
name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc
};
this.detect(eventData);
},
/**
* Hammer.gesture detection
* @param {Object} eventData
*/
detect: function detect(eventData) {
if(!this.current || this.stopped) {
return;
}
// extend event data with calculations about scale, distance etc
eventData = this.extendEventData(eventData);
// instance options
var inst_options = this.current.inst.options;
// call Hammer.gesture handlers
Hammer.utils.each(this.gestures, function(gesture) {
// only when the instance options have enabled this gesture
if(!this.stopped && inst_options[gesture.name] !== false) {
// if a handler returns false, we stop with the detection
if(gesture.handler.call(gesture, eventData, this.current.inst) === false) {
this.stopDetect();
return false;
}
}
}, this);
// store as previous event event
if(this.current) {
this.current.lastEvent = eventData;
}
// endevent, but not the last touch, so dont stop
if(eventData.eventType == Hammer.EVENT_END && !eventData.touches.length - 1) {
this.stopDetect();
}
return eventData;
},
/**
* clear the Hammer.gesture vars
* this is called on endDetect, but can also be used when a final Hammer.gesture has been detected
* to stop other Hammer.gestures from being fired
*/
stopDetect: function stopDetect() {
// clone current data to the store as the previous gesture
// used for the double tap gesture, since this is an other gesture detect session
this.previous = Hammer.utils.extend({}, this.current);
// reset the current
this.current = null;
// stopped!
this.stopped = true;
},
/**
* extend eventData for Hammer.gestures
* @param {Object} ev
* @returns {Object} ev
*/
extendEventData: function extendEventData(ev) {
var startEv = this.current.startEvent;
// if the touches change, set the new touches over the startEvent touches
// this because touchevents don't have all the touches on touchstart, or the
// user must place his fingers at the EXACT same time on the screen, which is not realistic
// but, sometimes it happens that both fingers are touching at the EXACT same time
if(startEv && (ev.touches.length != startEv.touches.length || ev.touches === startEv.touches)) {
// extend 1 level deep to get the touchlist with the touch objects
startEv.touches = [];
Hammer.utils.each(ev.touches, function(touch) {
startEv.touches.push(Hammer.utils.extend({}, touch));
});
}
var delta_time = ev.timeStamp - startEv.timeStamp
, delta_x = ev.center.pageX - startEv.center.pageX
, delta_y = ev.center.pageY - startEv.center.pageY
, velocity = Hammer.utils.getVelocity(delta_time, delta_x, delta_y)
, interimAngle
, interimDirection;
// end events (e.g. dragend) don't have useful values for interimDirection & interimAngle
// because the previous event has exactly the same coordinates
// so for end events, take the previous values of interimDirection & interimAngle
// instead of recalculating them and getting a spurious '0'
if(ev.eventType === 'end') {
interimAngle = this.current.lastEvent && this.current.lastEvent.interimAngle;
interimDirection = this.current.lastEvent && this.current.lastEvent.interimDirection;
}
else {
interimAngle = this.current.lastEvent && Hammer.utils.getAngle(this.current.lastEvent.center, ev.center);
interimDirection = this.current.lastEvent && Hammer.utils.getDirection(this.current.lastEvent.center, ev.center);
}
Hammer.utils.extend(ev, {
deltaTime: delta_time,
deltaX: delta_x,
deltaY: delta_y,
velocityX: velocity.x,
velocityY: velocity.y,
distance: Hammer.utils.getDistance(startEv.center, ev.center),
angle: Hammer.utils.getAngle(startEv.center, ev.center),
interimAngle: interimAngle,
direction: Hammer.utils.getDirection(startEv.center, ev.center),
interimDirection: interimDirection,
scale: Hammer.utils.getScale(startEv.touches, ev.touches),
rotation: Hammer.utils.getRotation(startEv.touches, ev.touches),
startEvent: startEv
});
return ev;
},
/**
* register new gesture
* @param {Object} gesture object, see gestures.js for documentation
* @returns {Array} gestures
*/
register: function register(gesture) {
// add an enable gesture options if there is no given
var options = gesture.defaults || {};
if(options[gesture.name] === undefined) {
options[gesture.name] = true;
}
// extend Hammer default options with the Hammer.gesture options
Hammer.utils.extend(Hammer.defaults, options, true);
// set its index
gesture.index = gesture.index || 1000;
// add Hammer.gesture to the list
this.gestures.push(gesture);
// sort the list by index
this.gestures.sort(function(a, b) {
if(a.index < b.index) { return -1; }
if(a.index > b.index) { return 1; }
return 0;
});
return this.gestures;
}
};
/**
* Drag
* Move with x fingers (default 1) around on the page. Blocking the scrolling when
* moving left and right is a good practice. When all the drag events are blocking
* you disable scrolling on that area.
* @events drag, drapleft, dragright, dragup, dragdown
*/
Hammer.gestures.Drag = {
name : 'drag',
index : 50,
defaults : {
drag_min_distance : 10,
// Set correct_for_drag_min_distance to true to make the starting point of the drag
// be calculated from where the drag was triggered, not from where the touch started.
// Useful to avoid a jerk-starting drag, which can make fine-adjustments
// through dragging difficult, and be visually unappealing.
correct_for_drag_min_distance: true,
// set 0 for unlimited, but this can conflict with transform
drag_max_touches : 1,
// prevent default browser behavior when dragging occurs
// be careful with it, it makes the element a blocking element
// when you are using the drag gesture, it is a good practice to set this true
drag_block_horizontal : false,
drag_block_vertical : false,
// drag_lock_to_axis keeps the drag gesture on the axis that it started on,
// It disallows vertical directions if the initial direction was horizontal, and vice versa.
drag_lock_to_axis : false,
// drag lock only kicks in when distance > drag_lock_min_distance
// This way, locking occurs only when the distance has become large enough to reliably determine the direction
drag_lock_min_distance : 25
},
triggered: false,
handler : function dragGesture(ev, inst) {
// current gesture isnt drag, but dragged is true
// this means an other gesture is busy. now call dragend
if(Hammer.detection.current.name != this.name && this.triggered) {
inst.trigger(this.name + 'end', ev);
this.triggered = false;
return;
}
// max touches
if(inst.options.drag_max_touches > 0 &&
ev.touches.length > inst.options.drag_max_touches) {
return;
}
switch(ev.eventType) {
case Hammer.EVENT_START:
this.triggered = false;
break;
case Hammer.EVENT_MOVE:
// when the distance we moved is too small we skip this gesture
// or we can be already in dragging
if(ev.distance < inst.options.drag_min_distance &&
Hammer.detection.current.name != this.name) {
return;
}
// we are dragging!
if(Hammer.detection.current.name != this.name) {
Hammer.detection.current.name = this.name;
if(inst.options.correct_for_drag_min_distance && ev.distance > 0) {
// When a drag is triggered, set the event center to drag_min_distance pixels from the original event center.
// Without this correction, the dragged distance would jumpstart at drag_min_distance pixels instead of at 0.
// It might be useful to save the original start point somewhere
var factor = Math.abs(inst.options.drag_min_distance / ev.distance);
Hammer.detection.current.startEvent.center.pageX += ev.deltaX * factor;
Hammer.detection.current.startEvent.center.pageY += ev.deltaY * factor;
// recalculate event data using new start point
ev = Hammer.detection.extendEventData(ev);
}
}
// lock drag to axis?
if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance <= ev.distance)) {
ev.drag_locked_to_axis = true;
}
var last_direction = Hammer.detection.current.lastEvent.direction;
if(ev.drag_locked_to_axis && last_direction !== ev.direction) {
// keep direction on the axis that the drag gesture started on
if(Hammer.utils.isVertical(last_direction)) {
ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN;
}
else {
ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT;
}
}
// first time, trigger dragstart event
if(!this.triggered) {
inst.trigger(this.name + 'start', ev);
this.triggered = true;
}
// trigger normal event
inst.trigger(this.name, ev);
// direction event, like dragdown
inst.trigger(this.name + ev.direction, ev);
// block the browser events
if((inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) ||
(inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) {
ev.preventDefault();
}
break;
case Hammer.EVENT_END:
// trigger dragend
if(this.triggered) {
inst.trigger(this.name + 'end', ev);
}
this.triggered = false;
break;
}
}
};
/**
* Hold
* Touch stays at the same place for x time
* @events hold
*/
Hammer.gestures.Hold = {
name : 'hold',
index : 10,
defaults: {
hold_timeout : 500,
hold_threshold: 1
},
timer : null,
handler : function holdGesture(ev, inst) {
switch(ev.eventType) {
case Hammer.EVENT_START:
// clear any running timers
clearTimeout(this.timer);
// set the gesture so we can check in the timeout if it still is
Hammer.detection.current.name = this.name;
// set timer and if after the timeout it still is hold,
// we trigger the hold event
this.timer = setTimeout(function() {
if(Hammer.detection.current.name == 'hold') {
inst.trigger('hold', ev);
}
}, inst.options.hold_timeout);
break;
// when you move or end we clear the timer
case Hammer.EVENT_MOVE:
if(ev.distance > inst.options.hold_threshold) {
clearTimeout(this.timer);
}
break;
case Hammer.EVENT_END:
clearTimeout(this.timer);
break;
}
}
};
/**
* Release
* Called as last, tells the user has released the screen
* @events release
*/
Hammer.gestures.Release = {
name : 'release',
index : Infinity,
handler: function releaseGesture(ev, inst) {
if(ev.eventType == Hammer.EVENT_END) {
inst.trigger(this.name, ev);
}
}
};
/**
* Swipe
* triggers swipe events when the end velocity is above the threshold
* @events swipe, swipeleft, swiperight, swipeup, swipedown
*/
Hammer.gestures.Swipe = {
name : 'swipe',
index : 40,
defaults: {
// set 0 for unlimited, but this can conflict with transform
swipe_min_touches: 1,
swipe_max_touches: 1,
swipe_velocity : 0.7
},
handler : function swipeGesture(ev, inst) {
if(ev.eventType == Hammer.EVENT_END) {
// max touches
if(inst.options.swipe_max_touches > 0 &&
ev.touches.length < inst.options.swipe_min_touches &&
ev.touches.length > inst.options.swipe_max_touches) {
return;
}
// when the distance we moved is too small we skip this gesture
// or we can be already in dragging
if(ev.velocityX > inst.options.swipe_velocity ||
ev.velocityY > inst.options.swipe_velocity) {
// trigger swipe events
inst.trigger(this.name, ev);
inst.trigger(this.name + ev.direction, ev);
}
}
}
};
/**
* Tap/DoubleTap
* Quick touch at a place or double at the same place
* @events tap, doubletap
*/
Hammer.gestures.Tap = {
name : 'tap',
index : 100,
defaults: {
tap_max_touchtime : 250,
tap_max_distance : 10,
tap_always : true,
doubletap_distance: 20,
doubletap_interval: 300
},
handler : function tapGesture(ev, inst) {
if(ev.eventType == Hammer.EVENT_END && ev.srcEvent.type != 'touchcancel') {
// previous gesture, for the double tap since these are two different gesture detections
var prev = Hammer.detection.previous,
did_doubletap = false;
// when the touchtime is higher then the max touch time
// or when the moving distance is too much
if(ev.deltaTime > inst.options.tap_max_touchtime ||
ev.distance > inst.options.tap_max_distance) {
return;
}
// check if double tap
if(prev && prev.name == 'tap' &&
(ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval &&
ev.distance < inst.options.doubletap_distance) {
inst.trigger('doubletap', ev);
did_doubletap = true;
}
// do a single tap
if(!did_doubletap || inst.options.tap_always) {
Hammer.detection.current.name = 'tap';
inst.trigger(Hammer.detection.current.name, ev);
}
}
}
};
/**
* Touch
* Called as first, tells the user has touched the screen
* @events touch
*/
Hammer.gestures.Touch = {
name : 'touch',
index : -Infinity,
defaults: {
// call preventDefault at touchstart, and makes the element blocking by
// disabling the scrolling of the page, but it improves gestures like
// transforming and dragging.
// be careful with using this, it can be very annoying for users to be stuck
// on the page
prevent_default : false,
// disable mouse events, so only touch (or pen!) input triggers events
prevent_mouseevents: false
},
handler : function touchGesture(ev, inst) {
if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) {
ev.stopDetect();
return;
}
if(inst.options.prevent_default) {
ev.preventDefault();
}
if(ev.eventType == Hammer.EVENT_START) {
inst.trigger(this.name, ev);
}
}
};
/**
* Transform
* User want to scale or rotate with 2 fingers
* @events transform, pinch, pinchin, pinchout, rotate
*/
Hammer.gestures.Transform = {
name : 'transform',
index : 45,
defaults : {
// factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1
transform_min_scale : 0.01,
// rotation in degrees
transform_min_rotation: 1,
// prevent default browser behavior when two touches are on the screen
// but it makes the element a blocking element
// when you are using the transform gesture, it is a good practice to set this true
transform_always_block: false
},
triggered: false,
handler : function transformGesture(ev, inst) {
// current gesture isnt drag, but dragged is true
// this means an other gesture is busy. now call dragend
if(Hammer.detection.current.name != this.name && this.triggered) {
inst.trigger(this.name + 'end', ev);
this.triggered = false;
return;
}
// atleast multitouch
if(ev.touches.length < 2) {
return;
}
// prevent default when two fingers are on the screen
if(inst.options.transform_always_block) {
ev.preventDefault();
}
switch(ev.eventType) {
case Hammer.EVENT_START:
this.triggered = false;
break;
case Hammer.EVENT_MOVE:
var scale_threshold = Math.abs(1 - ev.scale);
var rotation_threshold = Math.abs(ev.rotation);
// when the distance we moved is too small we skip this gesture
// or we can be already in dragging
if(scale_threshold < inst.options.transform_min_scale &&
rotation_threshold < inst.options.transform_min_rotation) {
return;
}
// we are transforming!
Hammer.detection.current.name = this.name;
// first time, trigger dragstart event
if(!this.triggered) {
inst.trigger(this.name + 'start', ev);
this.triggered = true;
}
inst.trigger(this.name, ev); // basic transform event
// trigger rotate event
if(rotation_threshold > inst.options.transform_min_rotation) {
inst.trigger('rotate', ev);
}
// trigger pinch event
if(scale_threshold > inst.options.transform_min_scale) {
inst.trigger('pinch', ev);
inst.trigger('pinch' + ((ev.scale < 1) ? 'in' : 'out'), ev);
}
break;
case Hammer.EVENT_END:
// trigger dragend
if(this.triggered) {
inst.trigger(this.name + 'end', ev);
}
this.triggered = false;
break;
}
}
};
// Based off Lo-Dash's excellent UMD wrapper (slightly modified) - https://github.com/bestiejs/lodash/blob/master/lodash.js#L5515-L5543
// some AMD build optimizers, like r.js, check for specific condition patterns like the following:
if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
// define as an anonymous module
define(function() {
return Hammer;
});
// check for `exports` after `define` in case a build optimizer adds an `exports` object
}
else if(typeof module === 'object' && typeof module.exports === 'object') {
module.exports = Hammer;
}
else {
window.Hammer = Hammer;
}
})(this);
\ No newline at end of file
/*! Hammer.JS - v1.0.6 - 2014-01-02
* http://eightmedia.github.com/hammer.js
*
* Copyright (c) 2014 Jorik Tangelder <j.tangelder@gmail.com>;
* Licensed under the MIT license */
!function(a,b){"use strict";function c(){d.READY||(d.event.determineEventTypes(),d.utils.each(d.gestures,function(a){d.detection.register(a)}),d.event.onTouch(d.DOCUMENT,d.EVENT_MOVE,d.detection.detect),d.event.onTouch(d.DOCUMENT,d.EVENT_END,d.detection.detect),d.READY=!0)}var d=function(a,b){return new d.Instance(a,b||{})};d.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},d.HAS_POINTEREVENTS=a.navigator.pointerEnabled||a.navigator.msPointerEnabled,d.HAS_TOUCHEVENTS="ontouchstart"in a,d.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android|silk/i,d.NO_MOUSEEVENTS=d.HAS_TOUCHEVENTS&&a.navigator.userAgent.match(d.MOBILE_REGEX),d.EVENT_TYPES={},d.DIRECTION_DOWN="down",d.DIRECTION_LEFT="left",d.DIRECTION_UP="up",d.DIRECTION_RIGHT="right",d.POINTER_MOUSE="mouse",d.POINTER_TOUCH="touch",d.POINTER_PEN="pen",d.EVENT_START="start",d.EVENT_MOVE="move",d.EVENT_END="end",d.DOCUMENT=a.document,d.plugins=d.plugins||{},d.gestures=d.gestures||{},d.READY=!1,d.utils={extend:function(a,c,d){for(var e in c)a[e]!==b&&d||(a[e]=c[e]);return a},each:function(a,c,d){var e,f;if("forEach"in a)a.forEach(c,d);else if(a.length!==b){for(e=0,f=a.length;f>e;e++)if(c.call(d,a[e],e,a)===!1)return}else for(e in a)if(a.hasOwnProperty(e)&&c.call(d,a[e],e,a)===!1)return},hasParent:function(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1},getCenter:function(a){var b=[],c=[];return d.utils.each(a,function(a){b.push("undefined"!=typeof a.clientX?a.clientX:a.pageX),c.push("undefined"!=typeof a.clientY?a.clientY:a.pageY)}),{pageX:(Math.min.apply(Math,b)+Math.max.apply(Math,b))/2,pageY:(Math.min.apply(Math,c)+Math.max.apply(Math,c))/2}},getVelocity:function(a,b,c){return{x:Math.abs(b/a)||0,y:Math.abs(c/a)||0}},getAngle:function(a,b){var c=b.pageY-a.pageY,d=b.pageX-a.pageX;return 180*Math.atan2(c,d)/Math.PI},getDirection:function(a,b){var c=Math.abs(a.pageX-b.pageX),e=Math.abs(a.pageY-b.pageY);return c>=e?a.pageX-b.pageX>0?d.DIRECTION_LEFT:d.DIRECTION_RIGHT:a.pageY-b.pageY>0?d.DIRECTION_UP:d.DIRECTION_DOWN},getDistance:function(a,b){var c=b.pageX-a.pageX,d=b.pageY-a.pageY;return Math.sqrt(c*c+d*d)},getScale:function(a,b){return a.length>=2&&b.length>=2?this.getDistance(b[0],b[1])/this.getDistance(a[0],a[1]):1},getRotation:function(a,b){return a.length>=2&&b.length>=2?this.getAngle(b[1],b[0])-this.getAngle(a[1],a[0]):0},isVertical:function(a){return a==d.DIRECTION_UP||a==d.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(a,b){b&&a&&a.style&&(d.utils.each(["webkit","khtml","moz","Moz","ms","o",""],function(c){d.utils.each(b,function(b){c&&(b=c+b.substring(0,1).toUpperCase()+b.substring(1)),b in a.style&&(a.style[b]=b)})}),"none"==b.userSelect&&(a.onselectstart=function(){return!1}),"none"==b.userDrag&&(a.ondragstart=function(){return!1}))}},d.Instance=function(a,b){var e=this;return c(),this.element=a,this.enabled=!0,this.options=d.utils.extend(d.utils.extend({},d.defaults),b||{}),this.options.stop_browser_behavior&&d.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),d.event.onTouch(a,d.EVENT_START,function(a){e.enabled&&d.detection.startDetect(e,a)}),this},d.Instance.prototype={on:function(a,b){var c=a.split(" ");return d.utils.each(c,function(a){this.element.addEventListener(a,b,!1)},this),this},off:function(a,b){var c=a.split(" ");return d.utils.each(c,function(a){this.element.removeEventListener(a,b,!1)},this),this},trigger:function(a,b){b||(b={});var c=d.DOCUMENT.createEvent("Event");c.initEvent(a,!0,!0),c.gesture=b;var e=this.element;return d.utils.hasParent(b.target,e)&&(e=b.target),e.dispatchEvent(c),this},enable:function(a){return this.enabled=a,this}};var e=null,f=!1,g=!1;d.event={bindDom:function(a,b,c){var e=b.split(" ");d.utils.each(e,function(b){a.addEventListener(b,c,!1)})},onTouch:function(a,b,c){var h=this;this.bindDom(a,d.EVENT_TYPES[b],function(i){var j=i.type.toLowerCase();if(!j.match(/mouse/)||!g){j.match(/touch/)||j.match(/pointerdown/)||j.match(/mouse/)&&1===i.which?f=!0:j.match(/mouse/)&&!i.which&&(f=!1),j.match(/touch|pointer/)&&(g=!0);var k=0;f&&(d.HAS_POINTEREVENTS&&b!=d.EVENT_END?k=d.PointerEvent.updatePointer(b,i):j.match(/touch/)?k=i.touches.length:g||(k=j.match(/up/)?0:1),k>0&&b==d.EVENT_END?b=d.EVENT_MOVE:k||(b=d.EVENT_END),(k||null===e)&&(e=i),c.call(d.detection,h.collectEventData(a,b,h.getTouchList(e,b),i)),d.HAS_POINTEREVENTS&&b==d.EVENT_END&&(k=d.PointerEvent.updatePointer(b,i))),k||(e=null,f=!1,g=!1,d.PointerEvent.reset())}})},determineEventTypes:function(){var a;a=d.HAS_POINTEREVENTS?d.PointerEvent.getEvents():d.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],d.EVENT_TYPES[d.EVENT_START]=a[0],d.EVENT_TYPES[d.EVENT_MOVE]=a[1],d.EVENT_TYPES[d.EVENT_END]=a[2]},getTouchList:function(a){return d.HAS_POINTEREVENTS?d.PointerEvent.getTouchList():a.touches?a.touches:(a.identifier=1,[a])},collectEventData:function(a,b,c,e){var f=d.POINTER_TOUCH;return(e.type.match(/mouse/)||d.PointerEvent.matchType(d.POINTER_MOUSE,e))&&(f=d.POINTER_MOUSE),{center:d.utils.getCenter(c),timeStamp:(new Date).getTime(),target:e.target,touches:c,eventType:b,pointerType:f,srcEvent:e,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return d.detection.stopDetect()}}}},d.PointerEvent={pointers:{},getTouchList:function(){var a=this,b=[];return d.utils.each(a.pointers,function(a){b.push(a)}),b},updatePointer:function(a,b){return a==d.EVENT_END?this.pointers={}:(b.identifier=b.pointerId,this.pointers[b.pointerId]=b),Object.keys(this.pointers).length},matchType:function(a,b){if(!b.pointerType)return!1;var c=b.pointerType,e={};return e[d.POINTER_MOUSE]=c===b.MSPOINTER_TYPE_MOUSE||c===d.POINTER_MOUSE,e[d.POINTER_TOUCH]=c===b.MSPOINTER_TYPE_TOUCH||c===d.POINTER_TOUCH,e[d.POINTER_PEN]=c===b.MSPOINTER_TYPE_PEN||c===d.POINTER_PEN,e[a]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},d.detection={gestures:[],current:null,previous:null,stopped:!1,startDetect:function(a,b){this.current||(this.stopped=!1,this.current={inst:a,startEvent:d.utils.extend({},b),lastEvent:!1,name:""},this.detect(b))},detect:function(a){if(this.current&&!this.stopped){a=this.extendEventData(a);var b=this.current.inst.options;return d.utils.each(this.gestures,function(c){return this.stopped||b[c.name]===!1||c.handler.call(c,a,this.current.inst)!==!1?void 0:(this.stopDetect(),!1)},this),this.current&&(this.current.lastEvent=a),a.eventType==d.EVENT_END&&!a.touches.length-1&&this.stopDetect(),a}},stopDetect:function(){this.previous=d.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(a){var b=this.current.startEvent;!b||a.touches.length==b.touches.length&&a.touches!==b.touches||(b.touches=[],d.utils.each(a.touches,function(a){b.touches.push(d.utils.extend({},a))}));var c,e,f=a.timeStamp-b.timeStamp,g=a.center.pageX-b.center.pageX,h=a.center.pageY-b.center.pageY,i=d.utils.getVelocity(f,g,h);return"end"===a.eventType?(c=this.current.lastEvent&&this.current.lastEvent.interimAngle,e=this.current.lastEvent&&this.current.lastEvent.interimDirection):(c=this.current.lastEvent&&d.utils.getAngle(this.current.lastEvent.center,a.center),e=this.current.lastEvent&&d.utils.getDirection(this.current.lastEvent.center,a.center)),d.utils.extend(a,{deltaTime:f,deltaX:g,deltaY:h,velocityX:i.x,velocityY:i.y,distance:d.utils.getDistance(b.center,a.center),angle:d.utils.getAngle(b.center,a.center),interimAngle:c,direction:d.utils.getDirection(b.center,a.center),interimDirection:e,scale:d.utils.getScale(b.touches,a.touches),rotation:d.utils.getRotation(b.touches,a.touches),startEvent:b}),a},register:function(a){var c=a.defaults||{};return c[a.name]===b&&(c[a.name]=!0),d.utils.extend(d.defaults,c,!0),a.index=a.index||1e3,this.gestures.push(a),this.gestures.sort(function(a,b){return a.index<b.index?-1:a.index>b.index?1:0}),this.gestures}},d.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,correct_for_drag_min_distance:!0,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(a,b){if(d.detection.current.name!=this.name&&this.triggered)return b.trigger(this.name+"end",a),this.triggered=!1,void 0;if(!(b.options.drag_max_touches>0&&a.touches.length>b.options.drag_max_touches))switch(a.eventType){case d.EVENT_START:this.triggered=!1;break;case d.EVENT_MOVE:if(a.distance<b.options.drag_min_distance&&d.detection.current.name!=this.name)return;if(d.detection.current.name!=this.name&&(d.detection.current.name=this.name,b.options.correct_for_drag_min_distance&&a.distance>0)){var c=Math.abs(b.options.drag_min_distance/a.distance);d.detection.current.startEvent.center.pageX+=a.deltaX*c,d.detection.current.startEvent.center.pageY+=a.deltaY*c,a=d.detection.extendEventData(a)}(d.detection.current.lastEvent.drag_locked_to_axis||b.options.drag_lock_to_axis&&b.options.drag_lock_min_distance<=a.distance)&&(a.drag_locked_to_axis=!0);var e=d.detection.current.lastEvent.direction;a.drag_locked_to_axis&&e!==a.direction&&(a.direction=d.utils.isVertical(e)?a.deltaY<0?d.DIRECTION_UP:d.DIRECTION_DOWN:a.deltaX<0?d.DIRECTION_LEFT:d.DIRECTION_RIGHT),this.triggered||(b.trigger(this.name+"start",a),this.triggered=!0),b.trigger(this.name,a),b.trigger(this.name+a.direction,a),(b.options.drag_block_vertical&&d.utils.isVertical(a.direction)||b.options.drag_block_horizontal&&!d.utils.isVertical(a.direction))&&a.preventDefault();break;case d.EVENT_END:this.triggered&&b.trigger(this.name+"end",a),this.triggered=!1}}},d.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(a,b){switch(a.eventType){case d.EVENT_START:clearTimeout(this.timer),d.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==d.detection.current.name&&b.trigger("hold",a)},b.options.hold_timeout);break;case d.EVENT_MOVE:a.distance>b.options.hold_threshold&&clearTimeout(this.timer);break;case d.EVENT_END:clearTimeout(this.timer)}}},d.gestures.Release={name:"release",index:1/0,handler:function(a,b){a.eventType==d.EVENT_END&&b.trigger(this.name,a)}},d.gestures.Swipe={name:"swipe",index:40,defaults:{swipe_min_touches:1,swipe_max_touches:1,swipe_velocity:.7},handler:function(a,b){if(a.eventType==d.EVENT_END){if(b.options.swipe_max_touches>0&&a.touches.length<b.options.swipe_min_touches&&a.touches.length>b.options.swipe_max_touches)return;(a.velocityX>b.options.swipe_velocity||a.velocityY>b.options.swipe_velocity)&&(b.trigger(this.name,a),b.trigger(this.name+a.direction,a))}}},d.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(a,b){if(a.eventType==d.EVENT_END&&"touchcancel"!=a.srcEvent.type){var c=d.detection.previous,e=!1;if(a.deltaTime>b.options.tap_max_touchtime||a.distance>b.options.tap_max_distance)return;c&&"tap"==c.name&&a.timeStamp-c.lastEvent.timeStamp<b.options.doubletap_interval&&a.distance<b.options.doubletap_distance&&(b.trigger("doubletap",a),e=!0),(!e||b.options.tap_always)&&(d.detection.current.name="tap",b.trigger(d.detection.current.name,a))}}},d.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(a,b){return b.options.prevent_mouseevents&&a.pointerType==d.POINTER_MOUSE?(a.stopDetect(),void 0):(b.options.prevent_default&&a.preventDefault(),a.eventType==d.EVENT_START&&b.trigger(this.name,a),void 0)}},d.gestures.Transform={name:"transform",index:45,defaults:{transform_min_scale:.01,transform_min_rotation:1,transform_always_block:!1},triggered:!1,handler:function(a,b){if(d.detection.current.name!=this.name&&this.triggered)return b.trigger(this.name+"end",a),this.triggered=!1,void 0;if(!(a.touches.length<2))switch(b.options.transform_always_block&&a.preventDefault(),a.eventType){case d.EVENT_START:this.triggered=!1;break;case d.EVENT_MOVE:var c=Math.abs(1-a.scale),e=Math.abs(a.rotation);if(c<b.options.transform_min_scale&&e<b.options.transform_min_rotation)return;d.detection.current.name=this.name,this.triggered||(b.trigger(this.name+"start",a),this.triggered=!0),b.trigger(this.name,a),e>b.options.transform_min_rotation&&b.trigger("rotate",a),c>b.options.transform_min_scale&&(b.trigger("pinch",a),b.trigger("pinch"+(a.scale<1?"in":"out"),a));break;case d.EVENT_END:this.triggered&&b.trigger(this.name+"end",a),this.triggered=!1}}},"function"==typeof define&&"object"==typeof define.amd&&define.amd?define(function(){return d}):"object"==typeof module&&"object"==typeof module.exports?module.exports=d:a.Hammer=d}(this);
//# sourceMappingURL=hammer.min.map
\ No newline at end of file
{"version":3,"file":"hammer.min.js","sources":["hammer.js"],"names":["window","undefined","setup","Hammer","READY","event","determineEventTypes","utils","each","gestures","gesture","detection","register","onTouch","DOCUMENT","EVENT_MOVE","detect","EVENT_END","element","options","Instance","defaults","stop_browser_behavior","userSelect","touchAction","touchCallout","contentZooming","userDrag","tapHighlightColor","HAS_POINTEREVENTS","navigator","pointerEnabled","msPointerEnabled","HAS_TOUCHEVENTS","MOBILE_REGEX","NO_MOUSEEVENTS","userAgent","match","EVENT_TYPES","DIRECTION_DOWN","DIRECTION_LEFT","DIRECTION_UP","DIRECTION_RIGHT","POINTER_MOUSE","POINTER_TOUCH","POINTER_PEN","EVENT_START","document","plugins","extend","dest","src","merge","key","obj","iterator","context","i","length","forEach","call","hasOwnProperty","hasParent","node","parent","parentNode","getCenter","touches","valuesX","valuesY","touch","push","clientX","pageX","clientY","pageY","Math","min","apply","max","getVelocity","delta_time","delta_x","delta_y","x","abs","y","getAngle","touch1","touch2","atan2","PI","getDirection","getDistance","sqrt","getScale","start","end","this","getRotation","isVertical","direction","stopDefaultBrowserBehavior","css_props","style","vendor","prop","substring","toUpperCase","onselectstart","ondragstart","self","enabled","ev","startDetect","prototype","on","handler","split","addEventListener","off","removeEventListener","trigger","eventData","createEvent","initEvent","target","dispatchEvent","enable","state","last_move_event","enable_detect","touch_triggered","bindDom","type","types","eventType","sourceEventType","toLowerCase","which","count_touches","PointerEvent","updatePointer","collectEventData","getTouchList","reset","getEvents","identifier","pointerType","matchType","center","timeStamp","Date","getTime","srcEvent","preventDefault","preventManipulation","stopPropagation","stopDetect","pointers","touchlist","pointer","pointerEvent","pointerId","Object","keys","pt","MSPOINTER_TYPE_MOUSE","MSPOINTER_TYPE_TOUCH","MSPOINTER_TYPE_PEN","current","previous","stopped","inst","startEvent","lastEvent","name","extendEventData","inst_options","startEv","interimAngle","interimDirection","velocity","deltaTime","deltaX","deltaY","velocityX","velocityY","distance","angle","scale","rotation","index","sort","a","b","Drag","drag_min_distance","correct_for_drag_min_distance","drag_max_touches","drag_block_horizontal","drag_block_vertical","drag_lock_to_axis","drag_lock_min_distance","triggered","factor","drag_locked_to_axis","last_direction","Hold","hold_timeout","hold_threshold","timer","clearTimeout","setTimeout","Release","Infinity","Swipe","swipe_min_touches","swipe_max_touches","swipe_velocity","Tap","tap_max_touchtime","tap_max_distance","tap_always","doubletap_distance","doubletap_interval","prev","did_doubletap","Touch","prevent_default","prevent_mouseevents","Transform","transform_min_scale","transform_min_rotation","transform_always_block","scale_threshold","rotation_threshold","define","amd","module","exports"],"mappings":";;;;;;;CAMA,SAAUA,EAAQC,GAChB,YA8EF,SAASC,KACJC,EAAOC,QAKVD,EAAOE,MAAMC,sBAGbH,EAAOI,MAAMC,KAAKL,EAAOM,SAAU,SAASC,GAC1CP,EAAOQ,UAAUC,SAASF,KAI5BP,EAAOE,MAAMQ,QAAQV,EAAOW,SAAUX,EAAOY,WAAYZ,EAAOQ,UAAUK,QAC1Eb,EAAOE,MAAMQ,QAAQV,EAAOW,SAAUX,EAAOc,UAAWd,EAAOQ,UAAUK,QAGzEb,EAAOC,OAAQ,GAtFjB,GAAID,GAAS,SAASe,EAASC,GAC7B,MAAO,IAAIhB,GAAOiB,SAASF,EAASC,OAItChB,GAAOkB,UAKLC,uBAEEC,WAAmB,OAGnBC,YAAmB,OACnBC,aAAmB,OACnBC,eAAmB,OACnBC,SAAmB,OACnBC,kBAAmB,kBASvBzB,EAAO0B,kBAAoB7B,EAAO8B,UAAUC,gBAAkB/B,EAAO8B,UAAUE,iBAC/E7B,EAAO8B,gBAAmB,gBAAkBjC,GAG5CG,EAAO+B,aAAe,6CACtB/B,EAAOgC,eAAiBhC,EAAO8B,iBAAmBjC,EAAO8B,UAAUM,UAAUC,MAAMlC,EAAO+B,cAI1F/B,EAAOmC,eAGPnC,EAAOoC,eAAiB,OACxBpC,EAAOqC,eAAiB,OACxBrC,EAAOsC,aAAe,KACtBtC,EAAOuC,gBAAkB,QAGzBvC,EAAOwC,cAAgB,QACvBxC,EAAOyC,cAAgB,QACvBzC,EAAO0C,YAAc,MAGrB1C,EAAO2C,YAAc,QACrB3C,EAAOY,WAAa,OACpBZ,EAAOc,UAAY,MAGnBd,EAAOW,SAAWd,EAAO+C,SAGzB5C,EAAO6C,QAAU7C,EAAO6C,YACxB7C,EAAOM,SAAWN,EAAOM,aAGzBN,EAAOC,OAAQ,EA0BfD,EAAOI,OASL0C,OAAQ,SAAgBC,EAAMC,EAAKC,GACjC,IAAI,GAAIC,KAAOF,GACVD,EAAKG,KAASpD,GAAamD,IAG9BF,EAAKG,GAAOF,EAAIE,GAElB,OAAOH,IAST1C,KAAM,SAAS8C,EAAKC,EAAUC,GAC5B,GAAIC,GAAGC,CAEP,IAAI,WAAaJ,GACfA,EAAIK,QAAQJ,EAAUC,OAGnB,IAAGF,EAAII,SAAWzD,GACrB,IAAKwD,EAAI,EAAGC,EAASJ,EAAII,OAAYA,EAAJD,EAAYA,IAC3C,GAAIF,EAASK,KAAKJ,EAASF,EAAIG,GAAIA,EAAGH,MAAS,EAC7C,WAMJ,KAAKG,IAAKH,GACR,GAAIA,EAAIO,eAAeJ,IAAMF,EAASK,KAAKJ,EAASF,EAAIG,GAAIA,EAAGH,MAAS,EACtE,QAaRQ,UAAW,SAASC,EAAMC,GACxB,KAAMD,GAAM,CACV,GAAGA,GAAQC,EACT,OAAO,CAETD,GAAOA,EAAKE,WAEd,OAAO,GASTC,UAAW,SAAmBC,GAC5B,GAAIC,MAAcC,IAQlB,OANAlE,GAAOI,MAAMC,KAAK2D,EAAS,SAASG,GAElCF,EAAQG,KAA8B,mBAAlBD,GAAME,QAA0BF,EAAME,QAAUF,EAAMG,OAC1EJ,EAAQE,KAA8B,mBAAlBD,GAAMI,QAA0BJ,EAAMI,QAAUJ,EAAMK,UAI1EF,OAASG,KAAKC,IAAIC,MAAMF,KAAMR,GAAWQ,KAAKG,IAAID,MAAMF,KAAMR,IAAY,EAC1EO,OAASC,KAAKC,IAAIC,MAAMF,KAAMP,GAAWO,KAAKG,IAAID,MAAMF,KAAMP,IAAY,IAY9EW,YAAa,SAAqBC,EAAYC,EAASC,GACrD,OACEC,EAAGR,KAAKS,IAAIH,EAAUD,IAAe,EACrCK,EAAGV,KAAKS,IAAIF,EAAUF,IAAe,IAWzCM,SAAU,SAAkBC,EAAQC,GAClC,GAAIH,GAAIG,EAAOd,MAAQa,EAAOb,MAC5BS,EAAIK,EAAOhB,MAAQe,EAAOf,KAC5B,OAA0B,KAAnBG,KAAKc,MAAMJ,EAAGF,GAAWR,KAAKe,IAUvCC,aAAc,SAAsBJ,EAAQC,GAC1C,GAAIL,GAAIR,KAAKS,IAAIG,EAAOf,MAAQgB,EAAOhB,OACrCa,EAAIV,KAAKS,IAAIG,EAAOb,MAAQc,EAAOd,MAErC,OAAGS,IAAKE,EACCE,EAAOf,MAAQgB,EAAOhB,MAAQ,EAAItE,EAAOqC,eAAiBrC,EAAOuC,gBAGjE8C,EAAOb,MAAQc,EAAOd,MAAQ,EAAIxE,EAAOsC,aAAetC,EAAOoC,gBAW1EsD,YAAa,SAAqBL,EAAQC,GACxC,GAAIL,GAAIK,EAAOhB,MAAQe,EAAOf,MAC5Ba,EAAIG,EAAOd,MAAQa,EAAOb,KAC5B,OAAOC,MAAKkB,KAAMV,EAAIA,EAAME,EAAIA,IAWlCS,SAAU,SAAkBC,EAAOC,GAEjC,MAAGD,GAAMtC,QAAU,GAAKuC,EAAIvC,QAAU,EAC7BwC,KAAKL,YAAYI,EAAI,GAAIA,EAAI,IAClCC,KAAKL,YAAYG,EAAM,GAAIA,EAAM,IAE9B,GAUTG,YAAa,SAAqBH,EAAOC,GAEvC,MAAGD,GAAMtC,QAAU,GAAKuC,EAAIvC,QAAU,EAC7BwC,KAAKX,SAASU,EAAI,GAAIA,EAAI,IAC/BC,KAAKX,SAASS,EAAM,GAAIA,EAAM,IAE3B,GASTI,WAAY,SAAoBC,GAC9B,MAAQA,IAAalG,EAAOsC,cAAgB4D,GAAalG,EAAOoC,gBASlE+D,2BAA4B,SAAoCpF,EAASqF,GACnEA,GAAcrF,GAAYA,EAAQsF,QAKtCrG,EAAOI,MAAMC,MAAM,SAAU,QAAS,MAAO,MAAO,KAAM,IAAK,IAAK,SAASiG,GAC3EtG,EAAOI,MAAMC,KAAK+F,EAAW,SAASG,GAE/BD,IACDC,EAAOD,EAASC,EAAKC,UAAU,EAAG,GAAGC,cAAgBF,EAAKC,UAAU,IAGnED,IAAQxF,GAAQsF,QACjBtF,EAAQsF,MAAME,GAAQA,OAMH,QAAxBH,EAAUhF,aACXL,EAAQ2F,cAAgB,WACtB,OAAO,IAKc,QAAtBN,EAAU5E,WACXT,EAAQ4F,YAAc,WACpB,OAAO,OAef3G,EAAOiB,SAAW,SAASF,EAASC,GAClC,GAAI4F,GAAOb,IA6BX,OAzBAhG,KAEAgG,KAAKhF,QAAUA,EAGfgF,KAAKc,SAAU,EAGfd,KAAK/E,QAAUhB,EAAOI,MAAM0C,OAC1B9C,EAAOI,MAAM0C,UAAW9C,EAAOkB,UAC/BF,OAGC+E,KAAK/E,QAAQG,uBACdnB,EAAOI,MAAM+F,2BAA2BJ,KAAKhF,QAASgF,KAAK/E,QAAQG,uBAIrEnB,EAAOE,MAAMQ,QAAQK,EAASf,EAAO2C,YAAa,SAASmE,GACtDF,EAAKC,SACN7G,EAAOQ,UAAUuG,YAAYH,EAAME,KAKhCf,MAIT/F,EAAOiB,SAAS+F,WAOdC,GAAI,SAAiB1G,EAAS2G,GAC5B,GAAI5G,GAAWC,EAAQ4G,MAAM,IAI7B,OAHAnH,GAAOI,MAAMC,KAAKC,EAAU,SAASC,GACnCwF,KAAKhF,QAAQqG,iBAAiB7G,EAAS2G,GAAS,IAC/CnB,MACIA,MAUTsB,IAAK,SAAkB9G,EAAS2G,GAC9B,GAAI5G,GAAWC,EAAQ4G,MAAM,IAI7B,OAHAnH,GAAOI,MAAMC,KAAKC,EAAU,SAASC,GACnCwF,KAAKhF,QAAQuG,oBAAoB/G,EAAS2G,GAAS,IAClDnB,MACIA,MAUTwB,QAAS,SAAsBhH,EAASiH,GAElCA,IACFA,KAIF,IAAItH,GAAQF,EAAOW,SAAS8G,YAAY,QACxCvH,GAAMwH,UAAUnH,GAAS,GAAM,GAC/BL,EAAMK,QAAUiH,CAIhB,IAAIzG,GAAUgF,KAAKhF,OAMnB,OALGf,GAAOI,MAAMuD,UAAU6D,EAAUG,OAAQ5G,KAC1CA,EAAUyG,EAAUG,QAGtB5G,EAAQ6G,cAAc1H,GACf6F,MAST8B,OAAQ,SAAgBC,GAEtB,MADA/B,MAAKc,QAAUiB,EACR/B,MAWX,IAAIgC,GAAkB,KAOlBC,GAAgB,EAOhBC,GAAkB,CAGtBjI,GAAOE,OAOLgI,QAAS,SAASnH,EAASoH,EAAMjB,GAC/B,GAAIkB,GAAQD,EAAKhB,MAAM,IACvBnH,GAAOI,MAAMC,KAAK+H,EAAO,SAASD,GAChCpH,EAAQqG,iBAAiBe,EAAMjB,GAAS,MAW5CxG,QAAS,SAAiBK,EAASsH,EAAWnB,GAC5C,GAAIN,GAAOb,IAEXA,MAAKmC,QAAQnH,EAASf,EAAOmC,YAAYkG,GAAY,SAAwBvB,GAC3E,GAAIwB,GAAkBxB,EAAGqB,KAAKI,aAI9B,KAAGD,EAAgBpG,MAAM,WAAY+F,EAArC,CAKQK,EAAgBpG,MAAM,UAC5BoG,EAAgBpG,MAAM,gBACrBoG,EAAgBpG,MAAM,UAAyB,IAAb4E,EAAG0B,MAEtCR,GAAgB,EAIVM,EAAgBpG,MAAM,WAAa4E,EAAG0B,QAC5CR,GAAgB,GAMfM,EAAgBpG,MAAM,mBACvB+F,GAAkB,EAIpB,IAAIQ,GAAgB,CAIjBT,KAEEhI,EAAO0B,mBAAqB2G,GAAarI,EAAOc,UACjD2H,EAAgBzI,EAAO0I,aAAaC,cAAcN,EAAWvB,GAGvDwB,EAAgBpG,MAAM,SAC5BuG,EAAgB3B,EAAG9C,QAAQT,OAGpB0E,IACPQ,EAAgBH,EAAgBpG,MAAM,MAAQ,EAAI,GAKjDuG,EAAgB,GAAKJ,GAAarI,EAAOc,UAC1CuH,EAAYrI,EAAOY,WAGZ6H,IACPJ,EAAYrI,EAAOc,YAIlB2H,GAAqC,OAApBV,KAClBA,EAAkBjB,GAIpBI,EAAQzD,KAAKzD,EAAOQ,UAAWoG,EAAKgC,iBAAiB7H,EAASsH,EAAWzB,EAAKiC,aAAad,EAAiBM,GAAYvB,IAGrH9G,EAAO0B,mBAAqB2G,GAAarI,EAAOc,YACjD2H,EAAgBzI,EAAO0I,aAAaC,cAAcN,EAAWvB,KAK7D2B,IACFV,EAAkB,KAClBC,GAAgB,EAChBC,GAAkB,EAClBjI,EAAO0I,aAAaI,aAU1B3I,oBAAqB,WAEnB,GAAIiI,EAIFA,GADCpI,EAAO0B,kBACA1B,EAAO0I,aAAaK,YAGtB/I,EAAOgC,gBAEX,aACA,YACA,yBAMA,uBACA,sBACA,gCAGJhC,EAAOmC,YAAYnC,EAAO2C,aAAeyF,EAAM,GAC/CpI,EAAOmC,YAAYnC,EAAOY,YAAcwH,EAAM,GAC9CpI,EAAOmC,YAAYnC,EAAOc,WAAasH,EAAM,IAS/CS,aAAc,SAAsB/B,GAElC,MAAG9G,GAAO0B,kBACD1B,EAAO0I,aAAaG,eAGrB/B,EAAG9C,QACF8C,EAAG9C,SAIV8C,EAAGkC,WAAa,GACRlC,KAWZ8B,iBAAkB,SAA0B7H,EAASsH,EAAWrE,EAAS8C,GAEvE,GAAImC,GAAcjJ,EAAOyC,aAKzB,QAJGqE,EAAGqB,KAAKjG,MAAM,UAAYlC,EAAO0I,aAAaQ,UAAUlJ,EAAOwC,cAAesE,MAC/EmC,EAAcjJ,EAAOwC,gBAIrB2G,OAAanJ,EAAOI,MAAM2D,UAAUC,GACpCoF,WAAa,GAAIC,OAAOC,UACxB3B,OAAab,EAAGa,OAChB3D,QAAaA,EACbqE,UAAaA,EACbY,YAAaA,EACbM,SAAazC,EAMb0C,eAAgB,WACXzD,KAAKwD,SAASE,qBACf1D,KAAKwD,SAASE,sBAGb1D,KAAKwD,SAASC,gBACfzD,KAAKwD,SAASC,kBAOlBE,gBAAiB,WACf3D,KAAKwD,SAASG,mBAQhBC,WAAY,WACV,MAAO3J,GAAOQ,UAAUmJ,iBAMhC3J,EAAO0I,cAKLkB,YAMAf,aAAc,WACZ,GAAIjC,GAAOb,KACP8D,IAOJ,OAJA7J,GAAOI,MAAMC,KAAKuG,EAAKgD,SAAU,SAASE,GACxCD,EAAUzF,KAAK0F,KAGVD,GAQTlB,cAAe,SAASR,EAAM4B,GAS5B,MARG5B,IAAQnI,EAAOc,UAChBiF,KAAK6D,aAGLG,EAAaf,WAAae,EAAaC,UACvCjE,KAAK6D,SAASG,EAAaC,WAAaD,GAGnCE,OAAOC,KAAKnE,KAAK6D,UAAUrG,QAQpC2F,UAAW,SAASD,EAAanC,GAC/B,IAAIA,EAAGmC,YACL,OAAO,CAGT,IAAIkB,GAAKrD,EAAGmC,YACVb,IAIF,OAHAA,GAAMpI,EAAOwC,eAAkB2H,IAAOrD,EAAGsD,sBAAwBD,IAAOnK,EAAOwC,cAC/E4F,EAAMpI,EAAOyC,eAAkB0H,IAAOrD,EAAGuD,sBAAwBF,IAAOnK,EAAOyC,cAC/E2F,EAAMpI,EAAO0C,aAAgByH,IAAOrD,EAAGwD,oBAAsBH,IAAOnK,EAAO0C,YACpE0F,EAAMa,IAOfF,UAAW,WACT,OACE,4BACA,4BACA,wDAOJD,MAAO,WACL/C,KAAK6D,cAKT5J,EAAOQ,WAELF,YAGAiK,QAAU,KAIVC,SAAU,KAGVC,SAAU,EAQV1D,YAAa,SAAqB2D,EAAMlD,GAEnCzB,KAAKwE,UAIRxE,KAAK0E,SAAU,EAEf1E,KAAKwE,SACHG,KAAYA,EACZC,WAAY3K,EAAOI,MAAM0C,UAAW0E,GACpCoD,WAAY,EACZC,KAAY,IAGd9E,KAAKlF,OAAO2G,KAQd3G,OAAQ,SAAgB2G,GACtB,GAAIzB,KAAKwE,UAAWxE,KAAK0E,QAAzB,CAKAjD,EAAYzB,KAAK+E,gBAAgBtD,EAGjC,IAAIuD,GAAehF,KAAKwE,QAAQG,KAAK1J,OAwBrC,OArBAhB,GAAOI,MAAMC,KAAK0F,KAAKzF,SAAU,SAASC,GAExC,MAAIwF,MAAK0E,SAAWM,EAAaxK,EAAQsK,SAAU,GAE9CtK,EAAQ2G,QAAQzD,KAAKlD,EAASiH,EAAWzB,KAAKwE,QAAQG,SAAU,EAFrE,QAGI3E,KAAK4D,cACE,IAGV5D,MAGAA,KAAKwE,UACNxE,KAAKwE,QAAQK,UAAYpD,GAIxBA,EAAUa,WAAarI,EAAOc,YAAc0G,EAAUxD,QAAQT,OAAS,GACxEwC,KAAK4D,aAGAnC,IASTmC,WAAY,WAGV5D,KAAKyE,SAAWxK,EAAOI,MAAM0C,UAAWiD,KAAKwE,SAG7CxE,KAAKwE,QAAU,KAGfxE,KAAK0E,SAAU,GASjBK,gBAAiB,SAAyBhE,GACxC,GAAIkE,GAAUjF,KAAKwE,QAAQI,YAMxBK,GAAYlE,EAAG9C,QAAQT,QAAUyH,EAAQhH,QAAQT,QAAUuD,EAAG9C,UAAYgH,EAAQhH,UAEnFgH,EAAQhH,WACRhE,EAAOI,MAAMC,KAAKyG,EAAG9C,QAAS,SAASG,GACrC6G,EAAQhH,QAAQI,KAAKpE,EAAOI,MAAM0C,UAAWqB,MAIjD,IAII8G,GACAC,EALApG,EAAagC,EAAGsC,UAAY4B,EAAQ5B,UACpCrE,EAAU+B,EAAGqC,OAAO7E,MAAQ0G,EAAQ7B,OAAO7E,MAC3CU,EAAU8B,EAAGqC,OAAO3E,MAAQwG,EAAQ7B,OAAO3E,MAC3C2G,EAAWnL,EAAOI,MAAMyE,YAAYC,EAAYC,EAASC,EAwC7D,OAhCoB,QAAjB8B,EAAGuB,WACJ4C,EAAelF,KAAKwE,QAAQK,WAAa7E,KAAKwE,QAAQK,UAAUK,aAChEC,EAAmBnF,KAAKwE,QAAQK,WAAa7E,KAAKwE,QAAQK,UAAUM,mBAGpED,EAAelF,KAAKwE,QAAQK,WAAa5K,EAAOI,MAAMgF,SAASW,KAAKwE,QAAQK,UAAUzB,OAAQrC,EAAGqC,QACjG+B,EAAmBnF,KAAKwE,QAAQK,WAAa5K,EAAOI,MAAMqF,aAAaM,KAAKwE,QAAQK,UAAUzB,OAAQrC,EAAGqC,SAG3GnJ,EAAOI,MAAM0C,OAAOgE,GAClBsE,UAAWtG,EAEXuG,OAAQtG,EACRuG,OAAQtG,EAERuG,UAAWJ,EAASlG,EACpBuG,UAAWL,EAAShG,EAEpBsG,SAAUzL,EAAOI,MAAMsF,YAAYsF,EAAQ7B,OAAQrC,EAAGqC,QAEtDuC,MAAO1L,EAAOI,MAAMgF,SAAS4F,EAAQ7B,OAAQrC,EAAGqC,QAChD8B,aAAcA,EAEd/E,UAAWlG,EAAOI,MAAMqF,aAAauF,EAAQ7B,OAAQrC,EAAGqC,QACxD+B,iBAAkBA,EAElBS,MAAO3L,EAAOI,MAAMwF,SAASoF,EAAQhH,QAAS8C,EAAG9C,SACjD4H,SAAU5L,EAAOI,MAAM4F,YAAYgF,EAAQhH,QAAS8C,EAAG9C,SAEvD2G,WAAYK,IAGPlE,GASTrG,SAAU,SAAkBF,GAE1B,GAAIS,GAAUT,EAAQW,YAqBtB,OApBGF,GAAQT,EAAQsK,QAAU/K,IAC3BkB,EAAQT,EAAQsK,OAAQ,GAI1B7K,EAAOI,MAAM0C,OAAO9C,EAAOkB,SAAUF,GAAS,GAG9CT,EAAQsL,MAAQtL,EAAQsL,OAAS,IAGjC9F,KAAKzF,SAAS8D,KAAK7D,GAGnBwF,KAAKzF,SAASwL,KAAK,SAASC,EAAGC,GAC7B,MAAGD,GAAEF,MAAQG,EAAEH,MAAgB,GAC5BE,EAAEF,MAAQG,EAAEH,MAAgB,EACxB,IAGF9F,KAAKzF,WAYhBN,EAAOM,SAAS2L,MACdpB,KAAW,OACXgB,MAAW,GACX3K,UACEgL,kBAA+B,GAM/BC,+BAA+B,EAG/BC,iBAA+B,EAK/BC,uBAA+B,EAC/BC,qBAA+B,EAI/BC,mBAA+B,EAI/BC,uBAA+B,IAGjCC,WAAW,EACXvF,QAAW,SAAqBJ,EAAI4D,GAGlC,GAAG1K,EAAOQ,UAAU+J,QAAQM,MAAQ9E,KAAK8E,MAAQ9E,KAAK0G,UAGpD,MAFA/B,GAAKnD,QAAQxB,KAAK8E,KAAO,MAAO/D,GAChCf,KAAK0G,WAAY,EACjB,MAIF,MAAG/B,EAAK1J,QAAQoL,iBAAmB,GACjCtF,EAAG9C,QAAQT,OAASmH,EAAK1J,QAAQoL,kBAInC,OAAOtF,EAAGuB,WACR,IAAKrI,GAAO2C,YACVoD,KAAK0G,WAAY,CACjB,MAEF,KAAKzM,GAAOY,WAGV,GAAGkG,EAAG2E,SAAWf,EAAK1J,QAAQkL,mBAC5BlM,EAAOQ,UAAU+J,QAAQM,MAAQ9E,KAAK8E,KACtC,MAIF,IAAG7K,EAAOQ,UAAU+J,QAAQM,MAAQ9E,KAAK8E,OACvC7K,EAAOQ,UAAU+J,QAAQM,KAAO9E,KAAK8E,KAClCH,EAAK1J,QAAQmL,+BAAiCrF,EAAG2E,SAAW,GAAG,CAIhE,GAAIiB,GAASjI,KAAKS,IAAIwF,EAAK1J,QAAQkL,kBAAoBpF,EAAG2E,SAC1DzL,GAAOQ,UAAU+J,QAAQI,WAAWxB,OAAO7E,OAASwC,EAAGuE,OAASqB,EAChE1M,EAAOQ,UAAU+J,QAAQI,WAAWxB,OAAO3E,OAASsC,EAAGwE,OAASoB,EAGhE5F,EAAK9G,EAAOQ,UAAUsK,gBAAgBhE,IAKvC9G,EAAOQ,UAAU+J,QAAQK,UAAU+B,qBAAwBjC,EAAK1J,QAAQuL,mBAAqB7B,EAAK1J,QAAQwL,wBAA0B1F,EAAG2E,YACxI3E,EAAG6F,qBAAsB,EAE3B,IAAIC,GAAiB5M,EAAOQ,UAAU+J,QAAQK,UAAU1E,SACrDY,GAAG6F,qBAAuBC,IAAmB9F,EAAGZ,YAG/CY,EAAGZ,UADFlG,EAAOI,MAAM6F,WAAW2G,GACT9F,EAAGwE,OAAS,EAAKtL,EAAOsC,aAAetC,EAAOoC,eAG9C0E,EAAGuE,OAAS,EAAKrL,EAAOqC,eAAiBrC,EAAOuC,iBAKhEwD,KAAK0G,YACP/B,EAAKnD,QAAQxB,KAAK8E,KAAO,QAAS/D,GAClCf,KAAK0G,WAAY,GAInB/B,EAAKnD,QAAQxB,KAAK8E,KAAM/D,GAGxB4D,EAAKnD,QAAQxB,KAAK8E,KAAO/D,EAAGZ,UAAWY,IAGnC4D,EAAK1J,QAAQsL,qBAAuBtM,EAAOI,MAAM6F,WAAWa,EAAGZ,YAChEwE,EAAK1J,QAAQqL,wBAA0BrM,EAAOI,MAAM6F,WAAWa,EAAGZ,aACnEY,EAAG0C,gBAEL,MAEF,KAAKxJ,GAAOc,UAEPiF,KAAK0G,WACN/B,EAAKnD,QAAQxB,KAAK8E,KAAO,MAAO/D,GAGlCf,KAAK0G,WAAY,KAWzBzM,EAAOM,SAASuM,MACdhC,KAAU,OACVgB,MAAU,GACV3K,UACE4L,aAAgB,IAChBC,eAAgB,GAElBC,MAAU,KACV9F,QAAU,SAAqBJ,EAAI4D,GACjC,OAAO5D,EAAGuB,WACR,IAAKrI,GAAO2C,YAEVsK,aAAalH,KAAKiH,OAGlBhN,EAAOQ,UAAU+J,QAAQM,KAAO9E,KAAK8E,KAIrC9E,KAAKiH,MAAQE,WAAW,WACc,QAAjClN,EAAOQ,UAAU+J,QAAQM,MAC1BH,EAAKnD,QAAQ,OAAQT,IAEtB4D,EAAK1J,QAAQ8L,aAChB,MAGF,KAAK9M,GAAOY,WACPkG,EAAG2E,SAAWf,EAAK1J,QAAQ+L,gBAC5BE,aAAalH,KAAKiH,MAEpB,MAEF,KAAKhN,GAAOc,UACVmM,aAAalH,KAAKiH,UAW1BhN,EAAOM,SAAS6M,SACdtC,KAAS,UACTgB,MAASuB,IACTlG,QAAS,SAAwBJ,EAAI4D,GAChC5D,EAAGuB,WAAarI,EAAOc,WACxB4J,EAAKnD,QAAQxB,KAAK8E,KAAM/D,KAU9B9G,EAAOM,SAAS+M,OACdxC,KAAU,QACVgB,MAAU,GACV3K,UAEEoM,kBAAmB,EACnBC,kBAAmB,EACnBC,eAAmB,IAErBtG,QAAU,SAAsBJ,EAAI4D,GAClC,GAAG5D,EAAGuB,WAAarI,EAAOc,UAAW,CAEnC,GAAG4J,EAAK1J,QAAQuM,kBAAoB,GAClCzG,EAAG9C,QAAQT,OAASmH,EAAK1J,QAAQsM,mBACjCxG,EAAG9C,QAAQT,OAASmH,EAAK1J,QAAQuM,kBACjC,QAKCzG,EAAGyE,UAAYb,EAAK1J,QAAQwM,gBAC7B1G,EAAG0E,UAAYd,EAAK1J,QAAQwM,kBAE5B9C,EAAKnD,QAAQxB,KAAK8E,KAAM/D,GACxB4D,EAAKnD,QAAQxB,KAAK8E,KAAO/D,EAAGZ,UAAWY,OAW/C9G,EAAOM,SAASmN,KACd5C,KAAU,MACVgB,MAAU,IACV3K,UACEwM,kBAAoB,IACpBC,iBAAoB,GACpBC,YAAoB,EACpBC,mBAAoB,GACpBC,mBAAoB,KAEtB5G,QAAU,SAAoBJ,EAAI4D,GAChC,GAAG5D,EAAGuB,WAAarI,EAAOc,WAAiC,eAApBgG,EAAGyC,SAASpB,KAAuB,CAExE,GAAI4F,GAAO/N,EAAOQ,UAAUgK,SAC1BwD,GAAgB,CAIlB,IAAGlH,EAAGsE,UAAYV,EAAK1J,QAAQ0M,mBAC7B5G,EAAG2E,SAAWf,EAAK1J,QAAQ2M,iBAC3B,MAICI,IAAqB,OAAbA,EAAKlD,MACb/D,EAAGsC,UAAY2E,EAAKnD,UAAUxB,UAAasB,EAAK1J,QAAQ8M,oBACzDhH,EAAG2E,SAAWf,EAAK1J,QAAQ6M,qBAC3BnD,EAAKnD,QAAQ,YAAaT,GAC1BkH,GAAgB,KAIdA,GAAiBtD,EAAK1J,QAAQ4M,cAChC5N,EAAOQ,UAAU+J,QAAQM,KAAO,MAChCH,EAAKnD,QAAQvH,EAAOQ,UAAU+J,QAAQM,KAAM/D,OAWpD9G,EAAOM,SAAS2N,OACdpD,KAAU,QACVgB,OAAWuB,IACXlM,UAMEgN,iBAAqB,EAGrBC,qBAAqB,GAEvBjH,QAAU,SAAsBJ,EAAI4D,GAClC,MAAGA,GAAK1J,QAAQmN,qBAAuBrH,EAAGmC,aAAejJ,EAAOwC,eAC9DsE,EAAG6C,aACH,SAGCe,EAAK1J,QAAQkN,iBACdpH,EAAG0C,iBAGF1C,EAAGuB,WAAarI,EAAO2C,aACxB+H,EAAKnD,QAAQxB,KAAK8E,KAAM/D,GAL1B,UAeJ9G,EAAOM,SAAS8N,WACdvD,KAAW,YACXgB,MAAW,GACX3K,UAEEmN,oBAAwB,IAExBC,uBAAwB,EAIxBC,wBAAwB,GAE1B9B,WAAW,EACXvF,QAAW,SAA0BJ,EAAI4D,GAGvC,GAAG1K,EAAOQ,UAAU+J,QAAQM,MAAQ9E,KAAK8E,MAAQ9E,KAAK0G,UAGpD,MAFA/B,GAAKnD,QAAQxB,KAAK8E,KAAO,MAAO/D,GAChCf,KAAK0G,WAAY,EACjB,MAIF,MAAG3F,EAAG9C,QAAQT,OAAS,GASvB,OAJGmH,EAAK1J,QAAQuN,wBACdzH,EAAG0C,iBAGE1C,EAAGuB,WACR,IAAKrI,GAAO2C,YACVoD,KAAK0G,WAAY,CACjB,MAEF,KAAKzM,GAAOY,WACV,GAAI4N,GAAkB/J,KAAKS,IAAI,EAAI4B,EAAG6E,OAClC8C,EAAqBhK,KAAKS,IAAI4B,EAAG8E,SAIrC,IAAG4C,EAAkB9D,EAAK1J,QAAQqN,qBAChCI,EAAqB/D,EAAK1J,QAAQsN,uBAClC,MAIFtO,GAAOQ,UAAU+J,QAAQM,KAAO9E,KAAK8E,KAGjC9E,KAAK0G,YACP/B,EAAKnD,QAAQxB,KAAK8E,KAAO,QAAS/D,GAClCf,KAAK0G,WAAY,GAGnB/B,EAAKnD,QAAQxB,KAAK8E,KAAM/D,GAGrB2H,EAAqB/D,EAAK1J,QAAQsN,wBACnC5D,EAAKnD,QAAQ,SAAUT,GAItB0H,EAAkB9D,EAAK1J,QAAQqN,sBAChC3D,EAAKnD,QAAQ,QAAST,GACtB4D,EAAKnD,QAAQ,SAAYT,EAAG6E,MAAQ,EAAK,KAAO,OAAQ7E,GAE1D,MAEF,KAAK9G,GAAOc,UAEPiF,KAAK0G,WACN/B,EAAKnD,QAAQxB,KAAK8E,KAAO,MAAO/D,GAGlCf,KAAK0G,WAAY,KAQH,kBAAViC,SAA6C,gBAAdA,QAAOC,KAAmBD,OAAOC,IAExED,OAAO,WACL,MAAO1O,KAIe,gBAAX4O,SAAiD,gBAAnBA,QAAOC,QAClDD,OAAOC,QAAU7O,EAGjBH,EAAOG,OAASA,GAEjB+F"}
\ No newline at end of file
{
"name": "hammerjs",
"title": "Hammer.JS",
"description": "A javascript library for multi-touch gestures",
"version": "1.0.6",
"homepage": "http://eightmedia.github.com/hammer.js",
"licenses": [
{
"type": "MIT",
"url": "https://github.com/eightmedia/hammer.js/blob/master/LICENSE"
}
],
"keywords": [
"touch",
"gestures",
"ender"
],
"author": {
"name": "Jorik Tangelder",
"email": "j.tangelder@gmail.com"
},
"repository": {
"type": "git",
"url": "git://github.com/eightmedia/hammer.js.git"
},
"bugs": {
"url": "https://github.com/eightmedia/hammer.js/issues"
},
"dependencies": {},
"devDependencies": {
"grunt": "0.4.x",
"grunt-contrib-connect": "0.5.x",
"grunt-contrib-concat": "0.3.x",
"grunt-contrib-uglify": "0.2.x",
"grunt-contrib-jshint": "0.7.x",
"grunt-contrib-watch": "0.5.x",
"faketouches": "git://github.com/jtangelder/faketouches.js.git",
"underscore": "1.5.x",
"grunt-saucelabs": "4.1.x",
"grunt-contrib-qunit": "~0.3.0"
},
"main": "hammer.js",
"engines": {
"node": ">=0.8.0"
},
"scripts": {
"test": "grunt test"
}
}
(function(Hammer) {
/**
* enable multitouch on the desktop by pressing the shiftkey
* the other touch goes in the opposite direction so the center keeps at its place
* it's recommended to enable Hammer.debug.showTouches for this one
*/
Hammer.plugins.fakeMultitouch = function() {
// keeps the start position to keep it centered
var start_pos = false;
// test for msMaxTouchPoints to enable this for IE10 with only one pointer (a mouse in all/most cases)
Hammer.HAS_POINTEREVENTS = navigator.msPointerEnabled &&
navigator.msMaxTouchPoints && navigator.msMaxTouchPoints >= 1;
/**
* overwrites Hammer.event.getTouchList.
* @param {Event} ev
* @param TOUCHTYPE type
* @return {Array} Touches
*/
Hammer.event.getTouchList = function(ev, eventType) {
// get the fake pointerEvent touchlist
if(Hammer.HAS_POINTEREVENTS) {
return Hammer.PointerEvent.getTouchList();
}
// get the touchlist
else if(ev.touches) {
return ev.touches;
}
// reset on start of a new touch
if(eventType == Hammer.EVENT_START) {
start_pos = false;
}
// when the shift key is pressed, multitouch is possible on desktop
// why shift? because ctrl and alt are taken by osx and linux
if(ev.shiftKey) {
// on touchstart we store the position of the mouse for multitouch
if(!start_pos) {
start_pos = {
pageX: ev.pageX,
pageY: ev.pageY
};
}
var distance_x = start_pos.pageX - ev.pageX;
var distance_y = start_pos.pageY - ev.pageY;
// fake second touch in the opposite direction
return [
{
identifier: 1,
pageX : start_pos.pageX - distance_x - 50,
pageY : start_pos.pageY - distance_y - -50,
target : ev.target
},
{
identifier: 2,
pageX : start_pos.pageX + distance_x - -50,
pageY : start_pos.pageY + distance_y - 50,
target : ev.target
}
];
}
// normal single touch
else {
start_pos = false;
return [
{
identifier: 1,
pageX : ev.pageX,
pageY : ev.pageY,
target : ev.target
}
];
}
};
};
})(window.Hammer);
\ No newline at end of file
(function(Hammer) {
/**
* ShowTouches gesture
* show all touch on the screen by placing elements at there pageX and pageY
* @param {Boolean} [force]
*/
Hammer.plugins.showTouches = function(force) {
// the circles under your fingers
var template_style = 'position:absolute;z-index:9999;left:0;top:0;height:14px;width:14px;border:solid 2px #777;' +
'background:rgba(255,255,255,.7);border-radius:20px;pointer-events:none;' +
'margin-top:-9px;margin-left:-9px;';
// elements by identifier
var touch_elements = {};
var touches_index = {};
/**
* remove unused touch elements
*/
function removeUnusedElements() {
// remove unused touch elements
for(var key in touch_elements) {
if(touch_elements.hasOwnProperty(key) && !touches_index[key]) {
document.body.removeChild(touch_elements[key]);
delete touch_elements[key];
}
}
}
Hammer.detection.register({
name : 'show_touches',
priority: 0,
handler : function(ev, inst) {
touches_index = {};
// clear old elements when not using a mouse
if(ev.pointerType != Hammer.POINTER_MOUSE && !force) {
removeUnusedElements();
return;
}
// place touches by index
for(var t = 0, total_touches = ev.touches.length; t < total_touches; t++) {
var touch = ev.touches[t];
var id = touch.identifier;
touches_index[id] = touch;
// new touch element
if(!touch_elements[id]) {
// create new element and attach base styles
var template = document.createElement('div');
template.setAttribute('style', template_style);
// append element to body
document.body.appendChild(template);
touch_elements[id] = template;
}
// Paul Irish says that translate is faster then left/top
touch_elements[id].style.left = touch.pageX + 'px';
touch_elements[id].style.top = touch.pageY + 'px';
}
removeUnusedElements();
}
});
};
})(window.Hammer);
jquery.hammer.js @ 170f8a81
Subproject commit 170f8a818d02712568590f2004b72cefef1b434d
/**
* Hammer
* use this to create instances
* @param {HTMLElement} element
* @param {Object} options
* @returns {Hammer.Instance}
* @constructor
*/
var Hammer = function(element, options) {
return new Hammer.Instance(element, options || {});
};
// default settings
Hammer.defaults = {
// add styles and attributes to the element to prevent the browser from doing
// its native behavior. this doesnt prevent the scrolling, but cancels
// the contextmenu, tap highlighting etc
// set to false to disable this
stop_browser_behavior: {
// this also triggers onselectstart=false for IE
userSelect : 'none',
// this makes the element blocking in IE10 >, you could experiment with the value
// see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241
touchAction : 'none',
touchCallout : 'none',
contentZooming : 'none',
userDrag : 'none',
tapHighlightColor: 'rgba(0,0,0,0)'
}
//
// more settings are defined per gesture at gestures.js
//
};
// detect touchevents
Hammer.HAS_POINTEREVENTS = window.navigator.pointerEnabled || window.navigator.msPointerEnabled;
Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window);
// dont use mouseevents on mobile devices
Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android|silk/i;
Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && window.navigator.userAgent.match(Hammer.MOBILE_REGEX);
// eventtypes per touchevent (start, move, end)
// are filled by Hammer.event.determineEventTypes on setup
Hammer.EVENT_TYPES = {};
// direction defines
Hammer.DIRECTION_DOWN = 'down';
Hammer.DIRECTION_LEFT = 'left';
Hammer.DIRECTION_UP = 'up';
Hammer.DIRECTION_RIGHT = 'right';
// pointer type
Hammer.POINTER_MOUSE = 'mouse';
Hammer.POINTER_TOUCH = 'touch';
Hammer.POINTER_PEN = 'pen';
// touch event defines
Hammer.EVENT_START = 'start';
Hammer.EVENT_MOVE = 'move';
Hammer.EVENT_END = 'end';
// hammer document where the base events are added at
Hammer.DOCUMENT = window.document;
// plugins and gestures namespaces
Hammer.plugins = Hammer.plugins || {};
Hammer.gestures = Hammer.gestures || {};
\ No newline at end of file
Hammer.detection = {
// contains all registred Hammer.gestures in the correct order
gestures: [],
// data of the current Hammer.gesture detection session
current : null,
// the previous Hammer.gesture session data
// is a full clone of the previous gesture.current object
previous: null,
// when this becomes true, no gestures are fired
stopped : false,
/**
* start Hammer.gesture detection
* @param {Hammer.Instance} inst
* @param {Object} eventData
*/
startDetect: function startDetect(inst, eventData) {
// already busy with a Hammer.gesture detection on an element
if(this.current) {
return;
}
this.stopped = false;
this.current = {
inst : inst, // reference to HammerInstance we're working for
startEvent: Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc
lastEvent : false, // last eventData
name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc
};
this.detect(eventData);
},
/**
* Hammer.gesture detection
* @param {Object} eventData
*/
detect: function detect(eventData) {
if(!this.current || this.stopped) {
return;
}
// extend event data with calculations about scale, distance etc
eventData = this.extendEventData(eventData);
// instance options
var inst_options = this.current.inst.options;
// call Hammer.gesture handlers
Hammer.utils.each(this.gestures, function(gesture) {
// only when the instance options have enabled this gesture
if(!this.stopped && inst_options[gesture.name] !== false) {
// if a handler returns false, we stop with the detection
if(gesture.handler.call(gesture, eventData, this.current.inst) === false) {
this.stopDetect();
return false;
}
}
}, this);
// store as previous event event
if(this.current) {
this.current.lastEvent = eventData;
}
// endevent, but not the last touch, so dont stop
if(eventData.eventType == Hammer.EVENT_END && !eventData.touches.length - 1) {
this.stopDetect();
}
return eventData;
},
/**
* clear the Hammer.gesture vars
* this is called on endDetect, but can also be used when a final Hammer.gesture has been detected
* to stop other Hammer.gestures from being fired
*/
stopDetect: function stopDetect() {
// clone current data to the store as the previous gesture
// used for the double tap gesture, since this is an other gesture detect session
this.previous = Hammer.utils.extend({}, this.current);
// reset the current
this.current = null;
// stopped!
this.stopped = true;
},
/**
* extend eventData for Hammer.gestures
* @param {Object} ev
* @returns {Object} ev
*/
extendEventData: function extendEventData(ev) {
var startEv = this.current.startEvent;
// if the touches change, set the new touches over the startEvent touches
// this because touchevents don't have all the touches on touchstart, or the
// user must place his fingers at the EXACT same time on the screen, which is not realistic
// but, sometimes it happens that both fingers are touching at the EXACT same time
if(startEv && (ev.touches.length != startEv.touches.length || ev.touches === startEv.touches)) {
// extend 1 level deep to get the touchlist with the touch objects
startEv.touches = [];
Hammer.utils.each(ev.touches, function(touch) {
startEv.touches.push(Hammer.utils.extend({}, touch));
});
}
var delta_time = ev.timeStamp - startEv.timeStamp
, delta_x = ev.center.pageX - startEv.center.pageX
, delta_y = ev.center.pageY - startEv.center.pageY
, velocity = Hammer.utils.getVelocity(delta_time, delta_x, delta_y)
, interimAngle
, interimDirection;
// end events (e.g. dragend) don't have useful values for interimDirection & interimAngle
// because the previous event has exactly the same coordinates
// so for end events, take the previous values of interimDirection & interimAngle
// instead of recalculating them and getting a spurious '0'
if(ev.eventType === 'end') {
interimAngle = this.current.lastEvent && this.current.lastEvent.interimAngle;
interimDirection = this.current.lastEvent && this.current.lastEvent.interimDirection;
}
else {
interimAngle = this.current.lastEvent && Hammer.utils.getAngle(this.current.lastEvent.center, ev.center);
interimDirection = this.current.lastEvent && Hammer.utils.getDirection(this.current.lastEvent.center, ev.center);
}
Hammer.utils.extend(ev, {
deltaTime: delta_time,
deltaX: delta_x,
deltaY: delta_y,
velocityX: velocity.x,
velocityY: velocity.y,
distance: Hammer.utils.getDistance(startEv.center, ev.center),
angle: Hammer.utils.getAngle(startEv.center, ev.center),
interimAngle: interimAngle,
direction: Hammer.utils.getDirection(startEv.center, ev.center),
interimDirection: interimDirection,
scale: Hammer.utils.getScale(startEv.touches, ev.touches),
rotation: Hammer.utils.getRotation(startEv.touches, ev.touches),
startEvent: startEv
});
return ev;
},
/**
* register new gesture
* @param {Object} gesture object, see gestures.js for documentation
* @returns {Array} gestures
*/
register: function register(gesture) {
// add an enable gesture options if there is no given
var options = gesture.defaults || {};
if(options[gesture.name] === undefined) {
options[gesture.name] = true;
}
// extend Hammer default options with the Hammer.gesture options
Hammer.utils.extend(Hammer.defaults, options, true);
// set its index
gesture.index = gesture.index || 1000;
// add Hammer.gesture to the list
this.gestures.push(gesture);
// sort the list by index
this.gestures.sort(function(a, b) {
if(a.index < b.index) { return -1; }
if(a.index > b.index) { return 1; }
return 0;
});
return this.gestures;
}
};
/**
* this holds the last move event,
* used to fix empty touchend issue
* see the onTouch event for an explanation
* @type {Object}
*/
var last_move_event = null;
/**
* when the mouse is hold down, this is true
* @type {Boolean}
*/
var enable_detect = false;
/**
* when touch events have been fired, this is true
* @type {Boolean}
*/
var touch_triggered = false;
Hammer.event = {
/**
* simple addEventListener
* @param {HTMLElement} element
* @param {String} type
* @param {Function} handler
*/
bindDom: function(element, type, handler) {
var types = type.split(' ');
Hammer.utils.each(types, function(type){
element.addEventListener(type, handler, false);
});
},
/**
* touch events with mouse fallback
* @param {HTMLElement} element
* @param {String} eventType like Hammer.EVENT_MOVE
* @param {Function} handler
*/
onTouch: function onTouch(element, eventType, handler) {
var self = this;
this.bindDom(element, Hammer.EVENT_TYPES[eventType], function bindDomOnTouch(ev) {
var sourceEventType = ev.type.toLowerCase();
// onmouseup, but when touchend has been fired we do nothing.
// this is for touchdevices which also fire a mouseup on touchend
if(sourceEventType.match(/mouse/) && touch_triggered) {
return;
}
// mousebutton must be down or a touch event
else if(sourceEventType.match(/touch/) || // touch events are always on screen
sourceEventType.match(/pointerdown/) || // pointerevents touch
(sourceEventType.match(/mouse/) && ev.which === 1) // mouse is pressed
) {
enable_detect = true;
}
// mouse isn't pressed
else if(sourceEventType.match(/mouse/) && !ev.which) {
enable_detect = false;
}
// we are in a touch event, set the touch triggered bool to true,
// this for the conflicts that may occur on ios and android
if(sourceEventType.match(/touch|pointer/)) {
touch_triggered = true;
}
// count the total touches on the screen
var count_touches = 0;
// when touch has been triggered in this detection session
// and we are now handling a mouse event, we stop that to prevent conflicts
if(enable_detect) {
// update pointerevent
if(Hammer.HAS_POINTEREVENTS && eventType != Hammer.EVENT_END) {
count_touches = Hammer.PointerEvent.updatePointer(eventType, ev);
}
// touch
else if(sourceEventType.match(/touch/)) {
count_touches = ev.touches.length;
}
// mouse
else if(!touch_triggered) {
count_touches = sourceEventType.match(/up/) ? 0 : 1;
}
// if we are in a end event, but when we remove one touch and
// we still have enough, set eventType to move
if(count_touches > 0 && eventType == Hammer.EVENT_END) {
eventType = Hammer.EVENT_MOVE;
}
// no touches, force the end event
else if(!count_touches) {
eventType = Hammer.EVENT_END;
}
// store the last move event
if(count_touches || last_move_event === null) {
last_move_event = ev;
}
// trigger the handler
handler.call(Hammer.detection, self.collectEventData(element, eventType, self.getTouchList(last_move_event, eventType), ev));
// remove pointerevent from list
if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) {
count_touches = Hammer.PointerEvent.updatePointer(eventType, ev);
}
}
// on the end we reset everything
if(!count_touches) {
last_move_event = null;
enable_detect = false;
touch_triggered = false;
Hammer.PointerEvent.reset();
}
});
},
/**
* we have different events for each device/browser
* determine what we need and set them in the Hammer.EVENT_TYPES constant
*/
determineEventTypes: function determineEventTypes() {
// determine the eventtype we want to set
var types;
// pointerEvents magic
if(Hammer.HAS_POINTEREVENTS) {
types = Hammer.PointerEvent.getEvents();
}
// on Android, iOS, blackberry, windows mobile we dont want any mouseevents
else if(Hammer.NO_MOUSEEVENTS) {
types = [
'touchstart',
'touchmove',
'touchend touchcancel'];
}
// for non pointer events browsers and mixed browsers,
// like chrome on windows8 touch laptop
else {
types = [
'touchstart mousedown',
'touchmove mousemove',
'touchend touchcancel mouseup'];
}
Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0];
Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1];
Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2];
},
/**
* create touchlist depending on the event
* @param {Object} ev
* @param {String} eventType used by the fakemultitouch plugin
*/
getTouchList: function getTouchList(ev/*, eventType*/) {
// get the fake pointerEvent touchlist
if(Hammer.HAS_POINTEREVENTS) {
return Hammer.PointerEvent.getTouchList();
}
// get the touchlist
else if(ev.touches) {
return ev.touches;
}
// make fake touchlist from mouse position
else {
ev.identifier = 1;
return [ev];
}
},
/**
* collect event data for Hammer js
* @param {HTMLElement} element
* @param {String} eventType like Hammer.EVENT_MOVE
* @param {Object} eventData
*/
collectEventData: function collectEventData(element, eventType, touches, ev) {
// find out pointerType
var pointerType = Hammer.POINTER_TOUCH;
if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) {
pointerType = Hammer.POINTER_MOUSE;
}
return {
center : Hammer.utils.getCenter(touches),
timeStamp : new Date().getTime(),
target : ev.target,
touches : touches,
eventType : eventType,
pointerType: pointerType,
srcEvent : ev,
/**
* prevent the browser default actions
* mostly used to disable scrolling of the browser
*/
preventDefault: function() {
if(this.srcEvent.preventManipulation) {
this.srcEvent.preventManipulation();
}
if(this.srcEvent.preventDefault) {
this.srcEvent.preventDefault();
}
},
/**
* stop bubbling the event up to its parents
*/
stopPropagation: function() {
this.srcEvent.stopPropagation();
},
/**
* immediately stop gesture detection
* might be useful after a swipe was detected
* @return {*}
*/
stopDetect: function() {
return Hammer.detection.stopDetect();
}
};
}
};
\ No newline at end of file
# Custom gestures
With Hammer.js it is easy to add your own gestures, just take a look at the gesture files.
When an gesture is added to the Hammer.gestures object, it is auto registered
at the setup of the first Hammer instance. You can also call Hammer.detection.register
manually and pass your gesture object as a param
## Gesture object
The object structure of a gesture:
````js
{ name: 'mygesture',
index: 1337,
defaults: {
mygesture_option: true
}
handler: function(type, ev, inst) {
// trigger gesture event
inst.trigger(this.name, ev);
}
}
````
`@param {String} name`
this should be the name of the gesture, lowercase
it is also being used to disable/enable the gesture per instance config.
`@param {Number} [index=1000]`
the index of the gesture, where it is going to be in the stack of gestures detection
like when you build an gesture that depends on the drag gesture, it is a good
idea to place it after the index of the drag gesture.
`@param {Object} [defaults={}]`
the default settings of the gesture. these are added to the instance settings,
and can be overruled per instance. you can also add the name of the gesture,
but this is also added by default (and set to true).
### Gesture handler
`@param {Function} handler`
this handles the gesture detection of your custom gesture and receives the
following arguments:
`@param {Object} eventData`
event data containing the following properties:
````js
timeStamp {Number} time the event occurred
target {HTMLElement} target element
touches {Array} touches (fingers, pointers, mouse) on the screen
pointerType {String} kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH
center {Object} center position of the touches. contains pageX and pageY
deltaTime {Number} the total time of the touches in the screen
deltaX {Number} the delta on x axis we haved moved
deltaY {Number} the delta on y axis we haved moved
velocityX {Number} the velocity on the x
velocityY {Number} the velocity on y
angle {Number} the angle we are moving
direction {String} the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT
distance {Number} the distance we haved moved
scale {Number} scaling of the touches, needs 2 touches
rotation {Number} rotation of the touches, needs 2 touches *
eventType {String} matches Hammer.EVENT_START|MOVE|END
srcEvent {Object} the source event, like TouchStart or MouseDown *
startEvent {Object} contains the same properties as above,
but from the first touch. this is used to calculate
distances, deltaTime, scaling etc
````
`@param {Hammer.Instance} inst`
the instance we are doing the detection for. you can get the options from
the inst.options object and trigger the gesture event by calling inst.trigger
## Handle gestures
inside the handler you can get/set Hammer.detection.current. This is the current
detection session. It has the following properties
`@param {String} name`
contains the name of the gesture we have detected. it has not a real function,
only to check in other gestures if something is detected.
like in the drag gesture we set it to 'drag' and in the swipe gesture we can
check if the current gesture is 'drag' by accessing Hammer.detection.current.name
`@readonly
@param {Hammer.Instance} inst`
the instance we do the detection for
`@readonly
@param {Object} startEvent`
contains the properties of the first gesture detection in this session.
Used for calculations about timing, distance, etc.
`@readonly
@param {Object} lastEvent`
contains all the properties of the last gesture detect in this session.
after the gesture detection session has been completed (user has released the screen)
the Hammer.detection.current object is copied into Hammer.detection.previous,
this is usefull for gestures like doubletap, where you need to know if the
previous gesture was a tap
options that have been set by the instance can be received by calling inst.options
You can trigger a gesture event by calling inst.trigger("mygesture", event).
The first param is the name of your gesture, the second the event argument
/**
* Drag
* Move with x fingers (default 1) around on the page. Blocking the scrolling when
* moving left and right is a good practice. When all the drag events are blocking
* you disable scrolling on that area.
* @events drag, drapleft, dragright, dragup, dragdown
*/
Hammer.gestures.Drag = {
name : 'drag',
index : 50,
defaults : {
drag_min_distance : 10,
// Set correct_for_drag_min_distance to true to make the starting point of the drag
// be calculated from where the drag was triggered, not from where the touch started.
// Useful to avoid a jerk-starting drag, which can make fine-adjustments
// through dragging difficult, and be visually unappealing.
correct_for_drag_min_distance: true,
// set 0 for unlimited, but this can conflict with transform
drag_max_touches : 1,
// prevent default browser behavior when dragging occurs
// be careful with it, it makes the element a blocking element
// when you are using the drag gesture, it is a good practice to set this true
drag_block_horizontal : false,
drag_block_vertical : false,
// drag_lock_to_axis keeps the drag gesture on the axis that it started on,
// It disallows vertical directions if the initial direction was horizontal, and vice versa.
drag_lock_to_axis : false,
// drag lock only kicks in when distance > drag_lock_min_distance
// This way, locking occurs only when the distance has become large enough to reliably determine the direction
drag_lock_min_distance : 25
},
triggered: false,
handler : function dragGesture(ev, inst) {
// current gesture isnt drag, but dragged is true
// this means an other gesture is busy. now call dragend
if(Hammer.detection.current.name != this.name && this.triggered) {
inst.trigger(this.name + 'end', ev);
this.triggered = false;
return;
}
// max touches
if(inst.options.drag_max_touches > 0 &&
ev.touches.length > inst.options.drag_max_touches) {
return;
}
switch(ev.eventType) {
case Hammer.EVENT_START:
this.triggered = false;
break;
case Hammer.EVENT_MOVE:
// when the distance we moved is too small we skip this gesture
// or we can be already in dragging
if(ev.distance < inst.options.drag_min_distance &&
Hammer.detection.current.name != this.name) {
return;
}
// we are dragging!
if(Hammer.detection.current.name != this.name) {
Hammer.detection.current.name = this.name;
if(inst.options.correct_for_drag_min_distance && ev.distance > 0) {
// When a drag is triggered, set the event center to drag_min_distance pixels from the original event center.
// Without this correction, the dragged distance would jumpstart at drag_min_distance pixels instead of at 0.
// It might be useful to save the original start point somewhere
var factor = Math.abs(inst.options.drag_min_distance / ev.distance);
Hammer.detection.current.startEvent.center.pageX += ev.deltaX * factor;
Hammer.detection.current.startEvent.center.pageY += ev.deltaY * factor;
// recalculate event data using new start point
ev = Hammer.detection.extendEventData(ev);
}
}
// lock drag to axis?
if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance <= ev.distance)) {
ev.drag_locked_to_axis = true;
}
var last_direction = Hammer.detection.current.lastEvent.direction;
if(ev.drag_locked_to_axis && last_direction !== ev.direction) {
// keep direction on the axis that the drag gesture started on
if(Hammer.utils.isVertical(last_direction)) {
ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN;
}
else {
ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT;
}
}
// first time, trigger dragstart event
if(!this.triggered) {
inst.trigger(this.name + 'start', ev);
this.triggered = true;
}
// trigger normal event
inst.trigger(this.name, ev);
// direction event, like dragdown
inst.trigger(this.name + ev.direction, ev);
// block the browser events
if((inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) ||
(inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) {
ev.preventDefault();
}
break;
case Hammer.EVENT_END:
// trigger dragend
if(this.triggered) {
inst.trigger(this.name + 'end', ev);
}
this.triggered = false;
break;
}
}
};
\ No newline at end of file
/**
* Hold
* Touch stays at the same place for x time
* @events hold
*/
Hammer.gestures.Hold = {
name : 'hold',
index : 10,
defaults: {
hold_timeout : 500,
hold_threshold: 1
},
timer : null,
handler : function holdGesture(ev, inst) {
switch(ev.eventType) {
case Hammer.EVENT_START:
// clear any running timers
clearTimeout(this.timer);
// set the gesture so we can check in the timeout if it still is
Hammer.detection.current.name = this.name;
// set timer and if after the timeout it still is hold,
// we trigger the hold event
this.timer = setTimeout(function() {
if(Hammer.detection.current.name == 'hold') {
inst.trigger('hold', ev);
}
}, inst.options.hold_timeout);
break;
// when you move or end we clear the timer
case Hammer.EVENT_MOVE:
if(ev.distance > inst.options.hold_threshold) {
clearTimeout(this.timer);
}
break;
case Hammer.EVENT_END:
clearTimeout(this.timer);
break;
}
}
};
\ No newline at end of file
/**
* Release
* Called as last, tells the user has released the screen
* @events release
*/
Hammer.gestures.Release = {
name : 'release',
index : Infinity,
handler: function releaseGesture(ev, inst) {
if(ev.eventType == Hammer.EVENT_END) {
inst.trigger(this.name, ev);
}
}
};
\ No newline at end of file
/**
* Swipe
* triggers swipe events when the end velocity is above the threshold
* @events swipe, swipeleft, swiperight, swipeup, swipedown
*/
Hammer.gestures.Swipe = {
name : 'swipe',
index : 40,
defaults: {
// set 0 for unlimited, but this can conflict with transform
swipe_min_touches: 1,
swipe_max_touches: 1,
swipe_velocity : 0.7
},
handler : function swipeGesture(ev, inst) {
if(ev.eventType == Hammer.EVENT_END) {
// max touches
if(inst.options.swipe_max_touches > 0 &&
ev.touches.length < inst.options.swipe_min_touches &&
ev.touches.length > inst.options.swipe_max_touches) {
return;
}
// when the distance we moved is too small we skip this gesture
// or we can be already in dragging
if(ev.velocityX > inst.options.swipe_velocity ||
ev.velocityY > inst.options.swipe_velocity) {
// trigger swipe events
inst.trigger(this.name, ev);
inst.trigger(this.name + ev.direction, ev);
}
}
}
};
\ No newline at end of file
/**
* Tap/DoubleTap
* Quick touch at a place or double at the same place
* @events tap, doubletap
*/
Hammer.gestures.Tap = {
name : 'tap',
index : 100,
defaults: {
tap_max_touchtime : 250,
tap_max_distance : 10,
tap_always : true,
doubletap_distance: 20,
doubletap_interval: 300
},
handler : function tapGesture(ev, inst) {
if(ev.eventType == Hammer.EVENT_END && ev.srcEvent.type != 'touchcancel') {
// previous gesture, for the double tap since these are two different gesture detections
var prev = Hammer.detection.previous,
did_doubletap = false;
// when the touchtime is higher then the max touch time
// or when the moving distance is too much
if(ev.deltaTime > inst.options.tap_max_touchtime ||
ev.distance > inst.options.tap_max_distance) {
return;
}
// check if double tap
if(prev && prev.name == 'tap' &&
(ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval &&
ev.distance < inst.options.doubletap_distance) {
inst.trigger('doubletap', ev);
did_doubletap = true;
}
// do a single tap
if(!did_doubletap || inst.options.tap_always) {
Hammer.detection.current.name = 'tap';
inst.trigger(Hammer.detection.current.name, ev);
}
}
}
};
\ No newline at end of file
/**
* Touch
* Called as first, tells the user has touched the screen
* @events touch
*/
Hammer.gestures.Touch = {
name : 'touch',
index : -Infinity,
defaults: {
// call preventDefault at touchstart, and makes the element blocking by
// disabling the scrolling of the page, but it improves gestures like
// transforming and dragging.
// be careful with using this, it can be very annoying for users to be stuck
// on the page
prevent_default : false,
// disable mouse events, so only touch (or pen!) input triggers events
prevent_mouseevents: false
},
handler : function touchGesture(ev, inst) {
if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) {
ev.stopDetect();
return;
}
if(inst.options.prevent_default) {
ev.preventDefault();
}
if(ev.eventType == Hammer.EVENT_START) {
inst.trigger(this.name, ev);
}
}
};
\ No newline at end of file
/**
* Transform
* User want to scale or rotate with 2 fingers
* @events transform, pinch, pinchin, pinchout, rotate
*/
Hammer.gestures.Transform = {
name : 'transform',
index : 45,
defaults : {
// factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1
transform_min_scale : 0.01,
// rotation in degrees
transform_min_rotation: 1,
// prevent default browser behavior when two touches are on the screen
// but it makes the element a blocking element
// when you are using the transform gesture, it is a good practice to set this true
transform_always_block: false
},
triggered: false,
handler : function transformGesture(ev, inst) {
// current gesture isnt drag, but dragged is true
// this means an other gesture is busy. now call dragend
if(Hammer.detection.current.name != this.name && this.triggered) {
inst.trigger(this.name + 'end', ev);
this.triggered = false;
return;
}
// atleast multitouch
if(ev.touches.length < 2) {
return;
}
// prevent default when two fingers are on the screen
if(inst.options.transform_always_block) {
ev.preventDefault();
}
switch(ev.eventType) {
case Hammer.EVENT_START:
this.triggered = false;
break;
case Hammer.EVENT_MOVE:
var scale_threshold = Math.abs(1 - ev.scale);
var rotation_threshold = Math.abs(ev.rotation);
// when the distance we moved is too small we skip this gesture
// or we can be already in dragging
if(scale_threshold < inst.options.transform_min_scale &&
rotation_threshold < inst.options.transform_min_rotation) {
return;
}
// we are transforming!
Hammer.detection.current.name = this.name;
// first time, trigger dragstart event
if(!this.triggered) {
inst.trigger(this.name + 'start', ev);
this.triggered = true;
}
inst.trigger(this.name, ev); // basic transform event
// trigger rotate event
if(rotation_threshold > inst.options.transform_min_rotation) {
inst.trigger('rotate', ev);
}
// trigger pinch event
if(scale_threshold > inst.options.transform_min_scale) {
inst.trigger('pinch', ev);
inst.trigger('pinch' + ((ev.scale < 1) ? 'in' : 'out'), ev);
}
break;
case Hammer.EVENT_END:
// trigger dragend
if(this.triggered) {
inst.trigger(this.name + 'end', ev);
}
this.triggered = false;
break;
}
}
};
\ No newline at end of file
/**
* create new hammer instance
* all methods should return the instance itself, so it is chainable.
* @param {HTMLElement} element
* @param {Object} [options={}]
* @returns {Hammer.Instance}
* @constructor
*/
Hammer.Instance = function(element, options) {
var self = this;
// setup HammerJS window events and register all gestures
// this also sets up the default options
setup();
this.element = element;
// start/stop detection option
this.enabled = true;
// merge options
this.options = Hammer.utils.extend(
Hammer.utils.extend({}, Hammer.defaults),
options || {});
// add some css to the element to prevent the browser from doing its native behavoir
if(this.options.stop_browser_behavior) {
Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior);
}
// start detection on touchstart
Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) {
if(self.enabled) {
Hammer.detection.startDetect(self, ev);
}
});
// return instance
return this;
};
Hammer.Instance.prototype = {
/**
* bind events to the instance
* @param {String} gesture
* @param {Function} handler
* @returns {Hammer.Instance}
*/
on: function onEvent(gesture, handler) {
var gestures = gesture.split(' ');
Hammer.utils.each(gestures, function(gesture) {
this.element.addEventListener(gesture, handler, false);
}, this);
return this;
},
/**
* unbind events to the instance
* @param {String} gesture
* @param {Function} handler
* @returns {Hammer.Instance}
*/
off: function offEvent(gesture, handler) {
var gestures = gesture.split(' ');
Hammer.utils.each(gestures, function(gesture) {
this.element.removeEventListener(gesture, handler, false);
}, this);
return this;
},
/**
* trigger gesture event
* @param {String} gesture
* @param {Object} [eventData]
* @returns {Hammer.Instance}
*/
trigger: function triggerEvent(gesture, eventData) {
// optional
if(!eventData) {
eventData = {};
}
// create DOM event
var event = Hammer.DOCUMENT.createEvent('Event');
event.initEvent(gesture, true, true);
event.gesture = eventData;
// trigger on the target if it is in the instance element,
// this is for event delegation tricks
var element = this.element;
if(Hammer.utils.hasParent(eventData.target, element)) {
element = eventData.target;
}
element.dispatchEvent(event);
return this;
},
/**
* enable of disable hammer.js detection
* @param {Boolean} state
* @returns {Hammer.Instance}
*/
enable: function enable(state) {
this.enabled = state;
return this;
}
};
(function(window, undefined) {
'use strict';
\ No newline at end of file
// Based off Lo-Dash's excellent UMD wrapper (slightly modified) - https://github.com/bestiejs/lodash/blob/master/lodash.js#L5515-L5543
// some AMD build optimizers, like r.js, check for specific condition patterns like the following:
if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
// define as an anonymous module
define(function() {
return Hammer;
});
// check for `exports` after `define` in case a build optimizer adds an `exports` object
}
else if(typeof module === 'object' && typeof module.exports === 'object') {
module.exports = Hammer;
}
else {
window.Hammer = Hammer;
}
})(this);
\ No newline at end of file
Hammer.PointerEvent = {
/**
* holds all pointers
* @type {Object}
*/
pointers: {},
/**
* get a list of pointers
* @returns {Array} touchlist
*/
getTouchList: function() {
var self = this;
var touchlist = [];
// we can use forEach since pointerEvents only is in IE10
Hammer.utils.each(self.pointers, function(pointer){
touchlist.push(pointer);
});
return touchlist;
},
/**
* update the position of a pointer
* @param {String} type Hammer.EVENT_END
* @param {Object} pointerEvent
*/
updatePointer: function(type, pointerEvent) {
if(type == Hammer.EVENT_END) {
this.pointers = {};
}
else {
pointerEvent.identifier = pointerEvent.pointerId;
this.pointers[pointerEvent.pointerId] = pointerEvent;
}
return Object.keys(this.pointers).length;
},
/**
* check if ev matches pointertype
* @param {String} pointerType Hammer.POINTER_MOUSE
* @param {PointerEvent} ev
*/
matchType: function(pointerType, ev) {
if(!ev.pointerType) {
return false;
}
var pt = ev.pointerType,
types = {};
types[Hammer.POINTER_MOUSE] = (pt === ev.MSPOINTER_TYPE_MOUSE || pt === Hammer.POINTER_MOUSE);
types[Hammer.POINTER_TOUCH] = (pt === ev.MSPOINTER_TYPE_TOUCH || pt === Hammer.POINTER_TOUCH);
types[Hammer.POINTER_PEN] = (pt === ev.MSPOINTER_TYPE_PEN || pt === Hammer.POINTER_PEN);
return types[pointerType];
},
/**
* get events
*/
getEvents: function() {
return [
'pointerdown MSPointerDown',
'pointermove MSPointerMove',
'pointerup pointercancel MSPointerUp MSPointerCancel'
];
},
/**
* reset the list
*/
reset: function() {
this.pointers = {};
}
};
// if the window events are set...
Hammer.READY = false;
/**
* setup events to detect gestures on the document
*/
function setup() {
if(Hammer.READY) {
return;
}
// find what eventtypes we add listeners to
Hammer.event.determineEventTypes();
// Register all gestures inside Hammer.gestures
Hammer.utils.each(Hammer.gestures, function(gesture){
Hammer.detection.register(gesture);
});
// Add touch events on the document
Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect);
Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect);
// Hammer is ready...!
Hammer.READY = true;
}
\ No newline at end of file
Hammer.utils = {
/**
* extend method,
* also used for cloning when dest is an empty object
* @param {Object} dest
* @param {Object} src
* @parm {Boolean} merge do a merge
* @returns {Object} dest
*/
extend: function extend(dest, src, merge) {
for(var key in src) {
if(dest[key] !== undefined && merge) {
continue;
}
dest[key] = src[key];
}
return dest;
},
/**
* for each
* @param obj
* @param iterator
*/
each: function(obj, iterator, context) {
var i, length;
// native forEach on arrays
if ('forEach' in obj) {
obj.forEach(iterator, context);
}
// arrays
else if(obj.length !== undefined) {
for (i = 0, length = obj.length; i < length; i++) {
if (iterator.call(context, obj[i], i, obj) === false) {
return;
}
}
}
// objects
else {
for (i in obj) {
if (obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj) === false) {
return;
}
}
}
},
/**
* find if a node is in the given parent
* used for event delegation tricks
* @param {HTMLElement} node
* @param {HTMLElement} parent
* @returns {boolean} has_parent
*/
hasParent: function(node, parent) {
while(node) {
if(node == parent) {
return true;
}
node = node.parentNode;
}
return false;
},
/**
* get the center of all the touches
* @param {Array} touches
* @returns {Object} center
*/
getCenter: function getCenter(touches) {
var valuesX = [], valuesY = [];
Hammer.utils.each(touches, function(touch) {
// I prefer clientX because it ignore the scrolling position
valuesX.push(typeof touch.clientX !== 'undefined' ? touch.clientX : touch.pageX );
valuesY.push(typeof touch.clientY !== 'undefined' ? touch.clientY : touch.pageY );
});
return {
pageX: ((Math.min.apply(Math, valuesX) + Math.max.apply(Math, valuesX)) / 2),
pageY: ((Math.min.apply(Math, valuesY) + Math.max.apply(Math, valuesY)) / 2)
};
},
/**
* calculate the velocity between two points
* @param {Number} delta_time
* @param {Number} delta_x
* @param {Number} delta_y
* @returns {Object} velocity
*/
getVelocity: function getVelocity(delta_time, delta_x, delta_y) {
return {
x: Math.abs(delta_x / delta_time) || 0,
y: Math.abs(delta_y / delta_time) || 0
};
},
/**
* calculate the angle between two coordinates
* @param {Touch} touch1
* @param {Touch} touch2
* @returns {Number} angle
*/
getAngle: function getAngle(touch1, touch2) {
var y = touch2.pageY - touch1.pageY,
x = touch2.pageX - touch1.pageX;
return Math.atan2(y, x) * 180 / Math.PI;
},
/**
* angle to direction define
* @param {Touch} touch1
* @param {Touch} touch2
* @returns {String} direction constant, like Hammer.DIRECTION_LEFT
*/
getDirection: function getDirection(touch1, touch2) {
var x = Math.abs(touch1.pageX - touch2.pageX),
y = Math.abs(touch1.pageY - touch2.pageY);
if(x >= y) {
return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT;
}
else {
return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN;
}
},
/**
* calculate the distance between two touches
* @param {Touch} touch1
* @param {Touch} touch2
* @returns {Number} distance
*/
getDistance: function getDistance(touch1, touch2) {
var x = touch2.pageX - touch1.pageX,
y = touch2.pageY - touch1.pageY;
return Math.sqrt((x * x) + (y * y));
},
/**
* calculate the scale factor between two touchLists (fingers)
* no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
* @param {Array} start
* @param {Array} end
* @returns {Number} scale
*/
getScale: function getScale(start, end) {
// need two fingers...
if(start.length >= 2 && end.length >= 2) {
return this.getDistance(end[0], end[1]) /
this.getDistance(start[0], start[1]);
}
return 1;
},
/**
* calculate the rotation degrees between two touchLists (fingers)
* @param {Array} start
* @param {Array} end
* @returns {Number} rotation
*/
getRotation: function getRotation(start, end) {
// need two fingers
if(start.length >= 2 && end.length >= 2) {
return this.getAngle(end[1], end[0]) -
this.getAngle(start[1], start[0]);
}
return 0;
},
/**
* boolean if the direction is vertical
* @param {String} direction
* @returns {Boolean} is_vertical
*/
isVertical: function isVertical(direction) {
return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN);
},
/**
* stop browser default behavior with css props
* @param {HtmlElement} element
* @param {Object} css_props
*/
stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) {
if(!css_props || !element || !element.style) {
return;
}
// with css properties for modern browsers
Hammer.utils.each(['webkit', 'khtml', 'moz', 'Moz', 'ms', 'o', ''], function(vendor) {
Hammer.utils.each(css_props, function(prop) {
// vender prefix at the property
if(vendor) {
prop = vendor + prop.substring(0, 1).toUpperCase() + prop.substring(1);
}
// set the style
if(prop in element.style) {
element.style[prop] = prop;
}
});
});
// also the disable onselectstart
if(css_props.userSelect == 'none') {
element.onselectstart = function() {
return false;
};
}
// and disable ondragstart
if(css_props.userDrag == 'none') {
element.ondragstart = function() {
return false;
};
}
}
};
var el = document.getElementById('toucharea');
// force showing touches
Hammer.plugins.showTouches(true);
// faker
var faker = new FakeTouches(el);
if(set_faketouches_type) {
faker.setTouchType(set_faketouches_type);
}
// hammer
var hammertime = new Hammer(el);
// all events
var all_events = ["touch", "release", "hold", "tap", "doubletap",
"dragstart", "drag", "dragend", "dragleft", "dragright",
"dragup", "dragdown", "swipe", "swipeleft", "swiperight",
"swipeup", "swipedown", "transformstart", "transform",
"transformend", "rotate", "pinch", "pinchin", "pinchout"];
// keep track of what events are triggered
var triggered_events = {};
hammertime.on(all_events.join(" "), function(ev) {
triggered_events[ev.type] = ev;
});
/**
* test gestures
* @param {String} gesture
* @param {String} expect_events
* @param {Function} callback
*/
function testGesture(gesture, expect_events, callback) {
// reset triggered events
triggered_events = {};
// trigger the gesture faker
faker.triggerGesture(gesture, function() {
var expect = expect_events.split(" ");
var events = Object.keys(triggered_events);
_.each(triggered_events, function(ev, name) {
testEventData(name, ev);
});
// trigger callback with true/false is all the events are triggered
// if also any other events are triggered it is false
var success = (events.length === expect.length);
// error msg
var msg = gesture +" detected";
if(!success) {
msg = gesture +" error. Events thrown: "+ events.join(" ");
}
// maybe something happens after the end, so wait a moment
callback(success, msg);
});
}
/**
* test gestures
*/
var gesture_tests = {
'Hold' : 'touch hold release',
'Tap' : 'touch tap release',
'DoubleTap' : 'touch tap doubletap release',
'DragRight' : 'touch drag dragstart dragright dragend release',
'SwipeRight' : 'touch drag dragstart dragright dragend swipe swiperight release',
'Rotate' : 'touch transform transformstart transformend rotate release',
'PinchIn' : 'touch transform transformstart transformend pinch pinchin release',
'PinchOut' : 'touch transform transformstart transformend pinch pinchout release'
};
for(var gesture in gesture_tests) {
if(gesture_tests.hasOwnProperty(gesture)) {
(function(gesture) {
if(gesture_tests[gesture].match(/transform/) && !faker.has_multitouch) {
return;
}
asyncTest(gesture, function() {
testGesture(gesture, gesture_tests[gesture], function(success, msg) {
ok(success, msg);
start();
});
});
})(gesture);
}
}
/**
* test if event data contains wright values
* @param {String} name
* @param {Object} ev
*/
function testEventData(name, ev) {
// types match
ok(ev.type == name, 'ev.type');
// has gesture object
ok(_.isObject(ev.gesture), 'ev.gesture');
// EVENT_START|MOVE|END
ok(ev.gesture.eventType, 'ev.gesture.eventType');
ok(_.isNumber(ev.gesture.angle), 'ev.gesture.angle');
ok(_.isObject(ev.gesture.center), 'ev.gesture.center');
ok(_.isNumber(ev.gesture.deltaTime), 'ev.gesture.deltatime');
ok(_.isNumber(ev.gesture.deltaX), 'ev.gesture.deltaX');
ok(_.isNumber(ev.gesture.deltaY), 'ev.gesture.deltaY');
ok(_.isNumber(ev.gesture.distance), 'ev.gesture.distance');
// direction
ok(ev.gesture.direction, 'ev.gesture.direction');
var dir;
if(dir = ev.type.match(/up|down|left|right/)) {
ok(ev.gesture.direction === Hammer['DIRECTION_'+ dir[0].toUpperCase()]);
}
// pointerType
ok(ev.gesture.pointerType, 'ev.gesture.pointerType');
var pointer_type = Hammer.POINTER_TOUCH;
if( faker.touch_type == FakeTouches.POINTER_MOUSE_EVENTS ||
faker.touch_type == FakeTouches.MOUSE_EVENTS) {
pointer_type = Hammer.POINTER_MOUSE;
}
ok(ev.gesture.pointerType == pointer_type, 'not matching pointertype: '+ ev.gesture.pointerType +':'+ pointer_type);
ok(_.isFunction(ev.gesture.preventDefault), 'ev.gesture.preventDefault');
ok(_.isNumber(ev.gesture.rotation), 'ev.gesture.rotation');
ok(_.isNumber(ev.gesture.scale), 'ev.gesture.scale');
ok(_.isObject(ev.gesture.srcEvent), 'ev.gesture.srcEvent');
ok(_.isObject(ev.gesture.startEvent), 'ev.gesture.startEvent');
ok(_.isFunction(ev.gesture.stopDetect), 'ev.gesture.stopDetect');
ok(_.isFunction(ev.gesture.stopPropagation), 'ev.gesture.stopPropagation');
ok(_.isElement(ev.gesture.target), 'ev.gesture.target');
ok(_.isNumber(ev.gesture.timeStamp), 'ev.gesture.timeStamp');
ok(_.isArray(ev.gesture.touches), 'ev.gesture.touches');
ok(ev.gesture.touches.length >= 1, 'ev.gesture.touches');
ok(_.isNumber(ev.gesture.velocityX), 'ev.gesture.velocityX');
ok(_.isNumber(ev.gesture.velocityY), 'ev.gesture.velocityY');
}
\ No newline at end of file
/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
//@ sourceMappingURL=jquery.min.map
*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;
return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="<a name='"+x+"'></a><div name='"+x+"'></div>",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&&gt(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Nt=/^(?:checkbox|radio)$/i,Ct=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:b.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l)
}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=ln(e,t),Pt.detach()),Gt[e]=n),n}function ln(e,t){var n=b(t.createElement(e)).appendTo(t.body),r=b.css(n[0],"display");return n.remove(),r}b.each(["height","width"],function(e,n){b.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(b.css(e,"display"))?b.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,i),i):0)}}}),b.support.opacity||(b.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=b.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===b.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),b(function(){b.support.reliableMarginRight||(b.cssHooks.marginRight={get:function(e,n){return n?b.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!b.support.pixelPosition&&b.fn.position&&b.each(["top","left"],function(e,n){b.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?b(e).position()[n]+"px":r):t}}})}),b.expr&&b.expr.filters&&(b.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!b.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||b.css(e,"display"))},b.expr.filters.visible=function(e){return!b.expr.filters.hidden(e)}),b.each({margin:"",padding:"",border:"Width"},function(e,t){b.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(b.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;b.fn.extend({serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=b.prop(this,"elements");return e?b.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!b(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Nt.test(e))}).map(function(e,t){var n=b(this).val();return null==n?null:b.isArray(n)?b.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),b.param=function(e,n){var r,i=[],o=function(e,t){t=b.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=b.ajaxSettings&&b.ajaxSettings.traditional),b.isArray(e)||e.jquery&&!b.isPlainObject(e))b.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(b.isArray(t))b.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==b.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}b.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){b.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),b.fn.hover=function(e,t){return this.mouseenter(e).mouseleave(t||e)};var mn,yn,vn=b.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Nn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Cn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=b.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=a.href}catch(Ln){yn=o.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(b.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(u){var l;return o[u]=!0,b.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||a||o[c]?a?!(l=c):t:(n.dataTypes.unshift(c),s(c),!1)}),l}return s(n.dataTypes[0])||!o["*"]&&s("*")}function Mn(e,n){var r,i,o=b.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&b.extend(!0,e,r),e}b.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),b.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&b.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?b("<div>").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:function(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("If-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p()}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slow:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window);
\ No newline at end of file
/**
* QUnit v1.4.0 - A JavaScript Unit Testing Framework
*
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2012 John Resig, Jörn Zaefferer
* Dual licensed under the MIT (MIT-LICENSE.txt)
* or GPL (GPL-LICENSE.txt) licenses.
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 15px 15px 0 0;
-moz-border-radius: 15px 15px 0 0;
-webkit-border-top-right-radius: 15px;
-webkit-border-top-left-radius: 15px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-header label {
display: inline-block;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 15px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
box-shadow: inset 0px 2px 13px #999;
-moz-box-shadow: inset 0px 2px 13px #999;
-webkit-box-shadow: inset 0px 2px 13px #999;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
margin: 0.5em;
padding: 0.4em 0.5em 0.4em 0.5em;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #5E740B;
background-color: #fff;
border-left: 26px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 26px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 15px 15px;
-moz-border-radius: 0 0 15px 15px;
-webkit-border-bottom-right-radius: 15px;
-webkit-border-bottom-left-radius: 15px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
width: 1000px;
height: 1000px;
}
/**
* QUnit v1.12.0 - A JavaScript Unit Testing Framework
*
* http://qunitjs.com
*
* Copyright 2013 jQuery Foundation and other contributors
* Released under the MIT license.
* https://jquery.org/license/
*/
(function( window ) {
var QUnit,
assert,
config,
onErrorFnPrev,
testId = 0,
fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty,
// Keep a local reference to Date (GH-283)
Date = window.Date,
setTimeout = window.setTimeout,
defined = {
setTimeout: typeof window.setTimeout !== "undefined",
sessionStorage: (function() {
var x = "qunit-test-string";
try {
sessionStorage.setItem( x, x );
sessionStorage.removeItem( x );
return true;
} catch( e ) {
return false;
}
}())
},
/**
* Provides a normalized error string, correcting an issue
* with IE 7 (and prior) where Error.prototype.toString is
* not properly implemented
*
* Based on http://es5.github.com/#x15.11.4.4
*
* @param {String|Error} error
* @return {String} error message
*/
errorString = function( error ) {
var name, message,
errorString = error.toString();
if ( errorString.substring( 0, 7 ) === "[object" ) {
name = error.name ? error.name.toString() : "Error";
message = error.message ? error.message.toString() : "";
if ( name && message ) {
return name + ": " + message;
} else if ( name ) {
return name;
} else if ( message ) {
return message;
} else {
return "Error";
}
} else {
return errorString;
}
},
/**
* Makes a clone of an object using only Array or Object as base,
* and copies over the own enumerable properties.
*
* @param {Object} obj
* @return {Object} New object with only the own properties (recursively).
*/
objectValues = function( obj ) {
// Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
/*jshint newcap: false */
var key, val,
vals = QUnit.is( "array", obj ) ? [] : {};
for ( key in obj ) {
if ( hasOwn.call( obj, key ) ) {
val = obj[key];
vals[key] = val === Object(val) ? objectValues(val) : val;
}
}
return vals;
};
function Test( settings ) {
extend( this, settings );
this.assertions = [];
this.testNumber = ++Test.count;
}
Test.count = 0;
Test.prototype = {
init: function() {
var a, b, li,
tests = id( "qunit-tests" );
if ( tests ) {
b = document.createElement( "strong" );
b.innerHTML = this.nameHtml;
// `a` initialized at top of scope
a = document.createElement( "a" );
a.innerHTML = "Rerun";
a.href = QUnit.url({ testNumber: this.testNumber });
li = document.createElement( "li" );
li.appendChild( b );
li.appendChild( a );
li.className = "running";
li.id = this.id = "qunit-test-output" + testId++;
tests.appendChild( li );
}
},
setup: function() {
if (
// Emit moduleStart when we're switching from one module to another
this.module !== config.previousModule ||
// They could be equal (both undefined) but if the previousModule property doesn't
// yet exist it means this is the first test in a suite that isn't wrapped in a
// module, in which case we'll just emit a moduleStart event for 'undefined'.
// Without this, reporters can get testStart before moduleStart which is a problem.
!hasOwn.call( config, "previousModule" )
) {
if ( hasOwn.call( config, "previousModule" ) ) {
runLoggingCallbacks( "moduleDone", QUnit, {
name: config.previousModule,
failed: config.moduleStats.bad,
passed: config.moduleStats.all - config.moduleStats.bad,
total: config.moduleStats.all
});
}
config.previousModule = this.module;
config.moduleStats = { all: 0, bad: 0 };
runLoggingCallbacks( "moduleStart", QUnit, {
name: this.module
});
}
config.current = this;
this.testEnvironment = extend({
setup: function() {},
teardown: function() {}
}, this.moduleTestEnvironment );
this.started = +new Date();
runLoggingCallbacks( "testStart", QUnit, {
name: this.testName,
module: this.module
});
/*jshint camelcase:false */
/**
* Expose the current test environment.
*
* @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead.
*/
QUnit.current_testEnvironment = this.testEnvironment;
/*jshint camelcase:true */
if ( !config.pollution ) {
saveGlobal();
}
if ( config.notrycatch ) {
this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
return;
}
try {
this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
} catch( e ) {
QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
}
},
run: function() {
config.current = this;
var running = id( "qunit-testresult" );
if ( running ) {
running.innerHTML = "Running: <br/>" + this.nameHtml;
}
if ( this.async ) {
QUnit.stop();
}
this.callbackStarted = +new Date();
if ( config.notrycatch ) {
this.callback.call( this.testEnvironment, QUnit.assert );
this.callbackRuntime = +new Date() - this.callbackStarted;
return;
}
try {
this.callback.call( this.testEnvironment, QUnit.assert );
this.callbackRuntime = +new Date() - this.callbackStarted;
} catch( e ) {
this.callbackRuntime = +new Date() - this.callbackStarted;
QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
// else next test will carry the responsibility
saveGlobal();
// Restart the tests if they're blocking
if ( config.blocking ) {
QUnit.start();
}
}
},
teardown: function() {
config.current = this;
if ( config.notrycatch ) {
if ( typeof this.callbackRuntime === "undefined" ) {
this.callbackRuntime = +new Date() - this.callbackStarted;
}
this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
return;
} else {
try {
this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
} catch( e ) {
QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
}
}
checkPollution();
},
finish: function() {
config.current = this;
if ( config.requireExpects && this.expected === null ) {
QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
} else if ( this.expected !== null && this.expected !== this.assertions.length ) {
QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
} else if ( this.expected === null && !this.assertions.length ) {
QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
}
var i, assertion, a, b, time, li, ol,
test = this,
good = 0,
bad = 0,
tests = id( "qunit-tests" );
this.runtime = +new Date() - this.started;
config.stats.all += this.assertions.length;
config.moduleStats.all += this.assertions.length;
if ( tests ) {
ol = document.createElement( "ol" );
ol.className = "qunit-assert-list";
for ( i = 0; i < this.assertions.length; i++ ) {
assertion = this.assertions[i];
li = document.createElement( "li" );
li.className = assertion.result ? "pass" : "fail";
li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
ol.appendChild( li );
if ( assertion.result ) {
good++;
} else {
bad++;
config.stats.bad++;
config.moduleStats.bad++;
}
}
// store result when possible
if ( QUnit.config.reorder && defined.sessionStorage ) {
if ( bad ) {
sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
} else {
sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
}
}
if ( bad === 0 ) {
addClass( ol, "qunit-collapsed" );
}
// `b` initialized at top of scope
b = document.createElement( "strong" );
b.innerHTML = this.nameHtml + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
addEvent(b, "click", function() {
var next = b.parentNode.lastChild,
collapsed = hasClass( next, "qunit-collapsed" );
( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
});
addEvent(b, "dblclick", function( e ) {
var target = e && e.target ? e.target : window.event.srcElement;
if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
target = target.parentNode;
}
if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
window.location = QUnit.url({ testNumber: test.testNumber });
}
});
// `time` initialized at top of scope
time = document.createElement( "span" );
time.className = "runtime";
time.innerHTML = this.runtime + " ms";
// `li` initialized at top of scope
li = id( this.id );
li.className = bad ? "fail" : "pass";
li.removeChild( li.firstChild );
a = li.firstChild;
li.appendChild( b );
li.appendChild( a );
li.appendChild( time );
li.appendChild( ol );
} else {
for ( i = 0; i < this.assertions.length; i++ ) {
if ( !this.assertions[i].result ) {
bad++;
config.stats.bad++;
config.moduleStats.bad++;
}
}
}
runLoggingCallbacks( "testDone", QUnit, {
name: this.testName,
module: this.module,
failed: bad,
passed: this.assertions.length - bad,
total: this.assertions.length,
duration: this.runtime
});
QUnit.reset();
config.current = undefined;
},
queue: function() {
var bad,
test = this;
synchronize(function() {
test.init();
});
function run() {
// each of these can by async
synchronize(function() {
test.setup();
});
synchronize(function() {
test.run();
});
synchronize(function() {
test.teardown();
});
synchronize(function() {
test.finish();
});
}
// `bad` initialized at top of scope
// defer when previous test run passed, if storage is available
bad = QUnit.config.reorder && defined.sessionStorage &&
+sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
if ( bad ) {
run();
} else {
synchronize( run, true );
}
}
};
// Root QUnit object.
// `QUnit` initialized at top of scope
QUnit = {
// call on start of module test to prepend name to all tests
module: function( name, testEnvironment ) {
config.currentModule = name;
config.currentModuleTestEnvironment = testEnvironment;
config.modules[name] = true;
},
asyncTest: function( testName, expected, callback ) {
if ( arguments.length === 2 ) {
callback = expected;
expected = null;
}
QUnit.test( testName, expected, callback, true );
},
test: function( testName, expected, callback, async ) {
var test,
nameHtml = "<span class='test-name'>" + escapeText( testName ) + "</span>";
if ( arguments.length === 2 ) {
callback = expected;
expected = null;
}
if ( config.currentModule ) {
nameHtml = "<span class='module-name'>" + escapeText( config.currentModule ) + "</span>: " + nameHtml;
}
test = new Test({
nameHtml: nameHtml,
testName: testName,
expected: expected,
async: async,
callback: callback,
module: config.currentModule,
moduleTestEnvironment: config.currentModuleTestEnvironment,
stack: sourceFromStacktrace( 2 )
});
if ( !validTest( test ) ) {
return;
}
test.queue();
},
// Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through.
expect: function( asserts ) {
if (arguments.length === 1) {
config.current.expected = asserts;
} else {
return config.current.expected;
}
},
start: function( count ) {
// QUnit hasn't been initialized yet.
// Note: RequireJS (et al) may delay onLoad
if ( config.semaphore === undefined ) {
QUnit.begin(function() {
// This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
setTimeout(function() {
QUnit.start( count );
});
});
return;
}
config.semaphore -= count || 1;
// don't start until equal number of stop-calls
if ( config.semaphore > 0 ) {
return;
}
// ignore if start is called more often then stop
if ( config.semaphore < 0 ) {
config.semaphore = 0;
QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
return;
}
// A slight delay, to avoid any current callbacks
if ( defined.setTimeout ) {
setTimeout(function() {
if ( config.semaphore > 0 ) {
return;
}
if ( config.timeout ) {
clearTimeout( config.timeout );
}
config.blocking = false;
process( true );
}, 13);
} else {
config.blocking = false;
process( true );
}
},
stop: function( count ) {
config.semaphore += count || 1;
config.blocking = true;
if ( config.testTimeout && defined.setTimeout ) {
clearTimeout( config.timeout );
config.timeout = setTimeout(function() {
QUnit.ok( false, "Test timed out" );
config.semaphore = 1;
QUnit.start();
}, config.testTimeout );
}
}
};
// `assert` initialized at top of scope
// Assert helpers
// All of these must either call QUnit.push() or manually do:
// - runLoggingCallbacks( "log", .. );
// - config.current.assertions.push({ .. });
// We attach it to the QUnit object *after* we expose the public API,
// otherwise `assert` will become a global variable in browsers (#341).
assert = {
/**
* Asserts rough true-ish result.
* @name ok
* @function
* @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
*/
ok: function( result, msg ) {
if ( !config.current ) {
throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
}
result = !!result;
msg = msg || (result ? "okay" : "failed" );
var source,
details = {
module: config.current.module,
name: config.current.testName,
result: result,
message: msg
};
msg = "<span class='test-message'>" + escapeText( msg ) + "</span>";
if ( !result ) {
source = sourceFromStacktrace( 2 );
if ( source ) {
details.source = source;
msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr></table>";
}
}
runLoggingCallbacks( "log", QUnit, details );
config.current.assertions.push({
result: result,
message: msg
});
},
/**
* Assert that the first two arguments are equal, with an optional message.
* Prints out both actual and expected values.
* @name equal
* @function
* @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
*/
equal: function( actual, expected, message ) {
/*jshint eqeqeq:false */
QUnit.push( expected == actual, actual, expected, message );
},
/**
* @name notEqual
* @function
*/
notEqual: function( actual, expected, message ) {
/*jshint eqeqeq:false */
QUnit.push( expected != actual, actual, expected, message );
},
/**
* @name propEqual
* @function
*/
propEqual: function( actual, expected, message ) {
actual = objectValues(actual);
expected = objectValues(expected);
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
},
/**
* @name notPropEqual
* @function
*/
notPropEqual: function( actual, expected, message ) {
actual = objectValues(actual);
expected = objectValues(expected);
QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
},
/**
* @name deepEqual
* @function
*/
deepEqual: function( actual, expected, message ) {
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
},
/**
* @name notDeepEqual
* @function
*/
notDeepEqual: function( actual, expected, message ) {
QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
},
/**
* @name strictEqual
* @function
*/
strictEqual: function( actual, expected, message ) {
QUnit.push( expected === actual, actual, expected, message );
},
/**
* @name notStrictEqual
* @function
*/
notStrictEqual: function( actual, expected, message ) {
QUnit.push( expected !== actual, actual, expected, message );
},
"throws": function( block, expected, message ) {
var actual,
expectedOutput = expected,
ok = false;
// 'expected' is optional
if ( typeof expected === "string" ) {
message = expected;
expected = null;
}
config.current.ignoreGlobalErrors = true;
try {
block.call( config.current.testEnvironment );
} catch (e) {
actual = e;
}
config.current.ignoreGlobalErrors = false;
if ( actual ) {
// we don't want to validate thrown error
if ( !expected ) {
ok = true;
expectedOutput = null;
// expected is a regexp
} else if ( QUnit.objectType( expected ) === "regexp" ) {
ok = expected.test( errorString( actual ) );
// expected is a constructor
} else if ( actual instanceof expected ) {
ok = true;
// expected is a validation function which returns true is validation passed
} else if ( expected.call( {}, actual ) === true ) {
expectedOutput = null;
ok = true;
}
QUnit.push( ok, actual, expectedOutput, message );
} else {
QUnit.pushFailure( message, null, "No exception was thrown." );
}
}
};
/**
* @deprecated since 1.8.0
* Kept assertion helpers in root for backwards compatibility.
*/
extend( QUnit, assert );
/**
* @deprecated since 1.9.0
* Kept root "raises()" for backwards compatibility.
* (Note that we don't introduce assert.raises).
*/
QUnit.raises = assert[ "throws" ];
/**
* @deprecated since 1.0.0, replaced with error pushes since 1.3.0
* Kept to avoid TypeErrors for undefined methods.
*/
QUnit.equals = function() {
QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
};
QUnit.same = function() {
QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
};
// We want access to the constructor's prototype
(function() {
function F() {}
F.prototype = QUnit;
QUnit = new F();
// Make F QUnit's constructor so that we can add to the prototype later
QUnit.constructor = F;
}());
/**
* Config object: Maintain internal state
* Later exposed as QUnit.config
* `config` initialized at top of scope
*/
config = {
// The queue of tests to run
queue: [],
// block until document ready
blocking: true,
// when enabled, show only failing tests
// gets persisted through sessionStorage and can be changed in UI via checkbox
hidepassed: false,
// by default, run previously failed tests first
// very useful in combination with "Hide passed tests" checked
reorder: true,
// by default, modify document.title when suite is done
altertitle: true,
// when enabled, all tests must call expect()
requireExpects: false,
// add checkboxes that are persisted in the query-string
// when enabled, the id is set to `true` as a `QUnit.config` property
urlConfig: [
{
id: "noglobals",
label: "Check for Globals",
tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
},
{
id: "notrycatch",
label: "No try-catch",
tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
}
],
// Set of all modules.
modules: {},
// logging callback queues
begin: [],
done: [],
log: [],
testStart: [],
testDone: [],
moduleStart: [],
moduleDone: []
};
// Export global variables, unless an 'exports' object exists,
// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
if ( typeof exports === "undefined" ) {
extend( window, QUnit.constructor.prototype );
// Expose QUnit object
window.QUnit = QUnit;
}
// Initialize more QUnit.config and QUnit.urlParams
(function() {
var i,
location = window.location || { search: "", protocol: "file:" },
params = location.search.slice( 1 ).split( "&" ),
length = params.length,
urlParams = {},
current;
if ( params[ 0 ] ) {
for ( i = 0; i < length; i++ ) {
current = params[ i ].split( "=" );
current[ 0 ] = decodeURIComponent( current[ 0 ] );
// allow just a key to turn on a flag, e.g., test.html?noglobals
current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
urlParams[ current[ 0 ] ] = current[ 1 ];
}
}
QUnit.urlParams = urlParams;
// String search anywhere in moduleName+testName
config.filter = urlParams.filter;
// Exact match of the module name
config.module = urlParams.module;
config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
// Figure out if we're running the tests from a server or not
QUnit.isLocal = location.protocol === "file:";
}());
// Extend QUnit object,
// these after set here because they should not be exposed as global functions
extend( QUnit, {
assert: assert,
config: config,
// Initialize the configuration options
init: function() {
extend( config, {
stats: { all: 0, bad: 0 },
moduleStats: { all: 0, bad: 0 },
started: +new Date(),
updateRate: 1000,
blocking: false,
autostart: true,
autorun: false,
filter: "",
queue: [],
semaphore: 1
});
var tests, banner, result,
qunit = id( "qunit" );
if ( qunit ) {
qunit.innerHTML =
"<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
"<h2 id='qunit-banner'></h2>" +
"<div id='qunit-testrunner-toolbar'></div>" +
"<h2 id='qunit-userAgent'></h2>" +
"<ol id='qunit-tests'></ol>";
}
tests = id( "qunit-tests" );
banner = id( "qunit-banner" );
result = id( "qunit-testresult" );
if ( tests ) {
tests.innerHTML = "";
}
if ( banner ) {
banner.className = "";
}
if ( result ) {
result.parentNode.removeChild( result );
}
if ( tests ) {
result = document.createElement( "p" );
result.id = "qunit-testresult";
result.className = "result";
tests.parentNode.insertBefore( result, tests );
result.innerHTML = "Running...<br/>&nbsp;";
}
},
// Resets the test setup. Useful for tests that modify the DOM.
/*
DEPRECATED: Use multiple tests instead of resetting inside a test.
Use testStart or testDone for custom cleanup.
This method will throw an error in 2.0, and will be removed in 2.1
*/
reset: function() {
var fixture = id( "qunit-fixture" );
if ( fixture ) {
fixture.innerHTML = config.fixture;
}
},
// Trigger an event on an element.
// @example triggerEvent( document.body, "click" );
triggerEvent: function( elem, type, event ) {
if ( document.createEvent ) {
event = document.createEvent( "MouseEvents" );
event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
elem.dispatchEvent( event );
} else if ( elem.fireEvent ) {
elem.fireEvent( "on" + type );
}
},
// Safe object type checking
is: function( type, obj ) {
return QUnit.objectType( obj ) === type;
},
objectType: function( obj ) {
if ( typeof obj === "undefined" ) {
return "undefined";
// consider: typeof null === object
}
if ( obj === null ) {
return "null";
}
var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
type = match && match[1] || "";
switch ( type ) {
case "Number":
if ( isNaN(obj) ) {
return "nan";
}
return "number";
case "String":
case "Boolean":
case "Array":
case "Date":
case "RegExp":
case "Function":
return type.toLowerCase();
}
if ( typeof obj === "object" ) {
return "object";
}
return undefined;
},
push: function( result, actual, expected, message ) {
if ( !config.current ) {
throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
}
var output, source,
details = {
module: config.current.module,
name: config.current.testName,
result: result,
message: message,
actual: actual,
expected: expected
};
message = escapeText( message ) || ( result ? "okay" : "failed" );
message = "<span class='test-message'>" + message + "</span>";
output = message;
if ( !result ) {
expected = escapeText( QUnit.jsDump.parse(expected) );
actual = escapeText( QUnit.jsDump.parse(actual) );
output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>";
if ( actual !== expected ) {
output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>";
output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>";
}
source = sourceFromStacktrace();
if ( source ) {
details.source = source;
output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
}
output += "</table>";
}
runLoggingCallbacks( "log", QUnit, details );
config.current.assertions.push({
result: !!result,
message: output
});
},
pushFailure: function( message, source, actual ) {
if ( !config.current ) {
throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
}
var output,
details = {
module: config.current.module,
name: config.current.testName,
result: false,
message: message
};
message = escapeText( message ) || "error";
message = "<span class='test-message'>" + message + "</span>";
output = message;
output += "<table>";
if ( actual ) {
output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText( actual ) + "</pre></td></tr>";
}
if ( source ) {
details.source = source;
output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
}
output += "</table>";
runLoggingCallbacks( "log", QUnit, details );
config.current.assertions.push({
result: false,
message: output
});
},
url: function( params ) {
params = extend( extend( {}, QUnit.urlParams ), params );
var key,
querystring = "?";
for ( key in params ) {
if ( hasOwn.call( params, key ) ) {
querystring += encodeURIComponent( key ) + "=" +
encodeURIComponent( params[ key ] ) + "&";
}
}
return window.location.protocol + "//" + window.location.host +
window.location.pathname + querystring.slice( 0, -1 );
},
extend: extend,
id: id,
addEvent: addEvent,
addClass: addClass,
hasClass: hasClass,
removeClass: removeClass
// load, equiv, jsDump, diff: Attached later
});
/**
* @deprecated: Created for backwards compatibility with test runner that set the hook function
* into QUnit.{hook}, instead of invoking it and passing the hook function.
* QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
* Doing this allows us to tell if the following methods have been overwritten on the actual
* QUnit object.
*/
extend( QUnit.constructor.prototype, {
// Logging callbacks; all receive a single argument with the listed properties
// run test/logs.html for any related changes
begin: registerLoggingCallback( "begin" ),
// done: { failed, passed, total, runtime }
done: registerLoggingCallback( "done" ),
// log: { result, actual, expected, message }
log: registerLoggingCallback( "log" ),
// testStart: { name }
testStart: registerLoggingCallback( "testStart" ),
// testDone: { name, failed, passed, total, duration }
testDone: registerLoggingCallback( "testDone" ),
// moduleStart: { name }
moduleStart: registerLoggingCallback( "moduleStart" ),
// moduleDone: { name, failed, passed, total }
moduleDone: registerLoggingCallback( "moduleDone" )
});
if ( typeof document === "undefined" || document.readyState === "complete" ) {
config.autorun = true;
}
QUnit.load = function() {
runLoggingCallbacks( "begin", QUnit, {} );
// Initialize the config, saving the execution queue
var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
numModules = 0,
moduleNames = [],
moduleFilterHtml = "",
urlConfigHtml = "",
oldconfig = extend( {}, config );
QUnit.init();
extend(config, oldconfig);
config.blocking = false;
len = config.urlConfig.length;
for ( i = 0; i < len; i++ ) {
val = config.urlConfig[i];
if ( typeof val === "string" ) {
val = {
id: val,
label: val,
tooltip: "[no tooltip available]"
};
}
config[ val.id ] = QUnit.urlParams[ val.id ];
urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
"' name='" + escapeText( val.id ) +
"' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) +
" title='" + escapeText( val.tooltip ) +
"'><label for='qunit-urlconfig-" + escapeText( val.id ) +
"' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
}
for ( i in config.modules ) {
if ( config.modules.hasOwnProperty( i ) ) {
moduleNames.push(i);
}
}
numModules = moduleNames.length;
moduleNames.sort( function( a, b ) {
return a.localeCompare( b );
});
moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
( config.module === undefined ? "selected='selected'" : "" ) +
">< All Modules ></option>";
for ( i = 0; i < numModules; i++) {
moduleFilterHtml += "<option value='" + escapeText( encodeURIComponent(moduleNames[i]) ) + "' " +
( config.module === moduleNames[i] ? "selected='selected'" : "" ) +
">" + escapeText(moduleNames[i]) + "</option>";
}
moduleFilterHtml += "</select>";
// `userAgent` initialized at top of scope
userAgent = id( "qunit-userAgent" );
if ( userAgent ) {
userAgent.innerHTML = navigator.userAgent;
}
// `banner` initialized at top of scope
banner = id( "qunit-header" );
if ( banner ) {
banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> ";
}
// `toolbar` initialized at top of scope
toolbar = id( "qunit-testrunner-toolbar" );
if ( toolbar ) {
// `filter` initialized at top of scope
filter = document.createElement( "input" );
filter.type = "checkbox";
filter.id = "qunit-filter-pass";
addEvent( filter, "click", function() {
var tmp,
ol = document.getElementById( "qunit-tests" );
if ( filter.checked ) {
ol.className = ol.className + " hidepass";
} else {
tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
ol.className = tmp.replace( / hidepass /, " " );
}
if ( defined.sessionStorage ) {
if (filter.checked) {
sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
} else {
sessionStorage.removeItem( "qunit-filter-passed-tests" );
}
}
});
if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
filter.checked = true;
// `ol` initialized at top of scope
ol = document.getElementById( "qunit-tests" );
ol.className = ol.className + " hidepass";
}
toolbar.appendChild( filter );
// `label` initialized at top of scope
label = document.createElement( "label" );
label.setAttribute( "for", "qunit-filter-pass" );
label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
label.innerHTML = "Hide passed tests";
toolbar.appendChild( label );
urlConfigCheckboxesContainer = document.createElement("span");
urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
// For oldIE support:
// * Add handlers to the individual elements instead of the container
// * Use "click" instead of "change"
// * Fallback from event.target to event.srcElement
addEvents( urlConfigCheckboxes, "click", function( event ) {
var params = {},
target = event.target || event.srcElement;
params[ target.name ] = target.checked ? true : undefined;
window.location = QUnit.url( params );
});
toolbar.appendChild( urlConfigCheckboxesContainer );
if (numModules > 1) {
moduleFilter = document.createElement( "span" );
moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
moduleFilter.innerHTML = moduleFilterHtml;
addEvent( moduleFilter.lastChild, "change", function() {
var selectBox = moduleFilter.getElementsByTagName("select")[0],
selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
window.location = QUnit.url({
module: ( selectedModule === "" ) ? undefined : selectedModule,
// Remove any existing filters
filter: undefined,
testNumber: undefined
});
});
toolbar.appendChild(moduleFilter);
}
}
// `main` initialized at top of scope
main = id( "qunit-fixture" );
if ( main ) {
config.fixture = main.innerHTML;
}
if ( config.autostart ) {
QUnit.start();
}
};
addEvent( window, "load", QUnit.load );
// `onErrorFnPrev` initialized at top of scope
// Preserve other handlers
onErrorFnPrev = window.onerror;
// Cover uncaught exceptions
// Returning true will suppress the default browser handler,
// returning false will let it run.
window.onerror = function ( error, filePath, linerNr ) {
var ret = false;
if ( onErrorFnPrev ) {
ret = onErrorFnPrev( error, filePath, linerNr );
}
// Treat return value as window.onerror itself does,
// Only do our handling if not suppressed.
if ( ret !== true ) {
if ( QUnit.config.current ) {
if ( QUnit.config.current.ignoreGlobalErrors ) {
return true;
}
QUnit.pushFailure( error, filePath + ":" + linerNr );
} else {
QUnit.test( "global failure", extend( function() {
QUnit.pushFailure( error, filePath + ":" + linerNr );
}, { validTest: validTest } ) );
}
return false;
}
return ret;
};
function done() {
config.autorun = true;
// Log the last module results
if ( config.currentModule ) {
runLoggingCallbacks( "moduleDone", QUnit, {
name: config.currentModule,
failed: config.moduleStats.bad,
passed: config.moduleStats.all - config.moduleStats.bad,
total: config.moduleStats.all
});
}
delete config.previousModule;
var i, key,
banner = id( "qunit-banner" ),
tests = id( "qunit-tests" ),
runtime = +new Date() - config.started,
passed = config.stats.all - config.stats.bad,
html = [
"Tests completed in ",
runtime,
" milliseconds.<br/>",
"<span class='passed'>",
passed,
"</span> assertions of <span class='total'>",
config.stats.all,
"</span> passed, <span class='failed'>",
config.stats.bad,
"</span> failed."
].join( "" );
if ( banner ) {
banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
}
if ( tests ) {
id( "qunit-testresult" ).innerHTML = html;
}
if ( config.altertitle && typeof document !== "undefined" && document.title ) {
// show ✖ for good, ✔ for bad suite result in title
// use escape sequences in case file gets loaded with non-utf-8-charset
document.title = [
( config.stats.bad ? "\u2716" : "\u2714" ),
document.title.replace( /^[\u2714\u2716] /i, "" )
].join( " " );
}
// clear own sessionStorage items if all tests passed
if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
// `key` & `i` initialized at top of scope
for ( i = 0; i < sessionStorage.length; i++ ) {
key = sessionStorage.key( i++ );
if ( key.indexOf( "qunit-test-" ) === 0 ) {
sessionStorage.removeItem( key );
}
}
}
// scroll back to top to show results
if ( window.scrollTo ) {
window.scrollTo(0, 0);
}
runLoggingCallbacks( "done", QUnit, {
failed: config.stats.bad,
passed: passed,
total: config.stats.all,
runtime: runtime
});
}
/** @return Boolean: true if this test should be ran */
function validTest( test ) {
var include,
filter = config.filter && config.filter.toLowerCase(),
module = config.module && config.module.toLowerCase(),
fullName = (test.module + ": " + test.testName).toLowerCase();
// Internally-generated tests are always valid
if ( test.callback && test.callback.validTest === validTest ) {
delete test.callback.validTest;
return true;
}
if ( config.testNumber ) {
return test.testNumber === config.testNumber;
}
if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
return false;
}
if ( !filter ) {
return true;
}
include = filter.charAt( 0 ) !== "!";
if ( !include ) {
filter = filter.slice( 1 );
}
// If the filter matches, we need to honour include
if ( fullName.indexOf( filter ) !== -1 ) {
return include;
}
// Otherwise, do the opposite
return !include;
}
// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
// Later Safari and IE10 are supposed to support error.stack as well
// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
function extractStacktrace( e, offset ) {
offset = offset === undefined ? 3 : offset;
var stack, include, i;
if ( e.stacktrace ) {
// Opera
return e.stacktrace.split( "\n" )[ offset + 3 ];
} else if ( e.stack ) {
// Firefox, Chrome
stack = e.stack.split( "\n" );
if (/^error$/i.test( stack[0] ) ) {
stack.shift();
}
if ( fileName ) {
include = [];
for ( i = offset; i < stack.length; i++ ) {
if ( stack[ i ].indexOf( fileName ) !== -1 ) {
break;
}
include.push( stack[ i ] );
}
if ( include.length ) {
return include.join( "\n" );
}
}
return stack[ offset ];
} else if ( e.sourceURL ) {
// Safari, PhantomJS
// hopefully one day Safari provides actual stacktraces
// exclude useless self-reference for generated Error objects
if ( /qunit.js$/.test( e.sourceURL ) ) {
return;
}
// for actual exceptions, this is useful
return e.sourceURL + ":" + e.line;
}
}
function sourceFromStacktrace( offset ) {
try {
throw new Error();
} catch ( e ) {
return extractStacktrace( e, offset );
}
}
/**
* Escape text for attribute or text content.
*/
function escapeText( s ) {
if ( !s ) {
return "";
}
s = s + "";
// Both single quotes and double quotes (for attributes)
return s.replace( /['"<>&]/g, function( s ) {
switch( s ) {
case "'":
return "&#039;";
case "\"":
return "&quot;";
case "<":
return "&lt;";
case ">":
return "&gt;";
case "&":
return "&amp;";
}
});
}
function synchronize( callback, last ) {
config.queue.push( callback );
if ( config.autorun && !config.blocking ) {
process( last );
}
}
function process( last ) {
function next() {
process( last );
}
var start = new Date().getTime();
config.depth = config.depth ? config.depth + 1 : 1;
while ( config.queue.length && !config.blocking ) {
if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
config.queue.shift()();
} else {
setTimeout( next, 13 );
break;
}
}
config.depth--;
if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
done();
}
}
function saveGlobal() {
config.pollution = [];
if ( config.noglobals ) {
for ( var key in window ) {
if ( hasOwn.call( window, key ) ) {
// in Opera sometimes DOM element ids show up here, ignore them
if ( /^qunit-test-output/.test( key ) ) {
continue;
}
config.pollution.push( key );
}
}
}
}
function checkPollution() {
var newGlobals,
deletedGlobals,
old = config.pollution;
saveGlobal();
newGlobals = diff( config.pollution, old );
if ( newGlobals.length > 0 ) {
QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
}
deletedGlobals = diff( old, config.pollution );
if ( deletedGlobals.length > 0 ) {
QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
}
}
// returns a new Array with the elements that are in a but not in b
function diff( a, b ) {
var i, j,
result = a.slice();
for ( i = 0; i < result.length; i++ ) {
for ( j = 0; j < b.length; j++ ) {
if ( result[i] === b[j] ) {
result.splice( i, 1 );
i--;
break;
}
}
}
return result;
}
function extend( a, b ) {
for ( var prop in b ) {
if ( hasOwn.call( b, prop ) ) {
// Avoid "Member not found" error in IE8 caused by messing with window.constructor
if ( !( prop === "constructor" && a === window ) ) {
if ( b[ prop ] === undefined ) {
delete a[ prop ];
} else {
a[ prop ] = b[ prop ];
}
}
}
}
return a;
}
/**
* @param {HTMLElement} elem
* @param {string} type
* @param {Function} fn
*/
function addEvent( elem, type, fn ) {
// Standards-based browsers
if ( elem.addEventListener ) {
elem.addEventListener( type, fn, false );
// IE
} else {
elem.attachEvent( "on" + type, fn );
}
}
/**
* @param {Array|NodeList} elems
* @param {string} type
* @param {Function} fn
*/
function addEvents( elems, type, fn ) {
var i = elems.length;
while ( i-- ) {
addEvent( elems[i], type, fn );
}
}
function hasClass( elem, name ) {
return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
}
function addClass( elem, name ) {
if ( !hasClass( elem, name ) ) {
elem.className += (elem.className ? " " : "") + name;
}
}
function removeClass( elem, name ) {
var set = " " + elem.className + " ";
// Class name may appear multiple times
while ( set.indexOf(" " + name + " ") > -1 ) {
set = set.replace(" " + name + " " , " ");
}
// If possible, trim it for prettiness, but not necessarily
elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
}
function id( name ) {
return !!( typeof document !== "undefined" && document && document.getElementById ) &&
document.getElementById( name );
}
function registerLoggingCallback( key ) {
return function( callback ) {
config[key].push( callback );
};
}
// Supports deprecated method of completely overwriting logging callbacks
function runLoggingCallbacks( key, scope, args ) {
var i, callbacks;
if ( QUnit.hasOwnProperty( key ) ) {
QUnit[ key ].call(scope, args );
} else {
callbacks = config[ key ];
for ( i = 0; i < callbacks.length; i++ ) {
callbacks[ i ].call( scope, args );
}
}
}
// Test for equality any JavaScript type.
// Author: Philippe Rathé <prathe@gmail.com>
QUnit.equiv = (function() {
// Call the o related callback with the given arguments.
function bindCallbacks( o, callbacks, args ) {
var prop = QUnit.objectType( o );
if ( prop ) {
if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
return callbacks[ prop ].apply( callbacks, args );
} else {
return callbacks[ prop ]; // or undefined
}
}
}
// the real equiv function
var innerEquiv,
// stack to decide between skip/abort functions
callers = [],
// stack to avoiding loops from circular referencing
parents = [],
parentsB = [],
getProto = Object.getPrototypeOf || function ( obj ) {
/*jshint camelcase:false */
return obj.__proto__;
},
callbacks = (function () {
// for string, boolean, number and null
function useStrictEquality( b, a ) {
/*jshint eqeqeq:false */
if ( b instanceof a.constructor || a instanceof b.constructor ) {
// to catch short annotation VS 'new' annotation of a
// declaration
// e.g. var i = 1;
// var j = new Number(1);
return a == b;
} else {
return a === b;
}
}
return {
"string": useStrictEquality,
"boolean": useStrictEquality,
"number": useStrictEquality,
"null": useStrictEquality,
"undefined": useStrictEquality,
"nan": function( b ) {
return isNaN( b );
},
"date": function( b, a ) {
return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
},
"regexp": function( b, a ) {
return QUnit.objectType( b ) === "regexp" &&
// the regex itself
a.source === b.source &&
// and its modifiers
a.global === b.global &&
// (gmi) ...
a.ignoreCase === b.ignoreCase &&
a.multiline === b.multiline &&
a.sticky === b.sticky;
},
// - skip when the property is a method of an instance (OOP)
// - abort otherwise,
// initial === would have catch identical references anyway
"function": function() {
var caller = callers[callers.length - 1];
return caller !== Object && typeof caller !== "undefined";
},
"array": function( b, a ) {
var i, j, len, loop, aCircular, bCircular;
// b could be an object literal here
if ( QUnit.objectType( b ) !== "array" ) {
return false;
}
len = a.length;
if ( len !== b.length ) {
// safe and faster
return false;
}
// track reference to avoid circular references
parents.push( a );
parentsB.push( b );
for ( i = 0; i < len; i++ ) {
loop = false;
for ( j = 0; j < parents.length; j++ ) {
aCircular = parents[j] === a[i];
bCircular = parentsB[j] === b[i];
if ( aCircular || bCircular ) {
if ( a[i] === b[i] || aCircular && bCircular ) {
loop = true;
} else {
parents.pop();
parentsB.pop();
return false;
}
}
}
if ( !loop && !innerEquiv(a[i], b[i]) ) {
parents.pop();
parentsB.pop();
return false;
}
}
parents.pop();
parentsB.pop();
return true;
},
"object": function( b, a ) {
/*jshint forin:false */
var i, j, loop, aCircular, bCircular,
// Default to true
eq = true,
aProperties = [],
bProperties = [];
// comparing constructors is more strict than using
// instanceof
if ( a.constructor !== b.constructor ) {
// Allow objects with no prototype to be equivalent to
// objects with Object as their constructor.
if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
return false;
}
}
// stack constructor before traversing properties
callers.push( a.constructor );
// track reference to avoid circular references
parents.push( a );
parentsB.push( b );
// be strict: don't ensure hasOwnProperty and go deep
for ( i in a ) {
loop = false;
for ( j = 0; j < parents.length; j++ ) {
aCircular = parents[j] === a[i];
bCircular = parentsB[j] === b[i];
if ( aCircular || bCircular ) {
if ( a[i] === b[i] || aCircular && bCircular ) {
loop = true;
} else {
eq = false;
break;
}
}
}
aProperties.push(i);
if ( !loop && !innerEquiv(a[i], b[i]) ) {
eq = false;
break;
}
}
parents.pop();
parentsB.pop();
callers.pop(); // unstack, we are done
for ( i in b ) {
bProperties.push( i ); // collect b's properties
}
// Ensures identical properties name
return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
}
};
}());
innerEquiv = function() { // can take multiple arguments
var args = [].slice.apply( arguments );
if ( args.length < 2 ) {
return true; // end transition
}
return (function( a, b ) {
if ( a === b ) {
return true; // catch the most you can
} else if ( a === null || b === null || typeof a === "undefined" ||
typeof b === "undefined" ||
QUnit.objectType(a) !== QUnit.objectType(b) ) {
return false; // don't lose time with error prone cases
} else {
return bindCallbacks(a, callbacks, [ b, a ]);
}
// apply transition with (1..n) arguments
}( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) );
};
return innerEquiv;
}());
/**
* jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
* http://flesler.blogspot.com Licensed under BSD
* (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
*
* @projectDescription Advanced and extensible data dumping for Javascript.
* @version 1.0.0
* @author Ariel Flesler
* @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
*/
QUnit.jsDump = (function() {
function quote( str ) {
return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
}
function literal( o ) {
return o + "";
}
function join( pre, arr, post ) {
var s = jsDump.separator(),
base = jsDump.indent(),
inner = jsDump.indent(1);
if ( arr.join ) {
arr = arr.join( "," + s + inner );
}
if ( !arr ) {
return pre + post;
}
return [ pre, inner + arr, base + post ].join(s);
}
function array( arr, stack ) {
var i = arr.length, ret = new Array(i);
this.up();
while ( i-- ) {
ret[i] = this.parse( arr[i] , undefined , stack);
}
this.down();
return join( "[", ret, "]" );
}
var reName = /^function (\w+)/,
jsDump = {
// type is used mostly internally, you can fix a (custom)type in advance
parse: function( obj, type, stack ) {
stack = stack || [ ];
var inStack, res,
parser = this.parsers[ type || this.typeOf(obj) ];
type = typeof parser;
inStack = inArray( obj, stack );
if ( inStack !== -1 ) {
return "recursion(" + (inStack - stack.length) + ")";
}
if ( type === "function" ) {
stack.push( obj );
res = parser.call( this, obj, stack );
stack.pop();
return res;
}
return ( type === "string" ) ? parser : this.parsers.error;
},
typeOf: function( obj ) {
var type;
if ( obj === null ) {
type = "null";
} else if ( typeof obj === "undefined" ) {
type = "undefined";
} else if ( QUnit.is( "regexp", obj) ) {
type = "regexp";
} else if ( QUnit.is( "date", obj) ) {
type = "date";
} else if ( QUnit.is( "function", obj) ) {
type = "function";
} else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
type = "window";
} else if ( obj.nodeType === 9 ) {
type = "document";
} else if ( obj.nodeType ) {
type = "node";
} else if (
// native arrays
toString.call( obj ) === "[object Array]" ||
// NodeList objects
( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
) {
type = "array";
} else if ( obj.constructor === Error.prototype.constructor ) {
type = "error";
} else {
type = typeof obj;
}
return type;
},
separator: function() {
return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&nbsp;" : " ";
},
// extra can be a number, shortcut for increasing-calling-decreasing
indent: function( extra ) {
if ( !this.multiline ) {
return "";
}
var chr = this.indentChar;
if ( this.HTML ) {
chr = chr.replace( /\t/g, " " ).replace( / /g, "&nbsp;" );
}
return new Array( this.depth + ( extra || 0 ) ).join(chr);
},
up: function( a ) {
this.depth += a || 1;
},
down: function( a ) {
this.depth -= a || 1;
},
setParser: function( name, parser ) {
this.parsers[name] = parser;
},
// The next 3 are exposed so you can use them
quote: quote,
literal: literal,
join: join,
//
depth: 1,
// This is the list of parsers, to modify them, use jsDump.setParser
parsers: {
window: "[Window]",
document: "[Document]",
error: function(error) {
return "Error(\"" + error.message + "\")";
},
unknown: "[Unknown]",
"null": "null",
"undefined": "undefined",
"function": function( fn ) {
var ret = "function",
// functions never have name in IE
name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
if ( name ) {
ret += " " + name;
}
ret += "( ";
ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
},
array: array,
nodelist: array,
"arguments": array,
object: function( map, stack ) {
/*jshint forin:false */
var ret = [ ], keys, key, val, i;
QUnit.jsDump.up();
keys = [];
for ( key in map ) {
keys.push( key );
}
keys.sort();
for ( i = 0; i < keys.length; i++ ) {
key = keys[ i ];
val = map[ key ];
ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
}
QUnit.jsDump.down();
return join( "{", ret, "}" );
},
node: function( node ) {
var len, i, val,
open = QUnit.jsDump.HTML ? "&lt;" : "<",
close = QUnit.jsDump.HTML ? "&gt;" : ">",
tag = node.nodeName.toLowerCase(),
ret = open + tag,
attrs = node.attributes;
if ( attrs ) {
for ( i = 0, len = attrs.length; i < len; i++ ) {
val = attrs[i].nodeValue;
// IE6 includes all attributes in .attributes, even ones not explicitly set.
// Those have values like undefined, null, 0, false, "" or "inherit".
if ( val && val !== "inherit" ) {
ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
}
}
}
ret += close;
// Show content of TextNode or CDATASection
if ( node.nodeType === 3 || node.nodeType === 4 ) {
ret += node.nodeValue;
}
return ret + open + "/" + tag + close;
},
// function calls it internally, it's the arguments part of the function
functionArgs: function( fn ) {
var args,
l = fn.length;
if ( !l ) {
return "";
}
args = new Array(l);
while ( l-- ) {
// 97 is 'a'
args[l] = String.fromCharCode(97+l);
}
return " " + args.join( ", " ) + " ";
},
// object calls it internally, the key part of an item in a map
key: quote,
// function calls it internally, it's the content of the function
functionCode: "[code]",
// node calls it internally, it's an html attribute value
attribute: quote,
string: quote,
date: quote,
regexp: literal,
number: literal,
"boolean": literal
},
// if true, entities are escaped ( <, >, \t, space and \n )
HTML: false,
// indentation unit
indentChar: " ",
// if true, items in a collection, are separated by a \n, else just a space.
multiline: true
};
return jsDump;
}());
// from jquery.js
function inArray( elem, array ) {
if ( array.indexOf ) {
return array.indexOf( elem );
}
for ( var i = 0, length = array.length; i < length; i++ ) {
if ( array[ i ] === elem ) {
return i;
}
}
return -1;
}
/*
* Javascript Diff Algorithm
* By John Resig (http://ejohn.org/)
* Modified by Chu Alan "sprite"
*
* Released under the MIT license.
*
* More Info:
* http://ejohn.org/projects/javascript-diff-algorithm/
*
* Usage: QUnit.diff(expected, actual)
*
* QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
*/
QUnit.diff = (function() {
/*jshint eqeqeq:false, eqnull:true */
function diff( o, n ) {
var i,
ns = {},
os = {};
for ( i = 0; i < n.length; i++ ) {
if ( !hasOwn.call( ns, n[i] ) ) {
ns[ n[i] ] = {
rows: [],
o: null
};
}
ns[ n[i] ].rows.push( i );
}
for ( i = 0; i < o.length; i++ ) {
if ( !hasOwn.call( os, o[i] ) ) {
os[ o[i] ] = {
rows: [],
n: null
};
}
os[ o[i] ].rows.push( i );
}
for ( i in ns ) {
if ( hasOwn.call( ns, i ) ) {
if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
n[ ns[i].rows[0] ] = {
text: n[ ns[i].rows[0] ],
row: os[i].rows[0]
};
o[ os[i].rows[0] ] = {
text: o[ os[i].rows[0] ],
row: ns[i].rows[0]
};
}
}
}
for ( i = 0; i < n.length - 1; i++ ) {
if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
n[ i + 1 ] == o[ n[i].row + 1 ] ) {
n[ i + 1 ] = {
text: n[ i + 1 ],
row: n[i].row + 1
};
o[ n[i].row + 1 ] = {
text: o[ n[i].row + 1 ],
row: i + 1
};
}
}
for ( i = n.length - 1; i > 0; i-- ) {
if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
n[ i - 1 ] == o[ n[i].row - 1 ]) {
n[ i - 1 ] = {
text: n[ i - 1 ],
row: n[i].row - 1
};
o[ n[i].row - 1 ] = {
text: o[ n[i].row - 1 ],
row: i - 1
};
}
}
return {
o: o,
n: n
};
}
return function( o, n ) {
o = o.replace( /\s+$/, "" );
n = n.replace( /\s+$/, "" );
var i, pre,
str = "",
out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
oSpace = o.match(/\s+/g),
nSpace = n.match(/\s+/g);
if ( oSpace == null ) {
oSpace = [ " " ];
}
else {
oSpace.push( " " );
}
if ( nSpace == null ) {
nSpace = [ " " ];
}
else {
nSpace.push( " " );
}
if ( out.n.length === 0 ) {
for ( i = 0; i < out.o.length; i++ ) {
str += "<del>" + out.o[i] + oSpace[i] + "</del>";
}
}
else {
if ( out.n[0].text == null ) {
for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
str += "<del>" + out.o[n] + oSpace[n] + "</del>";
}
}
for ( i = 0; i < out.n.length; i++ ) {
if (out.n[i].text == null) {
str += "<ins>" + out.n[i] + nSpace[i] + "</ins>";
}
else {
// `pre` initialized at top of scope
pre = "";
for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
pre += "<del>" + out.o[n] + oSpace[n] + "</del>";
}
str += " " + out.n[i].text + nSpace[i] + pre;
}
}
}
return str;
};
}());
// for CommonJS environments, export everything
if ( typeof exports !== "undefined" ) {
extend( exports, QUnit.constructor.prototype );
}
// get at whatever the global object is, like window in browsers
}( (function() {return this;}.call()) ));
\ No newline at end of file
(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.4";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var O="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?null:[]:w[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var k=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=k(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index<t.index?-1:1}),"value")};var F=function(n,t,r,e){var u={},i=k(t||w.identity);return A(n,function(t,a){var o=i.call(r,t,a,n);e(u,o,t)}),u};w.groupBy=function(n,t,r){return F(n,t,r,function(n,t,r){(w.has(n,t)?n[t]:n[t]=[]).push(r)})},w.countBy=function(n,t,r){return F(n,t,r,function(n,t){w.has(n,t)||(n[t]=0),n[t]++})},w.sortedIndex=function(n,t,r,e){r=null==r?w.identity:k(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i},w.bind=function(n,t){if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));var r=o.call(arguments,2);return function(){return n.apply(t,r.concat(o.call(arguments)))}},w.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);return 0===t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),"function"!=typeof/./&&(w.isFunction=function(n){return"function"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var M={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"}};M.unescape=w.invert(M.escape);var S={escape:RegExp("["+w.keys(M.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(M.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(S[n],function(t){return M[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=++N+"";return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var T=/(.)^/,q={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},B=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||T).source,(r.interpolate||T).source,(r.evaluate||T).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(B,function(n){return"\\"+q[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Basic Test Suite</title>
<!-- Load local QUnit. -->
<link rel="stylesheet" href="libs/qunit.css" media="screen">
<script src="libs/jquery.js"></script>
<script src="libs/qunit.js"></script>
<script src="libs/underscore.js"></script>
<script src="../node_modules/faketouches/faketouches.js"></script>
<script src="../hammer.js"></script>
<script src="../plugins/hammer.showtouches.js"></script>
</head>
<body>
<script>
Hammer.HAS_POINTEREVENTS = false;
Hammer.HAS_TOUCHEVENTS = false;
var set_faketouches_type = FakeTouches.MOUSE_EVENTS;
</script>
<div id="toucharea" style="width:500px;height:500px;"></div>
<div id="qunit"></div>
<script src="gestures.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Basic Test Suite</title>
<!-- Load local QUnit. -->
<link rel="stylesheet" href="libs/qunit.css" media="screen">
<script src="libs/jquery.js"></script>
<script src="libs/qunit.js"></script>
<script src="libs/underscore.js"></script>
<script src="../node_modules/faketouches/faketouches.js"></script>
<script src="../hammer.js"></script>
<script src="../plugins/hammer.showtouches.js"></script>
</head>
<body>
<script>
Hammer.HAS_POINTEREVENTS = false;
Hammer.HAS_TOUCHEVENTS = true;
var set_faketouches_type = FakeTouches.TOUCH_AND_MOUSE_EVENTS;
</script>
<div id="toucharea" style="width:500px;height:500px;"></div>
<div id="qunit"></div>
<script src="gestures.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Basic Test Suite</title>
<!-- Load local QUnit. -->
<link rel="stylesheet" href="libs/qunit.css" media="screen">
<script src="libs/jquery.js"></script>
<script src="libs/qunit.js"></script>
<script src="libs/underscore.js"></script>
<script src="../node_modules/faketouches/faketouches.js"></script>
<script src="../hammer.js"></script>
<script src="../plugins/hammer.showtouches.js"></script>
</head>
<body>
<script>
Hammer.HAS_POINTEREVENTS = true;
Hammer.HAS_TOUCHEVENTS = false;
var set_faketouches_type = FakeTouches.POINTER_MOUSE_EVENTS;
</script>
<div id="toucharea" style="width:500px;height:500px;"></div>
<div id="qunit"></div>
<script src="gestures.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Basic Test Suite</title>
<!-- Load local QUnit. -->
<link rel="stylesheet" href="libs/qunit.css" media="screen">
<script src="libs/jquery.js"></script>
<script src="libs/qunit.js"></script>
<script src="libs/underscore.js"></script>
<script src="../node_modules/faketouches/faketouches.js"></script>
<script src="../hammer.js"></script>
<script src="../plugins/hammer.showtouches.js"></script>
</head>
<body>
<script>
Hammer.HAS_POINTEREVENTS = true;
Hammer.HAS_TOUCHEVENTS = false;
var set_faketouches_type = FakeTouches.POINTER_TOUCH_EVENTS;
</script>
<div id="toucharea" style="width:500px;height:500px;"></div>
<div id="qunit"></div>
<script src="gestures.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Basic Test Suite</title>
<!-- Load local QUnit. -->
<link rel="stylesheet" href="libs/qunit.css" media="screen">
<script src="libs/jquery.js"></script>
<script src="libs/qunit.js"></script>
<script src="libs/underscore.js"></script>
<script src="../node_modules/faketouches/faketouches.js"></script>
<script src="../hammer.js"></script>
<script src="../plugins/hammer.showtouches.js"></script>
</head>
<body>
<script>
Hammer.HAS_POINTEREVENTS = false;
Hammer.HAS_TOUCHEVENTS = true;
var set_faketouches_type = FakeTouches.TOUCH_EVENTS;
</script>
<div id="toucharea" style="width:500px;height:500px;"></div>
<div id="qunit"></div>
<script src="gestures.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Basic Test Suite</title>
<!-- Load local QUnit. -->
<link rel="stylesheet" href="libs/qunit.css" media="screen">
<script src="libs/qunit.js"></script>
<!-- Load local lib and tests. -->
<script src="../hammer.js"></script>
<script src="utils.js"></script>
</head>
<body>
<div id="qunit"></div>
</body>
</html>
/**
* extend objects with new params
*/
test('utils.extend', function() {
expect(1);
deepEqual(
Hammer.utils.extend(
{a:1,b:3},
{b:2,c:3}
),
{a:1,b:2,c:3},
'Simple extend'
);
});
/**
* cloning with the extend util
* test clone references
*/
test('utils.extend.clone', function() {
expect(1);
var src = { foo: true };
var dest = Hammer.utils.extend({}, src);
src.foo = false;
deepEqual(dest, {foo:true}, 'Clone reference');
});
\ No newline at end of file
......@@ -2199,7 +2199,7 @@ class domotikaService(service.Service):
return self.daemonstatus
def web_on_getAuth(self, usr, pwd):
return dmdb.Users.find(where=['username=? AND passwd=? AND active=1', usr, pwd])
return dmdb.Users.find(where=["username='%s' AND passwd='%s' AND active=1" % ( usr, pwd)])
def web_on_pluginRequest(self, pname, ppath, pargs, pheaders):
return self.plugins.webRequest(pname, ppath, pargs, pheaders)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment