diff --git a/docs/forms/docs-forms.html b/docs/forms/docs-forms.html index df42b651..11b429f8 100755 --- a/docs/forms/docs-forms.html +++ b/docs/forms/docs-forms.html @@ -1,15 +1,15 @@ - - + + - - jQuery Mobile Docs - Forms - + + jQuery Mobile Docs - Forms + - - + +
@@ -18,13 +18,13 @@
- +

jQuery Mobile provides a complete set of finger-friendly form elements that are based on native HTML form elements.

- +

Form structure

- +

All forms should be wrapped in a form tag that has an action and method that will handle the form data processing on the server.

- + <form action="form.php" method="post"> ... @@ -37,10 +37,10 @@

Auto-initialization of form elements

By default, jQuery Mobile will automatically enhance certain native form controls into rich touch-friendly components. This is handled internally by finding form elements by tag name and running a plugin method on them, so for instance, a select element will be found and initialized with the "selectmenu" plugin, while an input element with a type="checkbox" will be enhanced with the "checkboxradio" plugin. Once initialized, you can address these enhanced components programmatically through their jQuery UI widget API methods (see documentation on available methods here: Form Plugin Methods).

- +

Preventing auto-initialization of form elements

If you'd prefer that a particular form control be left untouched by jQuery Mobile, simply give that element the attribute data-role="none". For example:

-
				
+	

 <label for="foo">
 <select name="foo" id="foo" data-role="none">
 	<option value="a" >A</option>
@@ -48,34 +48,36 @@
 	<option value="c" >C</option>
 </select>
 
- - + +

Or, if you'd like to prevent auto-initialization without adding attributes to your markup, you can customize the selector that is used for preventing auto-initialization by setting the page plugin's keepNative option (which defaults to "[data-role="none"]. Be sure to configure this option inside an event handler bound to the mobileinit event, so that it applies to the first page as well as subsequent pages that are loaded.


 $(document).bind('mobileinit',function(){
 	$.mobile.page.prototype.options.keepNative = "select, input.foo, textarea.bar";
-});	
+});
 		
- + +

One special case is that of selects. The above sample will prevent any and all augmentation from taking place on select elements in the page if select is included. If you wish to retain the native performance, look/feel of the menu itself and benefit from the visual augmentation of the select button by jQuery Mobile you can set $.mobile.nativeSelectMenu to true in a mobileinit callback as a global setting or use data-native="true" on a case by case basis.

+

Dynamic form layout

In jQuery Mobile, all form elements are designed to be a flexible width so they will comfortably fit the width of any mobile device. One optimization built into the framework is that we present labels and form elements differently based on screen width.

-

If a page is fairly narrow (~480px), the labels are styled as block-level elements so they will stack on top of the form element to save horizontal space.

+

If a page is fairly narrow (~480px), the labels are styled as block-level elements so they will stack on top of the form element to save horizontal space.

On wider screens, the labels and form elements are styled to be on the same line in a 2-column layout to take advantage of the screen real estate.

Field containers

- +

To improve the styling to labels and form elements on wider screens, we recommend wrapping a div or fieldset with the data-role="fieldcontain" attribute around each label/form element. The framework will add a thin vertical bottom border on this container to act as a field separator and visually align the label and form elements for quick scanning.

-
				
+

 <div data-role="fieldcontain">
 	...label/input code goes here...
 </div>
 
- - + +
- \ No newline at end of file + diff --git a/docs/forms/forms-all.html b/docs/forms/forms-all.html index cc116b03..665988fb 100755 --- a/docs/forms/forms-all.html +++ b/docs/forms/forms-all.html @@ -1,14 +1,14 @@ - - + + - - jQuery Mobile Docs - Forms - + + jQuery Mobile Docs - Forms + - - + +
@@ -17,43 +17,43 @@
- +
- +

Form elements

This page contains various progressive-enhancement driven form controls. Native elements are sometimes hidden from view, but their values are maintained so the form can be submitted normally.

- +

Browsers that don't support the custom controls will still deliver a usable experience, because all are based on native form elements.

- +
- +
- +
+
- +
- +
Choose as many snacks as you'd like: @@ -62,7 +62,7 @@ - + @@ -70,7 +70,7 @@
- +
Font styling: @@ -81,10 +81,10 @@ - +
- +
Choose a pet: @@ -101,7 +101,7 @@
- +
Layout view: @@ -113,7 +113,7 @@
- +
- +
+
+ + +
-
+
- +
- \ No newline at end of file + diff --git a/docs/forms/forms-selects.html b/docs/forms/forms-selects.html index 7c9f32a8..c6259f3b 100644 --- a/docs/forms/forms-selects.html +++ b/docs/forms/forms-selects.html @@ -1,15 +1,15 @@ - - + + - - jQuery Mobile Docs - Forms - + + jQuery Mobile Docs - Forms + - - + +
@@ -18,19 +18,19 @@
- +

Select menus

- +

The select menus are driven off native select elements, but the native selects are hidden from view and replaced with more style-friendly markup. The replacement buttons and menus are ARIA-enabled and are keyboard accessible on the desktop as well.

When clicked, if the menu has room it will appear as an overlay listbox, but if there are too many options to fit in the window without scrolling, the page content is wrapped in a div and hidden, and the menu is appended as a whole new page. This lets us take advantage of native scrolling while the menu is in use.

- +

To add a select widget to your page, start with a standard select element populated with a set of option elements. Set the for attribute of the label to match the ID of the select so they are semantically associated. Wrap them in a div with the data-role="fieldcontain" attribute to help visually group it in a longer form.

- +

The framework will find all select elements and automatically enhance them into the custom select menus.

-
	
+

 <div data-role="fieldcontain">
 	<label for="select-choice-1" class="select">Choose shipping method:</label>
 	<select name="select-choice-1" id="select-choice-1">
@@ -41,7 +41,7 @@
 	</select>
 </div>
 
- +

If there is a small number of options that will fit on the device's screen, it will appear as a small overlay with a pop transition.

@@ -114,36 +114,95 @@
-

Data attribute support

-

You can specify any jQuery Mobile button data- attribute on a select element too.

- -
- - -
- - + +

Option to use native menus

+

The custom select menus add the ability to theme the select and provide visual consistency across platforms In addition, it fixes over some missing functionality on certain platforms: optgroup support on Android, multi-select capability on WebOS, and adds an elegant way to handle placeholder values (explained below).

+

However, there is overhead involved in parsing the native select to build a custom menu and if the number of selects or options within are fairly large, this can impact the performance of the page. By adding the data-native="true" attribute to the select, the framework will use the browser's native select menu when the select button is clicked. Because this option doesn't use any of the custom menu parsing and menu generation logic, it is significantly faster than the custom menu version.

+ +

You can also set the global configuration $.mobile.nativeSelectMenus to true in a callback bound to the mobileinit event to achieve the same effect. The following must be included in the page after jQuery is loaded but before jQuery Mobile.

+ + +
+$(document).bind('mobileinit',function(){
+	$.mobile.nativeSelectMenus = true;
+});
+				
+
+ +
+ + +
+

Placeholder options

-

It's common for developers to include a "null" option in their select element to force a user to choose an option. If a placeholder option is present in your markup, jQuery Mobile will hide them in the overlay menu, showing only valid choices to the user, and display the placeholder text inside the menu as a header. Examples of null options are either:

+

It's common for developers to include a "null" option in their select element to force a user to choose an option. If a placeholder option is present in your markup, jQuery Mobile will hide them in the overlay menu, showing only valid choices to the user, and display the placeholder text inside the menu as a header. A placeholder option is added when the framework finds:

  • An option with no value attribute (or an empty value attribute)
  • An option with no text node
  • An option with a data-placeholder="true" attribute. (This allows you to use an option that has a value and a textnode as a placeholder option).
- +

You can disable this feature through the selectmenu plugin's hidePlaceholderMenuItems option, like this:

 	
 $.mobile.selectmenu.prototype.options.hidePlaceholderMenuItems = false;
 	
 	
- +

Here's a demo of various placeholder options:

- - + +
-
- - +
+ +
- - + +
- +

Disabled options

jQuery Mobile will automatically disable and style option tags with the disabled attribute. In the demo below, the second option "Rush: 3 days" has been set to disabled.

@@ -191,7 +250,7 @@ $.mobile.selectmenu.prototype.options.hidePlaceholderMenuItems = false; - +

Optgroup support

If a select menu contains optgroup elements, jQuery Mobile will create a divider & group items based on the label attribute's text:

@@ -211,11 +270,11 @@ $.mobile.selectmenu.prototype.options.hidePlaceholderMenuItems = false; - - + +

Multiple selects

If the multiple attribute is present in your markup, jQuery Mobile will enhance the element with a few extra considerations:

- +
  • A header element will be created inside the menu and display the placeholder text and a close button.
  • Clicking on an item inside the overlay menu will not close the widget.
  • @@ -225,7 +284,7 @@ $.mobile.selectmenu.prototype.options.hidePlaceholderMenuItems = false;
  • If no items are selected, the button's text will default to the placeholder text.
  • If no placeholder element exists, the default button text will be blank and the header will appear with just a close button. Because this isn't a friendly user experience, we recommended that you always specify a placeholder element when using multiple select boxes.
- +
- +

When a select is large enough to where the menu will open in a new page, the placeholder text is displayed in the button when no items are selected, and the label text is displayed in the menu's header. This differs from smaller overlay menus where the placeholder text is displayed in both the button and the header, and from full-page single selects where the placeholder text is not used at all.

- +
+ + + +

Data attribute support

+

You can specify any jQuery Mobile button data- attribute on a select element too. In this example, we're setting the theme, icon and inline properties though data- attributes.

+ +
+ + +
diff --git a/docs/forms/index.html b/docs/forms/index.html index 8c8cfe17..5d88d6a6 100755 --- a/docs/forms/index.html +++ b/docs/forms/index.html @@ -33,8 +33,13 @@
  • Theming forms
  • Submitting forms
  • Plugin methods
  • - + + + diff --git a/docs/pages/docs-navmodel.html b/docs/pages/docs-navmodel.html index 8faa5cb1..1cac0dd4 100644 --- a/docs/pages/docs-navmodel.html +++ b/docs/pages/docs-navmodel.html @@ -22,7 +22,7 @@

    A "page" in jQuery Mobile consists of an element (usually a div) with a data-role attribute set to "page", which generally contains div elements with roles of "header", "content", and "footer", each containing common markup, forms, and custom jQuery Mobile widgets.

    -

    The basic workflow with page loading is as follows: first, a page is requested with a normal HTTP request, and subsequent "pages" are then requested and injected into that page's DOM. Because of this, the DOM may have a number of "pages" in it at a time, each of which can be re-visited by linking to its ID attribute.

    +

    The basic workflow with page loading is as follows: first, a page is requested with a normal HTTP request, and subsequent "pages" are then requested and injected into that page's DOM. Because of this, the DOM may have a number of "pages" in it at a time, each of which can be re-visited by linking to its data-url attribute.

    When a url is initially requested, there may be one or more "pages" in the response, and only the first one will be shown. The advantage of storing more than one "page" is that it allows you to pre-fetch static pages that are likely to be visited.

    @@ -52,31 +52,20 @@

    jQuery Mobile manages http requests using a combination of generated absolute URL paths and manipulating a generated <base> element's href attribute. The combination of these two approaches allows us to create URLs that contain full path information for loading pages, and a base element to properly direct asset requests made by those loaded pages (such as images and stylesheets).

    -

    jQuery Mobile core contains 4 internal functions for manipulating a base url to be used in normalizing relative http requests:

    -

    Note: These functions have changed - docs will be updated soon!

    -
      -
    • getPathDir: function that returns a path with the last "/"-split segment removed (which is assumed to be a file url).

    • -
    • getBaseURL: function that returns either the location.hash, or a path specified via its argument, with the last segment removed.

    • -
    • setBaseURL: sets the <base> element's href attribute to the value of getBaseURL()

    • -
    • resetBaseURL: sets the <base> element's href attribute to the relative path of the initially-http-requested page.

    • -

    These are called at certain times during page requests and transitions: - On DOM ready, during the initial page load, a <base> element is created and appended to the <head> of the page. Immediately after that, resetBaseURL() is called to set the <base> element's href to location.pathname.

    - -

    Whenever a link with a relative URL is clicked, the $.mobile.changePage() function will prefixed that link's href with the value of getBaseURL(), which creates a full path to that file, relative to the document.

    - -

    Changing the hash value triggers the hashchange event handler, which first calls resetBaseURL(), and makes an Ajax request to the value of the hash (which is already a full path, requiring no base url). After that request is sent, setBaseURL() is called, which resets the <base> element's href attribute to the value of getBaseURL() and allows any references to images, stylesheets, and scripts within that page to be requested with a proper base path.

    +

    TODO: update description of internal base and urlHistory objects

    +

    Auto-generated pages and sub-hash urls

    -

    Some plugins may choose to dynamically break a page's content into separate navigable pages, which can then be reached via deep links. One example of this would be the Listview plugin, which will break a nested UL (or OL) into separate pages, which are each given an ID so they can be linked to like any normal "page" in jQuery Mobile. However, in order to link to these pages, the page that generates them must first be requested from the server. To make this work, pages that are auto-generated by plugins use the following special ID structure: - <div id="page.html&subpageidentifier">

    +

    Some plugins may choose to dynamically break a page's content into separate navigable pages, which can then be reached via deep links. One example of this would be the Listview plugin, which will break a nested UL (or OL) into separate pages, which are each given a data-url attribute so they can be linked to like any normal "page" in jQuery Mobile. However, in order to link to these pages, the page that generates them must first be requested from the server. To make this work, pages that are auto-generated by plugins use the following special data-url structure: + <div data-url="page.html&subpageidentifier">

    -

    So, for example, a page generated by the listview plugin may have an ID like this: id="artists.html&ui-page=listview-1"

    +

    So, for example, a page generated by the listview plugin may have an data-url attribute like this: data-url="artists.html&ui-page=listview-1"

    When a page is requested, jQuery Mobile knows to split the URL at "&ui-page" and make an HTTP request to the portion of the URL before that key. In the case of the listview example mentioned above, the URL would look like this: http://example.com/artists.html&ui-page=listview-1 - ...and jQuery Mobile would request artists.html, which would then generate its sub-pages, creating the div with id="artists.html&ui-page=listview-1", which it will then display as the active page.

    + ...and jQuery Mobile would request artists.html, which would then generate its sub-pages, creating the div with data-url="artists.html&ui-page=listview-1", which it will then display as the active page.

    -

    Note that the ID of the element contains the full URL path, not just the portion after &ui-page=. This allows jQuery Mobile to use a single consistent mechanism that matches URLs to page IDs.

    +

    Note that the data-url attribute of the element contains the full URL path, not just the portion after &ui-page=. This allows jQuery Mobile to use a single consistent mechanism that matches URLs to page data-url attributes.

    Cases when Ajax navigation will not be used

    @@ -96,7 +85,7 @@
    • When linking to directories, without a filename url, (such as href="typesofcats/" instead of href="typesofcats/index.html"), you must provide a trailing slash. This is because jQuery Mobile assumes the section after the last "/" character in a url is a filename, and it will remove that section when creating base urls from which future pages will be referenced.

    • -
    • Any unique assets referenced by pages in a jQuery Mobile-driven site should be placed inside the "page" element (the element with a data-role attribute of "page"). For example, links to styles and scripts that are specific to a particular page can be referenced inside that div. However, a better approach is to use jQuery Mobile's page events to trigger specific scripting when certain pages load.

    • +
    • Any unique assets referenced by pages in a jQuery Mobile-driven site should be placed inside the "page" element (the element with a data-role attribute of "page"). For example, links to styles and scripts that are specific to a particular page can be referenced inside that div. However, a better approach is to use jQuery Mobile's page events to trigger specific scripting when certain pages load. Note: you can return a page from the server with a data-url already specified in the markup, and jQuery Mobile will use that for the hash update. This allows you to ensure directory paths resolve with a trailing slash and will therefore be used in the base url path for future requests.

    • Conversely, any non-unique assets (those used site-wide) should be referenced in the <head> section of an HTML document, or at the very least, outside of the "page" element, to prevent running scripts more than once.

    • The "ui-page" key name used in sub-hash url references can be set to any value you'd like, so as to blend into your URL structure. This value is stored in jQuery.mobile.subPageUrlKey.

    diff --git a/experiments/progressbar/_progressbar-static.html b/experiments/progressbar/_progressbar-static.html deleted file mode 100644 index 9934054a..00000000 --- a/experiments/progressbar/_progressbar-static.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - jQuery Mobile Framework - Static Progressbar Example - - - - - - -
    -
    -

    Static Progressbar

    - -
    - -
    - -

    Just a simple static progressbar, for future reference.

    - - - -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/experiments/ui-datepicker/index.html b/experiments/ui-datepicker/index.html index 4f3e36e9..68ca44fd 100644 --- a/experiments/ui-datepicker/index.html +++ b/experiments/ui-datepicker/index.html @@ -5,67 +5,71 @@ jQuery Mobile Framework - Datepicker - - + + + + + +
    - - - - - - -
    -

    Datepicker Styled for mobile

    +

    jQuery UI's Datepicker Styled for mobile

    - - +

    The included files extend the jQuery UI datepicker to make it suitable for touch devices. This plugin is not included in jQuery Mobile by default, so you'll need to include the files yourself if you'd like to use them. Scroll down for usage instructions.

    +
    -
    -
    - - +
    + + +

    Usage Instructions

    + +

    The datepicker auto-generates from a regular input element with a type="date" attribute.

    + +
    
    +<label for="date">Date Input:</label>
    +<input type="date" name="date" id="date" value=""  />		
    +		
    + +

    We'd recommend wrapping the label and input in a fieldcontain div for presentation purposes, and these elements should be placed within a form element for C-Grade browser accessibility.

    + +

    Note: This plugin is not included in jQuery Mobile by default, so you'll need to include the following files in order to use it:

    + +
    
    +  <link rel="stylesheet" href="jquery.ui.datepicker.mobile.css" /> 
    +  <script src="jQuery.ui.datepicker.js"></script>
    +  <script src="jquery.ui.datepicker.mobile.js"></script>
    +
    + +

    You'll also want to configure the page plugin to convert "date" input elements to "text" inputs after they're enhanced with our datepicker, so that no native datepicker will conflict with the custom one we're adding. To do this, bind to the "mobileinit" event and set input types of "date" back to text using the page plugin's options:

    +
    	
    +<script>
    +  //reset type=date inputs to text
    +  $( document ).bind( "mobileinit", function(){
    +    $.mobile.page.prototype.options.degradeInputs.date = true;
    +  });	
    +</script>	
    +
    + +

    Be sure to place this event binding in a script that loads after jQuery, but before jQuery Mobile. Check this page's source for an example.

    + + + +
    diff --git a/experiments/ui-datepicker/jquery.ui.datepicker.css b/experiments/ui-datepicker/jquery.ui.datepicker.mobile.css old mode 100755 new mode 100644 similarity index 80% rename from experiments/ui-datepicker/jquery.ui.datepicker.css rename to experiments/ui-datepicker/jquery.ui.datepicker.mobile.css index 91b2e9a9..c9853a6c --- a/experiments/ui-datepicker/jquery.ui.datepicker.css +++ b/experiments/ui-datepicker/jquery.ui.datepicker.mobile.css @@ -12,8 +12,8 @@ div.hasDatepicker{ display: block; padding: 0; overflow: visible; margin: 8px 0 .ui-datepicker .ui-datepicker-header { position:relative; padding:.4em 0; border-bottom: 0; font-weight: bold; } .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { padding: 1px 0 1px 2px; position:absolute; top: .5em; margin-top: 0; text-indent: -9999px; } -.ui-datepicker .ui-datepicker-prev { left:2px; } -.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev { left:6px; } +.ui-datepicker .ui-datepicker-next { right:6px; } .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } .ui-datepicker select.ui-datepicker-month-year {width: 100%;} @@ -23,6 +23,10 @@ div.hasDatepicker{ display: block; padding: 0; overflow: visible; margin: 8px 0 .ui-datepicker td { border-width: 1px; padding: 0; text-align: center; } .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em 0; font-weight: bold; margin: 0; border-width: 0; text-align: center; text-decoration: none; } +.ui-datepicker-calendar th { padding-top: .3em; padding-bottom: .3em; } +.ui-datepicker-calendar th span, .ui-datepicker-calendar span.ui-state-default { opacity: .3; } +.ui-datepicker-calendar td a { padding-top: .5em; padding-bottom: .5em; } + .min-width-480px { div.hasDatepicker { width: 63%; display: inline-block; margin: 0; } } \ No newline at end of file diff --git a/experiments/ui-datepicker/jquery.ui.datepicker.mobile.js b/experiments/ui-datepicker/jquery.ui.datepicker.mobile.js new file mode 100644 index 00000000..9f1e168e --- /dev/null +++ b/experiments/ui-datepicker/jquery.ui.datepicker.mobile.js @@ -0,0 +1,55 @@ +/* +* jQuery Mobile Framework : temporary extension to port jQuery UI's datepicker for mobile +* Copyright (c) jQuery Project +* Dual licensed under the MIT or GPL Version 2 licenses. +* http://jquery.org/license +*/ +(function($, undefined ) { + + //cache previous datepicker ui method + var prevDp = $.fn.datepicker; + + //rewrite datepicker + $.fn.datepicker = function( options ){ + + var dp = this; + + //call cached datepicker plugin + prevDp.call( this, options ); + + //extend with some dom manipulation to update the markup for jQM + //call immediately + function updateDatepicker(){ + $( ".ui-datepicker-header", dp ).addClass("ui-body-c ui-corner-top").removeClass("ui-corner-all"); + $( ".ui-datepicker-prev, .ui-datepicker-next", dp ).attr("href", "#"); + $( ".ui-datepicker-prev", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-l", shadow: true, corners: true}); + $( ".ui-datepicker-next", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-r", shadow: true, corners: true}); + $( ".ui-datepicker-calendar th", dp ).addClass("ui-bar-c"); + $( ".ui-datepicker-calendar td", dp ).addClass("ui-body-c"); + $( ".ui-datepicker-calendar a", dp ).buttonMarkup({corners: false, shadow: false}); + $( ".ui-datepicker-calendar a.ui-state-active", dp ).addClass("ui-btn-active"); // selected date + $( ".ui-datepicker-calendar a.ui-state-highlight", dp ).addClass("ui-btn-up-e"); // today"s date + $( ".ui-datepicker-calendar .ui-btn", dp ).each(function(){ + var el = $(this); + // remove extra button markup - necessary for date value to be interpreted correctly + el.html( el.find( ".ui-btn-text" ).text() ); + }); + }; + + //update now + updateDatepicker(); + + // and on click + $( dp ).click( updateDatepicker ); + + //return jqm obj + return this; + }; + + //bind to pagecreate to automatically enhance date inputs + $( ".ui-page" ).live( "pagecreate", function(){ + $( "input[type='date'], input[data-type='date']" ).each(function(){ + $(this).after( $( "
    " ).datepicker({ altField: "#" + $(this).attr( "id" ), showOtherMonths: true }) ); + }); + }); +})( jQuery ); \ No newline at end of file diff --git a/js/jquery.mobile.core.js b/js/jquery.mobile.core.js index 4464da24..348564a6 100644 --- a/js/jquery.mobile.core.js +++ b/js/jquery.mobile.core.js @@ -29,14 +29,14 @@ //automatically handle clicks and form submissions through Ajax, when same-domain ajaxEnabled: true, - - // TODO: deprecated - remove at 1.0 - //automatically handle link clicks through Ajax, when possible - ajaxLinksEnabled: true, - // TODO: deprecated - remove at 1.0 - //automatically handle form submissions through Ajax, when possible - ajaxFormsEnabled: true, + // TODO: deprecated - remove at 1.0 + //automatically handle link clicks through Ajax, when possible + ajaxLinksEnabled: true, + + // TODO: deprecated - remove at 1.0 + //automatically handle form submissions through Ajax, when possible + ajaxFormsEnabled: true, //set default transition - 'none' for no transitions defaultTransition: 'slide', @@ -48,6 +48,8 @@ //configure meta viewport tag's content attr: metaViewportContent: "width=device-width, minimum-scale=1, maximum-scale=1", + nativeSelectMenus: false, + //support conditions that must be met in order to proceed gradeA: function(){ return $.support.mediaquery; diff --git a/js/jquery.mobile.dialog.js b/js/jquery.mobile.dialog.js index b87aa537..d7229f6c 100644 --- a/js/jquery.mobile.dialog.js +++ b/js/jquery.mobile.dialog.js @@ -49,7 +49,7 @@ $.widget( "mobile.dialog", $.mobile.widget, { } }) //destroy the dialog after hiding - .bind("pagehide",function(){ + .bind("pagehide.dialog",function(){ self.destroy(); $(this).remove(); }); diff --git a/js/jquery.mobile.forms.select.js b/js/jquery.mobile.forms.select.js index f892cddf..b4eaa1e1 100644 --- a/js/jquery.mobile.forms.select.js +++ b/js/jquery.mobile.forms.select.js @@ -18,7 +18,8 @@ $.widget( "mobile.selectmenu", $.mobile.widget, { menuPageTheme: 'b', overlayTheme: 'a', hidePlaceholderMenuItems: true, - closeText: 'Close' + closeText: 'Close', + useNativeMenu: false }, _create: function(){ @@ -27,7 +28,6 @@ $.widget( "mobile.selectmenu", $.mobile.widget, { o = this.options, select = this.element - .attr( "tabindex", "-1" ) .wrap( "
    " ), selectID = select.attr( "id" ), @@ -115,6 +115,9 @@ $.widget( "mobile.selectmenu", $.mobile.widget, { menuType; + // set to native menu + o.useNativeMenu = $.mobile.nativeSelectMenus || select.is( "[data-native]" ); + // add counter for multi selects if( isMultiple ){ self.buttonCount = $('') @@ -155,43 +158,72 @@ $.widget( "mobile.selectmenu", $.mobile.widget, { select .change(function(){ self.refresh(); - }) - .focus(function(){ - $(this).blur(); - button.focus(); }); - //button events - button - .bind( "touchstart" ,function( event ){ - //set startTouches to cached copy of - $( this ).data( "startTouches", $.extend({}, event.originalEvent.touches[ 0 ]) ); - }) - .bind( $.support.touch ? "touchend" : "mouseup" , function( event ){ - //if it's a scroll, don't open - if( $( this ).data( "moved" ) ){ - $( this ).removeData( "moved" ); - } - else{ - self.open(); - } - event.preventDefault(); - }) - .bind( "touchmove", function( event ){ - //if touch moved enough, set data moved and don't open menu - var thisTouches = event.originalEvent.touches[ 0 ], + //unbind dialog destroy on close + menuPage.unbind("pagehide.dialog"); + + //support for using the native select menu with a custom button + if( o.useNativeMenu ){ + + select + .appendTo(button) + .bind( "touchstart mousedown", function( e ){ + //add active class to button + button.addClass( $.mobile.activeBtnClass ); + + //ensure button isn't clicked + e.stopPropagation(); + }) + .bind( "focus mouseover", function(){ + button.trigger( "mouseover" ); + }) + .bind( "blur mouseout", function(){ + button + .trigger( "mouseout" ) + .removeClass( $.mobile.activeBtnClass ); + }); + + button.attr( "tabindex", "-1" ); + } else { + + select + .attr( "tabindex", "-1" ) + .focus(function(){ + $(this).blur(); + button.focus(); + }); + + //button events + button + .bind( "touchstart" , function( event ){ + //set startTouches to cached copy of + $( this ).data( "startTouches", $.extend({}, event.originalEvent.touches[ 0 ]) ); + }) + .bind( $.support.touch ? "touchend" : "mouseup" , function( event ){ + //if it's a scroll, don't open + if( $( this ).data( "moved" ) ){ + $( this ).removeData( "moved" ); + } else { + self.open(); + } + event.preventDefault(); + }) + .bind( "touchmove", function( event ){ + //if touch moved enough, set data moved and don't open menu + var thisTouches = event.originalEvent.touches[ 0 ], startTouches = $( this ).data( "startTouches" ), deltaX = Math.abs(thisTouches.pageX - startTouches.pageX), deltaY = Math.abs(thisTouches.pageY - startTouches.pageY); - if( deltaX > 10 || deltaY > 10 ){ - $( this ).data( "moved", true ); - } - }); + if( deltaX > 10 || deltaY > 10 ){ + $( this ).data( "moved", true ); + } + }); + } //events for list items list.delegate("li:not(.ui-disabled, .ui-li-divider)", "click", function(event){ - // clicking on the list item fires click on the link in listview.js. // to prevent this handler from firing twice if the link isn't clicked on, // short circuit unless the target is the link @@ -224,16 +256,19 @@ $.widget( "mobile.selectmenu", $.mobile.widget, { }); //events on "screen" overlay + close button - screen.add( headerClose ).add( menuPageClose ).click(function(event){ - self.close(); - event.preventDefault(); + screen + .add( headerClose ) + .add( menuPageClose ) + .bind("click", function(event){ + self.close(); + event.preventDefault(); - // if the dialog's close icon was clicked, prevent the dialog's close - // handler from firing. selectmenu's should take precedence - if( $.contains(menuPageClose[0], event.target) ){ - event.stopImmediatePropagation(); - } - }); + // if the dialog's close icon was clicked, prevent the dialog's close + // handler from firing. selectmenu's should take precedence + if( $.contains(menuPageClose[0], event.target) ){ + event.stopImmediatePropagation(); + } + }); }, _buildList: function(){ @@ -421,10 +456,15 @@ $.widget( "mobile.selectmenu", $.mobile.widget, { focusMenuItem(); } + + // wait before the dialog can be closed + setTimeout(function(){ + self.isOpen = true; + }, 400); }, close: function(){ - if( this.options.disabled ){ return; } + if( this.options.disabled || !this.isOpen ){ return; } var self = this; function focusButton(){ @@ -448,6 +488,8 @@ $.widget( "mobile.selectmenu", $.mobile.widget, { focusButton(); } + // allow the dialog to be closed again + this.isOpen = false; }, disable: function(){ diff --git a/js/jquery.mobile.media.js b/js/jquery.mobile.media.js index 7c0dbde0..c1762643 100644 --- a/js/jquery.mobile.media.js +++ b/js/jquery.mobile.media.js @@ -105,6 +105,14 @@ $(document).bind("mobileinit.htmlclass", function(){ //add orientation class to HTML element on flip/resize. if(event.orientation){ $html.removeClass( "portrait landscape" ).addClass( event.orientation ); + //Set the min-height to the size of the fullscreen. This is to fix issue #455 + if( event.orientation === 'portrait' ) { + $( '.ui-page' ).css( 'minHeight', ( screen.availHeight >= screen.availWidth ) ? screen.availHeight : screen.availWidth); + } else { + $( '.ui-page' ).css( 'minHeight', ( screen.availHeight <= screen.availWidth ) ? screen.availHeight : screen.availWidth); + } + + $.mobile.silentScroll(); } //add classes to HTML element for min/max breakpoints detectResolutionBreakpoints(); diff --git a/js/jquery.mobile.navigation.js b/js/jquery.mobile.navigation.js index 957cf713..72158554 100644 --- a/js/jquery.mobile.navigation.js +++ b/js/jquery.mobile.navigation.js @@ -299,6 +299,10 @@ isFormRequest = true; //make get requests bookmarkable if( data && type == 'get' ){ + if($.type( data ) == "object" ){ + data = $.param(data); + } + url += "?" + data; data = undefined; } @@ -318,6 +322,7 @@ //function for transitioning between two existing pages function transitionPages() { + $.mobile.silentScroll(); //get current scroll distance var currScroll = $window.scrollTop(), @@ -337,9 +342,6 @@ to.data("page")._trigger("beforeshow", {prevPage: from}); function loadComplete(){ - $.mobile.pageLoading( true ); - - reFocus( to ); if( changeHash !== false && url ){ if( !back ){ @@ -356,8 +358,9 @@ removeActiveLinkClass(); - //jump to top or prev scroll, if set - $.mobile.silentScroll( to.data( 'lastScroll' ) ); + //jump to top or prev scroll, sometimes on iOS the page has not rendered yet. I could only get by this with a setTimeout, but would like to avoid that. + $.mobile.silentScroll( to.data( 'lastScroll' ) ); + reFocus( to ); //trigger show/hide events, allow preventing focus change through return false from.data("page")._trigger("hide", null, {nextPage: to}); @@ -387,16 +390,21 @@ if(transition && (transition !== 'none')){ + $.mobile.pageLoading( true ); if( $.inArray(transition, perspectiveTransitions) >= 0 ){ addContainerClass('ui-mobile-viewport-perspective'); } addContainerClass('ui-mobile-viewport-transitioning'); - // animate in / out - from.addClass( transition + " out " + ( reverse ? "reverse" : "" ) ); + /* animate in / out + * This is in a setTimeout because we were often seeing pages in not animate across but rather go straight to + * the 'to' page. The loadComplete would still fire, so the browser thought it was applying the animation. From + * what I could tell this was a problem with the classes not being applied yet. + */ + setTimeout(function() { from.addClass( transition + " out " + ( reverse ? "reverse" : "" ) ); to.addClass( $.mobile.activePageClass + " " + transition + - " in " + ( reverse ? "reverse" : "" ) ); + " in " + ( reverse ? "reverse" : "" ) ); } , 0); // callback - remove classes, etc to.animationComplete(function() { @@ -407,6 +415,7 @@ }); } else{ + $.mobile.pageLoading( true ); from.removeClass( $.mobile.activePageClass ); to.addClass( $.mobile.activePageClass ); loadComplete(); diff --git a/js/jquery.mobile.page.js b/js/jquery.mobile.page.js index 581db802..74d6548c 100644 --- a/js/jquery.mobile.page.js +++ b/js/jquery.mobile.page.js @@ -37,6 +37,12 @@ $.widget( "mobile.page", $.mobile.widget, { if ( this._trigger( "beforeCreate" ) === false ) { return; } + + if( $( "html" ).hasClass( 'portrait' ) ) { + $elem.css( 'minHeight', ( screen.availHeight >= screen.availWidth ) ? screen.availHeight : screen.availWidth); + } else { + $elem.css( 'minHeight', ( screen.availHeight <= screen.availWidth ) ? screen.availHeight : screen.availWidth); + } //some of the form elements currently rely on the presence of ui-page and ui-content // classes so we'll handle page and content roles outside of the main role processing @@ -75,15 +81,10 @@ $.widget( "mobile.page", $.mobile.widget, { // auto-add back btn on pages beyond first view if ( o.addBackBtn && role === "header" && - ($.mobile.urlHistory.getPrev() || $(".ui-page").length > 1) && + $.mobile.urlHistory.stack.length > 0 && !leftbtn && $this.data( "backbtn" ) !== false ) { - $( ""+ o.backBtnText +"" ) - .click(function() { - history.back(); - return false; - }) - .prependTo( $this ); + $( ""+ o.backBtnText +"" ).prependTo( $this ); } //page title diff --git a/tests/jquery.testHelper.js b/tests/jquery.testHelper.js index 35a28269..b1d94bad 100644 --- a/tests/jquery.testHelper.js +++ b/tests/jquery.testHelper.js @@ -21,7 +21,7 @@ reloadLib: function(libName){ if(this.reloads[libName] === undefined) { this.reloads[libName] = { - lib: $("script[src$=" + libName + "]"), + lib: $("script[src$='" + libName + "']"), count: 0 }; } diff --git a/tests/unit/navigation/navigation_core.js b/tests/unit/navigation/navigation_core.js index d67a08d7..3838a437 100644 --- a/tests/unit/navigation/navigation_core.js +++ b/tests/unit/navigation/navigation_core.js @@ -78,16 +78,25 @@ test( "path.stripHash is working properly", function(){ same( $.mobile.path.stripHash( "#bar" ), "bar", "returns a hash without the # prefix"); - }); + test( "path.hasProtocol is working properly", function(){ + same( $.mobile.path.hasProtocol( "tel:5559999" ), true, "value in tel protocol format has protocol" ); + same( $.mobile.path.hasProtocol( location.href ), true, "location href has protocol" ); + same( $.mobile.path.hasProtocol( "foo/bar/baz.html" ), false, "simple directory path has no protocol" ); + same( $.mobile.path.hasProtocol( "file://foo/bar/baz.html" ), true, "simple directory path with file:// has protocol" ); + }); + + test( "path.isRelative is working properly", function(){ + same( $.mobile.path.isRelative("#foo/bar"), false, "path starting with a # is not relative" ); + same( $.mobile.path.isRelative("/foo/bar"), false, "path starting with a / is not relative" ); + same( $.mobile.path.isRelative("http://example.com/foo"), false, "full url path is not relative" ); + same( $.mobile.path.isRelative("foo/bar.html"), true, "simple path is relative" ); + }); + test( "path.isExternal is working properly", function(){ same( $.mobile.path.isExternal( location.href ), false, "same domain is not external" ); same( $.mobile.path.isExternal( "http://example.com" ), true, "example.com is external" ); - }); - - - test( "path.isExternal method is working properly", function(){ same($.mobile.path.isExternal("mailto:"), true, "mailto protocol"); same($.mobile.path.isExternal("http://foo.com"), true, "http protocol"); same($.mobile.path.isExternal("http://www.foo.com"), true, "http protocol with www"); @@ -100,4 +109,56 @@ same($.mobile.path.isExternal("#foo"), false, "local id reference"); }); + + test( "urlHistory is working properly", function(){ + //urlHistory + same( $.type( $.mobile.urlHistory.stack ), "array", "urlHistory.stack is an array" ); + + //preload the stack + $.mobile.urlHistory.stack[0] = { url: "foo", transition: "bar" }; + $.mobile.urlHistory.stack[1] = { url: "baz", transition: "shizam" }; + $.mobile.urlHistory.stack[2] = { url: "shizoo", transition: "shizaah" }; + + //active index + same( $.mobile.urlHistory.activeIndex , 0, "urlHistory.activeIndex is 0" ); + + //getActive + same( $.type( $.mobile.urlHistory.getActive() ) , "object", "active item is an object" ); + same( $.mobile.urlHistory.getActive().url , "foo", "active item has url foo" ); + same( $.mobile.urlHistory.getActive().transition , "bar", "active item has transition bar" ); + + //get prev / next + same( $.mobile.urlHistory.getPrev(), undefined, "urlHistory.getPrev() is undefined when active index is 0" ); + $.mobile.urlHistory.activeIndex = 1; + same( $.mobile.urlHistory.getPrev().url, "foo", "urlHistory.getPrev() has url foo when active index is 1" ); + $.mobile.urlHistory.activeIndex = 0; + same( $.mobile.urlHistory.getNext().url, "baz", "urlHistory.getNext() has url baz when active index is 0" ); + + //add new + $.mobile.urlHistory.activeIndex = 2; + $.mobile.urlHistory.addNew("test"); + same( $.mobile.urlHistory.stack.length, 4, "urlHistory.addNew() adds an item after the active index" ); + same( $.mobile.urlHistory.activeIndex, 3, "urlHistory.addNew() moves the activeIndex to the newly added item" ); + + //clearForward + $.mobile.urlHistory.activeIndex = 0; + $.mobile.urlHistory.clearForward(); + same( $.mobile.urlHistory.stack.length, 1, "urlHistory.clearForward() clears the url stack after the active index" ); + }); + + //url listening + asyncTest( "ability to disable our hash change event listening", function(){ + $.mobile.urlHistory.listeningEnabled = false; + var stillListening = false; + $(document).bind("pagebeforehide", function(){ + stillListening = true; + }); + location.hash = "foozball"; + setTimeout(function(){ + start(); + ok( $.mobile.urlHistory.listeningEnabled == stillListening, "urlHistory.listeningEnabled = false disables default hashchange event handler"); + location.hash = ""; + }, 1000); + }); + })(jQuery); \ No newline at end of file diff --git a/tests/unit/page/page_core.js b/tests/unit/page/page_core.js index bc610320..ce28dfe1 100644 --- a/tests/unit/page/page_core.js +++ b/tests/unit/page/page_core.js @@ -27,3 +27,6 @@ test( "unnested bar anchors are styled", function(){ ok($('.ui-bar > a').hasClass('ui-btn')); }); +test( "no auto-generated back button exists on first page", function(){ + ok( !$('.ui-header > [data-rel="back"]').length ); +}); diff --git a/tests/unit/select/index.html b/tests/unit/select/index.html index 0d932231..b2cdcee8 100644 --- a/tests/unit/select/index.html +++ b/tests/unit/select/index.html @@ -61,6 +61,33 @@
    +
    + +
    + +
    + +
    + +
    + +
    +