Line 1: | Line 1: | ||
<html> | <html> | ||
<body> | <body> | ||
− | <!-- jQuery --> | + | |
+ | |||
+ | <script> | ||
+ | /* | ||
+ | * jQuery Mobile v1.4.5 | ||
+ | * http://jquerymobile.com | ||
+ | * | ||
+ | * Copyright 2010, 2014 jQuery Foundation, Inc. and other contributors | ||
+ | * Released under the MIT license. | ||
+ | * http://jquery.org/license | ||
+ | * | ||
+ | */ | ||
+ | |||
+ | (function ( root, doc, factory ) { | ||
+ | if ( typeof define === "function" && define.amd ) { | ||
+ | // AMD. Register as an anonymous module. | ||
+ | define( [ "jquery" ], function ( $ ) { | ||
+ | factory( $, root, doc ); | ||
+ | return $.mobile; | ||
+ | }); | ||
+ | } else { | ||
+ | // Browser globals | ||
+ | factory( root.jQuery, root, doc ); | ||
+ | } | ||
+ | }( this, document, function ( jQuery, window, document, undefined ) {// This plugin is an experiment for abstracting away the touch and mouse | ||
+ | // events so that developers don't have to worry about which method of input | ||
+ | // the device their document is loaded on supports. | ||
+ | // | ||
+ | // The idea here is to allow the developer to register listeners for the | ||
+ | // basic mouse events, such as mousedown, mousemove, mouseup, and click, | ||
+ | // and the plugin will take care of registering the correct listeners | ||
+ | // behind the scenes to invoke the listener at the fastest possible time | ||
+ | // for that device, while still retaining the order of event firing in | ||
+ | // the traditional mouse environment, should multiple handlers be registered | ||
+ | // on the same element for different events. | ||
+ | // | ||
+ | // The current version exposes the following virtual events to jQuery bind methods: | ||
+ | // "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel" | ||
+ | |||
+ | (function( $, window, document, undefined ) { | ||
+ | |||
+ | var dataPropertyName = "virtualMouseBindings", | ||
+ | touchTargetPropertyName = "virtualTouchID", | ||
+ | virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ), | ||
+ | touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ), | ||
+ | mouseHookProps = $.event.mouseHooks ? $.event.mouseHooks.props : [], | ||
+ | mouseEventProps = $.event.props.concat( mouseHookProps ), | ||
+ | activeDocHandlers = {}, | ||
+ | resetTimerID = 0, | ||
+ | startX = 0, | ||
+ | startY = 0, | ||
+ | didScroll = false, | ||
+ | clickBlockList = [], | ||
+ | blockMouseTriggers = false, | ||
+ | blockTouchTriggers = false, | ||
+ | eventCaptureSupported = "addEventListener" in document, | ||
+ | $document = $( document ), | ||
+ | nextTouchID = 1, | ||
+ | lastTouchID = 0, threshold, | ||
+ | i; | ||
+ | |||
+ | $.vmouse = { | ||
+ | moveDistanceThreshold: 10, | ||
+ | clickDistanceThreshold: 10, | ||
+ | resetTimerDuration: 1500 | ||
+ | }; | ||
+ | |||
+ | function getNativeEvent( event ) { | ||
+ | |||
+ | while ( event && typeof event.originalEvent !== "undefined" ) { | ||
+ | event = event.originalEvent; | ||
+ | } | ||
+ | return event; | ||
+ | } | ||
+ | |||
+ | function createVirtualEvent( event, eventType ) { | ||
+ | |||
+ | var t = event.type, | ||
+ | oe, props, ne, prop, ct, touch, i, j, len; | ||
+ | |||
+ | event = $.Event( event ); | ||
+ | event.type = eventType; | ||
+ | |||
+ | oe = event.originalEvent; | ||
+ | props = $.event.props; | ||
+ | |||
+ | // addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280 | ||
+ | // https://github.com/jquery/jquery-mobile/issues/3280 | ||
+ | if ( t.search( /^(mouse|click)/ ) > -1 ) { | ||
+ | props = mouseEventProps; | ||
+ | } | ||
+ | |||
+ | // copy original event properties over to the new event | ||
+ | // this would happen if we could call $.event.fix instead of $.Event | ||
+ | // but we don't have a way to force an event to be fixed multiple times | ||
+ | if ( oe ) { | ||
+ | for ( i = props.length, prop; i; ) { | ||
+ | prop = props[ --i ]; | ||
+ | event[ prop ] = oe[ prop ]; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // make sure that if the mouse and click virtual events are generated | ||
+ | // without a .which one is defined | ||
+ | if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ) { | ||
+ | event.which = 1; | ||
+ | } | ||
+ | |||
+ | if ( t.search(/^touch/) !== -1 ) { | ||
+ | ne = getNativeEvent( oe ); | ||
+ | t = ne.touches; | ||
+ | ct = ne.changedTouches; | ||
+ | touch = ( t && t.length ) ? t[0] : ( ( ct && ct.length ) ? ct[ 0 ] : undefined ); | ||
+ | |||
+ | if ( touch ) { | ||
+ | for ( j = 0, len = touchEventProps.length; j < len; j++) { | ||
+ | prop = touchEventProps[ j ]; | ||
+ | event[ prop ] = touch[ prop ]; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return event; | ||
+ | } | ||
+ | |||
+ | function getVirtualBindingFlags( element ) { | ||
+ | |||
+ | var flags = {}, | ||
+ | b, k; | ||
+ | |||
+ | while ( element ) { | ||
+ | |||
+ | b = $.data( element, dataPropertyName ); | ||
+ | |||
+ | for ( k in b ) { | ||
+ | if ( b[ k ] ) { | ||
+ | flags[ k ] = flags.hasVirtualBinding = true; | ||
+ | } | ||
+ | } | ||
+ | element = element.parentNode; | ||
+ | } | ||
+ | return flags; | ||
+ | } | ||
+ | |||
+ | function getClosestElementWithVirtualBinding( element, eventType ) { | ||
+ | var b; | ||
+ | while ( element ) { | ||
+ | |||
+ | b = $.data( element, dataPropertyName ); | ||
+ | |||
+ | if ( b && ( !eventType || b[ eventType ] ) ) { | ||
+ | return element; | ||
+ | } | ||
+ | element = element.parentNode; | ||
+ | } | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | function enableTouchBindings() { | ||
+ | blockTouchTriggers = false; | ||
+ | } | ||
+ | |||
+ | function disableTouchBindings() { | ||
+ | blockTouchTriggers = true; | ||
+ | } | ||
+ | |||
+ | function enableMouseBindings() { | ||
+ | lastTouchID = 0; | ||
+ | clickBlockList.length = 0; | ||
+ | blockMouseTriggers = false; | ||
+ | |||
+ | // When mouse bindings are enabled, our | ||
+ | // touch bindings are disabled. | ||
+ | disableTouchBindings(); | ||
+ | } | ||
+ | |||
+ | function disableMouseBindings() { | ||
+ | // When mouse bindings are disabled, our | ||
+ | // touch bindings are enabled. | ||
+ | enableTouchBindings(); | ||
+ | } | ||
+ | |||
+ | function startResetTimer() { | ||
+ | clearResetTimer(); | ||
+ | resetTimerID = setTimeout( function() { | ||
+ | resetTimerID = 0; | ||
+ | enableMouseBindings(); | ||
+ | }, $.vmouse.resetTimerDuration ); | ||
+ | } | ||
+ | |||
+ | function clearResetTimer() { | ||
+ | if ( resetTimerID ) { | ||
+ | clearTimeout( resetTimerID ); | ||
+ | resetTimerID = 0; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function triggerVirtualEvent( eventType, event, flags ) { | ||
+ | var ve; | ||
+ | |||
+ | if ( ( flags && flags[ eventType ] ) || | ||
+ | ( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) { | ||
+ | |||
+ | ve = createVirtualEvent( event, eventType ); | ||
+ | |||
+ | $( event.target).trigger( ve ); | ||
+ | } | ||
+ | |||
+ | return ve; | ||
+ | } | ||
+ | |||
+ | function mouseEventCallback( event ) { | ||
+ | var touchID = $.data( event.target, touchTargetPropertyName ), | ||
+ | ve; | ||
+ | |||
+ | if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ) { | ||
+ | ve = triggerVirtualEvent( "v" + event.type, event ); | ||
+ | if ( ve ) { | ||
+ | if ( ve.isDefaultPrevented() ) { | ||
+ | event.preventDefault(); | ||
+ | } | ||
+ | if ( ve.isPropagationStopped() ) { | ||
+ | event.stopPropagation(); | ||
+ | } | ||
+ | if ( ve.isImmediatePropagationStopped() ) { | ||
+ | event.stopImmediatePropagation(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function handleTouchStart( event ) { | ||
+ | |||
+ | var touches = getNativeEvent( event ).touches, | ||
+ | target, flags, t; | ||
+ | |||
+ | if ( touches && touches.length === 1 ) { | ||
+ | |||
+ | target = event.target; | ||
+ | flags = getVirtualBindingFlags( target ); | ||
+ | |||
+ | if ( flags.hasVirtualBinding ) { | ||
+ | |||
+ | lastTouchID = nextTouchID++; | ||
+ | $.data( target, touchTargetPropertyName, lastTouchID ); | ||
+ | |||
+ | clearResetTimer(); | ||
+ | |||
+ | disableMouseBindings(); | ||
+ | didScroll = false; | ||
+ | |||
+ | t = getNativeEvent( event ).touches[ 0 ]; | ||
+ | startX = t.pageX; | ||
+ | startY = t.pageY; | ||
+ | |||
+ | triggerVirtualEvent( "vmouseover", event, flags ); | ||
+ | triggerVirtualEvent( "vmousedown", event, flags ); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function handleScroll( event ) { | ||
+ | if ( blockTouchTriggers ) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | if ( !didScroll ) { | ||
+ | triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) ); | ||
+ | } | ||
+ | |||
+ | didScroll = true; | ||
+ | startResetTimer(); | ||
+ | } | ||
+ | |||
+ | function handleTouchMove( event ) { | ||
+ | if ( blockTouchTriggers ) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | var t = getNativeEvent( event ).touches[ 0 ], | ||
+ | didCancel = didScroll, | ||
+ | moveThreshold = $.vmouse.moveDistanceThreshold, | ||
+ | flags = getVirtualBindingFlags( event.target ); | ||
+ | |||
+ | didScroll = didScroll || | ||
+ | ( Math.abs( t.pageX - startX ) > moveThreshold || | ||
+ | Math.abs( t.pageY - startY ) > moveThreshold ); | ||
+ | |||
+ | if ( didScroll && !didCancel ) { | ||
+ | triggerVirtualEvent( "vmousecancel", event, flags ); | ||
+ | } | ||
+ | |||
+ | triggerVirtualEvent( "vmousemove", event, flags ); | ||
+ | startResetTimer(); | ||
+ | } | ||
+ | |||
+ | function handleTouchEnd( event ) { | ||
+ | if ( blockTouchTriggers ) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | disableTouchBindings(); | ||
+ | |||
+ | var flags = getVirtualBindingFlags( event.target ), | ||
+ | ve, t; | ||
+ | triggerVirtualEvent( "vmouseup", event, flags ); | ||
+ | |||
+ | if ( !didScroll ) { | ||
+ | ve = triggerVirtualEvent( "vclick", event, flags ); | ||
+ | if ( ve && ve.isDefaultPrevented() ) { | ||
+ | // The target of the mouse events that follow the touchend | ||
+ | // event don't necessarily match the target used during the | ||
+ | // touch. This means we need to rely on coordinates for blocking | ||
+ | // any click that is generated. | ||
+ | t = getNativeEvent( event ).changedTouches[ 0 ]; | ||
+ | clickBlockList.push({ | ||
+ | touchID: lastTouchID, | ||
+ | x: t.clientX, | ||
+ | y: t.clientY | ||
+ | }); | ||
+ | |||
+ | // Prevent any mouse events that follow from triggering | ||
+ | // virtual event notifications. | ||
+ | blockMouseTriggers = true; | ||
+ | } | ||
+ | } | ||
+ | triggerVirtualEvent( "vmouseout", event, flags); | ||
+ | didScroll = false; | ||
+ | |||
+ | startResetTimer(); | ||
+ | } | ||
+ | |||
+ | function hasVirtualBindings( ele ) { | ||
+ | var bindings = $.data( ele, dataPropertyName ), | ||
+ | k; | ||
+ | |||
+ | if ( bindings ) { | ||
+ | for ( k in bindings ) { | ||
+ | if ( bindings[ k ] ) { | ||
+ | return true; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | function dummyMouseHandler() {} | ||
+ | |||
+ | function getSpecialEventObject( eventType ) { | ||
+ | var realType = eventType.substr( 1 ); | ||
+ | |||
+ | return { | ||
+ | setup: function(/* data, namespace */) { | ||
+ | // If this is the first virtual mouse binding for this element, | ||
+ | // add a bindings object to its data. | ||
+ | |||
+ | if ( !hasVirtualBindings( this ) ) { | ||
+ | $.data( this, dataPropertyName, {} ); | ||
+ | } | ||
+ | |||
+ | // If setup is called, we know it is the first binding for this | ||
+ | // eventType, so initialize the count for the eventType to zero. | ||
+ | var bindings = $.data( this, dataPropertyName ); | ||
+ | bindings[ eventType ] = true; | ||
+ | |||
+ | // If this is the first virtual mouse event for this type, | ||
+ | // register a global handler on the document. | ||
+ | |||
+ | activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1; | ||
+ | |||
+ | if ( activeDocHandlers[ eventType ] === 1 ) { | ||
+ | $document.bind( realType, mouseEventCallback ); | ||
+ | } | ||
+ | |||
+ | // Some browsers, like Opera Mini, won't dispatch mouse/click events | ||
+ | // for elements unless they actually have handlers registered on them. | ||
+ | // To get around this, we register dummy handlers on the elements. | ||
+ | |||
+ | $( this ).bind( realType, dummyMouseHandler ); | ||
+ | |||
+ | // For now, if event capture is not supported, we rely on mouse handlers. | ||
+ | if ( eventCaptureSupported ) { | ||
+ | // If this is the first virtual mouse binding for the document, | ||
+ | // register our touchstart handler on the document. | ||
+ | |||
+ | activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1; | ||
+ | |||
+ | if ( activeDocHandlers[ "touchstart" ] === 1 ) { | ||
+ | $document.bind( "touchstart", handleTouchStart ) | ||
+ | .bind( "touchend", handleTouchEnd ) | ||
+ | |||
+ | // On touch platforms, touching the screen and then dragging your finger | ||
+ | // causes the window content to scroll after some distance threshold is | ||
+ | // exceeded. On these platforms, a scroll prevents a click event from being | ||
+ | // dispatched, and on some platforms, even the touchend is suppressed. To | ||
+ | // mimic the suppression of the click event, we need to watch for a scroll | ||
+ | // event. Unfortunately, some platforms like iOS don't dispatch scroll | ||
+ | // events until *AFTER* the user lifts their finger (touchend). This means | ||
+ | // we need to watch both scroll and touchmove events to figure out whether | ||
+ | // or not a scroll happenens before the touchend event is fired. | ||
+ | |||
+ | .bind( "touchmove", handleTouchMove ) | ||
+ | .bind( "scroll", handleScroll ); | ||
+ | } | ||
+ | } | ||
+ | }, | ||
+ | |||
+ | teardown: function(/* data, namespace */) { | ||
+ | // If this is the last virtual binding for this eventType, | ||
+ | // remove its global handler from the document. | ||
+ | |||
+ | --activeDocHandlers[ eventType ]; | ||
+ | |||
+ | if ( !activeDocHandlers[ eventType ] ) { | ||
+ | $document.unbind( realType, mouseEventCallback ); | ||
+ | } | ||
+ | |||
+ | if ( eventCaptureSupported ) { | ||
+ | // If this is the last virtual mouse binding in existence, | ||
+ | // remove our document touchstart listener. | ||
+ | |||
+ | --activeDocHandlers[ "touchstart" ]; | ||
+ | |||
+ | if ( !activeDocHandlers[ "touchstart" ] ) { | ||
+ | $document.unbind( "touchstart", handleTouchStart ) | ||
+ | .unbind( "touchmove", handleTouchMove ) | ||
+ | .unbind( "touchend", handleTouchEnd ) | ||
+ | .unbind( "scroll", handleScroll ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var $this = $( this ), | ||
+ | bindings = $.data( this, dataPropertyName ); | ||
+ | |||
+ | // teardown may be called when an element was | ||
+ | // removed from the DOM. If this is the case, | ||
+ | // jQuery core may have already stripped the element | ||
+ | // of any data bindings so we need to check it before | ||
+ | // using it. | ||
+ | if ( bindings ) { | ||
+ | bindings[ eventType ] = false; | ||
+ | } | ||
+ | |||
+ | // Unregister the dummy event handler. | ||
+ | |||
+ | $this.unbind( realType, dummyMouseHandler ); | ||
+ | |||
+ | // If this is the last virtual mouse binding on the | ||
+ | // element, remove the binding data from the element. | ||
+ | |||
+ | if ( !hasVirtualBindings( this ) ) { | ||
+ | $this.removeData( dataPropertyName ); | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | } | ||
+ | |||
+ | // Expose our custom events to the jQuery bind/unbind mechanism. | ||
+ | |||
+ | for ( i = 0; i < virtualEventNames.length; i++ ) { | ||
+ | $.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] ); | ||
+ | } | ||
+ | |||
+ | // Add a capture click handler to block clicks. | ||
+ | // Note that we require event capture support for this so if the device | ||
+ | // doesn't support it, we punt for now and rely solely on mouse events. | ||
+ | if ( eventCaptureSupported ) { | ||
+ | document.addEventListener( "click", function( e ) { | ||
+ | var cnt = clickBlockList.length, | ||
+ | target = e.target, | ||
+ | x, y, ele, i, o, touchID; | ||
+ | |||
+ | if ( cnt ) { | ||
+ | x = e.clientX; | ||
+ | y = e.clientY; | ||
+ | threshold = $.vmouse.clickDistanceThreshold; | ||
+ | |||
+ | // The idea here is to run through the clickBlockList to see if | ||
+ | // the current click event is in the proximity of one of our | ||
+ | // vclick events that had preventDefault() called on it. If we find | ||
+ | // one, then we block the click. | ||
+ | // | ||
+ | // Why do we have to rely on proximity? | ||
+ | // | ||
+ | // Because the target of the touch event that triggered the vclick | ||
+ | // can be different from the target of the click event synthesized | ||
+ | // by the browser. The target of a mouse/click event that is synthesized | ||
+ | // from a touch event seems to be implementation specific. For example, | ||
+ | // some browsers will fire mouse/click events for a link that is near | ||
+ | // a touch event, even though the target of the touchstart/touchend event | ||
+ | // says the user touched outside the link. Also, it seems that with most | ||
+ | // browsers, the target of the mouse/click event is not calculated until the | ||
+ | // time it is dispatched, so if you replace an element that you touched | ||
+ | // with another element, the target of the mouse/click will be the new | ||
+ | // element underneath that point. | ||
+ | // | ||
+ | // Aside from proximity, we also check to see if the target and any | ||
+ | // of its ancestors were the ones that blocked a click. This is necessary | ||
+ | // because of the strange mouse/click target calculation done in the | ||
+ | // Android 2.1 browser, where if you click on an element, and there is a | ||
+ | // mouse/click handler on one of its ancestors, the target will be the | ||
+ | // innermost child of the touched element, even if that child is no where | ||
+ | // near the point of touch. | ||
+ | |||
+ | ele = target; | ||
+ | |||
+ | while ( ele ) { | ||
+ | for ( i = 0; i < cnt; i++ ) { | ||
+ | o = clickBlockList[ i ]; | ||
+ | touchID = 0; | ||
+ | |||
+ | if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) || | ||
+ | $.data( ele, touchTargetPropertyName ) === o.touchID ) { | ||
+ | // XXX: We may want to consider removing matches from the block list | ||
+ | // instead of waiting for the reset timer to fire. | ||
+ | e.preventDefault(); | ||
+ | e.stopPropagation(); | ||
+ | return; | ||
+ | } | ||
+ | } | ||
+ | ele = ele.parentNode; | ||
+ | } | ||
+ | } | ||
+ | }, true); | ||
+ | } | ||
+ | })( jQuery, window, document ); | ||
+ | |||
+ | (function( $ ) { | ||
+ | $.mobile = {}; | ||
+ | }( jQuery )); | ||
+ | |||
+ | (function( $, undefined ) { | ||
+ | var support = { | ||
+ | touch: "ontouchend" in document | ||
+ | }; | ||
+ | |||
+ | $.mobile.support = $.mobile.support || {}; | ||
+ | $.extend( $.support, support ); | ||
+ | $.extend( $.mobile.support, support ); | ||
+ | }( jQuery )); | ||
+ | |||
+ | |||
+ | (function( $, window, undefined ) { | ||
+ | var $document = $( document ), | ||
+ | supportTouch = $.mobile.support.touch, | ||
+ | scrollEvent = "touchmove scroll", | ||
+ | touchStartEvent = supportTouch ? "touchstart" : "mousedown", | ||
+ | touchStopEvent = supportTouch ? "touchend" : "mouseup", | ||
+ | touchMoveEvent = supportTouch ? "touchmove" : "mousemove"; | ||
+ | |||
+ | // setup new event shortcuts | ||
+ | $.each( ( "touchstart touchmove touchend " + | ||
+ | "tap taphold " + | ||
+ | "swipe swipeleft swiperight " + | ||
+ | "scrollstart scrollstop" ).split( " " ), function( i, name ) { | ||
+ | |||
+ | $.fn[ name ] = function( fn ) { | ||
+ | return fn ? this.bind( name, fn ) : this.trigger( name ); | ||
+ | }; | ||
+ | |||
+ | // jQuery < 1.8 | ||
+ | if ( $.attrFn ) { | ||
+ | $.attrFn[ name ] = true; | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | function triggerCustomEvent( obj, eventType, event, bubble ) { | ||
+ | var originalType = event.type; | ||
+ | event.type = eventType; | ||
+ | if ( bubble ) { | ||
+ | $.event.trigger( event, undefined, obj ); | ||
+ | } else { | ||
+ | $.event.dispatch.call( obj, event ); | ||
+ | } | ||
+ | event.type = originalType; | ||
+ | } | ||
+ | |||
+ | // also handles scrollstop | ||
+ | $.event.special.scrollstart = { | ||
+ | |||
+ | enabled: true, | ||
+ | setup: function() { | ||
+ | |||
+ | var thisObject = this, | ||
+ | $this = $( thisObject ), | ||
+ | scrolling, | ||
+ | timer; | ||
+ | |||
+ | function trigger( event, state ) { | ||
+ | scrolling = state; | ||
+ | triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event ); | ||
+ | } | ||
+ | |||
+ | // iPhone triggers scroll after a small delay; use touchmove instead | ||
+ | $this.bind( scrollEvent, function( event ) { | ||
+ | |||
+ | if ( !$.event.special.scrollstart.enabled ) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | if ( !scrolling ) { | ||
+ | trigger( event, true ); | ||
+ | } | ||
+ | |||
+ | clearTimeout( timer ); | ||
+ | timer = setTimeout( function() { | ||
+ | trigger( event, false ); | ||
+ | }, 50 ); | ||
+ | }); | ||
+ | }, | ||
+ | teardown: function() { | ||
+ | $( this ).unbind( scrollEvent ); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // also handles taphold | ||
+ | $.event.special.tap = { | ||
+ | tapholdThreshold: 750, | ||
+ | emitTapOnTaphold: true, | ||
+ | setup: function() { | ||
+ | var thisObject = this, | ||
+ | $this = $( thisObject ), | ||
+ | isTaphold = false; | ||
+ | |||
+ | $this.bind( "vmousedown", function( event ) { | ||
+ | isTaphold = false; | ||
+ | if ( event.which && event.which !== 1 ) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | var origTarget = event.target, | ||
+ | timer; | ||
+ | |||
+ | function clearTapTimer() { | ||
+ | clearTimeout( timer ); | ||
+ | } | ||
+ | |||
+ | function clearTapHandlers() { | ||
+ | clearTapTimer(); | ||
+ | |||
+ | $this.unbind( "vclick", clickHandler ) | ||
+ | .unbind( "vmouseup", clearTapTimer ); | ||
+ | $document.unbind( "vmousecancel", clearTapHandlers ); | ||
+ | } | ||
+ | |||
+ | function clickHandler( event ) { | ||
+ | clearTapHandlers(); | ||
+ | |||
+ | // ONLY trigger a 'tap' event if the start target is | ||
+ | // the same as the stop target. | ||
+ | if ( !isTaphold && origTarget === event.target ) { | ||
+ | triggerCustomEvent( thisObject, "tap", event ); | ||
+ | } else if ( isTaphold ) { | ||
+ | event.preventDefault(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | $this.bind( "vmouseup", clearTapTimer ) | ||
+ | .bind( "vclick", clickHandler ); | ||
+ | $document.bind( "vmousecancel", clearTapHandlers ); | ||
+ | |||
+ | timer = setTimeout( function() { | ||
+ | if ( !$.event.special.tap.emitTapOnTaphold ) { | ||
+ | isTaphold = true; | ||
+ | } | ||
+ | triggerCustomEvent( thisObject, "taphold", $.Event( "taphold", { target: origTarget } ) ); | ||
+ | }, $.event.special.tap.tapholdThreshold ); | ||
+ | }); | ||
+ | }, | ||
+ | teardown: function() { | ||
+ | $( this ).unbind( "vmousedown" ).unbind( "vclick" ).unbind( "vmouseup" ); | ||
+ | $document.unbind( "vmousecancel" ); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // Also handles swipeleft, swiperight | ||
+ | $.event.special.swipe = { | ||
+ | |||
+ | // More than this horizontal displacement, and we will suppress scrolling. | ||
+ | scrollSupressionThreshold: 30, | ||
+ | |||
+ | // More time than this, and it isn't a swipe. | ||
+ | durationThreshold: 1000, | ||
+ | |||
+ | // Swipe horizontal displacement must be more than this. | ||
+ | horizontalDistanceThreshold: 30, | ||
+ | |||
+ | // Swipe vertical displacement must be less than this. | ||
+ | verticalDistanceThreshold: 30, | ||
+ | |||
+ | getLocation: function ( event ) { | ||
+ | var winPageX = window.pageXOffset, | ||
+ | winPageY = window.pageYOffset, | ||
+ | x = event.clientX, | ||
+ | y = event.clientY; | ||
+ | |||
+ | if ( event.pageY === 0 && Math.floor( y ) > Math.floor( event.pageY ) || | ||
+ | event.pageX === 0 && Math.floor( x ) > Math.floor( event.pageX ) ) { | ||
+ | |||
+ | // iOS4 clientX/clientY have the value that should have been | ||
+ | // in pageX/pageY. While pageX/page/ have the value 0 | ||
+ | x = x - winPageX; | ||
+ | y = y - winPageY; | ||
+ | } else if ( y < ( event.pageY - winPageY) || x < ( event.pageX - winPageX ) ) { | ||
+ | |||
+ | // Some Android browsers have totally bogus values for clientX/Y | ||
+ | // when scrolling/zooming a page. Detectable since clientX/clientY | ||
+ | // should never be smaller than pageX/pageY minus page scroll | ||
+ | x = event.pageX - winPageX; | ||
+ | y = event.pageY - winPageY; | ||
+ | } | ||
+ | |||
+ | return { | ||
+ | x: x, | ||
+ | y: y | ||
+ | }; | ||
+ | }, | ||
+ | |||
+ | start: function( event ) { | ||
+ | var data = event.originalEvent.touches ? | ||
+ | event.originalEvent.touches[ 0 ] : event, | ||
+ | location = $.event.special.swipe.getLocation( data ); | ||
+ | return { | ||
+ | time: ( new Date() ).getTime(), | ||
+ | coords: [ location.x, location.y ], | ||
+ | origin: $( event.target ) | ||
+ | }; | ||
+ | }, | ||
+ | |||
+ | stop: function( event ) { | ||
+ | var data = event.originalEvent.touches ? | ||
+ | event.originalEvent.touches[ 0 ] : event, | ||
+ | location = $.event.special.swipe.getLocation( data ); | ||
+ | return { | ||
+ | time: ( new Date() ).getTime(), | ||
+ | coords: [ location.x, location.y ] | ||
+ | }; | ||
+ | }, | ||
+ | |||
+ | handleSwipe: function( start, stop, thisObject, origTarget ) { | ||
+ | if ( stop.time - start.time < $.event.special.swipe.durationThreshold && | ||
+ | Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold && | ||
+ | Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) { | ||
+ | var direction = start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight"; | ||
+ | |||
+ | triggerCustomEvent( thisObject, "swipe", $.Event( "swipe", { target: origTarget, swipestart: start, swipestop: stop }), true ); | ||
+ | triggerCustomEvent( thisObject, direction,$.Event( direction, { target: origTarget, swipestart: start, swipestop: stop } ), true ); | ||
+ | return true; | ||
+ | } | ||
+ | return false; | ||
+ | |||
+ | }, | ||
+ | |||
+ | // This serves as a flag to ensure that at most one swipe event event is | ||
+ | // in work at any given time | ||
+ | eventInProgress: false, | ||
+ | |||
+ | setup: function() { | ||
+ | var events, | ||
+ | thisObject = this, | ||
+ | $this = $( thisObject ), | ||
+ | context = {}; | ||
+ | |||
+ | // Retrieve the events data for this element and add the swipe context | ||
+ | events = $.data( this, "mobile-events" ); | ||
+ | if ( !events ) { | ||
+ | events = { length: 0 }; | ||
+ | $.data( this, "mobile-events", events ); | ||
+ | } | ||
+ | events.length++; | ||
+ | events.swipe = context; | ||
+ | |||
+ | context.start = function( event ) { | ||
+ | |||
+ | // Bail if we're already working on a swipe event | ||
+ | if ( $.event.special.swipe.eventInProgress ) { | ||
+ | return; | ||
+ | } | ||
+ | $.event.special.swipe.eventInProgress = true; | ||
+ | |||
+ | var stop, | ||
+ | start = $.event.special.swipe.start( event ), | ||
+ | origTarget = event.target, | ||
+ | emitted = false; | ||
+ | |||
+ | context.move = function( event ) { | ||
+ | if ( !start || event.isDefaultPrevented() ) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | stop = $.event.special.swipe.stop( event ); | ||
+ | if ( !emitted ) { | ||
+ | emitted = $.event.special.swipe.handleSwipe( start, stop, thisObject, origTarget ); | ||
+ | if ( emitted ) { | ||
+ | |||
+ | // Reset the context to make way for the next swipe event | ||
+ | $.event.special.swipe.eventInProgress = false; | ||
+ | } | ||
+ | } | ||
+ | // prevent scrolling | ||
+ | if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) { | ||
+ | event.preventDefault(); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | context.stop = function() { | ||
+ | emitted = true; | ||
+ | |||
+ | // Reset the context to make way for the next swipe event | ||
+ | $.event.special.swipe.eventInProgress = false; | ||
+ | $document.off( touchMoveEvent, context.move ); | ||
+ | context.move = null; | ||
+ | }; | ||
+ | |||
+ | $document.on( touchMoveEvent, context.move ) | ||
+ | .one( touchStopEvent, context.stop ); | ||
+ | }; | ||
+ | $this.on( touchStartEvent, context.start ); | ||
+ | }, | ||
+ | |||
+ | teardown: function() { | ||
+ | var events, context; | ||
+ | |||
+ | events = $.data( this, "mobile-events" ); | ||
+ | if ( events ) { | ||
+ | context = events.swipe; | ||
+ | delete events.swipe; | ||
+ | events.length--; | ||
+ | if ( events.length === 0 ) { | ||
+ | $.removeData( this, "mobile-events" ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if ( context ) { | ||
+ | if ( context.start ) { | ||
+ | $( this ).off( touchStartEvent, context.start ); | ||
+ | } | ||
+ | if ( context.move ) { | ||
+ | $document.off( touchMoveEvent, context.move ); | ||
+ | } | ||
+ | if ( context.stop ) { | ||
+ | $document.off( touchStopEvent, context.stop ); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | $.each({ | ||
+ | scrollstop: "scrollstart", | ||
+ | taphold: "tap", | ||
+ | swipeleft: "swipe.left", | ||
+ | swiperight: "swipe.right" | ||
+ | }, function( event, sourceEvent ) { | ||
+ | |||
+ | $.event.special[ event ] = { | ||
+ | setup: function() { | ||
+ | $( this ).bind( sourceEvent, $.noop ); | ||
+ | }, | ||
+ | teardown: function() { | ||
+ | $( this ).unbind( sourceEvent ); | ||
+ | } | ||
+ | }; | ||
+ | }); | ||
+ | |||
+ | })( jQuery, this ); | ||
+ | |||
+ | |||
+ | })); | ||
+ | |||
+ | </script> | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | <!---------------------------------------------- | ||
+ | -------------MY CODE ------------------------> | ||
<script> | <script> | ||
$(document).ready(function(){ | $(document).ready(function(){ |
Revision as of 06:55, 6 May 2017