0
+ − 1 /*
+ − 2
+ − 3 _/ _/_/ _/_/_/_/_/ _/
+ − 4 _/ _/ _/ _/_/ _/ _/ _/_/_/ _/_/_/
+ − 5 _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/
+ − 6 _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/
+ − 7 _/ _/_/ _/ _/ _/_/ _/_/_/ _/_/_/ _/ _/
+ − 8 _/
+ − 9 _/
+ − 10
+ − 11 Created by David Kaneda <http://www.davidkaneda.com>
+ − 12 Documentation and issue tracking on GitHub <http://wiki.github.com/senchalabs/jQTouch/>
+ − 13
+ − 14 Special thanks to Jonathan Stark <http://jonathanstark.com/>
+ − 15 and pinch/zoom <http://www.pinchzoom.com/>
+ − 16
+ − 17 (c) 2010 by jQTouch project members.
+ − 18 See LICENSE.txt for license.
+ − 19
+ − 20 $Revision: 166 $
+ − 21 $Date: Tue Mar 29 01:24:46 EDT 2011 $
+ − 22 $LastChangedBy: jonathanstark $
+ − 23
+ − 24
+ − 25 */
+ − 26
+ − 27 (function($) {
+ − 28 $.jQTouch = function(options) {
+ − 29
+ − 30 // Initialize internal jQT variables
+ − 31 var $body,
+ − 32 $head=$('head'),
+ − 33 initialPageId='',
+ − 34 hist=[],
+ − 35 newPageCount=0,
+ − 36 jQTSettings={},
+ − 37 currentPage='',
+ − 38 orientation='portrait',
+ − 39 tapReady=true,
+ − 40 lastTime=0,
+ − 41 lastAnimationTime=0,
+ − 42 touchSelectors=[],
+ − 43 publicObj={},
+ − 44 tapBuffer=351,
+ − 45 extensions=$.jQTouch.prototype.extensions,
+ − 46 animations=[],
+ − 47 hairExtensions='',
+ − 48 defaults = {
+ − 49 addGlossToIcon: true,
+ − 50 backSelector: '.back, .cancel, .goback',
+ − 51 cacheGetRequests: true,
+ − 52 debug: false,
+ − 53 fallback2dAnimation: 'fade',
+ − 54 fixedViewport: true,
+ − 55 formSelector: 'form',
+ − 56 fullScreen: true,
+ − 57 fullScreenClass: 'fullscreen',
+ − 58 hoverDelay: 50,
+ − 59 icon: null,
+ − 60 iconPad: null, // available in iOS 4.2 and later.
+ − 61 icon4: null, // available in iOS 4.2 and later.
+ − 62 moveThreshold: 10,
+ − 63 preloadImages: false,
+ − 64 pressDelay: 1000,
+ − 65 startupScreen: null,
+ − 66 statusBar: 'default', // other options: black-translucent, black
+ − 67 submitSelector: '.submit',
+ − 68 touchSelector: 'a, .touch',
+ − 69 useAnimations: true,
+ − 70 useFastTouch: true, // experimental
+ − 71 animations: [ // highest to lowest priority
+ − 72 {selector:'.cube', name:'cubeleft', is3d:true},
+ − 73 {selector:'.cubeleft', name:'cubeleft', is3d:true},
+ − 74 {selector:'.cuberight', name:'cuberight', is3d:true},
+ − 75 {selector:'.dissolve', name:'dissolve', is3d:false},
+ − 76 {selector:'.fade', name:'fade', is3d:false},
+ − 77 {selector:'.flip', name:'flipleft', is3d:true},
+ − 78 {selector:'.flipleft', name:'flipleft', is3d:true},
+ − 79 {selector:'.flipright', name:'flipright', is3d:true},
+ − 80 {selector:'.pop', name:'pop', is3d:true},
+ − 81 {selector:'.slide', name:'slideleft', is3d:false},
+ − 82 {selector:'.slidedown', name:'slidedown', is3d:false},
+ − 83 {selector:'.slideleft', name:'slideleft', is3d:false},
+ − 84 {selector:'.slideright', name:'slideright', is3d:false},
+ − 85 {selector:'.slideup', name:'slideup', is3d:false},
+ − 86 {selector:'.swap', name:'swapleft', is3d:true},
+ − 87 {selector:'#jqt > * > ul li a', name:'slideleft', is3d:false}
+ − 88 ]
+ − 89 };
+ − 90
+ − 91 function _debug(message) {
+ − 92 var now = (new Date).getTime();
+ − 93 var delta = now - lastTime;
+ − 94 lastTime = now;
+ − 95 if (jQTSettings.debug) {
+ − 96 if (message) {
+ − 97 _log(delta + ': ' + message);
+ − 98 } else {
+ − 99 _log(delta + ': ' + 'Called ' + arguments.callee.caller.name);
+ − 100 }
+ − 101 }
+ − 102 }
+ − 103 function _log(message) {
+ − 104 if (window.console !== undefined) {
+ − 105 console.log(message);
+ − 106 }
+ − 107 }
+ − 108 function addAnimation(animation) {
+ − 109 // _debug();
+ − 110 if (typeof(animation.selector) === 'string' && typeof(animation.name) === 'string') {
+ − 111 animations.push(animation);
+ − 112 }
+ − 113 }
+ − 114 function addPageToHistory(page, animation) {
+ − 115 _debug();
+ − 116 hist.unshift({
+ − 117 page: page,
+ − 118 animation: animation,
+ − 119 hash: '#' + page.attr('id'),
+ − 120 id: page.attr('id')
+ − 121 });
+ − 122 }
+ − 123 function clickHandler(e) {
+ − 124 _debug();
+ − 125
+ − 126 if (!tapReady) {
+ − 127 _debug('ClickHandler handler aborted because tap is not ready');
+ − 128 e.preventDefault();
+ − 129 return false;
+ − 130 }
+ − 131
+ − 132 // Figure out whether to prevent default
+ − 133 var $el = $(e.target);
+ − 134
+ − 135 // Find the nearest tappable ancestor
+ − 136 if (!$el.is(touchSelectors.join(', '))) {
+ − 137 $el = $(e.target).closest(touchSelectors.join(', '));
+ − 138 }
+ − 139
+ − 140 // Prevent default if we found an internal link (relative or absolute)
+ − 141 if ($el && $el.attr('href') && !$el.isExternalLink()) {
+ − 142 _debug('Need to prevent default click behavior');
+ − 143 e.preventDefault();
+ − 144 } else {
+ − 145 _debug('No need to prevent default click behavior');
+ − 146 }
+ − 147
+ − 148 // Trigger a tap event if touchstart is not on the job
+ − 149 if ($.support.touch) {
+ − 150 _debug('Not converting click to a tap event because touch handler is on the job');
+ − 151 } else {
+ − 152 _debug('Converting click event to a tap event because touch handlers are not present or off');
+ − 153 $(e.target).trigger('tap', e);
+ − 154 }
+ − 155
+ − 156 }
+ − 157 function doNavigation(fromPage, toPage, animation, goingBack) {
+ − 158 _debug();
+ − 159
+ − 160 // Error check for target page
+ − 161 if (toPage.length === 0) {
+ − 162 $.fn.unselect();
+ − 163 _debug('Target element is missing.');
+ − 164 return false;
+ − 165 }
+ − 166
+ − 167 // Error check for fromPage===toPage
+ − 168 if (toPage.hasClass('current')) {
+ − 169 $.fn.unselect();
+ − 170 _debug('You are already on the page you are trying to navigate to.');
+ − 171 return false;
+ − 172 }
+ − 173
+ − 174 // Collapse the keyboard
+ − 175 $(':focus').blur();
+ − 176
+ − 177 // Position the incoming page so toolbar is at top of viewport regardless of scroll position on from page
+ − 178 // toPage.css('top', window.pageYOffset);
+ − 179
+ − 180 fromPage.trigger('pageAnimationStart', { direction: 'out' });
+ − 181 toPage.trigger('pageAnimationStart', { direction: 'in' });
+ − 182
+ − 183 if ($.support.animationEvents && animation && jQTSettings.useAnimations) {
+ − 184
+ − 185 tapReady = false;
+ − 186
+ − 187 // Fail over to 2d animation if need be
+ − 188 if (!$.support.transform3d && animation.is3d) {
+ − 189 animation.name = jQTSettings.fallback2dAnimation;
+ − 190 }
+ − 191
+ − 192 // Reverse animation if need be
+ − 193 var finalAnimationName;
+ − 194 if (goingBack) {
+ − 195 if (animation.name.indexOf('left') > 0) {
+ − 196 finalAnimationName = animation.name.replace(/left/, 'right');
+ − 197 } else if (animation.name.indexOf('right') > 0) {
+ − 198 finalAnimationName = animation.name.replace(/right/, 'left');
+ − 199 } else if (animation.name.indexOf('up') > 0) {
+ − 200 finalAnimationName = animation.name.replace(/up/, 'down');
+ − 201 } else if (animation.name.indexOf('down') > 0) {
+ − 202 finalAnimationName = animation.name.replace(/down/, 'up');
+ − 203 } else {
+ − 204 finalAnimationName = animation.name;
+ − 205 }
+ − 206 } else {
+ − 207 finalAnimationName = animation.name;
+ − 208 }
+ − 209
+ − 210 // _debug('finalAnimationName is ' + finalAnimationName);
+ − 211
+ − 212 // Bind internal "cleanup" callback
+ − 213 fromPage.bind('webkitAnimationEnd', navigationEndHandler);
+ − 214 fromPage.bind('webkitTransitionEnd', navigationEndHandler);
+ − 215
+ − 216 // Trigger animations
+ − 217 scrollTo(0, 0);
+ − 218 toPage.addClass(finalAnimationName + ' in current');
+ − 219 fromPage.addClass(finalAnimationName + ' out');
+ − 220
+ − 221 } else {
+ − 222 toPage.addClass('current');
+ − 223 navigationEndHandler();
+ − 224 }
+ − 225
+ − 226 // Define private navigationEnd callback
+ − 227 function navigationEndHandler(event) {
+ − 228 _debug();
+ − 229
+ − 230 if ($.support.animationEvents && animation && jQTSettings.useAnimations) {
+ − 231 fromPage.unbind('webkitAnimationEnd', navigationEndHandler);
+ − 232 fromPage.unbind('webkitTransitionEnd', navigationEndHandler);
+ − 233 fromPage.removeClass(finalAnimationName + ' out current');
+ − 234 toPage.removeClass(finalAnimationName + ' in');
+ − 235 // scrollTo(0, 0);
+ − 236 // toPage.css('top', 0);
+ − 237 } else {
+ − 238 fromPage.removeClass(finalAnimationName + ' out current');
+ − 239 }
+ − 240
+ − 241 // Housekeeping
+ − 242 currentPage = toPage;
+ − 243 if (goingBack) {
+ − 244 hist.shift();
+ − 245 } else {
+ − 246 addPageToHistory(currentPage, animation);
+ − 247 }
+ − 248
+ − 249 fromPage.unselect();
+ − 250 lastAnimationTime = (new Date()).getTime();
+ − 251 setHash(currentPage.attr('id'));
+ − 252 tapReady = true;
+ − 253
+ − 254 // Trigger custom events
+ − 255 toPage.trigger('pageAnimationEnd', {direction:'in', animation:animation});
+ − 256 fromPage.trigger('pageAnimationEnd', {direction:'out', animation:animation});
+ − 257
+ − 258 }
+ − 259
+ − 260 // We's out
+ − 261 return true;
+ − 262 }
+ − 263 function getOrientation() {
+ − 264 _debug();
+ − 265 return orientation;
+ − 266 }
+ − 267 function goBack() {
+ − 268 _debug();
+ − 269
+ − 270 // Error checking
+ − 271 if (hist.length < 1 ) {
+ − 272 _debug('History is empty.');
+ − 273 }
+ − 274
+ − 275 if (hist.length === 1 ) {
+ − 276 _debug('You are on the first panel.');
+ − 277 }
+ − 278
+ − 279 var from = hist[0], to = hist[1];
+ − 280
+ − 281 if (doNavigation(from.page, to.page, from.animation, true)) {
+ − 282 return publicObj;
+ − 283 } else {
+ − 284 _debug('Could not go back.');
+ − 285 return false;
+ − 286 }
+ − 287
+ − 288 }
+ − 289 function goTo(toPage, animation, reverse) {
+ − 290 _debug();
+ − 291
+ − 292 if (reverse) {
+ − 293 _log('The reverse parameter of the goTo() function has been deprecated.');
+ − 294 }
+ − 295
+ − 296 var fromPage = hist[0].page;
+ − 297
+ − 298 if (typeof animation === 'string') {
+ − 299 for (var i=0, max=animations.length; i < max; i++) {
+ − 300 if (animations[i].name === animation) {
+ − 301 animation = animations[i];
+ − 302 break;
+ − 303 }
+ − 304 }
+ − 305 }
+ − 306
+ − 307 if (typeof(toPage) === 'string') {
+ − 308 var nextPage = $(toPage);
+ − 309 if (nextPage.length < 1) {
+ − 310 showPageByHref(toPage, {
+ − 311 'animation': animation
+ − 312 });
+ − 313 return;
+ − 314 } else {
+ − 315 toPage = nextPage;
+ − 316 }
+ − 317
+ − 318 }
+ − 319 if (doNavigation(fromPage, toPage, animation)) {
+ − 320 return publicObj;
+ − 321 } else {
+ − 322 _debug('Could not animate pages.');
+ − 323 return false;
+ − 324 }
+ − 325 }
+ − 326 function hashChangeHandler(e) {
+ − 327 _debug();
+ − 328 if (location.hash === hist[0].hash) {
+ − 329 _debug('We are on the right panel');
+ − 330 } else {
+ − 331 _debug('We are not on the right panel');
+ − 332 if(location.hash === hist[1].hash) {
+ − 333 goBack();
+ − 334 } else {
+ − 335 _debug(location.hash + ' !== ' + hist[1].hash);
+ − 336 }
+ − 337 }
+ − 338 }
+ − 339 function init(options) {
+ − 340 _debug();
+ − 341 jQTSettings = $.extend({}, defaults, options);
+ − 342
+ − 343 // Preload images
+ − 344 if (jQTSettings.preloadImages) {
+ − 345 for (var i = jQTSettings.preloadImages.length - 1; i >= 0; i--) {
+ − 346 (new Image()).src = jQTSettings.preloadImages[i];
+ − 347 };
+ − 348 }
+ − 349
+ − 350 // Set appropriate icon (retina display available in iOS 4.2 and later.)
+ − 351 var precomposed = (jQTSettings.addGlossToIcon) ? '' : '-precomposed';
+ − 352 if (jQTSettings.icon) {
+ − 353 hairExtensions += '<link rel="apple-touch-icon' + precomposed + '" href="' + jQTSettings.icon + '" />';
+ − 354 }
+ − 355 if (jQTSettings.iconPad) {
+ − 356 hairExtensions += '<link rel="apple-touch-icon' + precomposed + '" sizes="72x72" href="' + jQTSettings.iconPad + '" />';
+ − 357 }
+ − 358 if (jQTSettings.icon4) {
+ − 359 hairExtensions += '<link rel="apple-touch-icon' + precomposed + '" sizes="114x114" href="' + jQTSettings.icon4 + '" />';
+ − 360 }
+ − 361
+ − 362 // Set startup screen
+ − 363 if (jQTSettings.startupScreen) {
+ − 364 hairExtensions += '<link rel="apple-touch-startup-image" href="' + jQTSettings.startupScreen + '" />';
+ − 365 }
+ − 366
+ − 367 // Set viewport
+ − 368 if (jQTSettings.fixedViewport) {
+ − 369 hairExtensions += '<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;"/>';
+ − 370 }
+ − 371
+ − 372 // Set full-screen
+ − 373 if (jQTSettings.fullScreen) {
+ − 374 hairExtensions += '<meta name="apple-mobile-web-app-capable" content="yes" />';
+ − 375 if (jQTSettings.statusBar) {
+ − 376 hairExtensions += '<meta name="apple-mobile-web-app-status-bar-style" content="' + jQTSettings.statusBar + '" />';
+ − 377 }
+ − 378 }
+ − 379
+ − 380 // Attach hair extensions
+ − 381 if (hairExtensions) {
+ − 382 $head.prepend(hairExtensions);
+ − 383 }
+ − 384
+ − 385 }
+ − 386 function insertPages(nodes, animation) {
+ − 387 _debug();
+ − 388
+ − 389 var targetPage = null;
+ − 390 $(nodes).each(function(index, node) {
+ − 391 var $node = $(this);
+ − 392 if (!$node.attr('id')) {
+ − 393 $node.attr('id', 'page-' + (++newPageCount));
+ − 394 }
+ − 395
+ − 396 // Remove any existing instance
+ − 397 $('#' + $node.attr('id')).remove();
+ − 398
+ − 399 $body.trigger('pageInserted', {page: $node.appendTo($body)});
+ − 400
+ − 401 if ($node.hasClass('current') || !targetPage) {
+ − 402 targetPage = $node;
+ − 403 }
+ − 404 });
+ − 405 if (targetPage !== null) {
+ − 406 goTo(targetPage, animation);
+ − 407 return targetPage;
+ − 408 } else {
+ − 409 return false;
+ − 410 }
+ − 411 }
+ − 412 function mousedownHandler(e) {
+ − 413 var timeDiff = (new Date()).getTime() - lastAnimationTime;
+ − 414 if (timeDiff < tapBuffer) {
+ − 415 return false;
+ − 416 }
+ − 417 }
+ − 418 function orientationChangeHandler() {
+ − 419 _debug();
+ − 420
+ − 421 orientation = Math.abs(window.orientation) == 90 ? 'landscape' : 'portrait';
+ − 422 $body.removeClass('portrait landscape').addClass(orientation).trigger('turn', {orientation: orientation});
+ − 423 }
+ − 424 function setHash(hash) {
+ − 425 _debug();
+ − 426
+ − 427 // Trim leading # if need be
+ − 428 hash = hash.replace(/^#/, ''),
+ − 429
+ − 430 // Change hash
+ − 431 location.hash = '#' + hash;
+ − 432
+ − 433 }
+ − 434 function showPageByHref(href, options) {
+ − 435 _debug();
+ − 436
+ − 437 var defaults = {
+ − 438 data: null,
+ − 439 method: 'GET',
+ − 440 animation: null,
+ − 441 callback: null,
+ − 442 $referrer: null
+ − 443 };
+ − 444
+ − 445 var settings = $.extend({}, defaults, options);
+ − 446
+ − 447 if (href != '#') {
+ − 448 $.ajax({
+ − 449 url: href,
+ − 450 data: settings.data,
+ − 451 type: settings.method,
+ − 452 success: function (data, textStatus) {
+ − 453 var firstPage = insertPages(data, settings.animation);
+ − 454 if (firstPage) {
+ − 455 if (settings.method == 'GET' && jQTSettings.cacheGetRequests === true && settings.$referrer) {
+ − 456 settings.$referrer.attr('href', '#' + firstPage.attr('id'));
+ − 457 }
+ − 458 if (settings.callback) {
+ − 459 settings.callback(true);
+ − 460 }
+ − 461 }
+ − 462 },
+ − 463 error: function (data) {
+ − 464 if (settings.$referrer) {
+ − 465 settings.$referrer.unselect();
+ − 466 }
+ − 467 if (settings.callback) {
+ − 468 settings.callback(false);
+ − 469 }
+ − 470 }
+ − 471 });
+ − 472 } else if (settings.$referrer) {
+ − 473 settings.$referrer.unselect();
+ − 474 }
+ − 475 }
+ − 476 function submitHandler(e, callback) {
+ − 477 _debug();
+ − 478
+ − 479 $(':focus').blur();
+ − 480
+ − 481 e.preventDefault();
+ − 482
+ − 483 var $form = (typeof(e)==='string') ? $(e).eq(0) : (e.target ? $(e.target) : $(e));
+ − 484
+ − 485 _debug($form.attr('action'));
+ − 486
+ − 487 if ($form.length && $form.is(jQTSettings.formSelector) && $form.attr('action')) {
+ − 488 showPageByHref($form.attr('action'), {
+ − 489 data: $form.serialize(),
+ − 490 method: $form.attr('method') || "POST",
+ − 491 animation: animations[0] || null,
+ − 492 callback: callback
+ − 493 });
+ − 494 return false;
+ − 495 }
+ − 496 return false;
+ − 497 }
+ − 498 function submitParentForm($el) {
+ − 499 _debug();
+ − 500
+ − 501 var $form = $el.closest('form');
+ − 502 if ($form.length === 0) {
+ − 503 _debug('No parent form found');
+ − 504 } else {
+ − 505 _debug('About to submit parent form');
+ − 506 var evt = $.Event('submit');
+ − 507 evt.preventDefault();
+ − 508 $form.trigger(evt);
+ − 509 return false;
+ − 510 }
+ − 511 return true;
+ − 512 }
+ − 513 function supportForAnimationEvents() {
+ − 514 _debug();
+ − 515
+ − 516 return (typeof WebKitAnimationEvent != 'undefined');
+ − 517 }
+ − 518 function supportForCssMatrix() {
+ − 519 _debug();
+ − 520
+ − 521 return (typeof WebKitCSSMatrix != 'undefined');
+ − 522 }
+ − 523 function supportForTouchEvents() {
+ − 524 _debug();
+ − 525
+ − 526 /*
+ − 527 // If dev wants fast touch off, shut off touch whether device supports it or not
+ − 528 if (!jQTSettings.useFastTouch) {
+ − 529 return false
+ − 530 }
+ − 531
+ − 532 */
+ − 533 // Dev must want touch, so check for support
+ − 534 if (typeof TouchEvent != 'undefined') {
+ − 535 if (window.navigator.userAgent.indexOf('Mobile') > -1) { // Grrrr...
+ − 536 return true;
+ − 537 } else {
+ − 538 return false;
+ − 539 }
+ − 540 } else {
+ − 541 return false;
+ − 542 }
+ − 543 };
+ − 544 function supportForTransform3d() {
+ − 545 _debug();
+ − 546
+ − 547 var head, body, style, div, result;
+ − 548
+ − 549 head = document.getElementsByTagName('head')[0];
+ − 550 body = document.body;
+ − 551
+ − 552 style = document.createElement('style');
+ − 553 style.textContent = '@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){#jqtTestFor3dSupport{height:3px}}';
+ − 554
+ − 555 div = document.createElement('div');
+ − 556 div.id = 'jqtTestFor3dSupport';
+ − 557
+ − 558 // Add to the page
+ − 559 head.appendChild(style);
+ − 560 body.appendChild(div);
+ − 561
+ − 562 // Check the result
+ − 563 result = div.offsetHeight === 3;
+ − 564
+ − 565 // Clean up
+ − 566 style.parentNode.removeChild(style);
+ − 567 div.parentNode.removeChild(div);
+ − 568
+ − 569 // Pass back result
+ − 570 // _debug('Support for 3d transforms: ' + result);
+ − 571 return result;
+ − 572 };
+ − 573 function tapHandler(e){
+ − 574 _debug();
+ − 575
+ − 576 if (!tapReady) {
+ − 577 _debug('Tap is not ready');
+ − 578 return false;
+ − 579 }
+ − 580
+ − 581 // Grab the target element
+ − 582 var $el = $(e.target);
+ − 583
+ − 584 // Find the nearest tappable ancestor
+ − 585 if (!$el.is(touchSelectors.join(', '))) {
+ − 586 var $el = $(e.target).closest(touchSelectors.join(', '));
+ − 587 }
+ − 588
+ − 589 // Make sure we have a tappable element
+ − 590 if (!$el.length || !$el.attr('href')) {
+ − 591 _debug('Could not find a link related to tapped element');
+ − 592 return false;
+ − 593 }
+ − 594
+ − 595 // Init some vars
+ − 596 var target = $el.attr('target'),
+ − 597 hash = $el.attr('hash') || ($el.prop && $el.prop('hash')), //jQuery attr vs. prop
+ − 598 animation = null;
+ − 599
+ − 600 if ($el.isExternalLink()) {
+ − 601 $el.unselect();
+ − 602 return true;
+ − 603
+ − 604 } else if ($el.is(jQTSettings.backSelector)) {
+ − 605 // User clicked or tapped a back button
+ − 606 goBack(hash);
+ − 607
+ − 608 } else if ($el.is(jQTSettings.submitSelector)) {
+ − 609 // User clicked or tapped a submit element
+ − 610 submitParentForm($el);
+ − 611
+ − 612 } else if (target === '_webapp') {
+ − 613 // User clicked or tapped an internal link, fullscreen mode
+ − 614 window.location = $el.attr('href');
+ − 615 return false;
+ − 616
+ − 617 } else if ($el.attr('href') === '#') {
+ − 618 // Allow tap on item with no href
+ − 619 $el.unselect();
+ − 620 return true;
+ − 621
+ − 622 } else {
+ − 623
+ − 624 // Figure out the animation to use
+ − 625 for (var i=0, max=animations.length; i < max; i++) {
+ − 626 if ($el.is(animations[i].selector)) {
+ − 627 animation = animations[i];
+ − 628 break;
+ − 629 }
+ − 630 };
+ − 631
+ − 632 if (!animation) {
+ − 633 _log('Animation could not be found. Using slideleft.');
+ − 634 animation = 'slideleft';
+ − 635 }
+ − 636
+ − 637 if (hash && hash !== '#') {
+ − 638 // Internal href
+ − 639 $el.addClass('active');
+ − 640 goTo($(hash).data('referrer', $el), animation, $el.hasClass('reverse'));
+ − 641 return false;
+ − 642
+ − 643 } else {
+ − 644 // External href
+ − 645 $el.addClass('loading active');
+ − 646 showPageByHref($el.attr('href'), {
+ − 647 animation: animation,
+ − 648 callback: function() {
+ − 649 $el.removeClass('loading');
+ − 650 setTimeout($.fn.unselect, 250, $el);
+ − 651 },
+ − 652 $referrer: $el
+ − 653 });
+ − 654 return false;
+ − 655 }
+ − 656 }
+ − 657 }
+ − 658 function touchStartHandler(e) {
+ − 659 _debug();
+ − 660
+ − 661 if (!tapReady) {
+ − 662 _debug('TouchStart handler aborted because tap is not ready');
+ − 663 e.preventDefault();
+ − 664 return false;
+ − 665 }
+ − 666
+ − 667 var $el = $(e.target);
+ − 668
+ − 669 // Error check
+ − 670 if (!$el.length) {
+ − 671 _debug('Could not find target of touchstart event.');
+ − 672 return;
+ − 673 }
+ − 674
+ − 675 var startTime = (new Date).getTime(),
+ − 676 hoverTimeout = null,
+ − 677 pressTimeout = null,
+ − 678 touch,
+ − 679 startX,
+ − 680 startY,
+ − 681 deltaX = 0,
+ − 682 deltaY = 0,
+ − 683 deltaT = 0;
+ − 684
+ − 685 if (event.changedTouches && event.changedTouches.length) {
+ − 686 touch = event.changedTouches[0];
+ − 687 startX = touch.pageX;
+ − 688 startY = touch.pageY;
+ − 689 }
+ − 690
+ − 691 // Prep the element
+ − 692 $el.bind('touchmove',touchMoveHandler).bind('touchend',touchEndHandler).bind('touchcancel',touchCancelHandler);
+ − 693
+ − 694 hoverTimeout = setTimeout(function() {
+ − 695 $el.makeActive();
+ − 696 }, jQTSettings.hoverDelay);
+ − 697
+ − 698 pressTimeout = setTimeout(function() {
+ − 699 $el.unbind('touchmove',touchMoveHandler).unbind('touchend',touchEndHandler).unbind('touchcancel',touchCancelHandler);
+ − 700 $el.unselect();
+ − 701 clearTimeout(hoverTimeout);
+ − 702 $el.trigger('press');
+ − 703 }, jQTSettings.pressDelay);
+ − 704
+ − 705 // Private touch functions
+ − 706 function touchCancelHandler(e) {
+ − 707 _debug();
+ − 708 clearTimeout(hoverTimeout);
+ − 709 $el.unselect();
+ − 710 $el.unbind('touchmove',touchMoveHandler).unbind('touchend',touchEndHandler).unbind('touchcancel',touchCancelHandler);
+ − 711 }
+ − 712
+ − 713 function touchEndHandler(e) {
+ − 714 _debug();
+ − 715 // updateChanges();
+ − 716 $el.unbind('touchend',touchEndHandler).unbind('touchcancel',touchCancelHandler);
+ − 717 clearTimeout(hoverTimeout);
+ − 718 clearTimeout(pressTimeout);
+ − 719 if (Math.abs(deltaX) < jQTSettings.moveThreshold && Math.abs(deltaY) < jQTSettings.moveThreshold && deltaT < jQTSettings.pressDelay) {
+ − 720 // e.preventDefault();
+ − 721 // e.stopImmediatePropagation();
+ − 722 $el.trigger('tap', e);
+ − 723 } else {
+ − 724 $el.unselect();
+ − 725 }
+ − 726 }
+ − 727
+ − 728 function touchMoveHandler(e) {
+ − 729 // _debug();
+ − 730 updateChanges();
+ − 731 var absX = Math.abs(deltaX);
+ − 732 var absY = Math.abs(deltaY);
+ − 733 var direction;
+ − 734 if (absX > absY && (absX > 35) && deltaT < 1000) {
+ − 735 if (deltaX < 0) {
+ − 736 direction = 'left';
+ − 737 } else {
+ − 738 direction = 'right';
+ − 739 }
+ − 740 $el.unbind('touchmove',touchMoveHandler).unbind('touchend',touchEndHandler).unbind('touchcancel',touchCancelHandler);
+ − 741 $el.trigger('swipe', {direction:direction, deltaX:deltaX, deltaY: deltaY});
+ − 742 }
+ − 743 $el.unselect();
+ − 744 clearTimeout(hoverTimeout);
+ − 745 if (absX > jQTSettings.moveThreshold || absY > jQTSettings.moveThreshold) {
+ − 746 clearTimeout(pressTimeout);
+ − 747 }
+ − 748 }
+ − 749
+ − 750 function updateChanges() {
+ − 751 // _debug();
+ − 752 var firstFinger = event.changedTouches[0] || null;
+ − 753 deltaX = firstFinger.pageX - startX;
+ − 754 deltaY = firstFinger.pageY - startY;
+ − 755 deltaT = (new Date).getTime() - startTime;
+ − 756 // _debug('deltaX:'+deltaX+';deltaY:'+deltaY+';');
+ − 757 }
+ − 758
+ − 759 } // End touch handler
+ − 760 function useFastTouch(setting) {
+ − 761 _debug();
+ − 762
+ − 763 if (setting !== undefined) {
+ − 764 if (setting === true) {
+ − 765 if (supportForTouchEvents()) {
+ − 766 $.support.touch = true;
+ − 767 } else{
+ − 768 _log('This device does not support touch events');
+ − 769 };
+ − 770 } else {
+ − 771 $.support.touch = false;
+ − 772 }
+ − 773 }
+ − 774
+ − 775 return $.support.touch;
+ − 776
+ − 777 }
+ − 778
+ − 779 // Get the party started
+ − 780 init(options);
+ − 781
+ − 782 // Document ready stuff
+ − 783 $(document).ready(function() {
+ − 784
+ − 785 // Store some properties in the jQuery support object
+ − 786 $.support.animationEvents = supportForAnimationEvents();
+ − 787 $.support.cssMatrix = supportForCssMatrix();
+ − 788 $.support.touch = supportForTouchEvents() && jQTSettings.useFastTouch;
+ − 789 $.support.transform3d = supportForTransform3d();
+ − 790
+ − 791 if (!$.support.touch) {
+ − 792 _log('This device does not support touch interaction, or it has been deactivated by the developer. Some features might be unavailable.');
+ − 793 }
+ − 794 if (!$.support.transform3d) {
+ − 795 _log('This device does not support 3d animation. 2d animations will be used instead.');
+ − 796 }
+ − 797
+ − 798 // Define public jQuery functions
+ − 799 $.fn.isExternalLink = function() {
+ − 800 var $el = $(this);
+ − 801 return ($el.attr('target') == '_blank' || $el.attr('rel') == 'external' || $el.is('a[href^="http://maps.google.com"], a[href^="mailto:"], a[href^="tel:"], a[href^="javascript:"], a[href*="youtube.com/v"], a[href*="youtube.com/watch"]'));
+ − 802 }
+ − 803 $.fn.makeActive = function() {
+ − 804 return $(this).addClass('active');
+ − 805 }
+ − 806 $.fn.press = function(fn) {
+ − 807 if ($.isFunction(fn)) {
+ − 808 return $(this).live('press', fn);
+ − 809 } else {
+ − 810 return $(this).trigger('press');
+ − 811 }
+ − 812 }
+ − 813 $.fn.swipe = function(fn) {
+ − 814 if ($.isFunction(fn)) {
+ − 815 return $(this).live('swipe', fn);
+ − 816 } else {
+ − 817 return $(this).trigger('swipe');
+ − 818 }
+ − 819 }
+ − 820 $.fn.tap = function(fn) {
+ − 821 if ($.isFunction(fn)) {
+ − 822 return $(this).live('tap', fn);
+ − 823 } else {
+ − 824 return $(this).trigger('tap');
+ − 825 }
+ − 826 }
+ − 827 $.fn.unselect = function(obj) {
+ − 828 if (obj) {
+ − 829 obj.removeClass('active');
+ − 830 } else {
+ − 831 $('.active').removeClass('active');
+ − 832 }
+ − 833 }
+ − 834
+ − 835 // Add extensions
+ − 836 for (var i=0, max=extensions.length; i < max; i++) {
+ − 837 var fn = extensions[i];
+ − 838 if ($.isFunction(fn)) {
+ − 839 $.extend(publicObj, fn(publicObj));
+ − 840 }
+ − 841 }
+ − 842
+ − 843 // Set up animations array
+ − 844 if (jQTSettings['cubeSelector']) {
+ − 845 _log('NOTE: cubeSelector has been deprecated. Please use cubeleftSelector instead.');
+ − 846 jQTSettings['cubeleftSelector'] = jQTSettings['cubeSelector'];
+ − 847 }
+ − 848 if (jQTSettings['flipSelector']) {
+ − 849 _log('NOTE: flipSelector has been deprecated. Please use flipleftSelector instead.');
+ − 850 jQTSettings['flipleftSelector'] = jQTSettings['flipSelector'];
+ − 851 }
+ − 852 if (jQTSettings['slideSelector']) {
+ − 853 _log('NOTE: slideSelector has been deprecated. Please use slideleftSelector instead.');
+ − 854 jQTSettings['slideleftSelector'] = jQTSettings['slideSelector'];
+ − 855 }
+ − 856 for (var i=0, max=defaults.animations.length; i < max; i++) {
+ − 857 var animation = defaults.animations[i];
+ − 858 if(jQTSettings[animation.name + 'Selector'] !== undefined){
+ − 859 animation.selector = jQTSettings[animation.name + 'Selector'];
+ − 860 }
+ − 861 addAnimation(animation);
+ − 862 }
+ − 863
+ − 864 // Create an array of stuff that needs touch event handling
+ − 865 touchSelectors.push('input'); // TODO: Ask DK why inputs are considered touch selectors
+ − 866 touchSelectors.push(jQTSettings.touchSelector);
+ − 867 touchSelectors.push(jQTSettings.backSelector);
+ − 868 touchSelectors.push(jQTSettings.submitSelector);
+ − 869 $(touchSelectors.join(', ')).css('-webkit-touch-callout', 'none');
+ − 870
+ − 871 // Make sure we have a jqt element
+ − 872 $body = $('#jqt');
+ − 873 if ($body.length === 0) {
+ − 874 _log('Could not find an element with the id "jqt", so the body id has been set to "jqt". If you are having any problems, wrapping your panels in a div with the id "jqt" might help.');
+ − 875 $body = $('body').attr('id', 'jqt');
+ − 876 }
+ − 877
+ − 878 // Add some specific css if need be
+ − 879 if ($.support.transform3d) {
+ − 880 $body.addClass('supports3d');
+ − 881 }
+ − 882 if (jQTSettings.fullScreenClass && window.navigator.standalone == true) {
+ − 883 $body.addClass(jQTSettings.fullScreenClass + ' ' + jQTSettings.statusBar);
+ − 884 }
+ − 885 if (window.navigator.userAgent.match(/Android/ig)) { // Grr... added to postion checkbox labels. Lame. I know. - js
+ − 886 $body.addClass('android');
+ − 887 }
+ − 888
+ − 889 // Bind events
+ − 890 $(window).bind('hashchange', hashChangeHandler);
+ − 891 $body.bind('touchstart', touchStartHandler)
+ − 892 .bind('click', clickHandler)
+ − 893 .bind('mousedown', mousedownHandler)
+ − 894 .bind('orientationchange', orientationChangeHandler)
+ − 895 .bind('submit', submitHandler)
+ − 896 .bind('tap', tapHandler)
+ − 897 .trigger('orientationchange');
+ − 898
+ − 899
+ − 900 // Determine what the "current" (initial) panel should be
+ − 901 if ($('#jqt > .current').length == 0) {
+ − 902 currentPage = $('#jqt > *:first');
+ − 903 } else {
+ − 904 currentPage = $('#jqt > .current:first');
+ − 905 $('#jqt > .current').removeClass('current');
+ − 906 }
+ − 907
+ − 908 // Go to the top of the "current" page
+ − 909 $(currentPage).addClass('current');
+ − 910 initialPageId = $(currentPage).attr('id');
+ − 911 setHash(initialPageId);
+ − 912 addPageToHistory(currentPage);
+ − 913 scrollTo(0, 0);
+ − 914
+ − 915 // Make sure none of the panels yank the location bar into view
+ − 916 $('#jqt > *').css('minHeight', window.innerHeight);
+ − 917
+ − 918 });
+ − 919
+ − 920 // Expose public methods and properties
+ − 921 publicObj = {
+ − 922 addAnimation: addAnimation,
+ − 923 animations: animations,
+ − 924 getOrientation: getOrientation,
+ − 925 goBack: goBack,
+ − 926 goTo: goTo,
+ − 927 hist: hist,
+ − 928 settings: jQTSettings,
+ − 929 submitForm: submitHandler,
+ − 930 support: $.support,
+ − 931 useFastTouch: useFastTouch
+ − 932 }
+ − 933 return publicObj;
+ − 934 }
+ − 935
+ − 936 // Extensions directly manipulate the jQTouch object, before it's initialized.
+ − 937 $.jQTouch.prototype.extensions = [];
+ − 938 $.jQTouch.addExtension = function(extension) {
+ − 939 $.jQTouch.prototype.extensions.push(extension);
+ − 940 }
+ − 941
+ − 942 })(jQuery);