2010-09-10 22:23:13 +00:00
|
|
|
/*
|
2010-11-10 00:55:52 +00:00
|
|
|
* jQuery Mobile Framework : "selectmenu" plugin
|
2010-09-10 22:23:13 +00:00
|
|
|
* Copyright (c) jQuery Project
|
2010-11-20 03:47:47 +00:00
|
|
|
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
|
|
|
* http://jquery.org/license
|
2011-01-16 06:44:00 +00:00
|
|
|
*/
|
2011-06-29 00:54:30 +00:00
|
|
|
|
|
|
|
|
(function( $, undefined ) {
|
|
|
|
|
|
This commit decouples all widgets from the page plugin so that they can be used ad-hoc.
- Internally, each plugin self-initializes by binding to the pagecreate event.
- Unit tests have been added and adjusted to support some internal changes involved in this commit.
- In the process, the portions of the page plugin that were used to enhance the header,content,and footer sections of a native-app style page layout are now located in jquery.mobile.page.sections.js.
- No public API options have changed, except that the page plugin no longer has options for keepNative, and degradeInputs, as plugins now handle these internally (keepNative was never documented, and degradeInputs only affected slider, so it lives there now. Page options related to the page sections are now located in the page.sections script, but they are still configurable via the page plugin's options api.
- Make, Ant, and index files are updated with a new load order for all JS files.
2011-07-19 23:05:35 +00:00
|
|
|
//auto self-init widgets
|
2011-07-20 02:44:03 +00:00
|
|
|
$( document ).bind( "pagecreate enhance", function( e ){
|
This commit decouples all widgets from the page plugin so that they can be used ad-hoc.
- Internally, each plugin self-initializes by binding to the pagecreate event.
- Unit tests have been added and adjusted to support some internal changes involved in this commit.
- In the process, the portions of the page plugin that were used to enhance the header,content,and footer sections of a native-app style page layout are now located in jquery.mobile.page.sections.js.
- No public API options have changed, except that the page plugin no longer has options for keepNative, and degradeInputs, as plugins now handle these internally (keepNative was never documented, and degradeInputs only affected slider, so it lives there now. Page options related to the page sections are now located in the page.sections script, but they are still configurable via the page plugin's options api.
- Make, Ant, and index files are updated with a new load order for all JS files.
2011-07-19 23:05:35 +00:00
|
|
|
$( "select:not(:jqmData(role='slider'))", e.target )
|
|
|
|
|
.not( ":jqmData(role='none'), :jqmData(role='nojs')" )
|
|
|
|
|
.selectmenu();
|
|
|
|
|
});
|
|
|
|
|
|
2010-11-09 00:33:45 +00:00
|
|
|
$.widget( "mobile.selectmenu", $.mobile.widget, {
|
|
|
|
|
options: {
|
2010-11-11 04:04:10 +00:00
|
|
|
theme: null,
|
2011-01-16 06:44:00 +00:00
|
|
|
disabled: false,
|
2011-06-29 00:54:30 +00:00
|
|
|
icon: "arrow-d",
|
|
|
|
|
iconpos: "right",
|
2010-11-11 04:04:10 +00:00
|
|
|
inline: null,
|
|
|
|
|
corners: true,
|
|
|
|
|
shadow: true,
|
2010-11-11 04:39:48 +00:00
|
|
|
iconshadow: true,
|
2011-06-29 00:54:30 +00:00
|
|
|
menuPageTheme: "b",
|
|
|
|
|
overlayTheme: "a",
|
2010-12-07 20:45:20 +00:00
|
|
|
hidePlaceholderMenuItems: true,
|
2011-06-29 00:54:30 +00:00
|
|
|
closeText: "Close",
|
2011-03-25 16:44:46 +00:00
|
|
|
nativeMenu: true
|
2010-11-09 00:33:45 +00:00
|
|
|
},
|
2011-06-29 00:54:30 +00:00
|
|
|
_create: function() {
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2010-11-10 13:42:34 +00:00
|
|
|
var self = this,
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2010-11-11 03:54:57 +00:00
|
|
|
o = this.options,
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2010-11-10 13:42:34 +00:00
|
|
|
select = this.element
|
2010-12-07 20:45:20 +00:00
|
|
|
.wrap( "<div class='ui-select'>" ),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
|
|
|
|
selectID = select.attr( "id" ),
|
|
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
label = $( "label[for='"+ selectID +"']" ).addClass( "ui-select" ),
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// IE throws an exception at options.item() function when
|
|
|
|
|
// there is no selected item
|
|
|
|
|
// select first in this case
|
|
|
|
|
selectedIndex = select[ 0 ].selectedIndex == -1 ? 0 : select[ 0 ].selectedIndex,
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-02-02 01:49:07 +00:00
|
|
|
button = ( self.options.nativeMenu ? $( "<div/>" ) : $( "<a>", {
|
2010-11-09 00:33:45 +00:00
|
|
|
"href": "#",
|
|
|
|
|
"role": "button",
|
|
|
|
|
"id": buttonId,
|
|
|
|
|
"aria-haspopup": "true",
|
2011-01-16 06:44:00 +00:00
|
|
|
"aria-owns": menuId
|
2011-02-02 01:49:07 +00:00
|
|
|
}) )
|
2011-06-29 00:54:30 +00:00
|
|
|
.text( $( select[ 0 ].options.item( selectedIndex ) ).text() )
|
2010-11-09 00:33:45 +00:00
|
|
|
.insertBefore( select )
|
|
|
|
|
.buttonMarkup({
|
2011-01-16 06:44:00 +00:00
|
|
|
theme: o.theme,
|
2010-11-11 03:54:57 +00:00
|
|
|
icon: o.icon,
|
|
|
|
|
iconpos: o.iconpos,
|
|
|
|
|
inline: o.inline,
|
|
|
|
|
corners: o.corners,
|
|
|
|
|
shadow: o.shadow,
|
|
|
|
|
iconshadow: o.iconshadow
|
2010-11-09 00:33:45 +00:00
|
|
|
}),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Multi select or not
|
|
|
|
|
isMultiple = self.isMultiple = select[ 0 ].multiple;
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Opera does not properly support opacity on select elements
|
|
|
|
|
// In Mini, it hides the element, but not its text
|
|
|
|
|
// On the desktop,it seems to do the opposite
|
|
|
|
|
// for these reasons, using the nativeMenu option results in a full native select in Opera
|
|
|
|
|
if ( o.nativeMenu && window.opera && window.opera.version ) {
|
2011-02-02 17:04:18 +00:00
|
|
|
select.addClass( "ui-select-nativeonly" );
|
2011-03-13 06:56:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//vars for non-native menus
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( !o.nativeMenu ) {
|
2011-02-02 02:03:41 +00:00
|
|
|
var options = select.find("option"),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
buttonId = selectID + "-button",
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
menuId = selectID + "-menu",
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
thisPage = select.closest( ".ui-page" ),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
//button theme
|
2011-06-29 00:54:30 +00:00
|
|
|
theme = /ui-btn-up-([a-z])/.exec( button.attr( "class" ) )[1],
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-20 19:29:22 +00:00
|
|
|
menuPage = $( "<div data-" + $.mobile.ns + "role='dialog' data-" +$.mobile.ns + "theme='"+ o.menuPageTheme +"'>" +
|
2011-02-20 17:12:01 +00:00
|
|
|
"<div data-" + $.mobile.ns + "role='header'>" +
|
2011-02-02 02:03:41 +00:00
|
|
|
"<div class='ui-title'>" + label.text() + "</div>"+
|
|
|
|
|
"</div>"+
|
2011-02-20 17:12:01 +00:00
|
|
|
"<div data-" + $.mobile.ns + "role='content'></div>"+
|
2011-02-02 02:03:41 +00:00
|
|
|
"</div>" )
|
|
|
|
|
.appendTo( $.mobile.pageContainer )
|
|
|
|
|
.page(),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
menuPageContent = menuPage.find( ".ui-content" ),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
menuPageClose = menuPage.find( ".ui-header a" ),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
screen = $( "<div>", {"class": "ui-selectmenu-screen ui-screen-hidden"})
|
|
|
|
|
.appendTo( thisPage ),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-07-07 07:52:02 +00:00
|
|
|
listbox = $("<div>", { "class": "ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all ui-body-" + o.overlayTheme + " " + $.mobile.defaultDialogTransition })
|
2011-02-02 02:03:41 +00:00
|
|
|
.insertAfter(screen),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
list = $( "<ul>", {
|
|
|
|
|
"class": "ui-selectmenu-list",
|
|
|
|
|
"id": menuId,
|
|
|
|
|
"role": "listbox",
|
2011-02-20 18:43:02 +00:00
|
|
|
"aria-labelledby": buttonId
|
2011-02-02 02:03:41 +00:00
|
|
|
})
|
2011-02-20 18:43:02 +00:00
|
|
|
.attr( "data-" + $.mobile.ns + "theme", theme )
|
2011-02-02 02:03:41 +00:00
|
|
|
.appendTo( listbox ),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
header = $( "<div>", {
|
|
|
|
|
"class": "ui-header ui-bar-" + theme
|
|
|
|
|
})
|
|
|
|
|
.prependTo( listbox ),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
headerTitle = $( "<h1>", {
|
|
|
|
|
"class": "ui-title"
|
|
|
|
|
})
|
|
|
|
|
.appendTo( header ),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
headerClose = $( "<a>", {
|
|
|
|
|
"text": o.closeText,
|
|
|
|
|
"href": "#",
|
|
|
|
|
"class": "ui-btn-left"
|
|
|
|
|
})
|
2011-02-20 18:43:02 +00:00
|
|
|
.attr( "data-" + $.mobile.ns + "iconpos", "notext" )
|
|
|
|
|
.attr( "data-" + $.mobile.ns + "icon", "delete" )
|
2011-02-02 02:03:41 +00:00
|
|
|
.appendTo( header )
|
|
|
|
|
.buttonMarkup(),
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 02:03:41 +00:00
|
|
|
menuType;
|
2011-06-29 00:54:30 +00:00
|
|
|
} // End non native vars
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Add counter for multi selects
|
|
|
|
|
if ( isMultiple ) {
|
|
|
|
|
self.buttonCount = $( "<span>" )
|
|
|
|
|
.addClass( "ui-li-count ui-btn-up-c ui-btn-corner-all" )
|
2010-12-07 20:45:20 +00:00
|
|
|
.hide()
|
|
|
|
|
.appendTo( button );
|
|
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Disable if specified
|
|
|
|
|
if ( o.disabled ) {
|
|
|
|
|
this.disable();
|
|
|
|
|
}
|
2011-02-02 02:03:41 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Events on native select
|
|
|
|
|
select.change(function() {
|
|
|
|
|
self.refresh();
|
|
|
|
|
});
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Expose to other methods
|
|
|
|
|
$.extend( self, {
|
2010-11-11 02:40:20 +00:00
|
|
|
select: select,
|
2011-01-13 21:58:29 +00:00
|
|
|
optionElems: options,
|
2010-11-11 02:40:20 +00:00
|
|
|
selectID: selectID,
|
|
|
|
|
label: label,
|
2011-06-29 00:54:30 +00:00
|
|
|
buttonId: buttonId,
|
|
|
|
|
menuId: menuId,
|
|
|
|
|
thisPage: thisPage,
|
|
|
|
|
button: button,
|
|
|
|
|
menuPage: menuPage,
|
|
|
|
|
menuPageContent: menuPageContent,
|
|
|
|
|
screen: screen,
|
|
|
|
|
listbox: listbox,
|
|
|
|
|
list: list,
|
|
|
|
|
menuType: menuType,
|
|
|
|
|
header: header,
|
|
|
|
|
headerClose: headerClose,
|
|
|
|
|
headerTitle: headerTitle,
|
|
|
|
|
placeholder: ""
|
2011-03-13 06:56:36 +00:00
|
|
|
});
|
2011-01-28 07:20:57 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Support for using the native select menu with a custom button
|
|
|
|
|
if ( o.nativeMenu ) {
|
2011-01-27 05:35:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
select.appendTo( button )
|
|
|
|
|
.bind( "vmousedown", function() {
|
|
|
|
|
// Add active class to button
|
2011-01-14 18:02:24 +00:00
|
|
|
button.addClass( $.mobile.activeBtnClass );
|
|
|
|
|
})
|
2011-06-29 00:54:30 +00:00
|
|
|
.bind( "focus vmouseover", function() {
|
2011-02-19 01:39:04 +00:00
|
|
|
button.trigger( "vmouseover" );
|
2011-01-14 18:02:24 +00:00
|
|
|
})
|
2011-06-29 00:54:30 +00:00
|
|
|
.bind( "vmousemove", function() {
|
|
|
|
|
// Remove active class on scroll/touchmove
|
2011-02-02 06:41:07 +00:00
|
|
|
button.removeClass( $.mobile.activeBtnClass );
|
|
|
|
|
})
|
2011-06-29 00:54:30 +00:00
|
|
|
.bind( "change blur vmouseout", function() {
|
|
|
|
|
|
|
|
|
|
button.trigger( "vmouseout" )
|
2011-01-14 18:02:24 +00:00
|
|
|
.removeClass( $.mobile.activeBtnClass );
|
|
|
|
|
});
|
|
|
|
|
|
2011-03-16 06:57:17 +00:00
|
|
|
|
2011-01-27 05:20:40 +00:00
|
|
|
} else {
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Create list from select, update state
|
2011-02-02 01:49:07 +00:00
|
|
|
self.refresh();
|
2011-01-26 06:50:55 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
select.attr( "tabindex", "-1" )
|
|
|
|
|
.focus(function() {
|
2011-01-26 06:50:55 +00:00
|
|
|
$(this).blur();
|
|
|
|
|
button.focus();
|
2011-04-20 05:53:53 +00:00
|
|
|
});
|
2011-01-26 06:50:55 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Button events
|
|
|
|
|
button.bind( "vclick keydown" , function( event ) {
|
|
|
|
|
if ( event.type == "vclick" ||
|
|
|
|
|
event.keyCode && ( event.keyCode === $.mobile.keyCode.ENTER ||
|
|
|
|
|
event.keyCode === $.mobile.keyCode.SPACE ) ) {
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
self.open();
|
|
|
|
|
event.preventDefault();
|
2011-02-02 01:49:07 +00:00
|
|
|
}
|
2011-06-29 00:54:30 +00:00
|
|
|
});
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Events for list items
|
|
|
|
|
list.attr( "role", "listbox" )
|
|
|
|
|
.delegate( ".ui-li>a", "focusin", function() {
|
|
|
|
|
$( this ).attr( "tabindex", "0" );
|
|
|
|
|
})
|
|
|
|
|
.delegate( ".ui-li>a", "focusout", function() {
|
|
|
|
|
$( this ).attr( "tabindex", "-1" );
|
|
|
|
|
})
|
|
|
|
|
.delegate( "li:not(.ui-disabled, .ui-li-divider)", "vclick", function( event ) {
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// index of option tag to be selected
|
|
|
|
|
var oldIndex = select[ 0 ].selectedIndex,
|
|
|
|
|
newIndex = list.find( "li:not(.ui-li-divider)" ).index( this ),
|
|
|
|
|
option = self.optionElems.eq( newIndex )[ 0 ];
|
|
|
|
|
|
|
|
|
|
// toggle selected status on the tag for multi selects
|
|
|
|
|
option.selected = isMultiple ? !option.selected : true;
|
|
|
|
|
|
|
|
|
|
// toggle checkbox class for multiple selects
|
|
|
|
|
if ( isMultiple ) {
|
|
|
|
|
$( this ).find( ".ui-icon" )
|
|
|
|
|
.toggleClass( "ui-icon-checkbox-on", option.selected )
|
|
|
|
|
.toggleClass( "ui-icon-checkbox-off", !option.selected );
|
|
|
|
|
}
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// trigger change if value changed
|
|
|
|
|
if ( isMultiple || oldIndex !== newIndex ) {
|
|
|
|
|
select.trigger( "change" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//hide custom select for single selects only
|
|
|
|
|
if ( !isMultiple ) {
|
|
|
|
|
self.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
event.preventDefault();
|
2011-03-31 20:44:25 +00:00
|
|
|
})
|
|
|
|
|
//keyboard events for menu items
|
2011-06-29 00:54:30 +00:00
|
|
|
.keydown(function( event ) {
|
|
|
|
|
var target = $( event.target ),
|
|
|
|
|
li = target.closest( "li" ),
|
|
|
|
|
prev, next;
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-03-31 20:44:25 +00:00
|
|
|
// switch logic based on which key was pressed
|
2011-06-29 00:54:30 +00:00
|
|
|
switch ( event.keyCode ) {
|
2011-03-31 20:44:25 +00:00
|
|
|
// up or left arrow keys
|
|
|
|
|
case 38:
|
2011-06-29 00:54:30 +00:00
|
|
|
prev = li.prev();
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-03-31 20:44:25 +00:00
|
|
|
// if there's a previous option, focus it
|
|
|
|
|
if ( prev.length ) {
|
|
|
|
|
target
|
|
|
|
|
.blur()
|
|
|
|
|
.attr( "tabindex", "-1" );
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-03-31 20:44:25 +00:00
|
|
|
prev.find( "a" ).first().focus();
|
2011-04-20 05:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-31 20:44:25 +00:00
|
|
|
return false;
|
|
|
|
|
break;
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-03-31 20:44:25 +00:00
|
|
|
// down or right arrow keys
|
|
|
|
|
case 40:
|
2011-06-29 00:54:30 +00:00
|
|
|
next = li.next();
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-03-31 20:44:25 +00:00
|
|
|
// if there's a next option, focus it
|
|
|
|
|
if ( next.length ) {
|
|
|
|
|
target
|
|
|
|
|
.blur()
|
|
|
|
|
.attr( "tabindex", "-1" );
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-03-31 20:44:25 +00:00
|
|
|
next.find( "a" ).first().focus();
|
2011-04-20 05:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-31 20:44:25 +00:00
|
|
|
return false;
|
|
|
|
|
break;
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// If enter or space is pressed, trigger click
|
2011-03-31 20:44:25 +00:00
|
|
|
case 13:
|
|
|
|
|
case 32:
|
|
|
|
|
target.trigger( "vclick" );
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-03-31 20:44:25 +00:00
|
|
|
return false;
|
2011-04-20 05:53:53 +00:00
|
|
|
break;
|
2011-03-31 20:44:25 +00:00
|
|
|
}
|
2011-04-20 05:53:53 +00:00
|
|
|
});
|
2011-07-15 17:58:23 +00:00
|
|
|
|
2011-07-11 01:56:58 +00:00
|
|
|
// button refocus ensures proper height calculation
|
|
|
|
|
// by removing the inline style and ensuring page inclusion
|
|
|
|
|
self.menuPage.bind( "pagehide", function(){
|
|
|
|
|
self.list.appendTo( self.listbox );
|
|
|
|
|
self._focusButton();
|
|
|
|
|
});
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Events on "screen" overlay
|
|
|
|
|
screen.bind( "vclick", function( event ) {
|
2011-03-15 22:23:24 +00:00
|
|
|
self.close();
|
|
|
|
|
});
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Close button on small overlays
|
|
|
|
|
self.headerClose.click(function() {
|
|
|
|
|
if ( self.menuType == "overlay" ) {
|
2011-03-27 17:21:16 +00:00
|
|
|
self.close();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2011-07-15 17:58:23 +00:00
|
|
|
});
|
2011-03-13 06:56:36 +00:00
|
|
|
}
|
2010-11-09 00:33:45 +00:00
|
|
|
},
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
_buildList: function() {
|
2011-01-16 06:44:00 +00:00
|
|
|
var self = this,
|
2010-12-07 23:05:26 +00:00
|
|
|
o = this.options,
|
2011-02-02 00:28:30 +00:00
|
|
|
placeholder = this.placeholder,
|
|
|
|
|
optgroups = [],
|
|
|
|
|
lis = [],
|
|
|
|
|
dataIcon = self.isMultiple ? "checkbox-off" : "false";
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
self.list.empty().filter( ".ui-listview" ).listview( "destroy" );
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Populate menu with options from select element
|
|
|
|
|
self.select.find( "option" ).each(function( i ) {
|
|
|
|
|
var $this = $( this ),
|
2010-12-07 23:05:26 +00:00
|
|
|
$parent = $this.parent(),
|
2011-02-02 00:28:30 +00:00
|
|
|
text = $this.text(),
|
|
|
|
|
anchor = "<a href='#'>"+ text +"</a>",
|
|
|
|
|
classes = [],
|
|
|
|
|
extraAttrs = [];
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Are we inside an optgroup?
|
|
|
|
|
if ( $parent.is( "optgroup" ) ) {
|
|
|
|
|
var optLabel = $parent.attr( "label" );
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2010-12-03 15:57:21 +00:00
|
|
|
// has this optgroup already been built yet?
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( $.inArray( optLabel, optgroups ) === -1 ) {
|
2011-02-20 17:12:01 +00:00
|
|
|
lis.push( "<li data-" + $.mobile.ns + "role='list-divider'>"+ optLabel +"</li>" );
|
2010-12-03 15:57:21 +00:00
|
|
|
optgroups.push( optLabel );
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Find placeholder text
|
|
|
|
|
// TODO: Are you sure you want to use getAttribute? ^RW
|
|
|
|
|
if ( !this.getAttribute( "value" ) || text.length == 0 || $this.jqmData( "placeholder" ) ) {
|
|
|
|
|
if ( o.hidePlaceholderMenuItems ) {
|
2011-02-02 00:28:30 +00:00
|
|
|
classes.push( "ui-selectmenu-placeholder" );
|
2010-12-07 23:05:26 +00:00
|
|
|
}
|
|
|
|
|
placeholder = self.placeholder = text;
|
2010-12-07 20:45:20 +00:00
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2010-12-03 13:19:25 +00:00
|
|
|
// support disabled option tags
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( this.disabled ) {
|
2011-02-02 00:28:30 +00:00
|
|
|
classes.push( "ui-disabled" );
|
|
|
|
|
extraAttrs.push( "aria-disabled='true'" );
|
2010-12-03 13:19:25 +00:00
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-02-20 17:12:01 +00:00
|
|
|
lis.push( "<li data-" + $.mobile.ns + "icon='"+ dataIcon +"' class='"+ classes.join(" ") + "' " + extraAttrs.join(" ") +">"+ anchor +"</li>" )
|
2010-11-11 03:31:05 +00:00
|
|
|
});
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-02-02 00:28:30 +00:00
|
|
|
self.list.html( lis.join(" ") );
|
2011-04-20 05:53:53 +00:00
|
|
|
|
2011-03-31 20:44:25 +00:00
|
|
|
self.list.find( "li" )
|
|
|
|
|
.attr({ "role": "option", "tabindex": "-1" })
|
|
|
|
|
.first().attr( "tabindex", "0" );
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Hide header close link for single selects
|
|
|
|
|
if ( !this.isMultiple ) {
|
2010-12-07 20:45:20 +00:00
|
|
|
this.headerClose.hide();
|
|
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Hide header if it's not a multiselect and there's no placeholder
|
|
|
|
|
if ( !this.isMultiple && !placeholder.length ) {
|
2010-12-07 20:45:20 +00:00
|
|
|
this.header.hide();
|
2010-12-07 23:05:26 +00:00
|
|
|
} else {
|
2010-12-08 14:41:00 +00:00
|
|
|
this.headerTitle.text( this.placeholder );
|
2010-12-07 20:45:20 +00:00
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Now populated, create listview
|
2010-12-07 20:45:20 +00:00
|
|
|
self.list.listview();
|
2010-11-11 03:31:05 +00:00
|
|
|
},
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
refresh: function( forceRebuild ) {
|
2010-11-11 03:31:05 +00:00
|
|
|
var self = this,
|
|
|
|
|
select = this.element,
|
2010-12-07 20:45:20 +00:00
|
|
|
isMultiple = this.isMultiple,
|
2011-06-29 00:54:30 +00:00
|
|
|
options = this.optionElems = select.find( "option" ),
|
|
|
|
|
selected = options.filter( ":selected" ),
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2010-12-07 20:45:20 +00:00
|
|
|
// return an array of all selected index's
|
2011-06-29 00:54:30 +00:00
|
|
|
indicies = selected.map(function() {
|
2010-12-08 14:41:00 +00:00
|
|
|
return options.index( this );
|
2010-12-07 20:45:20 +00:00
|
|
|
}).get();
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( !self.options.nativeMenu &&
|
|
|
|
|
( forceRebuild || select[0].options.length != self.list.find( "li" ).length ) ) {
|
|
|
|
|
|
2010-11-11 03:31:05 +00:00
|
|
|
self._buildList();
|
2010-12-07 20:45:20 +00:00
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
self.button.find( ".ui-btn-text" )
|
|
|
|
|
.text(function() {
|
|
|
|
|
|
|
|
|
|
if ( !isMultiple ) {
|
2010-12-07 20:45:20 +00:00
|
|
|
return selected.text();
|
|
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
return selected.length ? selected.map(function() {
|
2011-06-29 05:06:30 +00:00
|
|
|
return $( this ).text();
|
2011-06-29 00:54:30 +00:00
|
|
|
}).get().join( ", " ) : self.placeholder;
|
2010-12-07 20:45:20 +00:00
|
|
|
});
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2010-12-07 20:45:20 +00:00
|
|
|
// multiple count inside button
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( isMultiple ) {
|
|
|
|
|
self.buttonCount[ selected.length > 1 ? "show" : "hide" ]().text( selected.length );
|
2010-12-07 20:45:20 +00:00
|
|
|
}
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( !self.options.nativeMenu ) {
|
|
|
|
|
|
|
|
|
|
self.list.find( "li:not(.ui-li-divider)" )
|
2011-02-02 01:49:07 +00:00
|
|
|
.removeClass( $.mobile.activeBtnClass )
|
2011-06-29 00:54:30 +00:00
|
|
|
.attr( "aria-selected", false )
|
|
|
|
|
.each(function( i ) {
|
|
|
|
|
|
|
|
|
|
if ( $.inArray( i, indicies ) > -1 ) {
|
|
|
|
|
var item = $( this ).addClass( $.mobile.activeBtnClass );
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Aria selected attr
|
|
|
|
|
item.find( "a" ).attr( "aria-selected", true );
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Multiple selects: add the "on" checkbox state to the icon
|
|
|
|
|
if ( isMultiple ) {
|
2011-06-29 05:06:30 +00:00
|
|
|
item.find( ".ui-icon" ).removeClass( "ui-icon-checkbox-off" ).addClass( "ui-icon-checkbox-on" );
|
2011-02-02 01:49:07 +00:00
|
|
|
}
|
2010-12-07 20:45:20 +00:00
|
|
|
}
|
2011-02-02 01:49:07 +00:00
|
|
|
});
|
2011-03-13 06:56:36 +00:00
|
|
|
}
|
2010-11-11 03:31:05 +00:00
|
|
|
},
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
open: function() {
|
|
|
|
|
if ( this.options.disabled || this.options.nativeMenu ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2010-11-11 02:40:20 +00:00
|
|
|
var self = this,
|
2011-02-13 20:11:53 +00:00
|
|
|
menuHeight = self.list.parent().outerHeight(),
|
|
|
|
|
menuWidth = self.list.parent().outerWidth(),
|
2011-06-29 00:54:30 +00:00
|
|
|
scrollTop = $( window ).scrollTop(),
|
2010-11-11 02:40:20 +00:00
|
|
|
btnOffset = self.button.offset().top,
|
2010-11-19 22:31:20 +00:00
|
|
|
screenHeight = window.innerHeight,
|
2011-03-27 17:15:06 +00:00
|
|
|
screenWidth = window.innerWidth;
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2010-11-20 00:19:51 +00:00
|
|
|
//add active class to button
|
|
|
|
|
self.button.addClass( $.mobile.activeBtnClass );
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-03-15 22:23:24 +00:00
|
|
|
//remove after delay
|
2011-06-29 00:54:30 +00:00
|
|
|
setTimeout(function() {
|
2011-03-15 22:23:24 +00:00
|
|
|
self.button.removeClass( $.mobile.activeBtnClass );
|
|
|
|
|
}, 300);
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
function focusMenuItem() {
|
2010-11-11 03:31:05 +00:00
|
|
|
self.list.find( ".ui-btn-active" ).focus();
|
|
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( menuHeight > screenHeight - 80 || !$.support.scrollTop ) {
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2010-11-11 02:40:20 +00:00
|
|
|
//for webos (set lastscroll using button offset)
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( scrollTop == 0 && btnOffset > screenHeight ) {
|
2011-06-29 05:06:30 +00:00
|
|
|
self.thisPage.one( "pagehide", function() {
|
2011-06-29 00:54:30 +00:00
|
|
|
$( this ).jqmData( "lastScroll", btnOffset );
|
2011-01-16 06:44:00 +00:00
|
|
|
});
|
2010-11-11 02:40:20 +00:00
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 05:06:30 +00:00
|
|
|
self.menuPage.one( "pageshow", function() {
|
2011-02-02 01:14:15 +00:00
|
|
|
// silentScroll() is called whenever a page is shown to restore
|
|
|
|
|
// any previous scroll position the page may have had. We need to
|
|
|
|
|
// wait for the "silentscroll" event before setting focus to avoid
|
2011-06-29 00:54:30 +00:00
|
|
|
// the browser"s "feature" which offsets rendering to make sure
|
2011-02-02 01:14:15 +00:00
|
|
|
// whatever has focus is in view.
|
2011-06-29 05:06:30 +00:00
|
|
|
$( window ).one( "silentscroll", function() {
|
2011-06-29 00:54:30 +00:00
|
|
|
focusMenuItem();
|
|
|
|
|
});
|
2011-06-29 17:41:07 +00:00
|
|
|
|
|
|
|
|
self.isOpen = true;
|
2011-02-02 01:14:15 +00:00
|
|
|
});
|
2011-01-16 06:44:00 +00:00
|
|
|
|
|
|
|
|
self.menuType = "page";
|
2010-11-11 02:40:20 +00:00
|
|
|
self.menuPageContent.append( self.list );
|
2011-06-29 00:54:30 +00:00
|
|
|
$.mobile.changePage( self.menuPage, {
|
2011-07-07 07:52:02 +00:00
|
|
|
transition: $.mobile.defaultDialogTransition
|
2011-06-29 00:54:30 +00:00
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
|
2010-11-11 02:40:20 +00:00
|
|
|
self.menuType = "overlay";
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
self.screen.height( $(document).height() )
|
2011-06-29 05:06:30 +00:00
|
|
|
.removeClass( "ui-screen-hidden" );
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// Try and center the overlay over the button
|
2011-01-29 15:15:40 +00:00
|
|
|
var roomtop = btnOffset - scrollTop,
|
|
|
|
|
roombot = scrollTop + screenHeight - btnOffset,
|
|
|
|
|
halfheight = menuHeight / 2,
|
2011-06-29 00:54:30 +00:00
|
|
|
maxwidth = parseFloat( self.list.parent().css( "max-width" ) ),
|
2011-03-13 07:02:11 +00:00
|
|
|
newtop, newleft;
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ) {
|
2011-03-13 06:58:21 +00:00
|
|
|
newtop = btnOffset + ( self.button.outerHeight() / 2 ) - halfheight;
|
2011-06-29 00:54:30 +00:00
|
|
|
} else {
|
|
|
|
|
// 30px tolerance off the edges
|
2011-03-13 06:58:21 +00:00
|
|
|
newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
|
|
|
|
|
}
|
2011-03-13 06:56:36 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
// If the menuwidth is smaller than the screen center is
|
|
|
|
|
if ( menuWidth < maxwidth ) {
|
|
|
|
|
newleft = ( screenWidth - menuWidth ) / 2;
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
//otherwise insure a >= 30px offset from the left
|
2011-01-29 15:15:40 +00:00
|
|
|
newleft = self.button.offset().left + self.button.outerWidth() / 2 - menuWidth / 2;
|
2011-06-29 00:54:30 +00:00
|
|
|
|
2011-03-13 06:58:21 +00:00
|
|
|
// 30px tolerance off the edges
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( newleft < 30 ) {
|
2011-03-13 06:58:21 +00:00
|
|
|
newleft = 30;
|
2011-06-29 00:54:30 +00:00
|
|
|
} else if ( (newleft + menuWidth) > screenWidth ) {
|
2011-03-13 06:58:21 +00:00
|
|
|
newleft = screenWidth - menuWidth - 30;
|
2011-02-13 20:11:53 +00:00
|
|
|
}
|
2011-03-13 06:58:21 +00:00
|
|
|
}
|
2011-01-29 15:15:40 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
self.listbox.append( self.list )
|
2010-11-20 00:15:48 +00:00
|
|
|
.removeClass( "ui-selectmenu-hidden" )
|
2011-01-29 15:15:40 +00:00
|
|
|
.css({
|
|
|
|
|
top: newtop,
|
|
|
|
|
left: newleft
|
2010-11-11 02:40:20 +00:00
|
|
|
})
|
2011-06-29 05:06:30 +00:00
|
|
|
.addClass( "in" );
|
2011-01-16 06:44:00 +00:00
|
|
|
|
|
|
|
|
focusMenuItem();
|
2011-01-27 05:20:40 +00:00
|
|
|
|
2011-06-29 17:41:07 +00:00
|
|
|
// duplicate with value set in page show for dialog sized selects
|
|
|
|
|
self.isOpen = true;
|
|
|
|
|
}
|
2010-11-11 02:40:20 +00:00
|
|
|
},
|
2011-07-15 17:58:23 +00:00
|
|
|
|
2011-07-11 01:56:58 +00:00
|
|
|
_focusButton : function(){
|
|
|
|
|
var self = this;
|
|
|
|
|
setTimeout(function() {
|
|
|
|
|
self.button.focus();
|
|
|
|
|
}, 40);
|
|
|
|
|
},
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
close: function() {
|
|
|
|
|
if ( this.options.disabled || !this.isOpen || this.options.nativeMenu ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-11 02:40:20 +00:00
|
|
|
var self = this;
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
if ( self.menuType == "page" ) {
|
2011-04-20 06:01:13 +00:00
|
|
|
// doesn't solve the possible issue with calling change page
|
|
|
|
|
// where the objects don't define data urls which prevents dialog key
|
|
|
|
|
// stripping - changePage has incoming refactor
|
|
|
|
|
window.history.back();
|
2010-11-11 02:40:20 +00:00
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
self.screen.addClass( "ui-screen-hidden" );
|
2011-06-29 00:54:30 +00:00
|
|
|
self.listbox.addClass( "ui-selectmenu-hidden" ).removeAttr( "style" ).removeClass( "in" );
|
2011-07-11 01:56:58 +00:00
|
|
|
self._focusButton();
|
2010-11-11 02:40:20 +00:00
|
|
|
}
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-01-27 05:20:40 +00:00
|
|
|
// allow the dialog to be closed again
|
|
|
|
|
this.isOpen = false;
|
2010-11-09 02:24:44 +00:00
|
|
|
},
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
disable: function() {
|
2011-06-29 05:06:30 +00:00
|
|
|
this.element.attr( "disabled", true );
|
|
|
|
|
this.button.addClass( "ui-disabled" ).attr( "aria-disabled", true );
|
2010-11-11 03:48:31 +00:00
|
|
|
return this._setOption( "disabled", true );
|
2010-11-09 00:33:45 +00:00
|
|
|
},
|
2011-01-16 06:44:00 +00:00
|
|
|
|
2011-06-29 00:54:30 +00:00
|
|
|
enable: function() {
|
|
|
|
|
this.element.attr( "disabled", false );
|
|
|
|
|
this.button.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
|
2010-11-11 03:48:31 +00:00
|
|
|
return this._setOption( "disabled", false );
|
2010-11-09 00:33:45 +00:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
})( jQuery );
|
2011-01-16 06:44:00 +00:00
|
|
|
|