1 (function( $, window, undefined ) {
3 var nsNormalizeDict = {};
5 // jQuery.mobile configurable options
6 $.mobile = $.extend( {}, {
8 // Version of the jQuery Mobile Framework
11 // Namespace used framework-wide for data-attrs. Default is no namespace
14 // Define the url parameter used for referencing widget-generated sub-pages.
15 // Translates to to example.html&ui-page=subpageIdentifier
16 // hash segment before &ui-page= is used to make Ajax request
17 subPageUrlKey: "ui-page",
19 // Class assigned to page currently in view, and during transitions
20 activePageClass: "ui-page-active",
22 // Class used for "active" button state, from CSS framework
23 activeBtnClass: "ui-btn-active",
25 // Class used for "focus" form element state, from CSS framework
26 focusClass: "ui-focus",
28 // Automatically handle clicks and form submissions through Ajax, when same-domain
31 // Automatically load and show pages based on location.hash
32 hashListeningEnabled: true,
34 // disable to prevent jquery from bothering with links
35 linkBindingEnabled: true,
37 // Set default page transition - 'none' for no transitions
38 defaultPageTransition: "fade",
40 // Set maximum window width for transitions to apply - 'false' for no limit
41 maxTransitionWidth: false,
43 // Minimum scroll distance that will be remembered when returning to a page
46 // DEPRECATED: the following property is no longer in use, but defined until 2.0 to prevent conflicts
47 touchOverflowEnabled: false,
49 // Set default dialog transition - 'none' for no transitions
50 defaultDialogTransition: "pop",
52 // Error response message - appears when an Ajax page request fails
53 pageLoadErrorMessage: "Error Loading Page",
55 // For error messages, which theme does the box uses?
56 pageLoadErrorMessageTheme: "e",
58 // replace calls to window.history.back with phonegaps navigation helper
59 // where it is provided on the window object
60 phonegapNavigationEnabled: false,
62 //automatically initialize the DOM when it's ready
63 autoInitializePage: true,
65 pushStateEnabled: true,
67 // allows users to opt in to ignoring content by marking a parent element as
69 ignoreContentEnabled: false,
71 // turn of binding to the native orientationchange due to android orientation behavior
72 orientationChangeEnabled: true,
78 // define the window and the document objects
80 $document: $( document ),
82 getAttrFixed : function( e, key ) {
83 var value = e.getAttribute( key );
85 return value === "true" ? true :
86 value === "false" ? false :
87 value === null ? undefined : value;
90 // TODO might be useful upstream in jquery itself ?
97 COMMAND_LEFT: 91, // COMMAND
108 MENU: 93, // COMMAND_RIGHT
113 NUMPAD_MULTIPLY: 106,
114 NUMPAD_SUBTRACT: 109,
123 WINDOWS: 91 // COMMAND
126 // Scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
127 silentScroll: function( ypos ) {
128 if ( $.type( ypos ) !== "number" ) {
129 ypos = $.mobile.defaultHomeScroll;
132 // prevent scrollstart and scrollstop events
133 $.event.special.scrollstart.enabled = false;
135 setTimeout( function() {
136 window.scrollTo( 0, ypos );
137 $.mobile.$document.trigger( "silentscroll", { x: 0, y: ypos });
140 setTimeout( function() {
141 $.event.special.scrollstart.enabled = true;
145 // Expose our cache for testing purposes.
146 nsNormalizeDict: nsNormalizeDict,
148 // Take a data attribute property, prepend the namespace
149 // and then camel case the attribute string. Add the result
150 // to our nsNormalizeDict so we don't have to do this again.
151 nsNormalize: function( prop ) {
156 return nsNormalizeDict[ prop ] || ( nsNormalizeDict[ prop ] = $.camelCase( $.mobile.ns + prop ) );
159 // Find the closest parent with a theme class on it. Note that
160 // we are not using $.fn.closest() on purpose here because this
161 // method gets called quite a bit and we need it to be as fast
163 getInheritedTheme: function( el, defaultTheme ) {
166 re = /ui-(bar|body|overlay)-([a-z])\b/,
170 c = e.className || "";
171 if ( c && ( m = re.exec( c ) ) && ( ltr = m[ 2 ] ) ) {
172 // We found a parent with a theme class
173 // on it so bail from this loop.
180 // Return the theme letter we found, if none, return the
181 // specified default.
183 return ltr || defaultTheme || "a";
186 // TODO the following $ and $.fn extensions can/probably should be moved into jquery.mobile.core.helpers
188 // Find the closest javascript page element to gather settings data jsperf test
189 // http://jsperf.com/single-complex-selector-vs-many-complex-selectors/edit
190 // possibly naive, but it shows that the parsing overhead for *just* the page selector vs
191 // the page and dialog selector is negligable. This could probably be speed up by
192 // doing a similar parent node traversal to the one found in the inherited theme code above
193 closestPageData: function( $target ) {
195 .closest( ':jqmData(role="page"), :jqmData(role="dialog")' )
199 enhanceable: function( $set ) {
200 return this.haveParents( $set, "enhance" );
203 hijackable: function( $set ) {
204 return this.haveParents( $set, "ajax" );
207 haveParents: function( $set, attr ) {
208 if ( !$.mobile.ignoreContentEnabled ) {
212 var count = $set.length,
214 e, $element, excluded;
216 for ( var i = 0; i < count; i++ ) {
217 $element = $set.eq( i );
222 var c = e.getAttribute ? e.getAttribute( "data-" + $.mobile.ns + attr ) : "";
224 if ( c === "false" ) {
233 $newSet = $newSet.add( $element );
240 getScreenHeight: function() {
241 // Native innerHeight returns more accurate value for this across platforms,
242 // jQuery version is here as a normalized fallback for platforms like Symbian
243 return window.innerHeight || $.mobile.$window.height();
247 // Mobile version of data and removeData and hasData methods
248 // ensures all data is set and retrieved using jQuery Mobile's data namespace
249 $.fn.jqmData = function( prop, value ) {
251 if ( typeof prop !== "undefined" ) {
253 prop = $.mobile.nsNormalize( prop );
256 // undefined is permitted as an explicit input for the second param
257 // in this case it returns the value and does not set it to undefined
258 if( arguments.length < 2 || value === undefined ){
259 result = this.data( prop );
261 result = this.data( prop, value );
267 $.jqmData = function( elem, prop, value ) {
269 if ( typeof prop !== "undefined" ) {
270 result = $.data( elem, prop ? $.mobile.nsNormalize( prop ) : prop, value );
275 $.fn.jqmRemoveData = function( prop ) {
276 return this.removeData( $.mobile.nsNormalize( prop ) );
279 $.jqmRemoveData = function( elem, prop ) {
280 return $.removeData( elem, $.mobile.nsNormalize( prop ) );
283 $.fn.removeWithDependents = function() {
284 $.removeWithDependents( this );
287 $.removeWithDependents = function( elem ) {
288 var $elem = $( elem );
290 ( $elem.jqmData( 'dependents' ) || $() ).remove();
294 $.fn.addDependents = function( newDependents ) {
295 $.addDependents( $( this ), newDependents );
298 $.addDependents = function( elem, newDependents ) {
299 var dependents = $( elem ).jqmData( 'dependents' ) || $();
301 $( elem ).jqmData( 'dependents', $.merge( dependents, newDependents ) );
304 // note that this helper doesn't attempt to handle the callback
305 // or setting of an html elements text, its only purpose is
306 // to return the html encoded version of the text in all cases. (thus the name)
307 $.fn.getEncodedText = function() {
308 return $( "<div/>" ).text( $( this ).text() ).html();
311 // fluent helper function for the mobile namespaced equivalent
312 $.fn.jqmEnhanceable = function() {
313 return $.mobile.enhanceable( this );
316 $.fn.jqmHijackable = function() {
317 return $.mobile.hijackable( this );
320 // Monkey-patching Sizzle to filter the :jqmData selector
321 var oldFind = $.find,
322 jqmDataRE = /:jqmData\(([^)]*)\)/g;
324 $.find = function( selector, context, ret, extra ) {
325 selector = selector.replace( jqmDataRE, "[data-" + ( $.mobile.ns || "" ) + "$1]" );
327 return oldFind.call( this, selector, context, ret, extra );
330 $.extend( $.find, oldFind );
332 $.find.matches = function( expr, set ) {
333 return $.find( expr, null, null, set );
336 $.find.matchesSelector = function( node, expr ) {
337 return $.find( expr, null, null, [ node ] ).length > 0;
343 delegateSelfInitWithSingleSelector: function( target, useKeepNative ) {
344 if ( typeof target !== 'function' ) {
347 var selector = target.prototype.options.initSelector;
348 var selectorRE = /:jqmData\(role='[A-z\-]+'\)$/;
349 if ( selectorRE.test(selector) ) {
350 var firstIdx = selector.indexOf( "'" ) + 1;
351 var lastIdx = selector.lastIndexOf( "'" );
352 var key = selector.substring( firstIdx, lastIdx );
353 if ( !$.creatorDict.hasOwnProperty( key ) ) {
354 $.creatorDict[key] = {};
355 $.creatorDict[key].target = target;
356 if ( useKeepNative === true ) {
357 $.creatorDict[key].useKeepNative = useKeepNative;
366 //auto self-init widgets
367 $( document ).bind( "pagecreate create", function( e ) {
368 var selector = "*[data-" + $.mobile.ns + "role]";
369 $( selector, e.target ).each( function () {
370 dataRoleValue = this.getAttribute( "data-role" );
371 matchedObj = $.creatorDict[dataRoleValue];
373 matchedObj.target.prototype.enhance( this, matchedObj.useKeepNative );