qedproject 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * jQuery Mobile v1.0b3
2
+ * jQuery Mobile v1.0rc1
3
3
  * http://jquerymobile.com/
4
4
  *
5
5
  * Copyright 2010, jQuery Project
@@ -278,6 +278,16 @@ $.Widget.prototype = {
278
278
  (function( $, undefined ) {
279
279
 
280
280
  $.widget( "mobile.widget", {
281
+ // decorate the parent _createWidget to trigger `widgetinit` for users
282
+ // who wish to do post post `widgetcreate` alterations/additions
283
+ //
284
+ // TODO create a pull request for jquery ui to trigger this event
285
+ // in the original _createWidget
286
+ _createWidget: function() {
287
+ $.Widget.prototype._createWidget.apply( this, arguments );
288
+ this._trigger( 'init' );
289
+ },
290
+
281
291
  _getCreateOptions: function() {
282
292
 
283
293
  var elem = this.element,
@@ -301,7 +311,7 @@ $.widget( "mobile.widget", {
301
311
 
302
312
  })( jQuery );
303
313
  /*
304
- * jQuery Mobile Framework : resolution and CSS media query related helpers and behavior
314
+ * jQuery Mobile Framework : a workaround for window.matchMedia
305
315
  * Copyright (c) jQuery Project
306
316
  * Dual licensed under the MIT or GPL Version 2 licenses.
307
317
  * http://jquery.org/license
@@ -421,9 +431,7 @@ $.extend( $.support, {
421
431
  touchOverflow: !!propExists( "overflowScrolling" ),
422
432
  boxShadow: !!propExists( "boxShadow" ) && !bb,
423
433
  scrollTop: ( "pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[ 0 ] ) && !webos,
424
- dynamicBaseTag: baseTagTest(),
425
- // TODO: This is a weak test. We may want to beef this up later.
426
- eventCapture: "addEventListener" in document
434
+ dynamicBaseTag: baseTagTest()
427
435
  });
428
436
 
429
437
  fakeBody.remove();
@@ -502,7 +510,7 @@ var dataPropertyName = "virtualMouseBindings",
502
510
  clickBlockList = [],
503
511
  blockMouseTriggers = false,
504
512
  blockTouchTriggers = false,
505
- eventCaptureSupported = $.support.eventCapture,
513
+ eventCaptureSupported = "addEventListener" in document,
506
514
  $document = $( document ),
507
515
  nextTouchID = 1,
508
516
  lastTouchID = 0;
@@ -542,6 +550,12 @@ function createVirtualEvent( event, eventType ) {
542
550
  }
543
551
  }
544
552
 
553
+ // make sure that if the mouse and click virtual events are generated
554
+ // without a .which one is defined
555
+ if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ){
556
+ event.which = 1;
557
+ }
558
+
545
559
  if ( t.search(/^touch/) !== -1 ) {
546
560
  ne = getNativeEvent( oe );
547
561
  t = ne.touches;
@@ -1809,11 +1823,19 @@ $.widget( "mobile.page", $.mobile.widget, {
1809
1823
  // Mobile version of data and removeData and hasData methods
1810
1824
  // ensures all data is set and retrieved using jQuery Mobile's data namespace
1811
1825
  $.fn.jqmData = function( prop, value ) {
1812
- return this.data( prop ? $.mobile.nsNormalize( prop ) : prop, value );
1826
+ var result;
1827
+ if ( typeof prop != "undefined" ) {
1828
+ result = this.data( prop ? $.mobile.nsNormalize( prop ) : prop, value );
1829
+ }
1830
+ return result;
1813
1831
  };
1814
1832
 
1815
1833
  $.jqmData = function( elem, prop, value ) {
1816
- return $.data( elem, $.mobile.nsNormalize( prop ), value );
1834
+ var result;
1835
+ if ( typeof prop != "undefined" ) {
1836
+ result = $.data( elem, prop ? $.mobile.nsNormalize( prop ) : prop, value );
1837
+ }
1838
+ return result;
1817
1839
  };
1818
1840
 
1819
1841
  $.fn.jqmRemoveData = function( prop ) {
@@ -1824,8 +1846,32 @@ $.widget( "mobile.page", $.mobile.widget, {
1824
1846
  return $.removeData( elem, $.mobile.nsNormalize( prop ) );
1825
1847
  };
1826
1848
 
1827
- $.jqmHasData = function( elem, prop ) {
1828
- return $.hasData( elem, $.mobile.nsNormalize( prop ) );
1849
+ $.fn.removeWithDependents = function() {
1850
+ $.removeWithDependents( this );
1851
+ };
1852
+
1853
+ $.removeWithDependents = function( elem ) {
1854
+ var $elem = $( elem );
1855
+
1856
+ ( $elem.jqmData('dependents') || $() ).remove();
1857
+ $elem.remove();
1858
+ };
1859
+
1860
+ $.fn.addDependents = function( newDependents ) {
1861
+ $.addDependents( $(this), newDependents );
1862
+ };
1863
+
1864
+ $.addDependents = function( elem, newDependents ) {
1865
+ var dependents = $(elem).jqmData( 'dependents' ) || $();
1866
+
1867
+ $(elem).jqmData( 'dependents', $.merge(dependents, newDependents) );
1868
+ };
1869
+
1870
+ // note that this helper doesn't attempt to handle the callback
1871
+ // or setting of an html elements text, its only purpose is
1872
+ // to return the html encoded version of the text in all cases. (thus the name)
1873
+ $.fn.getEncodedText = function() {
1874
+ return $( "<div/>" ).text( $(this).text() ).html();
1829
1875
  };
1830
1876
 
1831
1877
  // Monkey-patching Sizzle to filter the :jqmData selector
@@ -1875,20 +1921,21 @@ $.widget( "mobile.page", $.mobile.widget, {
1875
1921
  // [2]: http://jblas:password@mycompany.com:8080/mail/inbox
1876
1922
  // [3]: http://jblas:password@mycompany.com:8080
1877
1923
  // [4]: http:
1878
- // [5]: jblas:password@mycompany.com:8080
1879
- // [6]: jblas:password
1880
- // [7]: jblas
1881
- // [8]: password
1882
- // [9]: mycompany.com:8080
1883
- // [10]: mycompany.com
1884
- // [11]: 8080
1885
- // [12]: /mail/inbox
1886
- // [13]: /mail/
1887
- // [14]: inbox
1888
- // [15]: ?msg=1234&type=unread
1889
- // [16]: #msg-content
1924
+ // [5]: //
1925
+ // [6]: jblas:password@mycompany.com:8080
1926
+ // [7]: jblas:password
1927
+ // [8]: jblas
1928
+ // [9]: password
1929
+ // [10]: mycompany.com:8080
1930
+ // [11]: mycompany.com
1931
+ // [12]: 8080
1932
+ // [13]: /mail/inbox
1933
+ // [14]: /mail/
1934
+ // [15]: inbox
1935
+ // [16]: ?msg=1234&type=unread
1936
+ // [17]: #msg-content
1890
1937
  //
1891
- urlParseRE: /^(((([^:\/#\?]+:)?(?:\/\/((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
1938
+ urlParseRE: /^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
1892
1939
 
1893
1940
  //Parse a URL into a structure that allows easy access to
1894
1941
  //all of the URL components by name.
@@ -1899,34 +1946,31 @@ $.widget( "mobile.page", $.mobile.widget, {
1899
1946
  return url;
1900
1947
  }
1901
1948
 
1902
- var u = url || "",
1903
- matches = path.urlParseRE.exec( url ),
1904
- results;
1905
- if ( matches ) {
1949
+ var matches = path.urlParseRE.exec( url || "" ) || [];
1950
+
1906
1951
  // Create an object that allows the caller to access the sub-matches
1907
1952
  // by name. Note that IE returns an empty string instead of undefined,
1908
1953
  // like all other browsers do, so we normalize everything so its consistent
1909
1954
  // no matter what browser we're running on.
1910
- results = {
1911
- href: matches[0] || "",
1912
- hrefNoHash: matches[1] || "",
1913
- hrefNoSearch: matches[2] || "",
1914
- domain: matches[3] || "",
1915
- protocol: matches[4] || "",
1916
- authority: matches[5] || "",
1917
- username: matches[7] || "",
1918
- password: matches[8] || "",
1919
- host: matches[9] || "",
1920
- hostname: matches[10] || "",
1921
- port: matches[11] || "",
1922
- pathname: matches[12] || "",
1923
- directory: matches[13] || "",
1924
- filename: matches[14] || "",
1925
- search: matches[15] || "",
1926
- hash: matches[16] || ""
1955
+ return {
1956
+ href: matches[ 0 ] || "",
1957
+ hrefNoHash: matches[ 1 ] || "",
1958
+ hrefNoSearch: matches[ 2 ] || "",
1959
+ domain: matches[ 3 ] || "",
1960
+ protocol: matches[ 4 ] || "",
1961
+ doubleSlash: matches[ 5 ] || "",
1962
+ authority: matches[ 6 ] || "",
1963
+ username: matches[ 8 ] || "",
1964
+ password: matches[ 9 ] || "",
1965
+ host: matches[ 10 ] || "",
1966
+ hostname: matches[ 11 ] || "",
1967
+ port: matches[ 12 ] || "",
1968
+ pathname: matches[ 13 ] || "",
1969
+ directory: matches[ 14 ] || "",
1970
+ filename: matches[ 15 ] || "",
1971
+ search: matches[ 16 ] || "",
1972
+ hash: matches[ 17 ] || ""
1927
1973
  };
1928
- }
1929
- return results || {};
1930
1974
  },
1931
1975
 
1932
1976
  //Turn relPath into an asbolute path. absPath is
@@ -1986,13 +2030,14 @@ $.widget( "mobile.page", $.mobile.widget, {
1986
2030
  var relObj = path.parseUrl( relUrl ),
1987
2031
  absObj = path.parseUrl( absUrl ),
1988
2032
  protocol = relObj.protocol || absObj.protocol,
2033
+ doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash );
1989
2034
  authority = relObj.authority || absObj.authority,
1990
2035
  hasPath = relObj.pathname !== "",
1991
2036
  pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
1992
2037
  search = relObj.search || ( !hasPath && absObj.search ) || "",
1993
2038
  hash = relObj.hash;
1994
2039
 
1995
- return protocol + "//" + authority + pathname + search + hash;
2040
+ return protocol + doubleSlash + authority + pathname + search + hash;
1996
2041
  },
1997
2042
 
1998
2043
  //Add search (aka query) params to the specified url.
@@ -2248,41 +2293,83 @@ $.widget( "mobile.page", $.mobile.widget, {
2248
2293
  $.mobile.changePage.apply( null, pageTransitionQueue.pop() );
2249
2294
  }
2250
2295
  }
2251
-
2296
+
2252
2297
  // Save the last scroll distance per page, before it is hidden
2253
- var getLastScroll = (function( lastScrollEnabled ){
2254
- return function(){
2255
- if( !lastScrollEnabled ){
2256
- lastScrollEnabled = true;
2257
- return;
2258
- }
2259
-
2260
- lastScrollEnabled = false;
2261
-
2262
- var active = $.mobile.urlHistory.getActive(),
2263
- activePage = $( ".ui-page-active" ),
2264
- scrollElem = $( window ),
2265
- touchOverflow = $.support.touchOverflow && $.mobile.touchOverflowEnabled;
2266
-
2267
- if( touchOverflow ){
2268
- scrollElem = activePage.is( ".ui-native-fixed" ) ? activePage.find( ".ui-content" ) : activePage;
2269
- }
2270
-
2271
- if( active ){
2272
- var lastScroll = scrollElem.scrollTop();
2298
+ var setLastScrollEnabled = true,
2299
+ firstScrollElem, getScrollElem, setLastScroll, delayedSetLastScroll;
2300
+
2301
+ getScrollElem = function() {
2302
+ var scrollElem = $window, activePage,
2303
+ touchOverflow = $.support.touchOverflow && $.mobile.touchOverflowEnabled;
2304
+
2305
+ if( touchOverflow ){
2306
+ activePage = $( ".ui-page-active" );
2307
+ scrollElem = activePage.is( ".ui-native-fixed" ) ? activePage.find( ".ui-content" ) : activePage;
2308
+ }
2309
+
2310
+ return scrollElem;
2311
+ };
2312
+
2313
+ setLastScroll = function( scrollElem ) {
2314
+ // this barrier prevents setting the scroll value based on the browser
2315
+ // scrolling the window based on a hashchange
2316
+ if( !setLastScrollEnabled ) {
2317
+ return;
2318
+ }
2319
+
2320
+ var active = $.mobile.urlHistory.getActive();
2321
+
2322
+ if( active ) {
2323
+ var lastScroll = scrollElem && scrollElem.scrollTop();
2324
+
2325
+ // Set active page's lastScroll prop.
2326
+ // If the location we're scrolling to is less than minScrollBack, let it go.
2327
+ active.lastScroll = lastScroll < $.mobile.minScrollBack ? $.mobile.defaultHomeScroll : lastScroll;
2328
+ }
2329
+ };
2330
+
2331
+ // bind to scrollstop to gather scroll position. The delay allows for the hashchange
2332
+ // event to fire and disable scroll recording in the case where the browser scrolls
2333
+ // to the hash targets location (sometimes the top of the page). once pagechange fires
2334
+ // getLastScroll is again permitted to operate
2335
+ delayedSetLastScroll = function() {
2336
+ setTimeout( setLastScroll, 100, $(this) );
2337
+ };
2338
+
2339
+ // disable an scroll setting when a hashchange has been fired, this only works
2340
+ // because the recording of the scroll position is delayed for 100ms after
2341
+ // the browser might have changed the position because of the hashchange
2342
+ $window.bind( $.support.pushState ? "popstate" : "hashchange", function() {
2343
+ setLastScrollEnabled = false;
2344
+ });
2345
+
2346
+ // handle initial hashchange from chrome :(
2347
+ $window.one( $.support.pushState ? "popstate" : "hashchange", function() {
2348
+ setLastScrollEnabled = true;
2349
+ });
2350
+
2351
+ // wait until the mobile page container has been determined to bind to pagechange
2352
+ $window.one( "pagecontainercreate", function(){
2353
+ // once the page has changed, re-enable the scroll recording
2354
+ $.mobile.pageContainer.bind( "pagechange", function() {
2355
+ var scrollElem = getScrollElem();
2356
+
2357
+ setLastScrollEnabled = true;
2358
+
2359
+ // remove any binding that previously existed on the get scroll
2360
+ // which may or may not be different than the scroll element determined for
2361
+ // this page previously
2362
+ scrollElem.unbind( "scrollstop", delayedSetLastScroll );
2363
+
2364
+ // determine and bind to the current scoll element which may be the window
2365
+ // or in the case of touch overflow the element with touch overflow
2366
+ scrollElem.bind( "scrollstop", delayedSetLastScroll );
2367
+ });
2368
+ });
2369
+
2370
+ // bind to scrollstop for the first page as "pagechange" won't be fired in that case
2371
+ getScrollElem().bind( "scrollstop", delayedSetLastScroll );
2273
2372
 
2274
- // Set active page's lastScroll prop.
2275
- // If the Y location we're scrolling to is less than minScrollBack, let it go.
2276
- active.lastScroll = lastScroll < $.mobile.minScrollBack ? $.mobile.defaultHomeScroll : lastScroll;
2277
- }
2278
- };
2279
- })( true );
2280
-
2281
- // to get last scroll, we need to get scrolltop before the page change
2282
- // using beforechangepage or popstate/hashchange (whichever comes first)
2283
- $( document ).bind( "beforechangepage", getLastScroll );
2284
- $( window ).bind( $.support.pushState ? "popstate" : "hashchange", getLastScroll );
2285
-
2286
2373
  // Make the iOS clock quick-scroll work again if we're using native overflow scrolling
2287
2374
  /*
2288
2375
  if( $.support.touchOverflow ){
@@ -2304,7 +2391,7 @@ $.widget( "mobile.page", $.mobile.widget, {
2304
2391
  touchOverflow = $.support.touchOverflow && $.mobile.touchOverflowEnabled,
2305
2392
  toScroll = active.lastScroll || ( touchOverflow ? 0 : $.mobile.defaultHomeScroll ),
2306
2393
  screenHeight = getScreenHeight();
2307
-
2394
+
2308
2395
  // Scroll to top, hide addr bar
2309
2396
  window.scrollTo( 0, $.mobile.defaultHomeScroll );
2310
2397
 
@@ -2312,22 +2399,22 @@ $.widget( "mobile.page", $.mobile.widget, {
2312
2399
  //trigger before show/hide events
2313
2400
  fromPage.data( "page" )._trigger( "beforehide", null, { nextPage: toPage } );
2314
2401
  }
2315
-
2402
+
2316
2403
  if( !touchOverflow){
2317
2404
  toPage.height( screenHeight + toScroll );
2318
- }
2319
-
2405
+ }
2406
+
2320
2407
  toPage.data( "page" )._trigger( "beforeshow", null, { prevPage: fromPage || $( "" ) } );
2321
2408
 
2322
2409
  //clear page loader
2323
2410
  $.mobile.hidePageLoadingMsg();
2324
-
2411
+
2325
2412
  if( touchOverflow && toScroll ){
2326
-
2413
+
2327
2414
  toPage.addClass( "ui-mobile-pre-transition" );
2328
2415
  // Send focus to page as it is now display: block
2329
2416
  reFocus( toPage );
2330
-
2417
+
2331
2418
  //set page's scrollTop to remembered distance
2332
2419
  if( toPage.is( ".ui-native-fixed" ) ){
2333
2420
  toPage.find( ".ui-content" ).scrollTop( toScroll );
@@ -2350,7 +2437,7 @@ $.widget( "mobile.page", $.mobile.widget, {
2350
2437
  // Send focus to the newly shown page
2351
2438
  reFocus( toPage );
2352
2439
  }
2353
-
2440
+
2354
2441
  // Jump to top or prev scroll, sometimes on iOS the page has not rendered yet.
2355
2442
  if( !touchOverflow ){
2356
2443
  $.mobile.silentScroll( toScroll );
@@ -2361,7 +2448,7 @@ $.widget( "mobile.page", $.mobile.widget, {
2361
2448
  if( !touchOverflow ){
2362
2449
  fromPage.height( "" );
2363
2450
  }
2364
-
2451
+
2365
2452
  fromPage.data( "page" )._trigger( "hide", null, { nextPage: toPage } );
2366
2453
  }
2367
2454
 
@@ -2383,11 +2470,15 @@ $.widget( "mobile.page", $.mobile.widget, {
2383
2470
 
2384
2471
  return pageMin;
2385
2472
  }
2386
-
2473
+
2387
2474
  $.mobile.getScreenHeight = getScreenHeight;
2388
2475
 
2389
2476
  //simply set the active page's minimum height to screen height, depending on orientation
2390
2477
  function resetActivePageHeight(){
2478
+ // Don't apply this height in touch overflow enabled mode
2479
+ if( $.support.touchOverflow && $.mobile.touchOverflowEnabled ){
2480
+ return;
2481
+ }
2391
2482
  $( "." + $.mobile.activePageClass ).css( "min-height", getScreenHeight() );
2392
2483
  }
2393
2484
 
@@ -2417,20 +2508,12 @@ $.widget( "mobile.page", $.mobile.widget, {
2417
2508
  }
2418
2509
  };
2419
2510
 
2420
- //update location.hash, with or without triggering hashchange event
2421
- //TODO - deprecate this one at 1.0
2422
- $.mobile.updateHash = path.set;
2423
-
2424
2511
  //expose path object on $.mobile
2425
2512
  $.mobile.path = path;
2426
2513
 
2427
2514
  //expose base object on $.mobile
2428
2515
  $.mobile.base = base;
2429
2516
 
2430
- //url stack, useful when plugins need to be aware of previous pages viewed
2431
- //TODO: deprecate this one at 1.0
2432
- $.mobile.urlstack = urlHistory.stack;
2433
-
2434
2517
  //history stack
2435
2518
  $.mobile.urlHistory = urlHistory;
2436
2519
 
@@ -2467,6 +2550,26 @@ $.widget( "mobile.page", $.mobile.widget, {
2467
2550
  return asParsedObject ? $.extend( {}, documentBase ) : documentBase.href;
2468
2551
  };
2469
2552
 
2553
+ $.mobile._bindPageRemove = function() {
2554
+ var page = $(this);
2555
+
2556
+ // when dom caching is not enabled or the page is embedded bind to remove the page on hide
2557
+ if( !page.data("page").options.domCache
2558
+ && page.is(":jqmData(external-page='true')") ) {
2559
+
2560
+ page.bind( 'pagehide.remove', function() {
2561
+ var $this = $( this ),
2562
+ prEvent = new $.Event( "pageremove" );
2563
+
2564
+ $this.trigger( prEvent );
2565
+
2566
+ if( !prEvent.isDefaultPrevented() ){
2567
+ $this.removeWithDependents();
2568
+ }
2569
+ });
2570
+ }
2571
+ };
2572
+
2470
2573
  // Load a page into the DOM.
2471
2574
  $.mobile.loadPage = function( url, options ) {
2472
2575
  // This function uses deferred notifications to let callers
@@ -2504,6 +2607,11 @@ $.widget( "mobile.page", $.mobile.widget, {
2504
2607
  settings.data = undefined;
2505
2608
  }
2506
2609
 
2610
+ // If the caller is using a "post" request, reloadPage must be true
2611
+ if( settings.data && settings.type === "post" ){
2612
+ settings.reloadPage = true;
2613
+ }
2614
+
2507
2615
  // The absolute version of the URL minus any dialog/subpage params.
2508
2616
  // In otherwords the real URL of the page to be loaded.
2509
2617
  var fileUrl = path.getFilePath( absUrl ),
@@ -2521,6 +2629,15 @@ $.widget( "mobile.page", $.mobile.widget, {
2521
2629
  // Check to see if the page already exists in the DOM.
2522
2630
  page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
2523
2631
 
2632
+ // If we failed to find the page, check to see if the url is a
2633
+ // reference to an embedded page. If so, it may have been dynamically
2634
+ // injected by a developer, in which case it would be lacking a data-url
2635
+ // attribute and in need of enhancement.
2636
+ if ( page.length === 0 && !path.isPath( dataUrl ) ) {
2637
+ page = settings.pageContainer.children( "#" + dataUrl )
2638
+ .attr( "data-" + $.mobile.ns + "url", dataUrl )
2639
+ }
2640
+
2524
2641
  // If we failed to find a page in the DOM, check the URL to see if it
2525
2642
  // refers to the first page in the application.
2526
2643
  if ( page.length === 0 && $.mobile.firstPage && path.isFirstPageUrl( absUrl ) ) {
@@ -2545,6 +2662,18 @@ $.widget( "mobile.page", $.mobile.widget, {
2545
2662
  dupCachedPage = page;
2546
2663
  }
2547
2664
 
2665
+ var mpc = settings.pageContainer,
2666
+ pblEvent = new $.Event( "pagebeforeload" ),
2667
+ triggerData = { url: url, absUrl: absUrl, dataUrl: dataUrl, deferred: deferred, options: settings };
2668
+
2669
+ // Let listeners know we're about to load a page.
2670
+ mpc.trigger( pblEvent, triggerData );
2671
+
2672
+ // If the default behavior is prevented, stop here!
2673
+ if( pblEvent.isDefaultPrevented() ){
2674
+ return deferred.promise();
2675
+ }
2676
+
2548
2677
  if ( settings.showLoadMsg ) {
2549
2678
 
2550
2679
  // This configurable timeout allows cached pages a brief delay to load without showing a message
@@ -2581,7 +2710,7 @@ $.widget( "mobile.page", $.mobile.widget, {
2581
2710
  newPageTitle = html.match( /<title[^>]*>([^<]*)/ ) && RegExp.$1,
2582
2711
 
2583
2712
  // TODO handle dialogs again
2584
- pageElemRegex = new RegExp( ".*(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>).*" ),
2713
+ pageElemRegex = new RegExp( "(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>)" ),
2585
2714
  dataUrlRegex = new RegExp( "\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?" );
2586
2715
 
2587
2716
 
@@ -2593,9 +2722,6 @@ $.widget( "mobile.page", $.mobile.widget, {
2593
2722
  && RegExp.$1 ) {
2594
2723
  url = fileUrl = path.getFilePath( RegExp.$1 );
2595
2724
  }
2596
- else{
2597
-
2598
- }
2599
2725
 
2600
2726
  if ( base ) {
2601
2727
  base.set( fileUrl );
@@ -2634,20 +2760,16 @@ $.widget( "mobile.page", $.mobile.widget, {
2634
2760
  }
2635
2761
 
2636
2762
  //append to page and enhance
2763
+ // TODO taging a page with external to make sure that embedded pages aren't removed
2764
+ // by the various page handling code is bad. Having page handling code in many
2765
+ // places is bad. Solutions post 1.0
2637
2766
  page
2638
2767
  .attr( "data-" + $.mobile.ns + "url", path.convertUrlToDataUrl( fileUrl ) )
2768
+ .attr( "data-" + $.mobile.ns + "external-page", true )
2639
2769
  .appendTo( settings.pageContainer );
2640
2770
 
2641
2771
  // wait for page creation to leverage options defined on widget
2642
- page.one('pagecreate', function(){
2643
-
2644
- // when dom caching is not enabled bind to remove the page on hide
2645
- if( !page.data("page").options.domCache ){
2646
- page.bind( "pagehide.remove", function(){
2647
- $(this).remove();
2648
- });
2649
- }
2650
- });
2772
+ page.one( 'pagecreate', $.mobile._bindPageRemove );
2651
2773
 
2652
2774
  enhancePage( page, settings.role );
2653
2775
 
@@ -2665,6 +2787,12 @@ $.widget( "mobile.page", $.mobile.widget, {
2665
2787
  hideMsg();
2666
2788
  }
2667
2789
 
2790
+ // Add the page reference to our triggerData.
2791
+ triggerData.page = page;
2792
+
2793
+ // Let listeners know the page loaded successfully.
2794
+ settings.pageContainer.trigger( "pageload", triggerData );
2795
+
2668
2796
  deferred.resolve( absUrl, options, page, dupCachedPage );
2669
2797
  },
2670
2798
  error: function() {
@@ -2673,6 +2801,19 @@ $.widget( "mobile.page", $.mobile.widget, {
2673
2801
  base.set( path.get() );
2674
2802
  }
2675
2803
 
2804
+ var plfEvent = new $.Event( "pageloadfailed" );
2805
+
2806
+ // Let listeners know the page load failed.
2807
+ settings.pageContainer.trigger( plfEvent, triggerData );
2808
+
2809
+ // If the default behavior is prevented, stop here!
2810
+ // Note that it is the responsibility of the listener/handler
2811
+ // that called preventDefault(), to resolve/reject the
2812
+ // deferred object within the triggerData.
2813
+ if( plfEvent.isDefaultPrevented() ){
2814
+ return;
2815
+ }
2816
+
2676
2817
  // Remove loading message.
2677
2818
  if ( settings.showLoadMsg ) {
2678
2819
 
@@ -2709,43 +2850,6 @@ $.widget( "mobile.page", $.mobile.widget, {
2709
2850
 
2710
2851
  // Show a specific page in the page container.
2711
2852
  $.mobile.changePage = function( toPage, options ) {
2712
- // XXX: REMOVE_BEFORE_SHIPPING_1.0
2713
- // This is temporary code that makes changePage() compatible with previous alpha versions.
2714
- if ( typeof options !== "object" ) {
2715
- var opts = null;
2716
-
2717
- // Map old-style call signature for form submit to the new options object format.
2718
- if ( typeof toPage === "object" && toPage.url && toPage.type ) {
2719
- opts = {
2720
- type: toPage.type,
2721
- data: toPage.data,
2722
- forcePageLoad: true
2723
- };
2724
- toPage = toPage.url;
2725
- }
2726
-
2727
- // The arguments passed into the function need to be re-mapped
2728
- // to the new options object format.
2729
- var len = arguments.length;
2730
- if ( len > 1 ) {
2731
- var argNames = [ "transition", "reverse", "changeHash", "fromHashChange" ], i;
2732
- for ( i = 1; i < len; i++ ) {
2733
- var a = arguments[ i ];
2734
- if ( typeof a !== "undefined" ) {
2735
- opts = opts || {};
2736
- opts[ argNames[ i - 1 ] ] = a;
2737
- }
2738
- }
2739
- }
2740
-
2741
- // If an options object was created, then we know changePage() was called
2742
- // with an old signature.
2743
- if ( opts ) {
2744
- return $.mobile.changePage( toPage, opts );
2745
- }
2746
- }
2747
- // XXX: REMOVE_BEFORE_SHIPPING_1.0
2748
-
2749
2853
  // If we are in the midst of a transition, queue the current request.
2750
2854
  // We'll call changePage() once we're done with the current transition to
2751
2855
  // service the request.
@@ -2769,8 +2873,6 @@ $.widget( "mobile.page", $.mobile.widget, {
2769
2873
  // Let listeners know we're about to change the current page.
2770
2874
  mpc.trigger( pbcEvent, triggerData );
2771
2875
 
2772
- mpc.trigger( "beforechangepage", triggerData ); // XXX: DEPRECATED for 1.0
2773
-
2774
2876
  // If the default behavior is prevented, stop here!
2775
2877
  if( pbcEvent.isDefaultPrevented() ){
2776
2878
  return;
@@ -2799,7 +2901,6 @@ $.widget( "mobile.page", $.mobile.widget, {
2799
2901
  $.mobile.changePage( newPage, options );
2800
2902
  })
2801
2903
  .fail(function( url, options ) {
2802
- // XXX_jblas: Fire off changepagefailed notificaiton.
2803
2904
  isPageTransitioning = false;
2804
2905
 
2805
2906
  //clear out the active button state
@@ -2808,7 +2909,6 @@ $.widget( "mobile.page", $.mobile.widget, {
2808
2909
  //release transition lock so navigation is free again
2809
2910
  releasePageTransitionLock();
2810
2911
  settings.pageContainer.trigger( "pagechangefailed", triggerData );
2811
- settings.pageContainer.trigger( "changepagefailed", triggerData ); // XXX: DEPRECATED for 1.0
2812
2912
  });
2813
2913
  return;
2814
2914
  }
@@ -2826,16 +2926,19 @@ $.widget( "mobile.page", $.mobile.widget, {
2826
2926
  pageTitle = document.title,
2827
2927
  isDialog = settings.role === "dialog" || toPage.jqmData( "role" ) === "dialog";
2828
2928
 
2829
- // If we are trying to transition to the same page that we are currently on ignore the request.
2830
- // an illegal same page request is defined by the current page being the same as the url, as long as there's history
2831
- // and toPage is not an array or object (those are allowed to be "same")
2832
- //
2833
- // XXX_jblas: We need to remove this at some point when we allow for transitions
2834
- // to the same page.
2835
- if( fromPage && fromPage[0] === toPage[0] ) {
2929
+ // By default, we prevent changePage requests when the fromPage and toPage
2930
+ // are the same element, but folks that generate content manually/dynamically
2931
+ // and reuse pages want to be able to transition to the same page. To allow
2932
+ // this, they will need to change the default value of allowSamePageTransition
2933
+ // to true, *OR*, pass it in as an option when they manually call changePage().
2934
+ // It should be noted that our default transition animations assume that the
2935
+ // formPage and toPage are different elements, so they may behave unexpectedly.
2936
+ // It is up to the developer that turns on the allowSamePageTransitiona option
2937
+ // to either turn off transition animations, or make sure that an appropriate
2938
+ // animation transition is used.
2939
+ if( fromPage && fromPage[0] === toPage[0] && !settings.allowSamePageTransition ) {
2836
2940
  isPageTransitioning = false;
2837
2941
  mpc.trigger( "pagechange", triggerData );
2838
- mpc.trigger( "changepage", triggerData ); // XXX: DEPRECATED for 1.0
2839
2942
  return;
2840
2943
  }
2841
2944
 
@@ -2923,8 +3026,6 @@ $.widget( "mobile.page", $.mobile.widget, {
2923
3026
 
2924
3027
  // Let listeners know we're all done changing the current page.
2925
3028
  mpc.trigger( "pagechange", triggerData );
2926
-
2927
- mpc.trigger( "changepage", triggerData ); // XXX: DEPRECATED for 1.0
2928
3029
  });
2929
3030
  };
2930
3031
 
@@ -2938,7 +3039,8 @@ $.widget( "mobile.page", $.mobile.widget, {
2938
3039
  pageContainer: undefined,
2939
3040
  showLoadMsg: true, //loading message shows by default when pages are being fetched during changePage
2940
3041
  dataUrl: undefined,
2941
- fromPage: undefined
3042
+ fromPage: undefined,
3043
+ allowSamePageTransition: false
2942
3044
  };
2943
3045
 
2944
3046
  /* Event Bindings - hashchange, submit, and click */
@@ -3023,6 +3125,12 @@ $.widget( "mobile.page", $.mobile.widget, {
3023
3125
 
3024
3126
  //add active state on vclick
3025
3127
  $( document ).bind( "vclick", function( event ) {
3128
+ // if this isn't a left click we don't care. Its important to note
3129
+ // that when the virtual event is generated it will create
3130
+ if ( event.which > 1 ){
3131
+ return;
3132
+ }
3133
+
3026
3134
  var link = findClosestLink( event.target );
3027
3135
  if ( link ) {
3028
3136
  if ( path.parseUrl( link.getAttribute( "href" ) || "#" ).hash !== "#" ) {
@@ -3037,7 +3145,10 @@ $.widget( "mobile.page", $.mobile.widget, {
3037
3145
  // click routing - direct to HTTP or Ajax, accordingly
3038
3146
  $( document ).bind( "click", function( event ) {
3039
3147
  var link = findClosestLink( event.target );
3040
- if ( !link ) {
3148
+
3149
+ // If there is no link associated with the click or its not a left
3150
+ // click we want to ignore the click
3151
+ if ( !link || event.which > 1) {
3041
3152
  return;
3042
3153
  }
3043
3154
 
@@ -3053,18 +3164,18 @@ $.widget( "mobile.page", $.mobile.widget, {
3053
3164
  return false;
3054
3165
  }
3055
3166
 
3167
+ var baseUrl = getClosestBaseUrl( $link ),
3168
+
3169
+ //get href, if defined, otherwise default to empty hash
3170
+ href = path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl );
3171
+
3056
3172
  //if ajax is disabled, exit early
3057
- if( !$.mobile.ajaxEnabled ){
3173
+ if( !$.mobile.ajaxEnabled && !path.isEmbeddedPage( href ) ){
3058
3174
  httpCleanup();
3059
3175
  //use default click handling
3060
3176
  return;
3061
3177
  }
3062
3178
 
3063
- var baseUrl = getClosestBaseUrl( $link ),
3064
-
3065
- //get href, if defined, otherwise default to empty hash
3066
- href = path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl );
3067
-
3068
3179
  // XXX_jblas: Ideally links to application pages should be specified as
3069
3180
  // an url to the application document with a hash that is either
3070
3181
  // the site relative path or id to the page. But some of the
@@ -3172,7 +3283,7 @@ $.widget( "mobile.page", $.mobile.widget, {
3172
3283
  isForward: function() { window.history.forward(); }
3173
3284
  });
3174
3285
 
3175
- // prevent changepage
3286
+ // prevent changePage()
3176
3287
  return;
3177
3288
  } else {
3178
3289
  // if the current active page is a dialog and we're navigating
@@ -3201,7 +3312,12 @@ $.widget( "mobile.page", $.mobile.widget, {
3201
3312
 
3202
3313
  //if to is defined, load it
3203
3314
  if ( to ) {
3204
- to = ( typeof to === "string" && !path.isPath( to ) ) ? ( '#' + to ) : to;
3315
+ // At this point, 'to' can be one of 3 things, a cached page element from
3316
+ // a history stack entry, an id, or site-relative/absolute URL. If 'to' is
3317
+ // an id, we need to resolve it against the documentBase, not the location.href,
3318
+ // since the hashchange could've been the result of a forward/backward navigation
3319
+ // that crosses from an external page/dialog to an internal page/dialog.
3320
+ to = ( typeof to === "string" && !path.isPath( to ) ) ? ( path.makeUrlAbsolute( '#' + to, documentBase ) ) : to;
3205
3321
  $.mobile.changePage( to, changePageOptions );
3206
3322
  } else {
3207
3323
  //there's no hash, go to the first page in the dom
@@ -3271,28 +3387,47 @@ $.widget( "mobile.page", $.mobile.widget, {
3271
3387
  return url;
3272
3388
  },
3273
3389
 
3390
+ // TODO sort out a single barrier to hashchange functionality
3391
+ nextHashChangePrevented: function( value ) {
3392
+ $.mobile.urlHistory.ignoreNextHashChange = value;
3393
+ self.onHashChangeDisabled = value;
3394
+ },
3395
+
3274
3396
  // on hash change we want to clean up the url
3275
3397
  // NOTE this takes place *after* the vanilla navigation hash change
3276
3398
  // handling has taken place and set the state of the DOM
3277
3399
  onHashChange: function( e ) {
3278
- var href, state;
3279
-
3280
- self.hashchangeFired = true;
3281
-
3282
- // only replaceState when the hash doesn't represent an embeded page
3283
- if( $.mobile.path.isPath(location.hash) ) {
3400
+ // disable this hash change
3401
+ if( self.onHashChangeDisabled ){
3402
+ return;
3403
+ }
3404
+
3405
+ var href, state,
3406
+ hash = location.hash,
3407
+ isPath = $.mobile.path.isPath( hash );
3408
+ hash = isPath ? hash.replace( "#", "" ) : hash;
3284
3409
 
3285
- // propulate the hash when its not available
3286
- state = self.state();
3410
+ // propulate the hash when its not available
3411
+ state = self.state();
3287
3412
 
3288
- // make the hash abolute with the current href
3289
- href = $.mobile.path.makeUrlAbsolute( state.hash.replace("#", ""), location.href );
3413
+ // make the hash abolute with the current href
3414
+ href = $.mobile.path.makeUrlAbsolute( hash, location.href );
3290
3415
 
3416
+ if ( isPath ) {
3291
3417
  href = self.resetUIKeys( href );
3292
-
3293
- // replace the current url with the new href and store the state
3294
- history.replaceState( state, document.title, href );
3295
3418
  }
3419
+
3420
+ // replace the current url with the new href and store the state
3421
+ // Note that in some cases we might be replacing an url with the
3422
+ // same url. We do this anyways because we need to make sure that
3423
+ // all of our history entries have a state object associated with
3424
+ // them. This allows us to work around the case where window.history.back()
3425
+ // is called to transition from an external page to an embedded page.
3426
+ // In that particular case, a hashchange event is *NOT* generated by the browser.
3427
+ // Ensuring each history entry has a state object means that onPopState()
3428
+ // will always trigger our hashchange callback even when a hashchange event
3429
+ // is not fired.
3430
+ history.replaceState( state, document.title, href );
3296
3431
  },
3297
3432
 
3298
3433
  // on popstate (ie back or forward) we need to replace the hash that was there previously
@@ -3304,14 +3439,14 @@ $.widget( "mobile.page", $.mobile.widget, {
3304
3439
  // or forward popstate
3305
3440
  if( poppedState ) {
3306
3441
  // disable any hashchange triggered by the browser
3307
- $.mobile.urlHistory.ignoreNextHashChange = true;
3442
+ self.nextHashChangePrevented( true );
3308
3443
 
3309
3444
  // defer our manual hashchange until after the browser fired
3310
3445
  // version has come and gone
3311
3446
  setTimeout(function() {
3312
3447
  // make sure that the manual hash handling takes place
3313
- $.mobile.urlHistory.ignoreNextHashChange = false;
3314
-
3448
+ self.nextHashChangePrevented( false );
3449
+
3315
3450
  // change the page based on the hash
3316
3451
  $.mobile._handleHashChange( poppedState.hash );
3317
3452
  }, 100);
@@ -3356,7 +3491,7 @@ function css3TransitionHandler( name, reverse, $to, $from ) {
3356
3491
 
3357
3492
  $to.add( $from ).removeClass( "out in reverse " + name );
3358
3493
 
3359
- if ( $from ) {
3494
+ if ( $from && $from[ 0 ] !== $to[ 0 ] ) {
3360
3495
  $from.removeClass( $.mobile.activePageClass );
3361
3496
  }
3362
3497
 
@@ -3427,10 +3562,13 @@ $( document ).bind( "pagecreate enhance", function( e ){
3427
3562
  optType = o.degradeInputs[ type ] || "text";
3428
3563
 
3429
3564
  if ( o.degradeInputs[ type ] ) {
3430
- $this.replaceWith(
3431
- $( "<div>" ).html( $this.clone() ).html()
3432
- .replace( /\s+type=["']?\w+['"]?/, " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\" " )
3433
- );
3565
+ var html = $( "<div>" ).html( $this.clone() ).html(),
3566
+ // In IE browsers, the type sometimes doesn't exist in the cloned markup, so we replace the closing tag instead
3567
+ hasType = html.indexOf( " type=" ) > -1,
3568
+ findstr = hasType ? /\s+type=["']?\w+['"]?/ : /\/?>/,
3569
+ repstr = " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\"" + ( hasType ? "" : ">" );
3570
+
3571
+ $this.replaceWith( html.replace( findstr, repstr ) );
3434
3572
  }
3435
3573
  });
3436
3574
 
@@ -3451,27 +3589,36 @@ $.widget( "mobile.dialog", $.mobile.widget, {
3451
3589
  initSelector : ":jqmData(role='dialog')"
3452
3590
  },
3453
3591
  _create: function() {
3454
- var $el = this.element,
3455
- pageTheme = $el.attr( "class" ).match( /ui-body-[a-z]/ );
3456
-
3592
+ var self = this,
3593
+ $el = this.element,
3594
+ pageTheme = $el.attr( "class" ).match( /ui-body-[a-z]/ ),
3595
+ headerCloseButton = $( "<a href='#' data-" + $.mobile.ns + "icon='delete' data-" + $.mobile.ns + "iconpos='notext'>"+ this.options.closeBtnText + "</a>" );
3596
+
3457
3597
  if( pageTheme.length ){
3458
3598
  $el.removeClass( pageTheme[ 0 ] );
3459
- }
3460
-
3599
+ }
3600
+
3461
3601
  $el.addClass( "ui-body-" + this.options.theme );
3462
-
3602
+
3463
3603
  // Class the markup for dialog styling
3464
3604
  // Set aria role
3465
3605
  $el.attr( "role", "dialog" )
3466
3606
  .addClass( "ui-dialog" )
3467
3607
  .find( ":jqmData(role='header')" )
3468
3608
  .addClass( "ui-corner-top ui-overlay-shadow" )
3469
- .prepend( "<a href='#' data-" + $.mobile.ns + "icon='delete' data-" + $.mobile.ns + "rel='back' data-" + $.mobile.ns + "iconpos='notext'>"+ this.options.closeBtnText + "</a>" )
3609
+ .prepend( headerCloseButton )
3470
3610
  .end()
3471
3611
  .find( ":jqmData(role='content'),:jqmData(role='footer')" )
3472
3612
  .last()
3473
3613
  .addClass( "ui-corner-bottom ui-overlay-shadow" );
3474
3614
 
3615
+ // this must be an anonymous function so that select menu dialogs can replace
3616
+ // the close method. This is a change from previously just defining data-rel=back
3617
+ // on the button and letting nav handle it
3618
+ headerCloseButton.bind( "vclick", function() {
3619
+ self.close();
3620
+ });
3621
+
3475
3622
  /* bind events
3476
3623
  - clicks and submits should use the closing transition that the dialog opened with
3477
3624
  unless a data-transition is specified on the link/form
@@ -3613,6 +3760,7 @@ $.widget( "mobile.collapsible", $.mobile.widget, {
3613
3760
  collapsed: true,
3614
3761
  heading: ">:header,>legend",
3615
3762
  theme: null,
3763
+ contentTheme: null,
3616
3764
  iconTheme: "d",
3617
3765
  initSelector: ":jqmData(role='collapsible')"
3618
3766
  },
@@ -3620,10 +3768,11 @@ $.widget( "mobile.collapsible", $.mobile.widget, {
3620
3768
 
3621
3769
  var $el = this.element,
3622
3770
  o = this.options,
3623
- collapsibleContain = $el.addClass( "ui-collapsible-contain" ),
3771
+ collapsible = $el.addClass( "ui-collapsible" ),
3624
3772
  collapsibleHeading = $el.find( o.heading ).eq( 0 ),
3625
- collapsibleContent = collapsibleContain.wrapInner( "<div class='ui-collapsible-content'></div>" ).find( ".ui-collapsible-content" ),
3626
- collapsibleParent = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" );
3773
+ collapsibleContent = collapsible.wrapInner( "<div class='ui-collapsible-content'></div>" ).find( ".ui-collapsible-content" ),
3774
+ collapsibleSet = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" ),
3775
+ colllapsiblesInSet = collapsibleSet.children( ":jqmData(role='collapsible')" );
3627
3776
 
3628
3777
  // Replace collapsibleHeading if it's a legend
3629
3778
  if ( collapsibleHeading.is( "legend" ) ) {
@@ -3631,6 +3780,20 @@ $.widget( "mobile.collapsible", $.mobile.widget, {
3631
3780
  collapsibleHeading.next().remove();
3632
3781
  }
3633
3782
 
3783
+ // If we are in a collapsible set
3784
+ if ( collapsibleSet.length ) {
3785
+ // Inherit the theme from collapsible-set
3786
+ if ( !o.theme ) {
3787
+ o.theme = collapsibleSet.jqmData( "theme" );
3788
+ }
3789
+ // Inherit the content-theme from collapsible-set
3790
+ if ( !o.contentTheme ) {
3791
+ o.contentTheme = collapsibleSet.jqmData( "content-theme" );
3792
+ }
3793
+ }
3794
+
3795
+ collapsibleContent.addClass( ( o.contentTheme ) ? ( "ui-body-" + o.contentTheme ) : "");
3796
+
3634
3797
  collapsibleHeading
3635
3798
  //drop heading in before content
3636
3799
  .insertBefore( collapsibleContent )
@@ -3640,117 +3803,96 @@ $.widget( "mobile.collapsible", $.mobile.widget, {
3640
3803
  .wrapInner( "<a href='#' class='ui-collapsible-heading-toggle'></a>" )
3641
3804
  .find( "a:eq(0)" )
3642
3805
  .buttonMarkup({
3643
- shadow: !collapsibleParent.length,
3806
+ shadow: false,
3644
3807
  corners: false,
3645
3808
  iconPos: "left",
3646
3809
  icon: "plus",
3647
3810
  theme: o.theme
3648
- })
3649
- .find( ".ui-icon" )
3650
- .removeAttr( "class" )
3651
- .buttonMarkup({
3652
- shadow: true,
3653
- corners: true,
3654
- iconPos: "notext",
3655
- icon: "plus",
3656
- theme: o.iconTheme
3811
+ });
3812
+
3813
+ if ( !collapsibleSet.length ) {
3814
+ collapsibleHeading
3815
+ .find( "a:eq(0), .ui-btn-inner" )
3816
+ .addClass( "ui-corner-top ui-corner-bottom" );
3817
+ } else {
3818
+ // If we are in a collapsible set
3819
+
3820
+ // Initialize the collapsible set if it's not already initialized
3821
+ if ( !collapsibleSet.jqmData( "collapsiblebound" ) ) {
3822
+
3823
+ collapsibleSet
3824
+ .jqmData( "collapsiblebound", true )
3825
+ .bind( "expand", function( event ) {
3826
+
3827
+ $( event.target )
3828
+ .closest( ".ui-collapsible" )
3829
+ .siblings( ".ui-collapsible" )
3830
+ .trigger( "collapse" );
3831
+
3657
3832
  });
3833
+ }
3658
3834
 
3659
- if ( !collapsibleParent.length ) {
3660
- collapsibleHeading
3661
- .find( "a:eq(0)" )
3662
- .addClass( "ui-corner-all" )
3835
+ colllapsiblesInSet.first()
3836
+ .find( "a:eq(0)" )
3837
+ .addClass( "ui-corner-top" )
3838
+ .find( ".ui-btn-inner" )
3839
+ .addClass( "ui-corner-top" );
3840
+
3841
+ colllapsiblesInSet.last()
3842
+ .jqmData( "collapsible-last", true )
3843
+ .find( "a:eq(0)" )
3844
+ .addClass( "ui-corner-bottom" )
3663
3845
  .find( ".ui-btn-inner" )
3664
- .addClass( "ui-corner-all" );
3665
- } else {
3666
- if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
3667
- collapsibleHeading
3668
- .find( "a:eq(0), .ui-btn-inner" )
3669
3846
  .addClass( "ui-corner-bottom" );
3670
- }
3847
+
3848
+
3849
+ if ( collapsible.jqmData( "collapsible-last" ) ) {
3850
+ collapsibleHeading
3851
+ .find( "a:eq(0), .ui-btn-inner" )
3852
+ .addClass( "ui-corner-bottom" );
3671
3853
  }
3854
+ }
3672
3855
 
3673
3856
  //events
3674
- collapsibleContain
3675
- .bind( "collapse", function( event ) {
3676
- if ( ! event.isDefaultPrevented() &&
3677
- $( event.target ).closest( ".ui-collapsible-contain" ).is( collapsibleContain ) ) {
3857
+ collapsible
3858
+ .bind( "expand collapse", function( event ) {
3859
+ if ( !event.isDefaultPrevented() ) {
3678
3860
 
3679
3861
  event.preventDefault();
3680
3862
 
3863
+ var $this = $( this ),
3864
+ isCollapse = ( event.type === "collapse" ),
3865
+ contentTheme = o.contentTheme;
3866
+
3681
3867
  collapsibleHeading
3682
- .addClass( "ui-collapsible-heading-collapsed" )
3868
+ .toggleClass( "ui-collapsible-heading-collapsed", isCollapse)
3683
3869
  .find( ".ui-collapsible-heading-status" )
3684
3870
  .text( o.expandCueText )
3685
3871
  .end()
3686
3872
  .find( ".ui-icon" )
3687
- .removeClass( "ui-icon-minus" )
3688
- .addClass( "ui-icon-plus" );
3873
+ .toggleClass( "ui-icon-minus", !isCollapse )
3874
+ .toggleClass( "ui-icon-plus", isCollapse );
3689
3875
 
3690
- collapsibleContent.addClass( "ui-collapsible-content-collapsed" ).attr( "aria-hidden", true );
3876
+ $this.toggleClass( "ui-collapsible-collapsed", isCollapse );
3877
+ collapsibleContent.toggleClass( "ui-collapsible-content-collapsed", isCollapse ).attr( "aria-hidden", isCollapse );
3691
3878
 
3692
- if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
3879
+ if ( contentTheme && ( !collapsibleSet.length || collapsible.jqmData( "collapsible-last" ) ) ) {
3693
3880
  collapsibleHeading
3694
3881
  .find( "a:eq(0), .ui-btn-inner" )
3695
- .addClass( "ui-corner-bottom" );
3696
- }
3697
- }
3698
- })
3699
- .bind( "expand", function( event ) {
3700
- if ( !event.isDefaultPrevented() ) {
3701
-
3702
- event.preventDefault();
3703
-
3704
- collapsibleHeading
3705
- .removeClass( "ui-collapsible-heading-collapsed" )
3706
- .find( ".ui-collapsible-heading-status" ).text( o.collapseCueText );
3707
-
3708
- collapsibleHeading.find( ".ui-icon" ).removeClass( "ui-icon-plus" ).addClass( "ui-icon-minus" );
3709
-
3710
- collapsibleContent.removeClass( "ui-collapsible-content-collapsed" ).attr( "aria-hidden", false );
3711
-
3712
- if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
3713
-
3714
- collapsibleHeading
3715
- .find( "a:eq(0), .ui-btn-inner" )
3716
- .removeClass( "ui-corner-bottom" );
3882
+ .toggleClass( "ui-corner-bottom", isCollapse );
3883
+ collapsibleContent.toggleClass( "ui-corner-bottom", !isCollapse );
3717
3884
  }
3718
3885
  }
3719
3886
  })
3720
3887
  .trigger( o.collapsed ? "collapse" : "expand" );
3721
3888
 
3722
- // Close others in a set
3723
- if ( collapsibleParent.length && !collapsibleParent.jqmData( "collapsiblebound" ) ) {
3724
-
3725
- collapsibleParent
3726
- .jqmData( "collapsiblebound", true )
3727
- .bind( "expand", function( event ) {
3728
-
3729
- $( event.target )
3730
- .closest( ".ui-collapsible-contain" )
3731
- .siblings( ".ui-collapsible-contain" )
3732
- .trigger( "collapse" );
3733
-
3734
- });
3735
-
3736
- var set = collapsibleParent.children( ":jqmData(role='collapsible')" );
3737
-
3738
- set.first()
3739
- .find( "a:eq(0)" )
3740
- .addClass( "ui-corner-top" )
3741
- .find( ".ui-btn-inner" )
3742
- .addClass( "ui-corner-top" );
3743
-
3744
- set.last().jqmData( "collapsible-last", true );
3745
- }
3746
-
3747
3889
  collapsibleHeading
3748
- .bind( "vclick", function( event ) {
3890
+ .bind( "click", function( event ) {
3749
3891
 
3750
3892
  var type = collapsibleHeading.is( ".ui-collapsible-heading-collapsed" ) ?
3751
3893
  "expand" : "collapse";
3752
3894
 
3753
- collapsibleContain.trigger( type );
3895
+ collapsible.trigger( type );
3754
3896
 
3755
3897
  event.preventDefault();
3756
3898
  });
@@ -3965,7 +4107,7 @@ $.widget( "mobile.listview", $.mobile.widget, {
3965
4107
  $li = this.element.children( "li" );
3966
4108
  // at create time the li are not visible yet so we need to rely on .ui-screen-hidden
3967
4109
  $visibleli = create?$li.not( ".ui-screen-hidden" ):$li.filter( ":visible" );
3968
-
4110
+
3969
4111
  this._removeCorners( $li );
3970
4112
 
3971
4113
  // Select the first visible li element
@@ -4092,7 +4234,7 @@ $.widget( "mobile.listview", $.mobile.widget, {
4092
4234
 
4093
4235
  self._itemApply( $list, item );
4094
4236
  }
4095
-
4237
+
4096
4238
  this._refreshCorners( create );
4097
4239
  },
4098
4240
 
@@ -4155,8 +4297,12 @@ $.widget( "mobile.listview", $.mobile.widget, {
4155
4297
 
4156
4298
  }).listview();
4157
4299
 
4158
- //on pagehide, remove any nested pages along with the parent page, as long as they aren't active
4159
- if( hasSubPages && parentPage.data("page").options.domCache === false ){
4300
+ // on pagehide, remove any nested pages along with the parent page, as long as they aren't active
4301
+ // and aren't embedded
4302
+ if( hasSubPages &&
4303
+ parentPage.is( ":jqmData(external-page='true')" ) &&
4304
+ parentPage.data("page").options.domCache === false ) {
4305
+
4160
4306
  var newRemove = function( e, ui ){
4161
4307
  var nextPage = ui.nextPage, npURL;
4162
4308
 
@@ -4308,7 +4454,7 @@ $( ":jqmData(role='listview')" ).live( "listviewcreate", function() {
4308
4454
  });
4309
4455
 
4310
4456
  })( jQuery );/*
4311
- * jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
4457
+ * jQuery Mobile Framework : "nojs" plugin - class to make elements hidden to A grade browsers
4312
4458
  * Copyright (c) jQuery Project
4313
4459
  * Dual licensed under the MIT or GPL Version 2 licenses.
4314
4460
  * http://jquery.org/license
@@ -4538,7 +4684,9 @@ $.widget( "mobile.button", $.mobile.widget, {
4538
4684
  _create: function() {
4539
4685
  var $el = this.element,
4540
4686
  o = this.options,
4541
- type;
4687
+ type,
4688
+ name,
4689
+ $buttonPlaceholder;
4542
4690
 
4543
4691
  // Add ARIA role
4544
4692
  this.button = $( "<div></div>" )
@@ -4555,25 +4703,27 @@ $.widget( "mobile.button", $.mobile.widget, {
4555
4703
  .insertBefore( $el )
4556
4704
  .append( $el.addClass( "ui-btn-hidden" ) );
4557
4705
 
4558
- // Add hidden input during submit
4559
4706
  type = $el.attr( "type" );
4560
-
4561
- if ( type !== "button" && type !== "reset" ) {
4562
-
4563
- $el.bind( "vclick", function() {
4564
-
4565
- var $buttonPlaceholder = $( "<input>", {
4566
- type: "hidden",
4567
- name: $el.attr( "name" ),
4568
- value: $el.attr( "value" )
4569
- })
4570
- .insertBefore( $el );
4571
-
4572
- // Bind to doc to remove after submit handling
4573
- $( document ).submit(function(){
4574
- $buttonPlaceholder.remove();
4707
+ name = $el.attr( "name" );
4708
+
4709
+ // Add hidden input during submit if input type="submit" has a name.
4710
+ if ( type !== "button" && type !== "reset" && name ) {
4711
+ $el.bind( "vclick", function() {
4712
+ // Add hidden input if it doesn’t already exist.
4713
+ if( $buttonPlaceholder === undefined ) {
4714
+ $buttonPlaceholder = $( "<input>", {
4715
+ type: "hidden",
4716
+ name: $el.attr( "name" ),
4717
+ value: $el.attr( "value" )
4718
+ })
4719
+ .insertBefore( $el );
4720
+
4721
+ // Bind to doc to remove after submit handling
4722
+ $( document ).submit(function(){
4723
+ $buttonPlaceholder.remove();
4724
+ });
4725
+ }
4575
4726
  });
4576
- });
4577
4727
  }
4578
4728
 
4579
4729
  this.refresh();
@@ -4893,13 +5043,17 @@ $.widget( "mobile.slider", $.mobile.widget, {
4893
5043
  }
4894
5044
 
4895
5045
  if ( !preventInputUpdate ) {
5046
+ var valueChanged = false;
5047
+
4896
5048
  // update control"s value
4897
5049
  if ( cType === "input" ) {
5050
+ valueChanged = control.val() !== newval;
4898
5051
  control.val( newval );
4899
5052
  } else {
5053
+ valueChanged = control[ 0 ].selectedIndex !== newval;
4900
5054
  control[ 0 ].selectedIndex = newval;
4901
5055
  }
4902
- if ( !isfromControl ) {
5056
+ if ( !isfromControl && valueChanged ) {
4903
5057
  control.trigger( "change" );
4904
5058
  }
4905
5059
  }
@@ -4941,7 +5095,7 @@ $( document ).bind( "pagecreate create", function( e ){
4941
5095
  $.widget( "mobile.textinput", $.mobile.widget, {
4942
5096
  options: {
4943
5097
  theme: null,
4944
- initSelector: "input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea"
5098
+ initSelector: "input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea, input:not([type])"
4945
5099
  },
4946
5100
 
4947
5101
  _create: function() {
@@ -4964,18 +5118,21 @@ $.widget( "mobile.textinput", $.mobile.widget, {
4964
5118
  input.addClass("ui-input-text ui-body-"+ o.theme );
4965
5119
 
4966
5120
  focusedEl = input;
4967
-
4968
- // XXX: Temporary workaround for issue 785. Turn off autocorrect and
4969
- // autocomplete since the popup they use can't be dismissed by
4970
- // the user. Note that we test for the presence of the feature
4971
- // by looking for the autocorrect property on the input element.
4972
- if ( typeof input[0].autocorrect !== "undefined" ) {
5121
+
5122
+ // XXX: Temporary workaround for issue 785 (Apple bug 8910589).
5123
+ // Turn off autocorrect and autocomplete on non-iOS 5 devices
5124
+ // since the popup they use can't be dismissed by the user. Note
5125
+ // that we test for the presence of the feature by looking for
5126
+ // the autocorrect property on the input element. We currently
5127
+ // have no test for iOS 5 or newer so we're temporarily using
5128
+ // the touchOverflow support flag for jQM 1.0. Yes, I feel dirty. - jblas
5129
+ if ( typeof input[0].autocorrect !== "undefined" && !$.support.touchOverflow ) {
4973
5130
  // Set the attribute instead of the property just in case there
4974
5131
  // is code that attempts to make modifications via HTML.
4975
5132
  input[0].setAttribute( "autocorrect", "off" );
4976
5133
  input[0].setAttribute( "autocomplete", "off" );
4977
5134
  }
4978
-
5135
+
4979
5136
 
4980
5137
  //"search" input widget
4981
5138
  if ( input.is( "[type='search'],:jqmData(type='search')" ) ) {
@@ -5056,11 +5213,11 @@ $.widget( "mobile.textinput", $.mobile.widget, {
5056
5213
 
5057
5214
  //auto self-init widgets
5058
5215
  $( document ).bind( "pagecreate create", function( e ){
5059
-
5216
+
5060
5217
  $( $.mobile.textinput.prototype.options.initSelector, e.target )
5061
5218
  .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
5062
5219
  .textinput();
5063
-
5220
+
5064
5221
  });
5065
5222
 
5066
5223
  })( jQuery );
@@ -5079,13 +5236,13 @@ $( document ).bind( "pagecreate create", function( e ){
5079
5236
  label = widget.label,
5080
5237
  thisPage = widget.select.closest( ".ui-page" ),
5081
5238
  screen = $( "<div>", {"class": "ui-selectmenu-screen ui-screen-hidden"} ).appendTo( thisPage ),
5082
- selectOptions = widget.select.find("option"),
5239
+ selectOptions = widget._selectOptions(),
5083
5240
  isMultiple = widget.isMultiple = widget.select[ 0 ].multiple,
5084
5241
  buttonId = selectID + "-button",
5085
5242
  menuId = selectID + "-menu",
5086
5243
  menuPage = $( "<div data-" + $.mobile.ns + "role='dialog' data-" +$.mobile.ns + "theme='"+ widget.options.menuPageTheme +"'>" +
5087
5244
  "<div data-" + $.mobile.ns + "role='header'>" +
5088
- "<div class='ui-title'>" + label.text() + "</div>"+
5245
+ "<div class='ui-title'>" + label.getEncodedText() + "</div>"+
5089
5246
  "</div>"+
5090
5247
  "<div data-" + $.mobile.ns + "role='content'></div>"+
5091
5248
  "</div>" ).appendTo( $.mobile.pageContainer ).page(),
@@ -5174,7 +5331,7 @@ $( document ).bind( "pagecreate create", function( e ){
5174
5331
  // index of option tag to be selected
5175
5332
  var oldIndex = self.select[ 0 ].selectedIndex,
5176
5333
  newIndex = self.list.find( "li:not(.ui-li-divider)" ).index( this ),
5177
- option = self.selectOptions.eq( newIndex )[ 0 ];
5334
+ option = self._selectOptions().eq( newIndex )[ 0 ];
5178
5335
 
5179
5336
  // toggle selected status on the tag for multi selects
5180
5337
  option.selected = self.isMultiple ? !option.selected : true;
@@ -5252,6 +5409,20 @@ $( document ).bind( "pagecreate create", function( e ){
5252
5409
  self.menuPage.bind( "pagehide", function() {
5253
5410
  self.list.appendTo( self.listbox );
5254
5411
  self._focusButton();
5412
+
5413
+ // TODO centralize page removal binding / handling in the page plugin.
5414
+ // Suggestion from @jblas to do refcounting
5415
+ //
5416
+ // TODO extremely confusing dependency on the open method where the pagehide.remove
5417
+ // bindings are stripped to prevent the parent page from disappearing. The way
5418
+ // we're keeping pages in the DOM right now sucks
5419
+ //
5420
+ // rebind the page remove that was unbound in the open function
5421
+ // to allow for the parent page removal from actions other than the use
5422
+ // of a dialog sized custom select
5423
+ //
5424
+ // doing this here provides for the back button on the custom select dialog
5425
+ $.mobile._bindPageRemove.call( self.thisPage );
5255
5426
  });
5256
5427
 
5257
5428
  // Events on "screen" overlay
@@ -5266,18 +5437,32 @@ $( document ).bind( "pagecreate create", function( e ){
5266
5437
  return false;
5267
5438
  }
5268
5439
  });
5440
+
5441
+ // track this dependency so that when the parent page
5442
+ // is removed on pagehide it will also remove the menupage
5443
+ self.thisPage.addDependents( this.menuPage );
5269
5444
  },
5270
5445
 
5271
- refresh: function( forceRebuild ){
5446
+ _isRebuildRequired: function() {
5447
+ var list = this.list.find( "li" ),
5448
+ options = this._selectOptions();
5449
+
5450
+ // TODO exceedingly naive method to determine difference
5451
+ // ignores value changes etc in favor of a forcedRebuild
5452
+ // from the user in the refresh method
5453
+ return options.text() !== list.text();
5454
+ },
5455
+
5456
+ refresh: function( forceRebuild , foo ){
5272
5457
  var self = this,
5273
5458
  select = this.element,
5274
5459
  isMultiple = this.isMultiple,
5275
- options = this.selectOptions = select.find( "option" ),
5460
+ options = this._selectOptions(),
5276
5461
  selected = this.selected(),
5277
5462
  // return an array of all selected index's
5278
5463
  indicies = this.selectedIndices();
5279
5464
 
5280
- if ( forceRebuild || select[0].options.length != self.list.find( "li" ).length ) {
5465
+ if ( forceRebuild || this._isRebuildRequired() ) {
5281
5466
  self._buildList();
5282
5467
  }
5283
5468
 
@@ -5313,18 +5498,6 @@ $( document ).bind( "pagecreate create", function( e ){
5313
5498
  var self = this;
5314
5499
 
5315
5500
  if ( self.menuType == "page" ) {
5316
- // TODO centralize page removal binding / handling in the page plugin.
5317
- // Suggestion from @jblas to do refcounting
5318
- //
5319
- // rebind the page remove that was unbound in the open function
5320
- // to allow for the parent page removal from actions other than the use
5321
- // of a dialog sized custom select
5322
- if( !self.thisPage.data("page").options.domCache ){
5323
- self.thisPage.bind( "pagehide.remove", function() {
5324
- $(self).remove();
5325
- });
5326
- }
5327
-
5328
5501
  // doesn't solve the possible issue with calling change page
5329
5502
  // where the objects don't define data urls which prevents dialog key
5330
5503
  // stripping - changePage has incoming refactor
@@ -5348,7 +5521,10 @@ $( document ).bind( "pagecreate create", function( e ){
5348
5521
  var self = this,
5349
5522
  menuHeight = self.list.parent().outerHeight(),
5350
5523
  menuWidth = self.list.parent().outerWidth(),
5351
- scrollTop = $( window ).scrollTop(),
5524
+ activePage = $( ".ui-page-active" ),
5525
+ tOverflow = $.support.touchOverflow && $.mobile.touchOverflowEnabled,
5526
+ tScrollElem = activePage.is( ".ui-native-fixed" ) ? activePage.find( ".ui-content" ) : activePage;
5527
+ scrollTop = tOverflow ? tScrollElem.scrollTop() : $( window ).scrollTop(),
5352
5528
  btnOffset = self.button.offset().top,
5353
5529
  screenHeight = window.innerHeight,
5354
5530
  screenWidth = window.innerWidth;
@@ -5461,7 +5637,7 @@ $( document ).bind( "pagecreate create", function( e ){
5461
5637
  self.select.find( "option" ).each( function( i ) {
5462
5638
  var $this = $( this ),
5463
5639
  $parent = $this.parent(),
5464
- text = $this.text(),
5640
+ text = $this.getEncodedText(),
5465
5641
  anchor = "<a href='#'>"+ text +"</a>",
5466
5642
  classes = [],
5467
5643
  extraAttrs = [];
@@ -5572,6 +5748,10 @@ $.widget( "mobile.selectmenu", $.mobile.widget, {
5572
5748
  },
5573
5749
 
5574
5750
  _theme: function(){
5751
+ if ( this.options.theme ){
5752
+ return this.options.theme;
5753
+ }
5754
+
5575
5755
  var themedParent, theme;
5576
5756
  // if no theme is defined, try to find closest theme container
5577
5757
  // TODO move to core as something like findCurrentTheme
@@ -5597,6 +5777,10 @@ $.widget( "mobile.selectmenu", $.mobile.widget, {
5597
5777
  }, 40);
5598
5778
  },
5599
5779
 
5780
+ _selectOptions: function() {
5781
+ return this.select.find( "option" );
5782
+ },
5783
+
5600
5784
  // setup items that are generally necessary for select menu extension
5601
5785
  _preExtension: function(){
5602
5786
  this.select = this.element.wrap( "<div class='ui-select'>" );
@@ -5604,7 +5788,6 @@ $.widget( "mobile.selectmenu", $.mobile.widget, {
5604
5788
  this.label = $( "label[for='"+ this.selectID +"']" ).addClass( "ui-select" );
5605
5789
  this.isMultiple = this.select[ 0 ].multiple;
5606
5790
  this.options.theme = this._theme();
5607
- this.selectOptions = this.select.find( "option" );
5608
5791
  },
5609
5792
 
5610
5793
  _create: function() {
@@ -5653,7 +5836,7 @@ $.widget( "mobile.selectmenu", $.mobile.widget, {
5653
5836
  this.buttonCount = $( "<span>" )
5654
5837
  .addClass( "ui-li-count ui-btn-up-c ui-btn-corner-all" )
5655
5838
  .hide()
5656
- .appendTo( button );
5839
+ .appendTo( button.addClass('ui-li-has-count') );
5657
5840
  }
5658
5841
 
5659
5842
  // Disable if specified
@@ -5695,14 +5878,14 @@ $.widget( "mobile.selectmenu", $.mobile.widget, {
5695
5878
  },
5696
5879
 
5697
5880
  selected: function() {
5698
- return this.selectOptions.filter( ":selected" );
5881
+ return this._selectOptions().filter( ":selected" );
5699
5882
  },
5700
5883
 
5701
5884
  selectedIndices: function() {
5702
5885
  var self = this;
5703
5886
 
5704
5887
  return this.selected().map( function() {
5705
- return self.selectOptions.index( this );
5888
+ return self._selectOptions().index( this );
5706
5889
  }).get();
5707
5890
  },
5708
5891
 
@@ -5734,6 +5917,11 @@ $.widget( "mobile.selectmenu", $.mobile.widget, {
5734
5917
  this.setButtonCount();
5735
5918
  },
5736
5919
 
5920
+ // open and close preserved in native selects
5921
+ // to simplify users code when looping over selects
5922
+ open: $.noop,
5923
+ close: $.noop,
5924
+
5737
5925
  disable: function() {
5738
5926
  this._setDisabled( true );
5739
5927
  this.button.addClass( "ui-disabled" );
@@ -5763,7 +5951,12 @@ $( document ).bind( "pagecreate create", function( e ){
5763
5951
  $.fn.buttonMarkup = function( options ) {
5764
5952
  return this.each( function() {
5765
5953
  var el = $( this ),
5766
- o = $.extend( {}, $.fn.buttonMarkup.defaults, el.jqmData(), options ),
5954
+ o = $.extend( {}, $.fn.buttonMarkup.defaults, {
5955
+ icon: el.jqmData( "icon" ),
5956
+ iconpos: el.jqmData( "iconpos" ),
5957
+ theme: el.jqmData( "theme" ),
5958
+ inline: el.jqmData( "inline" )
5959
+ }, options ),
5767
5960
 
5768
5961
  // Classes Defined
5769
5962
  innerClass = "ui-btn-inner",
@@ -5831,6 +6024,7 @@ $.fn.buttonMarkup.defaults = {
5831
6024
  corners: true,
5832
6025
  shadow: true,
5833
6026
  iconshadow: true,
6027
+ inline: false,
5834
6028
  wrapperEls: "span"
5835
6029
  };
5836
6030
 
@@ -5957,7 +6151,7 @@ $( document ).bind( "pagecreate create", function( e ){
5957
6151
  });
5958
6152
 
5959
6153
  })(jQuery);/*
5960
- * jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
6154
+ * jQuery Mobile Framework : "links" plugin - simple class additions for links
5961
6155
  * Copyright (c) jQuery Project
5962
6156
  * Dual licensed under the MIT or GPL Version 2 licenses.
5963
6157
  * http://jquery.org/license
@@ -5992,7 +6186,7 @@ var slideDownClass = "ui-header-fixed ui-fixed-inline fade",
5992
6186
 
5993
6187
  $.fn.fixHeaderFooter = function( options ) {
5994
6188
 
5995
- if ( !$.support.scrollTop ) {
6189
+ if ( !$.support.scrollTop || ( $.support.touchOverflow && $.mobile.touchOverflowEnabled ) ) {
5996
6190
  return this;
5997
6191
  }
5998
6192
 
@@ -6014,7 +6208,7 @@ $.fn.fixHeaderFooter = function( options ) {
6014
6208
  // single controller for all showing,hiding,toggling
6015
6209
  $.mobile.fixedToolbars = (function() {
6016
6210
 
6017
- if ( !$.support.scrollTop || $.support.touchOverflow ) {
6211
+ if ( !$.support.scrollTop || ( $.support.touchOverflow && $.mobile.touchOverflowEnabled ) ) {
6018
6212
  return;
6019
6213
  }
6020
6214
 
@@ -6328,9 +6522,6 @@ $.mobile.fixedToolbars = (function() {
6328
6522
  };
6329
6523
  })();
6330
6524
 
6331
- // TODO - Deprecated namepace on $. Remove in a later release
6332
- $.fixedToolbars = $.mobile.fixedToolbars;
6333
-
6334
6525
  //auto self-init widgets
6335
6526
  $( document ).bind( "pagecreate create", function( event ) {
6336
6527
 
@@ -6338,7 +6529,7 @@ $( document ).bind( "pagecreate create", function( event ) {
6338
6529
 
6339
6530
  $( event.target ).each(function() {
6340
6531
 
6341
- if ( !$.support.scrollTop || $.support.touchOverflow ) {
6532
+ if ( !$.support.scrollTop || ( $.support.touchOverflow && $.mobile.touchOverflowEnabled ) ) {
6342
6533
  return this;
6343
6534
  }
6344
6535
 
@@ -6369,8 +6560,12 @@ $( document ).bind( "pagecreate create", function( event ) {
6369
6560
 
6370
6561
  (function( $, undefined ) {
6371
6562
 
6563
+ // Enable touch overflow scrolling when it's natively supported
6372
6564
  $.mobile.touchOverflowEnabled = false;
6373
6565
 
6566
+ // Enabled zoom when touch overflow is enabled. Can cause usability issues, unfortunately
6567
+ $.mobile.touchOverflowZoomEnabled = false;
6568
+
6374
6569
  $( document ).bind( "pagecreate", function( event ) {
6375
6570
  if( $.support.touchOverflow && $.mobile.touchOverflowEnabled ){
6376
6571
 
@@ -6419,108 +6614,7 @@ $( document ).bind( "pagecreate", function( event ) {
6419
6614
  });
6420
6615
 
6421
6616
  })( jQuery );
6422
- /*
6423
- * jQuery Mobile Framework : resolution and CSS media query related helpers and behavior
6424
- * Copyright (c) jQuery Project
6425
- * Dual licensed under the MIT or GPL Version 2 licenses.
6426
- * http://jquery.org/license
6427
- */
6428
- (function( $, undefined ) {
6429
-
6430
- var $window = $( window ),
6431
- $html = $( "html" ),
6432
-
6433
- //media-query-like width breakpoints, which are translated to classes on the html element
6434
- resolutionBreakpoints = [ 320, 480, 768, 1024 ];
6435
-
6436
- /*
6437
- private function for adding/removing breakpoint classes to HTML element for faux media-query support
6438
- It does not require media query support, instead using JS to detect screen width > cross-browser support
6439
- This function is called on orientationchange, resize, and mobileinit, and is bound via the 'htmlclass' event namespace
6440
- */
6441
- function detectResolutionBreakpoints() {
6442
- var currWidth = $window.width(),
6443
- minPrefix = "min-width-",
6444
- maxPrefix = "max-width-",
6445
- minBreakpoints = [],
6446
- maxBreakpoints = [],
6447
- unit = "px",
6448
- breakpointClasses;
6449
-
6450
- $html.removeClass( minPrefix + resolutionBreakpoints.join(unit + " " + minPrefix) + unit + " " +
6451
- maxPrefix + resolutionBreakpoints.join( unit + " " + maxPrefix) + unit );
6452
-
6453
- $.each( resolutionBreakpoints, function( i, breakPoint ) {
6454
- if( currWidth >= breakPoint ) {
6455
- minBreakpoints.push( minPrefix + breakPoint + unit );
6456
- }
6457
- if( currWidth <= breakPoint ) {
6458
- maxBreakpoints.push( maxPrefix + breakPoint + unit );
6459
- }
6460
- });
6461
-
6462
- if ( minBreakpoints.length ) {
6463
- breakpointClasses = minBreakpoints.join(" ");
6464
- }
6465
- if ( maxBreakpoints.length ) {
6466
- breakpointClasses += " " + maxBreakpoints.join(" ");
6467
- }
6468
-
6469
- $html.addClass( breakpointClasses );
6470
- };
6471
-
6472
- /* $.mobile.addResolutionBreakpoints method:
6473
- pass either a number or an array of numbers and they'll be added to the min/max breakpoint classes
6474
- Examples:
6475
- $.mobile.addResolutionBreakpoints( 500 );
6476
- $.mobile.addResolutionBreakpoints( [500, 1200] );
6477
- */
6478
- $.mobile.addResolutionBreakpoints = function( newbps ) {
6479
- if( $.type( newbps ) === "array" ){
6480
- resolutionBreakpoints = resolutionBreakpoints.concat( newbps );
6481
- } else {
6482
- resolutionBreakpoints.push( newbps );
6483
- }
6484
-
6485
- resolutionBreakpoints.sort(function( a, b ) {
6486
- return a - b;
6487
- });
6488
-
6489
- detectResolutionBreakpoints();
6490
- };
6491
-
6492
- /* on mobileinit, add classes to HTML element
6493
- and set handlers to update those on orientationchange and resize
6494
- */
6495
- $( document ).bind( "mobileinit.htmlclass", function() {
6496
- // bind to orientationchange and resize
6497
- // to add classes to HTML element for min/max breakpoints and orientation
6498
-
6499
- var ev = $.support.orientation;
6500
-
6501
- $window.bind( "orientationchange.htmlclass throttledresize.htmlclass", function( event ) {
6502
-
6503
- // add orientation class to HTML element on flip/resize.
6504
- if ( event.orientation ) {
6505
- $html.removeClass( "portrait landscape" ).addClass( event.orientation );
6506
- }
6507
-
6508
- // add classes to HTML element for min/max breakpoints
6509
- detectResolutionBreakpoints();
6510
- });
6511
- });
6512
-
6513
- /* Manually trigger an orientationchange event when the dom ready event fires.
6514
- This will ensure that any viewport meta tag that may have been injected
6515
- has taken effect already, allowing us to properly calculate the width of the
6516
- document.
6517
- */
6518
- $(function() {
6519
- //trigger event manually
6520
- $window.trigger( "orientationchange.htmlclass" );
6521
- });
6522
-
6523
- })(jQuery);/*!
6617
+ /*!
6524
6618
  * jQuery Mobile v@VERSION
6525
6619
  * http://jquerymobile.com/
6526
6620
  *
@@ -6582,15 +6676,6 @@ $(function() {
6582
6676
  $html.removeClass( "ui-loading" );
6583
6677
  },
6584
6678
 
6585
- // XXX: deprecate for 1.0
6586
- pageLoading: function ( done ) {
6587
- if ( done ) {
6588
- $.mobile.hidePageLoadingMsg();
6589
- } else {
6590
- $.mobile.showPageLoadingMsg();
6591
- }
6592
- },
6593
-
6594
6679
  // find and enhance the pages in the dom and transition to the first page.
6595
6680
  initializePage: function() {
6596
6681
  // find present pages
@@ -6617,6 +6702,10 @@ $(function() {
6617
6702
  // define page container
6618
6703
  $.mobile.pageContainer = $pages.first().parent().addClass( "ui-mobile-viewport" );
6619
6704
 
6705
+ // alert listeners that the pagecontainer has been determined for binding
6706
+ // to events triggered on it
6707
+ $window.trigger( "pagecontainercreate" );
6708
+
6620
6709
  // cue page loading message
6621
6710
  $.mobile.showPageLoadingMsg();
6622
6711
 
@@ -6630,6 +6719,24 @@ $(function() {
6630
6719
  }
6631
6720
  }
6632
6721
  });
6722
+
6723
+ // This function injects a meta viewport tag to prevent scaling. Off by default, on by default when touchOverflow scrolling is enabled
6724
+ function disableZoom() {
6725
+ var cont = "user-scalable=no",
6726
+ meta = $( "meta[name='viewport']" );
6727
+
6728
+ if( meta.length ){
6729
+ meta.attr( "content", meta.attr( "content" ) + ", " + cont );
6730
+ }
6731
+ else{
6732
+ $( "head" ).prepend( "<meta>", { "name": "viewport", "content": cont } );
6733
+ }
6734
+ }
6735
+
6736
+ // if touch-overflow is enabled, disable user scaling, as it creates usability issues
6737
+ if( $.support.touchOverflow && $.mobile.touchOverflowEnabled && !$.mobile.touchOverflowZoomEnabled ){
6738
+ disableZoom();
6739
+ }
6633
6740
 
6634
6741
  // initialize events now, after mobileinit has occurred
6635
6742
  $.mobile._registerInternalEvents();