Subversion Repositories HomeAutomation

Rev

Rev 1872 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 1872 Rev 1883
1
/*!
1
/*!
2
 * jQuery Mobile v1.0b1
2
 * jQuery Mobile v1.0b1
3
 * http://jquerymobile.com/
3
 * http://jquerymobile.com/
4
 *
4
 *
5
 * Copyright 2010, jQuery Project
5
 * Copyright 2010, jQuery Project
6
 * Dual licensed under the MIT or GPL Version 2 licenses.
6
 * Dual licensed under the MIT or GPL Version 2 licenses.
7
 * http://jquery.org/license
7
 * http://jquery.org/license
8
 */
8
 */
9
/*!
9
/*!
10
 * jQuery UI Widget @VERSION
10
 * jQuery UI Widget @VERSION
11
 *
11
 *
12
 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
12
 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
13
 * Dual licensed under the MIT or GPL Version 2 licenses.
13
 * Dual licensed under the MIT or GPL Version 2 licenses.
14
 * http://jquery.org/license
14
 * http://jquery.org/license
15
 *
15
 *
16
 * http://docs.jquery.com/UI/Widget
16
 * http://docs.jquery.com/UI/Widget
17
 */
17
 */
18
(function( $, undefined ) {
18
(function( $, undefined ) {
19
 
19
 
20
// jQuery 1.4+
20
// jQuery 1.4+
21
if ( $.cleanData ) {
21
if ( $.cleanData ) {
22
    var _cleanData = $.cleanData;
22
    var _cleanData = $.cleanData;
23
    $.cleanData = function( elems ) {
23
    $.cleanData = function( elems ) {
24
        for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
24
        for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
25
            $( elem ).triggerHandler( "remove" );
25
            $( elem ).triggerHandler( "remove" );
26
        }
26
        }
27
        _cleanData( elems );
27
        _cleanData( elems );
28
    };
28
    };
29
} else {
29
} else {
30
    var _remove = $.fn.remove;
30
    var _remove = $.fn.remove;
31
    $.fn.remove = function( selector, keepData ) {
31
    $.fn.remove = function( selector, keepData ) {
32
        return this.each(function() {
32
        return this.each(function() {
33
            if ( !keepData ) {
33
            if ( !keepData ) {
34
                if ( !selector || $.filter( selector, [ this ] ).length ) {
34
                if ( !selector || $.filter( selector, [ this ] ).length ) {
35
                    $( "*", this ).add( [ this ] ).each(function() {
35
                    $( "*", this ).add( [ this ] ).each(function() {
36
                        $( this ).triggerHandler( "remove" );
36
                        $( this ).triggerHandler( "remove" );
37
                    });
37
                    });
38
                }
38
                }
39
            }
39
            }
40
            return _remove.call( $(this), selector, keepData );
40
            return _remove.call( $(this), selector, keepData );
41
        });
41
        });
42
    };
42
    };
43
}
43
}
44
 
44
 
45
$.widget = function( name, base, prototype ) {
45
$.widget = function( name, base, prototype ) {
46
    var namespace = name.split( "." )[ 0 ],
46
    var namespace = name.split( "." )[ 0 ],
47
        fullName;
47
        fullName;
48
    name = name.split( "." )[ 1 ];
48
    name = name.split( "." )[ 1 ];
49
    fullName = namespace + "-" + name;
49
    fullName = namespace + "-" + name;
50
 
50
 
51
    if ( !prototype ) {
51
    if ( !prototype ) {
52
        prototype = base;
52
        prototype = base;
53
        base = $.Widget;
53
        base = $.Widget;
54
    }
54
    }
55
 
55
 
56
    // create selector for plugin
56
    // create selector for plugin
57
    $.expr[ ":" ][ fullName ] = function( elem ) {
57
    $.expr[ ":" ][ fullName ] = function( elem ) {
58
        return !!$.data( elem, name );
58
        return !!$.data( elem, name );
59
    };
59
    };
60
 
60
 
61
    $[ namespace ] = $[ namespace ] || {};
61
    $[ namespace ] = $[ namespace ] || {};
62
    $[ namespace ][ name ] = function( options, element ) {
62
    $[ namespace ][ name ] = function( options, element ) {
63
        // allow instantiation without initializing for simple inheritance
63
        // allow instantiation without initializing for simple inheritance
64
        if ( arguments.length ) {
64
        if ( arguments.length ) {
65
            this._createWidget( options, element );
65
            this._createWidget( options, element );
66
        }
66
        }
67
    };
67
    };
68
 
68
 
69
    var basePrototype = new base();
69
    var basePrototype = new base();
70
    // we need to make the options hash a property directly on the new instance
70
    // we need to make the options hash a property directly on the new instance
71
    // otherwise we'll modify the options hash on the prototype that we're
71
    // otherwise we'll modify the options hash on the prototype that we're
72
    // inheriting from
72
    // inheriting from
73
//  $.each( basePrototype, function( key, val ) {
73
//  $.each( basePrototype, function( key, val ) {
74
//      if ( $.isPlainObject(val) ) {
74
//      if ( $.isPlainObject(val) ) {
75
//          basePrototype[ key ] = $.extend( {}, val );
75
//          basePrototype[ key ] = $.extend( {}, val );
76
//      }
76
//      }
77
//  });
77
//  });
78
    basePrototype.options = $.extend( true, {}, basePrototype.options );
78
    basePrototype.options = $.extend( true, {}, basePrototype.options );
79
    $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
79
    $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
80
        namespace: namespace,
80
        namespace: namespace,
81
        widgetName: name,
81
        widgetName: name,
82
        widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
82
        widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
83
        widgetBaseClass: fullName
83
        widgetBaseClass: fullName
84
    }, prototype );
84
    }, prototype );
85
 
85
 
86
    $.widget.bridge( name, $[ namespace ][ name ] );
86
    $.widget.bridge( name, $[ namespace ][ name ] );
87
};
87
};
88
 
88
 
89
$.widget.bridge = function( name, object ) {
89
$.widget.bridge = function( name, object ) {
90
    $.fn[ name ] = function( options ) {
90
    $.fn[ name ] = function( options ) {
91
        var isMethodCall = typeof options === "string",
91
        var isMethodCall = typeof options === "string",
92
            args = Array.prototype.slice.call( arguments, 1 ),
92
            args = Array.prototype.slice.call( arguments, 1 ),
93
            returnValue = this;
93
            returnValue = this;
94
 
94
 
95
        // allow multiple hashes to be passed on init
95
        // allow multiple hashes to be passed on init
96
        options = !isMethodCall && args.length ?
96
        options = !isMethodCall && args.length ?
97
            $.extend.apply( null, [ true, options ].concat(args) ) :
97
            $.extend.apply( null, [ true, options ].concat(args) ) :
98
            options;
98
            options;
99
 
99
 
100
        // prevent calls to internal methods
100
        // prevent calls to internal methods
101
        if ( isMethodCall && options.charAt( 0 ) === "_" ) {
101
        if ( isMethodCall && options.charAt( 0 ) === "_" ) {
102
            return returnValue;
102
            return returnValue;
103
        }
103
        }
104
 
104
 
105
        if ( isMethodCall ) {
105
        if ( isMethodCall ) {
106
            this.each(function() {
106
            this.each(function() {
107
                var instance = $.data( this, name );
107
                var instance = $.data( this, name );
108
                if ( !instance ) {
108
                if ( !instance ) {
109
                    throw "cannot call methods on " + name + " prior to initialization; " +
109
                    throw "cannot call methods on " + name + " prior to initialization; " +
110
                        "attempted to call method '" + options + "'";
110
                        "attempted to call method '" + options + "'";
111
                }
111
                }
112
                if ( !$.isFunction( instance[options] ) ) {
112
                if ( !$.isFunction( instance[options] ) ) {
113
                    throw "no such method '" + options + "' for " + name + " widget instance";
113
                    throw "no such method '" + options + "' for " + name + " widget instance";
114
                }
114
                }
115
                var methodValue = instance[ options ].apply( instance, args );
115
                var methodValue = instance[ options ].apply( instance, args );
116
                if ( methodValue !== instance && methodValue !== undefined ) {
116
                if ( methodValue !== instance && methodValue !== undefined ) {
117
                    returnValue = methodValue;
117
                    returnValue = methodValue;
118
                    return false;
118
                    return false;
119
                }
119
                }
120
            });
120
            });
121
        } else {
121
        } else {
122
            this.each(function() {
122
            this.each(function() {
123
                var instance = $.data( this, name );
123
                var instance = $.data( this, name );
124
                if ( instance ) {
124
                if ( instance ) {
125
                    instance.option( options || {} )._init();
125
                    instance.option( options || {} )._init();
126
                } else {
126
                } else {
127
                    $.data( this, name, new object( options, this ) );
127
                    $.data( this, name, new object( options, this ) );
128
                }
128
                }
129
            });
129
            });
130
        }
130
        }
131
 
131
 
132
        return returnValue;
132
        return returnValue;
133
    };
133
    };
134
};
134
};
135
 
135
 
136
$.Widget = function( options, element ) {
136
$.Widget = function( options, element ) {
137
    // allow instantiation without initializing for simple inheritance
137
    // allow instantiation without initializing for simple inheritance
138
    if ( arguments.length ) {
138
    if ( arguments.length ) {
139
        this._createWidget( options, element );
139
        this._createWidget( options, element );
140
    }
140
    }
141
};
141
};
142
 
142
 
143
$.Widget.prototype = {
143
$.Widget.prototype = {
144
    widgetName: "widget",
144
    widgetName: "widget",
145
    widgetEventPrefix: "",
145
    widgetEventPrefix: "",
146
    options: {
146
    options: {
147
        disabled: false
147
        disabled: false
148
    },
148
    },
149
    _createWidget: function( options, element ) {
149
    _createWidget: function( options, element ) {
150
        // $.widget.bridge stores the plugin instance, but we do it anyway
150
        // $.widget.bridge stores the plugin instance, but we do it anyway
151
        // so that it's stored even before the _create function runs
151
        // so that it's stored even before the _create function runs
152
        $.data( element, this.widgetName, this );
152
        $.data( element, this.widgetName, this );
153
        this.element = $( element );
153
        this.element = $( element );
154
        this.options = $.extend( true, {},
154
        this.options = $.extend( true, {},
155
            this.options,
155
            this.options,
156
            this._getCreateOptions(),
156
            this._getCreateOptions(),
157
            options );
157
            options );
158
 
158
 
159
        var self = this;
159
        var self = this;
160
        this.element.bind( "remove." + this.widgetName, function() {
160
        this.element.bind( "remove." + this.widgetName, function() {
161
            self.destroy();
161
            self.destroy();
162
        });
162
        });
163
 
163
 
164
        this._create();
164
        this._create();
165
        this._trigger( "create" );
165
        this._trigger( "create" );
166
        this._init();
166
        this._init();
167
    },
167
    },
168
    _getCreateOptions: function() {
168
    _getCreateOptions: function() {
169
        var options = {};
169
        var options = {};
170
        if ( $.metadata ) {
170
        if ( $.metadata ) {
171
            options = $.metadata.get( element )[ this.widgetName ];
171
            options = $.metadata.get( element )[ this.widgetName ];
172
        }
172
        }
173
        return options;
173
        return options;
174
    },
174
    },
175
    _create: function() {},
175
    _create: function() {},
176
    _init: function() {},
176
    _init: function() {},
177
 
177
 
178
    destroy: function() {
178
    destroy: function() {
179
        this.element
179
        this.element
180
            .unbind( "." + this.widgetName )
180
            .unbind( "." + this.widgetName )
181
            .removeData( this.widgetName );
181
            .removeData( this.widgetName );
182
        this.widget()
182
        this.widget()
183
            .unbind( "." + this.widgetName )
183
            .unbind( "." + this.widgetName )
184
            .removeAttr( "aria-disabled" )
184
            .removeAttr( "aria-disabled" )
185
            .removeClass(
185
            .removeClass(
186
                this.widgetBaseClass + "-disabled " +
186
                this.widgetBaseClass + "-disabled " +
187
                "ui-state-disabled" );
187
                "ui-state-disabled" );
188
    },
188
    },
189
 
189
 
190
    widget: function() {
190
    widget: function() {
191
        return this.element;
191
        return this.element;
192
    },
192
    },
193
 
193
 
194
    option: function( key, value ) {
194
    option: function( key, value ) {
195
        var options = key;
195
        var options = key;
196
 
196
 
197
        if ( arguments.length === 0 ) {
197
        if ( arguments.length === 0 ) {
198
            // don't return a reference to the internal hash
198
            // don't return a reference to the internal hash
199
            return $.extend( {}, this.options );
199
            return $.extend( {}, this.options );
200
        }
200
        }
201
 
201
 
202
        if  (typeof key === "string" ) {
202
        if  (typeof key === "string" ) {
203
            if ( value === undefined ) {
203
            if ( value === undefined ) {
204
                return this.options[ key ];
204
                return this.options[ key ];
205
            }
205
            }
206
            options = {};
206
            options = {};
207
            options[ key ] = value;
207
            options[ key ] = value;
208
        }
208
        }
209
 
209
 
210
        this._setOptions( options );
210
        this._setOptions( options );
211
 
211
 
212
        return this;
212
        return this;
213
    },
213
    },
214
    _setOptions: function( options ) {
214
    _setOptions: function( options ) {
215
        var self = this;
215
        var self = this;
216
        $.each( options, function( key, value ) {
216
        $.each( options, function( key, value ) {
217
            self._setOption( key, value );
217
            self._setOption( key, value );
218
        });
218
        });
219
 
219
 
220
        return this;
220
        return this;
221
    },
221
    },
222
    _setOption: function( key, value ) {
222
    _setOption: function( key, value ) {
223
        this.options[ key ] = value;
223
        this.options[ key ] = value;
224
 
224
 
225
        if ( key === "disabled" ) {
225
        if ( key === "disabled" ) {
226
            this.widget()
226
            this.widget()
227
                [ value ? "addClass" : "removeClass"](
227
                [ value ? "addClass" : "removeClass"](
228
                    this.widgetBaseClass + "-disabled" + " " +
228
                    this.widgetBaseClass + "-disabled" + " " +
229
                    "ui-state-disabled" )
229
                    "ui-state-disabled" )
230
                .attr( "aria-disabled", value );
230
                .attr( "aria-disabled", value );
231
        }
231
        }
232
 
232
 
233
        return this;
233
        return this;
234
    },
234
    },
235
 
235
 
236
    enable: function() {
236
    enable: function() {
237
        return this._setOption( "disabled", false );
237
        return this._setOption( "disabled", false );
238
    },
238
    },
239
    disable: function() {
239
    disable: function() {
240
        return this._setOption( "disabled", true );
240
        return this._setOption( "disabled", true );
241
    },
241
    },
242
 
242
 
243
    _trigger: function( type, event, data ) {
243
    _trigger: function( type, event, data ) {
244
        var callback = this.options[ type ];
244
        var callback = this.options[ type ];
245
 
245
 
246
        event = $.Event( event );
246
        event = $.Event( event );
247
        event.type = ( type === this.widgetEventPrefix ?
247
        event.type = ( type === this.widgetEventPrefix ?
248
            type :
248
            type :
249
            this.widgetEventPrefix + type ).toLowerCase();
249
            this.widgetEventPrefix + type ).toLowerCase();
250
        data = data || {};
250
        data = data || {};
251
 
251
 
252
        // copy original event properties over to the new event
252
        // copy original event properties over to the new event
253
        // this would happen if we could call $.event.fix instead of $.Event
253
        // this would happen if we could call $.event.fix instead of $.Event
254
        // but we don't have a way to force an event to be fixed multiple times
254
        // but we don't have a way to force an event to be fixed multiple times
255
        if ( event.originalEvent ) {
255
        if ( event.originalEvent ) {
256
            for ( var i = $.event.props.length, prop; i; ) {
256
            for ( var i = $.event.props.length, prop; i; ) {
257
                prop = $.event.props[ --i ];
257
                prop = $.event.props[ --i ];
258
                event[ prop ] = event.originalEvent[ prop ];
258
                event[ prop ] = event.originalEvent[ prop ];
259
            }
259
            }
260
        }
260
        }
261
 
261
 
262
        this.element.trigger( event, data );
262
        this.element.trigger( event, data );
263
 
263
 
264
        return !( $.isFunction(callback) &&
264
        return !( $.isFunction(callback) &&
265
            callback.call( this.element[0], event, data ) === false ||
265
            callback.call( this.element[0], event, data ) === false ||
266
            event.isDefaultPrevented() );
266
            event.isDefaultPrevented() );
267
    }
267
    }
268
};
268
};
269
 
269
 
270
})( jQuery );
270
})( jQuery );
271
/*
271
/*
272
* jQuery Mobile Framework : widget factory extentions for mobile
272
* jQuery Mobile Framework : widget factory extentions for mobile
273
* Copyright (c) jQuery Project
273
* Copyright (c) jQuery Project
274
* Dual licensed under the MIT or GPL Version 2 licenses.
274
* Dual licensed under the MIT or GPL Version 2 licenses.
275
* http://jquery.org/license
275
* http://jquery.org/license
276
*/
276
*/
277
(function($, undefined ) {
277
(function($, undefined ) {
278
 
278
 
279
$.widget( "mobile.widget", {
279
$.widget( "mobile.widget", {
280
    _getCreateOptions: function() {
280
    _getCreateOptions: function() {
281
        var elem = this.element,
281
        var elem = this.element,
282
            options = {};
282
            options = {};
283
        $.each( this.options, function( option ) {
283
        $.each( this.options, function( option ) {
284
            var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) {
284
            var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) {
285
                return "-" + c.toLowerCase();
285
                return "-" + c.toLowerCase();
286
            } ) );
286
            } ) );
287
            if ( value !== undefined ) {
287
            if ( value !== undefined ) {
288
                options[ option ] = value;
288
                options[ option ] = value;
289
            }
289
            }
290
        });
290
        });
291
        return options;
291
        return options;
292
    }
292
    }
293
});
293
});
294
 
294
 
295
})( jQuery );
295
})( jQuery );
296
/*
296
/*
297
* jQuery Mobile Framework : resolution and CSS media query related helpers and behavior
297
* jQuery Mobile Framework : resolution and CSS media query related helpers and behavior
298
* Copyright (c) jQuery Project
298
* Copyright (c) jQuery Project
299
* Dual licensed under the MIT or GPL Version 2 licenses.
299
* Dual licensed under the MIT or GPL Version 2 licenses.
300
* http://jquery.org/license
300
* http://jquery.org/license
301
*/
301
*/
302
(function($, undefined ) {
302
(function($, undefined ) {
303
 
303
 
304
var $window = $(window),
304
var $window = $(window),
305
    $html = $( "html" ),
305
    $html = $( "html" ),
306
 
306
 
307
    //media-query-like width breakpoints, which are translated to classes on the html element
307
    //media-query-like width breakpoints, which are translated to classes on the html element
308
    resolutionBreakpoints = [320,480,768,1024];
308
    resolutionBreakpoints = [320,480,768,1024];
309
 
309
 
310
 
310
 
311
/* $.mobile.media method: pass a CSS media type or query and get a bool return
311
/* $.mobile.media method: pass a CSS media type or query and get a bool return
312
    note: this feature relies on actual media query support for media queries, though types will work most anywhere
312
    note: this feature relies on actual media query support for media queries, though types will work most anywhere
313
    examples:
313
    examples:
314
        $.mobile.media('screen') //>> tests for screen media type
314
        $.mobile.media('screen') //>> tests for screen media type
315
        $.mobile.media('screen and (min-width: 480px)') //>> tests for screen media type with window width > 480px
315
        $.mobile.media('screen and (min-width: 480px)') //>> tests for screen media type with window width > 480px
316
        $.mobile.media('@media screen and (-webkit-min-device-pixel-ratio: 2)') //>> tests for webkit 2x pixel ratio (iPhone 4)
316
        $.mobile.media('@media screen and (-webkit-min-device-pixel-ratio: 2)') //>> tests for webkit 2x pixel ratio (iPhone 4)
317
*/
317
*/
318
$.mobile.media = (function() {
318
$.mobile.media = (function() {
319
    // TODO: use window.matchMedia once at least one UA implements it
319
    // TODO: use window.matchMedia once at least one UA implements it
320
    var cache = {},
320
    var cache = {},
321
        testDiv = $( "<div id='jquery-mediatest'>" ),
321
        testDiv = $( "<div id='jquery-mediatest'>" ),
322
        fakeBody = $( "<body>" ).append( testDiv );
322
        fakeBody = $( "<body>" ).append( testDiv );
323
 
323
 
324
    return function( query ) {
324
    return function( query ) {
325
        if ( !( query in cache ) ) {
325
        if ( !( query in cache ) ) {
326
            var styleBlock = document.createElement('style'),
326
            var styleBlock = document.createElement('style'),
327
                cssrule = "@media " + query + " { #jquery-mediatest { position:absolute; } }";
327
                cssrule = "@media " + query + " { #jquery-mediatest { position:absolute; } }";
328
            //must set type for IE! 
328
            //must set type for IE! 
329
            styleBlock.type = "text/css";
329
            styleBlock.type = "text/css";
330
            if (styleBlock.styleSheet){
330
            if (styleBlock.styleSheet){
331
              styleBlock.styleSheet.cssText = cssrule;
331
              styleBlock.styleSheet.cssText = cssrule;
332
            }
332
            }
333
            else {
333
            else {
334
              styleBlock.appendChild(document.createTextNode(cssrule));
334
              styleBlock.appendChild(document.createTextNode(cssrule));
335
            }
335
            }
336
               
336
               
337
            $html.prepend( fakeBody ).prepend( styleBlock );
337
            $html.prepend( fakeBody ).prepend( styleBlock );
338
            cache[ query ] = testDiv.css( "position" ) === "absolute";
338
            cache[ query ] = testDiv.css( "position" ) === "absolute";
339
            fakeBody.add( styleBlock ).remove();
339
            fakeBody.add( styleBlock ).remove();
340
        }
340
        }
341
        return cache[ query ];
341
        return cache[ query ];
342
    };
342
    };
343
})();
343
})();
344
 
344
 
345
/*
345
/*
346
    private function for adding/removing breakpoint classes to HTML element for faux media-query support
346
    private function for adding/removing breakpoint classes to HTML element for faux media-query support
347
    It does not require media query support, instead using JS to detect screen width > cross-browser support
347
    It does not require media query support, instead using JS to detect screen width > cross-browser support
348
    This function is called on orientationchange, resize, and mobileinit, and is bound via the 'htmlclass' event namespace
348
    This function is called on orientationchange, resize, and mobileinit, and is bound via the 'htmlclass' event namespace
349
*/
349
*/
350
function detectResolutionBreakpoints(){
350
function detectResolutionBreakpoints(){
351
    var currWidth = $window.width(),
351
    var currWidth = $window.width(),
352
        minPrefix = "min-width-",
352
        minPrefix = "min-width-",
353
        maxPrefix = "max-width-",
353
        maxPrefix = "max-width-",
354
        minBreakpoints = [],
354
        minBreakpoints = [],
355
        maxBreakpoints = [],
355
        maxBreakpoints = [],
356
        unit = "px",
356
        unit = "px",
357
        breakpointClasses;
357
        breakpointClasses;
358
 
358
 
359
    $html.removeClass( minPrefix + resolutionBreakpoints.join(unit + " " + minPrefix) + unit + " " +
359
    $html.removeClass( minPrefix + resolutionBreakpoints.join(unit + " " + minPrefix) + unit + " " +
360
        maxPrefix + resolutionBreakpoints.join( unit + " " + maxPrefix) + unit );
360
        maxPrefix + resolutionBreakpoints.join( unit + " " + maxPrefix) + unit );
361
 
361
 
362
    $.each(resolutionBreakpoints,function( i, breakPoint ){
362
    $.each(resolutionBreakpoints,function( i, breakPoint ){
363
        if( currWidth >= breakPoint ){
363
        if( currWidth >= breakPoint ){
364
            minBreakpoints.push( minPrefix + breakPoint + unit );
364
            minBreakpoints.push( minPrefix + breakPoint + unit );
365
        }
365
        }
366
        if( currWidth <= breakPoint ){
366
        if( currWidth <= breakPoint ){
367
            maxBreakpoints.push( maxPrefix + breakPoint + unit );
367
            maxBreakpoints.push( maxPrefix + breakPoint + unit );
368
        }
368
        }
369
    });
369
    });
370
 
370
 
371
    if( minBreakpoints.length ){ breakpointClasses = minBreakpoints.join(" "); }
371
    if( minBreakpoints.length ){ breakpointClasses = minBreakpoints.join(" "); }
372
    if( maxBreakpoints.length ){ breakpointClasses += " " +  maxBreakpoints.join(" "); }
372
    if( maxBreakpoints.length ){ breakpointClasses += " " +  maxBreakpoints.join(" "); }
373
 
373
 
374
    $html.addClass( breakpointClasses );
374
    $html.addClass( breakpointClasses );
375
};
375
};
376
 
376
 
377
/* $.mobile.addResolutionBreakpoints method:
377
/* $.mobile.addResolutionBreakpoints method:
378
    pass either a number or an array of numbers and they'll be added to the min/max breakpoint classes
378
    pass either a number or an array of numbers and they'll be added to the min/max breakpoint classes
379
    Examples:
379
    Examples:
380
        $.mobile.addResolutionBreakpoints( 500 );
380
        $.mobile.addResolutionBreakpoints( 500 );
381
        $.mobile.addResolutionBreakpoints( [500, 1200] );
381
        $.mobile.addResolutionBreakpoints( [500, 1200] );
382
*/
382
*/
383
$.mobile.addResolutionBreakpoints = function( newbps ){
383
$.mobile.addResolutionBreakpoints = function( newbps ){
384
    if( $.type( newbps ) === "array" ){
384
    if( $.type( newbps ) === "array" ){
385
        resolutionBreakpoints = resolutionBreakpoints.concat( newbps );
385
        resolutionBreakpoints = resolutionBreakpoints.concat( newbps );
386
    }
386
    }
387
    else {
387
    else {
388
        resolutionBreakpoints.push( newbps );
388
        resolutionBreakpoints.push( newbps );
389
    }
389
    }
390
    resolutionBreakpoints.sort(function(a,b){ return a-b; });
390
    resolutionBreakpoints.sort(function(a,b){ return a-b; });
391
    detectResolutionBreakpoints();
391
    detectResolutionBreakpoints();
392
};
392
};
393
 
393
 
394
/*  on mobileinit, add classes to HTML element
394
/*  on mobileinit, add classes to HTML element
395
    and set handlers to update those on orientationchange and resize*/
395
    and set handlers to update those on orientationchange and resize*/
396
$(document).bind("mobileinit.htmlclass", function(){
396
$(document).bind("mobileinit.htmlclass", function(){
397
    /* bind to orientationchange and resize
397
    /* bind to orientationchange and resize
398
    to add classes to HTML element for min/max breakpoints and orientation */
398
    to add classes to HTML element for min/max breakpoints and orientation */
399
    var ev = $.support.orientation;
399
    var ev = $.support.orientation;
400
    $window.bind("orientationchange.htmlclass throttledResize.htmlclass", function(event){
400
    $window.bind("orientationchange.htmlclass throttledResize.htmlclass", function(event){
401
        //add orientation class to HTML element on flip/resize.
401
        //add orientation class to HTML element on flip/resize.
402
        if(event.orientation){
402
        if(event.orientation){
403
            $html.removeClass( "portrait landscape" ).addClass( event.orientation );
403
            $html.removeClass( "portrait landscape" ).addClass( event.orientation );
404
        }
404
        }
405
        //add classes to HTML element for min/max breakpoints
405
        //add classes to HTML element for min/max breakpoints
406
        detectResolutionBreakpoints();
406
        detectResolutionBreakpoints();
407
    });
407
    });
408
});
408
});
409
 
409
 
410
/* Manually trigger an orientationchange event when the dom ready event fires.
410
/* Manually trigger an orientationchange event when the dom ready event fires.
411
   This will ensure that any viewport meta tag that may have been injected
411
   This will ensure that any viewport meta tag that may have been injected
412
   has taken effect already, allowing us to properly calculate the width of the
412
   has taken effect already, allowing us to properly calculate the width of the
413
   document.
413
   document.
414
*/
414
*/
415
$(function(){
415
$(function(){
416
    //trigger event manually
416
    //trigger event manually
417
    $window.trigger( "orientationchange.htmlclass" );
417
    $window.trigger( "orientationchange.htmlclass" );
418
});
418
});
419
 
419
 
420
})(jQuery);/*
420
})(jQuery);/*
421
* jQuery Mobile Framework : support tests
421
* jQuery Mobile Framework : support tests
422
* Copyright (c) jQuery Project
422
* Copyright (c) jQuery Project
423
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
423
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
424
* Note: Code is in draft form and is subject to change
424
* Note: Code is in draft form and is subject to change
425
*/
425
*/
426
( function( $, undefined  ) {
426
( function( $, undefined  ) {
427
 
427
 
428
var fakeBody = $( "<body>"  ).prependTo( "html" ),
428
var fakeBody = $( "<body>"  ).prependTo( "html" ),
429
    fbCSS = fakeBody[ 0 ].style,
429
    fbCSS = fakeBody[ 0 ].style,
430
    vendors = [ "webkit", "moz", "o" ],
430
    vendors = [ "webkit", "moz", "o" ],
431
    webos = "palmGetResource" in window, //only used to rule out scrollTop 
431
    webos = "palmGetResource" in window, //only used to rule out scrollTop 
432
    bb = window.blackberry; //only used to rule out box shadow, as it's filled opaque on BB
432
    bb = window.blackberry; //only used to rule out box shadow, as it's filled opaque on BB
433
 
433
 
434
// thx Modernizr
434
// thx Modernizr
435
function propExists( prop  ){
435
function propExists( prop  ){
436
    var uc_prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
436
    var uc_prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
437
        props   = ( prop + " " + vendors.join( uc_prop + " " ) + uc_prop ).split( " " );
437
        props   = ( prop + " " + vendors.join( uc_prop + " " ) + uc_prop ).split( " " );
438
    for( var v in props ){
438
    for( var v in props ){
439
        if( fbCSS[ v ] !== undefined  ){
439
        if( fbCSS[ v ] !== undefined  ){
440
            return true;
440
            return true;
441
        }
441
        }
442
    }
442
    }
443
}
443
}
444
 
444
 
445
// test for dynamic-updating base tag support ( allows us to avoid href,src attr rewriting )
445
// test for dynamic-updating base tag support ( allows us to avoid href,src attr rewriting )
446
function baseTagTest(){
446
function baseTagTest(){
447
    var fauxBase = location.protocol + "//" + location.host + location.pathname + "ui-dir/",
447
    var fauxBase = location.protocol + "//" + location.host + location.pathname + "ui-dir/",
448
        base = $( "head base" ),
448
        base = $( "head base" ),
449
        fauxEle = null,
449
        fauxEle = null,
450
        href = "";
450
        href = "";
451
    if ( !base.length ) {
451
    if ( !base.length ) {
452
        base = fauxEle = $( "<base>", { "href": fauxBase} ).appendTo( "head" );
452
        base = fauxEle = $( "<base>", { "href": fauxBase} ).appendTo( "head" );
453
    }
453
    }
454
    else {
454
    else {
455
        href = base.attr( "href" );
455
        href = base.attr( "href" );
456
    }
456
    }
457
    var link = $( "<a href='testurl'></a>"  ).prependTo( fakeBody  ),
457
    var link = $( "<a href='testurl'></a>"  ).prependTo( fakeBody  ),
458
        rebase = link[ 0 ].href;
458
        rebase = link[ 0 ].href;
459
    base[ 0 ].href = href ? href : location.pathname;
459
    base[ 0 ].href = href ? href : location.pathname;
460
    if ( fauxEle ) {
460
    if ( fauxEle ) {
461
        fauxEle.remove();
461
        fauxEle.remove();
462
    }
462
    }
463
    return rebase.indexOf( fauxBase ) === 0;
463
    return rebase.indexOf( fauxBase ) === 0;
464
}
464
}
465
 
465
 
466
 
466
 
467
// non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683
467
// non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683
468
// allows for inclusion of IE 6+, including Windows Mobile 7
468
// allows for inclusion of IE 6+, including Windows Mobile 7
469
$.mobile.browser = {};
469
$.mobile.browser = {};
470
$.mobile.browser.ie = ( function() {
470
$.mobile.browser.ie = ( function() {
471
    var v = 3,
471
    var v = 3,
472
    div = document.createElement( "div" ),
472
    div = document.createElement( "div" ),
473
    a = div.all || [];
473
    a = div.all || [];
474
    while ( div.innerHTML = "<!--[if gt IE " + ( ++v ) + "]><br><![endif]-->", a[ 0 ] );
474
    while ( div.innerHTML = "<!--[if gt IE " + ( ++v ) + "]><br><![endif]-->", a[ 0 ] );
475
    return v > 4 ? v : !v;
475
    return v > 4 ? v : !v;
476
}() );
476
}() );
477
 
477
 
478
 
478
 
479
$.extend( $.support, {
479
$.extend( $.support, {
480
    orientation: "orientation" in window,
480
    orientation: "orientation" in window,
481
    touch: "ontouchend" in document,
481
    touch: "ontouchend" in document,
482
    cssTransitions: "WebKitTransitionEvent" in window,
482
    cssTransitions: "WebKitTransitionEvent" in window,
483
    pushState: !!history.pushState,
483
    pushState: !!history.pushState,
484
    mediaquery: $.mobile.media( "only all" ),
484
    mediaquery: $.mobile.media( "only all" ),
485
    cssPseudoElement: !!propExists( "content" ),
485
    cssPseudoElement: !!propExists( "content" ),
486
    boxShadow: !!propExists( "boxShadow" ) && !bb,
486
    boxShadow: !!propExists( "boxShadow" ) && !bb,
487
    scrollTop: ( "pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[ 0 ] ) && !webos,
487
    scrollTop: ( "pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[ 0 ] ) && !webos,
488
    dynamicBaseTag: baseTagTest(),
488
    dynamicBaseTag: baseTagTest(),
489
    eventCapture: ( "addEventListener" in document ) // This is a weak test. We may want to beef this up later.
489
    eventCapture: ( "addEventListener" in document ) // This is a weak test. We may want to beef this up later.
490
} );
490
} );
491
 
491
 
492
fakeBody.remove();
492
fakeBody.remove();
493
 
493
 
494
// for ruling out shadows via css
494
// for ruling out shadows via css
495
if( !$.support.boxShadow  ){ $( "html" ).addClass( "ui-mobile-nosupport-boxshadow" ); }
495
if( !$.support.boxShadow  ){ $( "html" ).addClass( "ui-mobile-nosupport-boxshadow" ); }
496
 
496
 
497
} )( jQuery  );/*
497
} )( jQuery  );/*
498
* jQuery Mobile Framework : "mouse" plugin
498
* jQuery Mobile Framework : "mouse" plugin
499
* Copyright (c) jQuery Project
499
* Copyright (c) jQuery Project
500
* Dual licensed under the MIT or GPL Version 2 licenses.
500
* Dual licensed under the MIT or GPL Version 2 licenses.
501
* http://jquery.org/license
501
* http://jquery.org/license
502
*/
502
*/
503
 
503
 
504
// This plugin is an experiment for abstracting away the touch and mouse
504
// This plugin is an experiment for abstracting away the touch and mouse
505
// events so that developers don't have to worry about which method of input
505
// events so that developers don't have to worry about which method of input
506
// the device their document is loaded on supports.
506
// the device their document is loaded on supports.
507
//
507
//
508
// The idea here is to allow the developer to register listeners for the
508
// The idea here is to allow the developer to register listeners for the
509
// basic mouse events, such as mousedown, mousemove, mouseup, and click,
509
// basic mouse events, such as mousedown, mousemove, mouseup, and click,
510
// and the plugin will take care of registering the correct listeners
510
// and the plugin will take care of registering the correct listeners
511
// behind the scenes to invoke the listener at the fastest possible time
511
// behind the scenes to invoke the listener at the fastest possible time
512
// for that device, while still retaining the order of event firing in
512
// for that device, while still retaining the order of event firing in
513
// the traditional mouse environment, should multiple handlers be registered
513
// the traditional mouse environment, should multiple handlers be registered
514
// on the same element for different events.
514
// on the same element for different events.
515
//
515
//
516
// The current version exposes the following virtual events to jQuery bind methods:
516
// The current version exposes the following virtual events to jQuery bind methods:
517
// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
517
// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
518
 
518
 
519
(function($, window, document, undefined) {
519
(function($, window, document, undefined) {
520
 
520
 
521
var dataPropertyName = "virtualMouseBindings",
521
var dataPropertyName = "virtualMouseBindings",
522
    touchTargetPropertyName = "virtualTouchID",
522
    touchTargetPropertyName = "virtualTouchID",
523
    virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),
523
    virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),
524
    touchEventProps = "clientX clientY pageX pageY screenX screenY".split(" "),
524
    touchEventProps = "clientX clientY pageX pageY screenX screenY".split(" "),
525
    activeDocHandlers = {},
525
    activeDocHandlers = {},
526
    resetTimerID = 0,
526
    resetTimerID = 0,
527
    startX = 0,
527
    startX = 0,
528
    startY = 0,
528
    startY = 0,
529
    didScroll = false,
529
    didScroll = false,
530
    clickBlockList = [],
530
    clickBlockList = [],
531
    blockMouseTriggers = false,
531
    blockMouseTriggers = false,
532
    blockTouchTriggers = false,
532
    blockTouchTriggers = false,
533
    eventCaptureSupported = $.support.eventCapture,
533
    eventCaptureSupported = $.support.eventCapture,
534
    $document = $(document),
534
    $document = $(document),
535
    nextTouchID = 1,
535
    nextTouchID = 1,
536
    lastTouchID = 0;
536
    lastTouchID = 0;
537
 
537
 
538
$.vmouse = {
538
$.vmouse = {
539
    moveDistanceThreshold: 10,
539
    moveDistanceThreshold: 10,
540
    clickDistanceThreshold: 10,
540
    clickDistanceThreshold: 10,
541
    resetTimerDuration: 1500
541
    resetTimerDuration: 1500
542
};
542
};
543
 
543
 
544
function getNativeEvent(event)
544
function getNativeEvent(event)
545
{
545
{
546
    while (event && typeof event.originalEvent !== "undefined") {
546
    while (event && typeof event.originalEvent !== "undefined") {
547
        event = event.originalEvent;
547
        event = event.originalEvent;
548
    }
548
    }
549
    return event;
549
    return event;
550
}
550
}
551
 
551
 
552
function createVirtualEvent(event, eventType)
552
function createVirtualEvent(event, eventType)
553
{
553
{
554
    var t = event.type;
554
    var t = event.type;
555
    event = $.Event(event);
555
    event = $.Event(event);
556
    event.type = eventType;
556
    event.type = eventType;
557
   
557
   
558
    var oe = event.originalEvent;
558
    var oe = event.originalEvent;
559
    var props = $.event.props;
559
    var props = $.event.props;
560
   
560
   
561
    // copy original event properties over to the new event
561
    // copy original event properties over to the new event
562
    // this would happen if we could call $.event.fix instead of $.Event
562
    // this would happen if we could call $.event.fix instead of $.Event
563
    // but we don't have a way to force an event to be fixed multiple times
563
    // but we don't have a way to force an event to be fixed multiple times
564
    if (oe) {
564
    if (oe) {
565
        for ( var i = props.length, prop; i; ) {
565
        for ( var i = props.length, prop; i; ) {
566
            prop = props[ --i ];
566
            prop = props[ --i ];
567
            event[prop] = oe[prop];
567
            event[prop] = oe[prop];
568
        }
568
        }
569
    }
569
    }
570
   
570
   
571
    if (t.search(/^touch/) !== -1){
571
    if (t.search(/^touch/) !== -1){
572
        var ne = getNativeEvent(oe),
572
        var ne = getNativeEvent(oe),
573
            t = ne.touches,
573
            t = ne.touches,
574
            ct = ne.changedTouches,
574
            ct = ne.changedTouches,
575
            touch = (t && t.length) ? t[0] : ((ct && ct.length) ? ct[0] : undefined);
575
            touch = (t && t.length) ? t[0] : ((ct && ct.length) ? ct[0] : undefined);
576
        if (touch){
576
        if (touch){
577
            for (var i = 0, len = touchEventProps.length; i < len; i++){
577
            for (var i = 0, len = touchEventProps.length; i < len; i++){
578
                var prop = touchEventProps[i];
578
                var prop = touchEventProps[i];
579
                event[prop] = touch[prop];
579
                event[prop] = touch[prop];
580
            }
580
            }
581
        }
581
        }
582
    }
582
    }
583
 
583
 
584
    return event;
584
    return event;
585
}
585
}
586
 
586
 
587
function getVirtualBindingFlags(element)
587
function getVirtualBindingFlags(element)
588
{
588
{
589
    var flags = {};
589
    var flags = {};
590
    while (element){
590
    while (element){
591
        var b = $.data(element, dataPropertyName);
591
        var b = $.data(element, dataPropertyName);
592
        for (var k in b) {
592
        for (var k in b) {
593
            if (b[k]){
593
            if (b[k]){
594
                flags[k] = flags.hasVirtualBinding = true;
594
                flags[k] = flags.hasVirtualBinding = true;
595
            }
595
            }
596
        }
596
        }
597
        element = element.parentNode;
597
        element = element.parentNode;
598
    }
598
    }
599
    return flags;
599
    return flags;
600
}
600
}
601
 
601
 
602
function getClosestElementWithVirtualBinding(element, eventType)
602
function getClosestElementWithVirtualBinding(element, eventType)
603
{
603
{
604
    while (element){
604
    while (element){
605
        var b = $.data(element, dataPropertyName);
605
        var b = $.data(element, dataPropertyName);
606
        if (b && (!eventType || b[eventType])) {
606
        if (b && (!eventType || b[eventType])) {
607
            return element;
607
            return element;
608
        }
608
        }
609
        element = element.parentNode;
609
        element = element.parentNode;
610
    }
610
    }
611
    return null;
611
    return null;
612
}
612
}
613
 
613
 
614
function enableTouchBindings()
614
function enableTouchBindings()
615
{
615
{
616
    blockTouchTriggers = false;
616
    blockTouchTriggers = false;
617
}
617
}
618
 
618
 
619
function disableTouchBindings()
619
function disableTouchBindings()
620
{
620
{
621
    blockTouchTriggers = true;
621
    blockTouchTriggers = true;
622
}
622
}
623
 
623
 
624
function enableMouseBindings()
624
function enableMouseBindings()
625
{
625
{
626
    lastTouchID = 0;
626
    lastTouchID = 0;
627
    clickBlockList.length = 0;
627
    clickBlockList.length = 0;
628
    blockMouseTriggers = false;
628
    blockMouseTriggers = false;
629
 
629
 
630
    // When mouse bindings are enabled, our
630
    // When mouse bindings are enabled, our
631
    // touch bindings are disabled.
631
    // touch bindings are disabled.
632
    disableTouchBindings();
632
    disableTouchBindings();
633
}
633
}
634
 
634
 
635
function disableMouseBindings()
635
function disableMouseBindings()
636
{
636
{
637
    // When mouse bindings are disabled, our
637
    // When mouse bindings are disabled, our
638
    // touch bindings are enabled.
638
    // touch bindings are enabled.
639
    enableTouchBindings();
639
    enableTouchBindings();
640
}
640
}
641
 
641
 
642
function startResetTimer()
642
function startResetTimer()
643
{
643
{
644
    clearResetTimer();
644
    clearResetTimer();
645
    resetTimerID = setTimeout(function(){
645
    resetTimerID = setTimeout(function(){
646
        resetTimerID = 0;
646
        resetTimerID = 0;
647
        enableMouseBindings();
647
        enableMouseBindings();
648
    }, $.vmouse.resetTimerDuration);
648
    }, $.vmouse.resetTimerDuration);
649
}
649
}
650
 
650
 
651
function clearResetTimer()
651
function clearResetTimer()
652
{
652
{
653
    if (resetTimerID){
653
    if (resetTimerID){
654
        clearTimeout(resetTimerID);
654
        clearTimeout(resetTimerID);
655
        resetTimerID = 0;
655
        resetTimerID = 0;
656
    }
656
    }
657
}
657
}
658
 
658
 
659
function triggerVirtualEvent(eventType, event, flags)
659
function triggerVirtualEvent(eventType, event, flags)
660
{
660
{
661
    var defaultPrevented = false;
661
    var defaultPrevented = false;
662
 
662
 
663
    if ((flags && flags[eventType]) || (!flags && getClosestElementWithVirtualBinding(event.target, eventType))) {
663
    if ((flags && flags[eventType]) || (!flags && getClosestElementWithVirtualBinding(event.target, eventType))) {
664
        var ve = createVirtualEvent(event, eventType);
664
        var ve = createVirtualEvent(event, eventType);
665
        $(event.target).trigger(ve);
665
        $(event.target).trigger(ve);
666
        defaultPrevented = ve.isDefaultPrevented();
666
        defaultPrevented = ve.isDefaultPrevented();
667
    }
667
    }
668
 
668
 
669
    return defaultPrevented;
669
    return defaultPrevented;
670
}
670
}
671
 
671
 
672
function mouseEventCallback(event)
672
function mouseEventCallback(event)
673
{
673
{
674
    var touchID = $.data(event.target, touchTargetPropertyName);
674
    var touchID = $.data(event.target, touchTargetPropertyName);
675
    if (!blockMouseTriggers && (!lastTouchID || lastTouchID !== touchID)){
675
    if (!blockMouseTriggers && (!lastTouchID || lastTouchID !== touchID)){
676
        triggerVirtualEvent("v" + event.type, event);
676
        triggerVirtualEvent("v" + event.type, event);
677
    }
677
    }
678
}
678
}
679
 
679
 
680
function handleTouchStart(event)
680
function handleTouchStart(event)
681
{
681
{
682
    var touches = getNativeEvent(event).touches;
682
    var touches = getNativeEvent(event).touches;
683
    if (touches && touches.length === 1){
683
    if (touches && touches.length === 1){
684
        var target = event.target,
684
        var target = event.target,
685
            flags = getVirtualBindingFlags(target);
685
            flags = getVirtualBindingFlags(target);
686
   
686
   
687
        if (flags.hasVirtualBinding){
687
        if (flags.hasVirtualBinding){
688
            lastTouchID = nextTouchID++;
688
            lastTouchID = nextTouchID++;
689
            $.data(target, touchTargetPropertyName, lastTouchID);
689
            $.data(target, touchTargetPropertyName, lastTouchID);
690
   
690
   
691
            clearResetTimer();
691
            clearResetTimer();
692
           
692
           
693
            disableMouseBindings();
693
            disableMouseBindings();
694
            didScroll = false;
694
            didScroll = false;
695
           
695
           
696
            var t = getNativeEvent(event).touches[0];
696
            var t = getNativeEvent(event).touches[0];
697
            startX = t.pageX;
697
            startX = t.pageX;
698
            startY = t.pageY;
698
            startY = t.pageY;
699
       
699
       
700
            triggerVirtualEvent("vmouseover", event, flags);
700
            triggerVirtualEvent("vmouseover", event, flags);
701
            triggerVirtualEvent("vmousedown", event, flags);
701
            triggerVirtualEvent("vmousedown", event, flags);
702
        }
702
        }
703
    }
703
    }
704
}
704
}
705
 
705
 
706
function handleScroll(event)
706
function handleScroll(event)
707
{
707
{
708
    if (blockTouchTriggers){
708
    if (blockTouchTriggers){
709
        return;
709
        return;
710
    }
710
    }
711
 
711
 
712
    if (!didScroll){
712
    if (!didScroll){
713
        triggerVirtualEvent("vmousecancel", event, getVirtualBindingFlags(event.target));
713
        triggerVirtualEvent("vmousecancel", event, getVirtualBindingFlags(event.target));
714
    }
714
    }
715
 
715
 
716
    didScroll = true;
716
    didScroll = true;
717
    startResetTimer();
717
    startResetTimer();
718
}
718
}
719
 
719
 
720
function handleTouchMove(event)
720
function handleTouchMove(event)
721
{
721
{
722
    if (blockTouchTriggers){
722
    if (blockTouchTriggers){
723
        return;
723
        return;
724
    }
724
    }
725
 
725
 
726
    var t = getNativeEvent(event).touches[0];
726
    var t = getNativeEvent(event).touches[0];
727
 
727
 
728
    var didCancel = didScroll,
728
    var didCancel = didScroll,
729
        moveThreshold = $.vmouse.moveDistanceThreshold;
729
        moveThreshold = $.vmouse.moveDistanceThreshold;
730
    didScroll = didScroll
730
    didScroll = didScroll
731
        || (Math.abs(t.pageX - startX) > moveThreshold || Math.abs(t.pageY - startY) > moveThreshold);
731
        || (Math.abs(t.pageX - startX) > moveThreshold || Math.abs(t.pageY - startY) > moveThreshold);
732
 
732
 
733
    var flags = getVirtualBindingFlags(event.target);
733
    var flags = getVirtualBindingFlags(event.target);
734
    if (didScroll && !didCancel){
734
    if (didScroll && !didCancel){
735
        triggerVirtualEvent("vmousecancel", event, flags);
735
        triggerVirtualEvent("vmousecancel", event, flags);
736
    }
736
    }
737
    triggerVirtualEvent("vmousemove", event, flags);
737
    triggerVirtualEvent("vmousemove", event, flags);
738
    startResetTimer();
738
    startResetTimer();
739
}
739
}
740
 
740
 
741
function handleTouchEnd(event)
741
function handleTouchEnd(event)
742
{
742
{
743
    if (blockTouchTriggers){
743
    if (blockTouchTriggers){
744
        return;
744
        return;
745
    }
745
    }
746
 
746
 
747
    disableTouchBindings();
747
    disableTouchBindings();
748
 
748
 
749
    var flags = getVirtualBindingFlags(event.target);
749
    var flags = getVirtualBindingFlags(event.target);
750
    triggerVirtualEvent("vmouseup", event, flags);
750
    triggerVirtualEvent("vmouseup", event, flags);
751
    if (!didScroll){
751
    if (!didScroll){
752
        if (triggerVirtualEvent("vclick", event, flags)){
752
        if (triggerVirtualEvent("vclick", event, flags)){
753
            // The target of the mouse events that follow the touchend
753
            // The target of the mouse events that follow the touchend
754
            // event don't necessarily match the target used during the
754
            // event don't necessarily match the target used during the
755
            // touch. This means we need to rely on coordinates for blocking
755
            // touch. This means we need to rely on coordinates for blocking
756
            // any click that is generated.
756
            // any click that is generated.
757
            var t = getNativeEvent(event).changedTouches[0];
757
            var t = getNativeEvent(event).changedTouches[0];
758
            clickBlockList.push({ touchID: lastTouchID, x: t.clientX, y: t.clientY });
758
            clickBlockList.push({ touchID: lastTouchID, x: t.clientX, y: t.clientY });
759
 
759
 
760
            // Prevent any mouse events that follow from triggering
760
            // Prevent any mouse events that follow from triggering
761
            // virtual event notifications.
761
            // virtual event notifications.
762
            blockMouseTriggers = true;
762
            blockMouseTriggers = true;
763
        }
763
        }
764
    }
764
    }
765
    triggerVirtualEvent("vmouseout", event, flags);
765
    triggerVirtualEvent("vmouseout", event, flags);
766
    didScroll = false;
766
    didScroll = false;
767
   
767
   
768
    startResetTimer();
768
    startResetTimer();
769
}
769
}
770
 
770
 
771
function hasVirtualBindings(ele)
771
function hasVirtualBindings(ele)
772
{
772
{
773
    var bindings = $.data(ele, dataPropertyName), k;
773
    var bindings = $.data(ele, dataPropertyName), k;
774
    if (bindings){
774
    if (bindings){
775
        for (k in bindings){
775
        for (k in bindings){
776
            if (bindings[k]){
776
            if (bindings[k]){
777
                return true;
777
                return true;
778
            }
778
            }
779
        }
779
        }
780
    }
780
    }
781
    return false;
781
    return false;
782
}
782
}
783
 
783
 
784
function dummyMouseHandler(){}
784
function dummyMouseHandler(){}
785
 
785
 
786
function getSpecialEventObject(eventType)
786
function getSpecialEventObject(eventType)
787
{
787
{
788
    var realType = eventType.substr(1);
788
    var realType = eventType.substr(1);
789
    return {
789
    return {
790
        setup: function(data, namespace) {
790
        setup: function(data, namespace) {
791
            // If this is the first virtual mouse binding for this element,
791
            // If this is the first virtual mouse binding for this element,
792
            // add a bindings object to its data.
792
            // add a bindings object to its data.
793
 
793
 
794
            if (!hasVirtualBindings(this)){
794
            if (!hasVirtualBindings(this)){
795
                $.data(this, dataPropertyName, {});
795
                $.data(this, dataPropertyName, {});
796
            }
796
            }
797
 
797
 
798
            // If setup is called, we know it is the first binding for this
798
            // If setup is called, we know it is the first binding for this
799
            // eventType, so initialize the count for the eventType to zero.
799
            // eventType, so initialize the count for the eventType to zero.
800
 
800
 
801
            var bindings = $.data(this, dataPropertyName);
801
            var bindings = $.data(this, dataPropertyName);
802
            bindings[eventType] = true;
802
            bindings[eventType] = true;
803
 
803
 
804
            // If this is the first virtual mouse event for this type,
804
            // If this is the first virtual mouse event for this type,
805
            // register a global handler on the document.
805
            // register a global handler on the document.
806
 
806
 
807
            activeDocHandlers[eventType] = (activeDocHandlers[eventType] || 0) + 1;
807
            activeDocHandlers[eventType] = (activeDocHandlers[eventType] || 0) + 1;
808
            if (activeDocHandlers[eventType] === 1){
808
            if (activeDocHandlers[eventType] === 1){
809
                $document.bind(realType, mouseEventCallback);
809
                $document.bind(realType, mouseEventCallback);
810
            }
810
            }
811
 
811
 
812
            // Some browsers, like Opera Mini, won't dispatch mouse/click events
812
            // Some browsers, like Opera Mini, won't dispatch mouse/click events
813
            // for elements unless they actually have handlers registered on them.
813
            // for elements unless they actually have handlers registered on them.
814
            // To get around this, we register dummy handlers on the elements.
814
            // To get around this, we register dummy handlers on the elements.
815
 
815
 
816
            $(this).bind(realType, dummyMouseHandler);
816
            $(this).bind(realType, dummyMouseHandler);
817
 
817
 
818
            // For now, if event capture is not supported, we rely on mouse handlers.
818
            // For now, if event capture is not supported, we rely on mouse handlers.
819
            if (eventCaptureSupported){
819
            if (eventCaptureSupported){
820
                // If this is the first virtual mouse binding for the document,
820
                // If this is the first virtual mouse binding for the document,
821
                // register our touchstart handler on the document.
821
                // register our touchstart handler on the document.
822
   
822
   
823
                activeDocHandlers["touchstart"] = (activeDocHandlers["touchstart"] || 0) + 1;
823
                activeDocHandlers["touchstart"] = (activeDocHandlers["touchstart"] || 0) + 1;
824
                if (activeDocHandlers["touchstart"] === 1) {
824
                if (activeDocHandlers["touchstart"] === 1) {
825
                    $document.bind("touchstart", handleTouchStart)
825
                    $document.bind("touchstart", handleTouchStart)
826
 
826
 
827
                        .bind("touchend", handleTouchEnd)
827
                        .bind("touchend", handleTouchEnd)
828
                   
828
                   
829
                        // On touch platforms, touching the screen and then dragging your finger
829
                        // On touch platforms, touching the screen and then dragging your finger
830
                        // causes the window content to scroll after some distance threshold is
830
                        // causes the window content to scroll after some distance threshold is
831
                        // exceeded. On these platforms, a scroll prevents a click event from being
831
                        // exceeded. On these platforms, a scroll prevents a click event from being
832
                        // dispatched, and on some platforms, even the touchend is suppressed. To
832
                        // dispatched, and on some platforms, even the touchend is suppressed. To
833
                        // mimic the suppression of the click event, we need to watch for a scroll
833
                        // mimic the suppression of the click event, we need to watch for a scroll
834
                        // event. Unfortunately, some platforms like iOS don't dispatch scroll
834
                        // event. Unfortunately, some platforms like iOS don't dispatch scroll
835
                        // events until *AFTER* the user lifts their finger (touchend). This means
835
                        // events until *AFTER* the user lifts their finger (touchend). This means
836
                        // we need to watch both scroll and touchmove events to figure out whether
836
                        // we need to watch both scroll and touchmove events to figure out whether
837
                        // or not a scroll happenens before the touchend event is fired.
837
                        // or not a scroll happenens before the touchend event is fired.
838
                   
838
                   
839
                        .bind("touchmove", handleTouchMove)
839
                        .bind("touchmove", handleTouchMove)
840
                        .bind("scroll", handleScroll);         
840
                        .bind("scroll", handleScroll);         
841
                }
841
                }
842
            }
842
            }
843
        },
843
        },
844
 
844
 
845
        teardown: function(data, namespace) {
845
        teardown: function(data, namespace) {
846
            // If this is the last virtual binding for this eventType,
846
            // If this is the last virtual binding for this eventType,
847
            // remove its global handler from the document.
847
            // remove its global handler from the document.
848
 
848
 
849
            --activeDocHandlers[eventType];
849
            --activeDocHandlers[eventType];
850
            if (!activeDocHandlers[eventType]){
850
            if (!activeDocHandlers[eventType]){
851
                $document.unbind(realType, mouseEventCallback);
851
                $document.unbind(realType, mouseEventCallback);
852
            }
852
            }
853
 
853
 
854
            if (eventCaptureSupported){
854
            if (eventCaptureSupported){
855
                // If this is the last virtual mouse binding in existence,
855
                // If this is the last virtual mouse binding in existence,
856
                // remove our document touchstart listener.
856
                // remove our document touchstart listener.
857
   
857
   
858
                --activeDocHandlers["touchstart"];
858
                --activeDocHandlers["touchstart"];
859
                if (!activeDocHandlers["touchstart"]) {
859
                if (!activeDocHandlers["touchstart"]) {
860
                    $document.unbind("touchstart", handleTouchStart)
860
                    $document.unbind("touchstart", handleTouchStart)
861
                        .unbind("touchmove", handleTouchMove)
861
                        .unbind("touchmove", handleTouchMove)
862
                        .unbind("touchend", handleTouchEnd)
862
                        .unbind("touchend", handleTouchEnd)
863
                        .unbind("scroll", handleScroll);
863
                        .unbind("scroll", handleScroll);
864
                }
864
                }
865
            }
865
            }
866
 
866
 
867
            var $this = $(this),
867
            var $this = $(this),
868
                bindings = $.data(this, dataPropertyName);
868
                bindings = $.data(this, dataPropertyName);
869
 
869
 
870
            // teardown may be called when an element was
870
            // teardown may be called when an element was
871
            // removed from the DOM. If this is the case,
871
            // removed from the DOM. If this is the case,
872
            // jQuery core may have already stripped the element
872
            // jQuery core may have already stripped the element
873
            // of any data bindings so we need to check it before
873
            // of any data bindings so we need to check it before
874
            // using it.
874
            // using it.
875
            if (bindings){
875
            if (bindings){
876
                bindings[eventType] = false;
876
                bindings[eventType] = false;
877
            }
877
            }
878
 
878
 
879
            // Unregister the dummy event handler.
879
            // Unregister the dummy event handler.
880
 
880
 
881
            $this.unbind(realType, dummyMouseHandler);
881
            $this.unbind(realType, dummyMouseHandler);
882
 
882
 
883
            // If this is the last virtual mouse binding on the
883
            // If this is the last virtual mouse binding on the
884
            // element, remove the binding data from the element.
884
            // element, remove the binding data from the element.
885
 
885
 
886
            if (!hasVirtualBindings(this)){
886
            if (!hasVirtualBindings(this)){
887
                $this.removeData(dataPropertyName);
887
                $this.removeData(dataPropertyName);
888
            }
888
            }
889
        }
889
        }
890
    };
890
    };
891
}
891
}
892
 
892
 
893
// Expose our custom events to the jQuery bind/unbind mechanism.
893
// Expose our custom events to the jQuery bind/unbind mechanism.
894
 
894
 
895
for (var i = 0; i < virtualEventNames.length; i++){
895
for (var i = 0; i < virtualEventNames.length; i++){
896
    $.event.special[virtualEventNames[i]] = getSpecialEventObject(virtualEventNames[i]);
896
    $.event.special[virtualEventNames[i]] = getSpecialEventObject(virtualEventNames[i]);
897
}
897
}
898
 
898
 
899
// Add a capture click handler to block clicks.
899
// Add a capture click handler to block clicks.
900
// Note that we require event capture support for this so if the device
900
// Note that we require event capture support for this so if the device
901
// doesn't support it, we punt for now and rely solely on mouse events.
901
// doesn't support it, we punt for now and rely solely on mouse events.
902
if (eventCaptureSupported){
902
if (eventCaptureSupported){
903
    document.addEventListener("click", function(e){
903
    document.addEventListener("click", function(e){
904
        var cnt = clickBlockList.length;
904
        var cnt = clickBlockList.length;
905
        var target = e.target;
905
        var target = e.target;
906
        if (cnt) {
906
        if (cnt) {
907
            var x = e.clientX,
907
            var x = e.clientX,
908
                y = e.clientY,
908
                y = e.clientY,
909
                threshold = $.vmouse.clickDistanceThreshold;
909
                threshold = $.vmouse.clickDistanceThreshold;
910
 
910
 
911
            // The idea here is to run through the clickBlockList to see if
911
            // The idea here is to run through the clickBlockList to see if
912
            // the current click event is in the proximity of one of our
912
            // the current click event is in the proximity of one of our
913
            // vclick events that had preventDefault() called on it. If we find
913
            // vclick events that had preventDefault() called on it. If we find
914
            // one, then we block the click.
914
            // one, then we block the click.
915
            //
915
            //
916
            // Why do we have to rely on proximity?
916
            // Why do we have to rely on proximity?
917
            //
917
            //
918
            // Because the target of the touch event that triggered the vclick
918
            // Because the target of the touch event that triggered the vclick
919
            // can be different from the target of the click event synthesized
919
            // can be different from the target of the click event synthesized
920
            // by the browser. The target of a mouse/click event that is syntehsized
920
            // by the browser. The target of a mouse/click event that is syntehsized
921
            // from a touch event seems to be implementation specific. For example,
921
            // from a touch event seems to be implementation specific. For example,
922
            // some browsers will fire mouse/click events for a link that is near
922
            // some browsers will fire mouse/click events for a link that is near
923
            // a touch event, even though the target of the touchstart/touchend event
923
            // a touch event, even though the target of the touchstart/touchend event
924
            // says the user touched outside the link. Also, it seems that with most
924
            // says the user touched outside the link. Also, it seems that with most
925
            // browsers, the target of the mouse/click event is not calculated until the
925
            // browsers, the target of the mouse/click event is not calculated until the
926
            // time it is dispatched, so if you replace an element that you touched
926
            // time it is dispatched, so if you replace an element that you touched
927
            // with another element, the target of the mouse/click will be the new
927
            // with another element, the target of the mouse/click will be the new
928
            // element underneath that point.
928
            // element underneath that point.
929
            //
929
            //
930
            // Aside from proximity, we also check to see if the target and any
930
            // Aside from proximity, we also check to see if the target and any
931
            // of its ancestors were the ones that blocked a click. This is necessary
931
            // of its ancestors were the ones that blocked a click. This is necessary
932
            // because of the strange mouse/click target calculation done in the
932
            // because of the strange mouse/click target calculation done in the
933
            // Android 2.1 browser, where if you click on an element, and there is a
933
            // Android 2.1 browser, where if you click on an element, and there is a
934
            // mouse/click handler on one of its ancestors, the target will be the
934
            // mouse/click handler on one of its ancestors, the target will be the
935
            // innermost child of the touched element, even if that child is no where
935
            // innermost child of the touched element, even if that child is no where
936
            // near the point of touch.
936
            // near the point of touch.
937
           
937
           
938
            var ele = target;
938
            var ele = target;
939
            while (ele) {
939
            while (ele) {
940
                for (var i = 0; i < cnt; i++) {
940
                for (var i = 0; i < cnt; i++) {
941
                    var o = clickBlockList[i],
941
                    var o = clickBlockList[i],
942
                        touchID = 0;
942
                        touchID = 0;
943
                    if ((ele === target && Math.abs(o.x - x) < threshold && Math.abs(o.y - y) < threshold) || $.data(ele, touchTargetPropertyName) === o.touchID){
943
                    if ((ele === target && Math.abs(o.x - x) < threshold && Math.abs(o.y - y) < threshold) || $.data(ele, touchTargetPropertyName) === o.touchID){
944
                        // XXX: We may want to consider removing matches from the block list
944
                        // XXX: We may want to consider removing matches from the block list
945
                        //      instead of waiting for the reset timer to fire.
945
                        //      instead of waiting for the reset timer to fire.
946
                        e.preventDefault();
946
                        e.preventDefault();
947
                        e.stopPropagation();
947
                        e.stopPropagation();
948
                        return;
948
                        return;
949
                    }
949
                    }
950
                }
950
                }
951
                ele = ele.parentNode;
951
                ele = ele.parentNode;
952
            }
952
            }
953
        }
953
        }
954
    }, true);
954
    }, true);
955
}
955
}
956
})(jQuery, window, document);
956
})(jQuery, window, document);
957
/*
957
/*
958
* jQuery Mobile Framework : events
958
* jQuery Mobile Framework : events
959
* Copyright (c) jQuery Project
959
* Copyright (c) jQuery Project
960
* Dual licensed under the MIT or GPL Version 2 licenses.
960
* Dual licensed under the MIT or GPL Version 2 licenses.
961
* http://jquery.org/license
961
* http://jquery.org/license
962
*/
962
*/
963
(function($, undefined ) {
963
(function($, undefined ) {
964
 
964
 
965
// add new event shortcuts
965
// add new event shortcuts
966
$.each( "touchstart touchmove touchend orientationchange throttledresize tap taphold swipe swipeleft swiperight scrollstart scrollstop".split( " " ), function( i, name ) {
966
$.each( "touchstart touchmove touchend orientationchange throttledresize tap taphold swipe swipeleft swiperight scrollstart scrollstop".split( " " ), function( i, name ) {
967
    $.fn[ name ] = function( fn ) {
967
    $.fn[ name ] = function( fn ) {
968
        return fn ? this.bind( name, fn ) : this.trigger( name );
968
        return fn ? this.bind( name, fn ) : this.trigger( name );
969
    };
969
    };
970
    $.attrFn[ name ] = true;
970
    $.attrFn[ name ] = true;
971
});
971
});
972
 
972
 
973
var supportTouch = $.support.touch,
973
var supportTouch = $.support.touch,
974
    scrollEvent = "touchmove scroll",
974
    scrollEvent = "touchmove scroll",
975
    touchStartEvent = supportTouch ? "touchstart" : "mousedown",
975
    touchStartEvent = supportTouch ? "touchstart" : "mousedown",
976
    touchStopEvent = supportTouch ? "touchend" : "mouseup",
976
    touchStopEvent = supportTouch ? "touchend" : "mouseup",
977
    touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
977
    touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
978
 
978
 
979
function triggerCustomEvent(obj, eventType, event)
979
function triggerCustomEvent(obj, eventType, event)
980
{
980
{
981
    var originalType = event.type;
981
    var originalType = event.type;
982
    event.type = eventType;
982
    event.type = eventType;
983
    $.event.handle.call( obj, event );
983
    $.event.handle.call( obj, event );
984
    event.type = originalType;
984
    event.type = originalType;
985
}
985
}
986
 
986
 
987
// also handles scrollstop
987
// also handles scrollstop
988
$.event.special.scrollstart = {
988
$.event.special.scrollstart = {
989
    enabled: true,
989
    enabled: true,
990
   
990
   
991
    setup: function() {
991
    setup: function() {
992
        var thisObject = this,
992
        var thisObject = this,
993
            $this = $( thisObject ),
993
            $this = $( thisObject ),
994
            scrolling,
994
            scrolling,
995
            timer;
995
            timer;
996
       
996
       
997
        function trigger( event, state ) {
997
        function trigger( event, state ) {
998
            scrolling = state;
998
            scrolling = state;
999
            triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
999
            triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
1000
        }
1000
        }
1001
       
1001
       
1002
        // iPhone triggers scroll after a small delay; use touchmove instead
1002
        // iPhone triggers scroll after a small delay; use touchmove instead
1003
        $this.bind( scrollEvent, function( event ) {
1003
        $this.bind( scrollEvent, function( event ) {
1004
            if ( !$.event.special.scrollstart.enabled ) {
1004
            if ( !$.event.special.scrollstart.enabled ) {
1005
                return;
1005
                return;
1006
            }
1006
            }
1007
           
1007
           
1008
            if ( !scrolling ) {
1008
            if ( !scrolling ) {
1009
                trigger( event, true );
1009
                trigger( event, true );
1010
            }
1010
            }
1011
           
1011
           
1012
            clearTimeout( timer );
1012
            clearTimeout( timer );
1013
            timer = setTimeout(function() {
1013
            timer = setTimeout(function() {
1014
                trigger( event, false );
1014
                trigger( event, false );
1015
            }, 50 );
1015
            }, 50 );
1016
        });
1016
        });
1017
    }
1017
    }
1018
};
1018
};
1019
 
1019
 
1020
// also handles taphold
1020
// also handles taphold
1021
$.event.special.tap = {
1021
$.event.special.tap = {
1022
    setup: function() {
1022
    setup: function() {
1023
        var thisObject = this,
1023
        var thisObject = this,
1024
            $this = $( thisObject );
1024
            $this = $( thisObject );
1025
       
1025
       
1026
        $this
1026
        $this
1027
            .bind("vmousedown", function( event ) {
1027
            .bind("vmousedown", function( event ) {
1028
                if ( event.which && event.which !== 1 ) {
1028
                if ( event.which && event.which !== 1 ) {
1029
                    return false;
1029
                    return false;
1030
                }
1030
                }
1031
               
1031
               
1032
                var touching = true,
1032
                var touching = true,
1033
                    origTarget = event.target,
1033
                    origTarget = event.target,
1034
                    origEvent = event.originalEvent,
1034
                    origEvent = event.originalEvent,
1035
                    timer;
1035
                    timer;
1036
                   
1036
                   
1037
                function clearTapHandlers() {
1037
                function clearTapHandlers() {
1038
                    touching = false;
1038
                    touching = false;
1039
                    clearTimeout(timer);
1039
                    clearTimeout(timer);
1040
                    $this.unbind("vclick", clickHandler).unbind("vmousecancel", clearTapHandlers);
1040
                    $this.unbind("vclick", clickHandler).unbind("vmousecancel", clearTapHandlers);
1041
                }
1041
                }
1042
               
1042
               
1043
                function clickHandler(event) {
1043
                function clickHandler(event) {
1044
                    clearTapHandlers();
1044
                    clearTapHandlers();
1045
 
1045
 
1046
                    /* ONLY trigger a 'tap' event if the start target is
1046
                    /* ONLY trigger a 'tap' event if the start target is
1047
                     * the same as the stop target.
1047
                     * the same as the stop target.
1048
                     */
1048
                     */
1049
                    if ( origTarget == event.target ) {
1049
                    if ( origTarget == event.target ) {
1050
                        triggerCustomEvent( thisObject, "tap", event );
1050
                        triggerCustomEvent( thisObject, "tap", event );
1051
                    }
1051
                    }
1052
                }
1052
                }
1053
 
1053
 
1054
                $this.bind("vmousecancel", clearTapHandlers).bind("vclick", clickHandler);
1054
                $this.bind("vmousecancel", clearTapHandlers).bind("vclick", clickHandler);
1055
 
1055
 
1056
                timer = setTimeout(function() {
1056
                timer = setTimeout(function() {
1057
                    if ( touching ) {
1057
                    if ( touching ) {
1058
                        triggerCustomEvent( thisObject, "taphold", event );
1058
                        triggerCustomEvent( thisObject, "taphold", event );
1059
                    }
1059
                    }
1060
                }, 750 );
1060
                }, 750 );
1061
            });
1061
            });
1062
    }
1062
    }
1063
};
1063
};
1064
 
1064
 
1065
// also handles swipeleft, swiperight
1065
// also handles swipeleft, swiperight
1066
$.event.special.swipe = {
1066
$.event.special.swipe = {
1067
    setup: function() {
1067
    setup: function() {
1068
        var thisObject = this,
1068
        var thisObject = this,
1069
            $this = $( thisObject );
1069
            $this = $( thisObject );
1070
       
1070
       
1071
        $this
1071
        $this
1072
            .bind( touchStartEvent, function( event ) {
1072
            .bind( touchStartEvent, function( event ) {
1073
                var data = event.originalEvent.touches ?
1073
                var data = event.originalEvent.touches ?
1074
                        event.originalEvent.touches[ 0 ] :
1074
                        event.originalEvent.touches[ 0 ] :
1075
                        event,
1075
                        event,
1076
                    start = {
1076
                    start = {
1077
                        time: (new Date).getTime(),
1077
                        time: (new Date).getTime(),
1078
                        coords: [ data.pageX, data.pageY ],
1078
                        coords: [ data.pageX, data.pageY ],
1079
                        origin: $( event.target )
1079
                        origin: $( event.target )
1080
                    },
1080
                    },
1081
                    stop;
1081
                    stop;
1082
               
1082
               
1083
                function moveHandler( event ) {
1083
                function moveHandler( event ) {
1084
                    if ( !start ) {
1084
                    if ( !start ) {
1085
                        return;
1085
                        return;
1086
                    }
1086
                    }
1087
                   
1087
                   
1088
                    var data = event.originalEvent.touches ?
1088
                    var data = event.originalEvent.touches ?
1089
                            event.originalEvent.touches[ 0 ] :
1089
                            event.originalEvent.touches[ 0 ] :
1090
                            event;
1090
                            event;
1091
                    stop = {
1091
                    stop = {
1092
                            time: (new Date).getTime(),
1092
                            time: (new Date).getTime(),
1093
                            coords: [ data.pageX, data.pageY ]
1093
                            coords: [ data.pageX, data.pageY ]
1094
                    };
1094
                    };
1095
                   
1095
                   
1096
                    // prevent scrolling
1096
                    // prevent scrolling
1097
                    if ( Math.abs( start.coords[0] - stop.coords[0] ) > 10 ) {
1097
                    if ( Math.abs( start.coords[0] - stop.coords[0] ) > 10 ) {
1098
                        event.preventDefault();
1098
                        event.preventDefault();
1099
                    }
1099
                    }
1100
                }
1100
                }
1101
               
1101
               
1102
                $this
1102
                $this
1103
                    .bind( touchMoveEvent, moveHandler )
1103
                    .bind( touchMoveEvent, moveHandler )
1104
                    .one( touchStopEvent, function( event ) {
1104
                    .one( touchStopEvent, function( event ) {
1105
                        $this.unbind( touchMoveEvent, moveHandler );
1105
                        $this.unbind( touchMoveEvent, moveHandler );
1106
                        if ( start && stop ) {
1106
                        if ( start && stop ) {
1107
                            if ( stop.time - start.time < 1000 &&
1107
                            if ( stop.time - start.time < 1000 &&
1108
                                    Math.abs( start.coords[0] - stop.coords[0]) > 30 &&
1108
                                    Math.abs( start.coords[0] - stop.coords[0]) > 30 &&
1109
                                    Math.abs( start.coords[1] - stop.coords[1]) < 75 ) {
1109
                                    Math.abs( start.coords[1] - stop.coords[1]) < 75 ) {
1110
                                start.origin
1110
                                start.origin
1111
                                .trigger( "swipe" )
1111
                                .trigger( "swipe" )
1112
 
1112
 
1113
                                .trigger( start.coords[0] > stop.coords[0] ? "swipeleft" : "swiperight" );
1113
                                .trigger( start.coords[0] > stop.coords[0] ? "swipeleft" : "swiperight" );
1114
                            }
1114
                            }
1115
                        }
1115
                        }
1116
                        start = stop = undefined;
1116
                        start = stop = undefined;
1117
                    });
1117
                    });
1118
            });
1118
            });
1119
    }
1119
    }
1120
};
1120
};
1121
 
1121
 
1122
(function($){
1122
(function($){
1123
    // "Cowboy" Ben Alman
1123
    // "Cowboy" Ben Alman
1124
   
1124
   
1125
    var win = $(window),
1125
    var win = $(window),
1126
        special_event,
1126
        special_event,
1127
        get_orientation,
1127
        get_orientation,
1128
        last_orientation;
1128
        last_orientation;
1129
   
1129
   
1130
    $.event.special.orientationchange = special_event = {
1130
    $.event.special.orientationchange = special_event = {
1131
        setup: function(){
1131
        setup: function(){
1132
            // If the event is supported natively, return false so that jQuery
1132
            // If the event is supported natively, return false so that jQuery
1133
            // will bind to the event using DOM methods.
1133
            // will bind to the event using DOM methods.
1134
            if ( $.support.orientation ) { return false; }
1134
            if ( $.support.orientation ) { return false; }
1135
           
1135
           
1136
            // Get the current orientation to avoid initial double-triggering.
1136
            // Get the current orientation to avoid initial double-triggering.
1137
            last_orientation = get_orientation();
1137
            last_orientation = get_orientation();
1138
           
1138
           
1139
            // Because the orientationchange event doesn't exist, simulate the
1139
            // Because the orientationchange event doesn't exist, simulate the
1140
            // event by testing window dimensions on resize.
1140
            // event by testing window dimensions on resize.
1141
            win.bind( "throttledresize", handler );
1141
            win.bind( "throttledresize", handler );
1142
        },
1142
        },
1143
        teardown: function(){
1143
        teardown: function(){
1144
            // If the event is not supported natively, return false so that
1144
            // If the event is not supported natively, return false so that
1145
            // jQuery will unbind the event using DOM methods.
1145
            // jQuery will unbind the event using DOM methods.
1146
            if ( $.support.orientation ) { return false; }
1146
            if ( $.support.orientation ) { return false; }
1147
           
1147
           
1148
            // Because the orientationchange event doesn't exist, unbind the
1148
            // Because the orientationchange event doesn't exist, unbind the
1149
            // resize event handler.
1149
            // resize event handler.
1150
            win.unbind( "throttledresize", handler );
1150
            win.unbind( "throttledresize", handler );
1151
        },
1151
        },
1152
        add: function( handleObj ) {
1152
        add: function( handleObj ) {
1153
            // Save a reference to the bound event handler.
1153
            // Save a reference to the bound event handler.
1154
            var old_handler = handleObj.handler;
1154
            var old_handler = handleObj.handler;
1155
           
1155
           
1156
            handleObj.handler = function( event ) {
1156
            handleObj.handler = function( event ) {
1157
                // Modify event object, adding the .orientation property.
1157
                // Modify event object, adding the .orientation property.
1158
                event.orientation = get_orientation();
1158
                event.orientation = get_orientation();
1159
               
1159
               
1160
                // Call the originally-bound event handler and return its result.
1160
                // Call the originally-bound event handler and return its result.
1161
                return old_handler.apply( this, arguments );
1161
                return old_handler.apply( this, arguments );
1162
            };
1162
            };
1163
        }
1163
        }
1164
    };
1164
    };
1165
   
1165
   
1166
    // If the event is not supported natively, this handler will be bound to
1166
    // If the event is not supported natively, this handler will be bound to
1167
    // the window resize event to simulate the orientationchange event.
1167
    // the window resize event to simulate the orientationchange event.
1168
    function handler() {
1168
    function handler() {
1169
        // Get the current orientation.
1169
        // Get the current orientation.
1170
        var orientation = get_orientation();
1170
        var orientation = get_orientation();
1171
       
1171
       
1172
        if ( orientation !== last_orientation ) {
1172
        if ( orientation !== last_orientation ) {
1173
            // The orientation has changed, so trigger the orientationchange event.
1173
            // The orientation has changed, so trigger the orientationchange event.
1174
            last_orientation = orientation;
1174
            last_orientation = orientation;
1175
            win.trigger( "orientationchange" );
1175
            win.trigger( "orientationchange" );
1176
        }
1176
        }
1177
    };
1177
    };
1178
   
1178
   
1179
    // Get the current page orientation. This method is exposed publicly, should it
1179
    // Get the current page orientation. This method is exposed publicly, should it
1180
    // be needed, as jQuery.event.special.orientationchange.orientation()
1180
    // be needed, as jQuery.event.special.orientationchange.orientation()
1181
    $.event.special.orientationchange.orientation = get_orientation = function() {
1181
    $.event.special.orientationchange.orientation = get_orientation = function() {
1182
        var elem = document.documentElement;
1182
        var elem = document.documentElement;
1183
        return elem && elem.clientWidth / elem.clientHeight < 1.1 ? "portrait" : "landscape";
1183
        return elem && elem.clientWidth / elem.clientHeight < 1.1 ? "portrait" : "landscape";
1184
    };
1184
    };
1185
   
1185
   
1186
})(jQuery);
1186
})(jQuery);
1187
 
1187
 
1188
 
1188
 
1189
// throttled resize event
1189
// throttled resize event
1190
(function(){
1190
(function(){
1191
    $.event.special.throttledresize = {
1191
    $.event.special.throttledresize = {
1192
        setup: function() {
1192
        setup: function() {
1193
            $( this ).bind( "resize", handler );   
1193
            $( this ).bind( "resize", handler );   
1194
        },
1194
        },
1195
        teardown: function(){
1195
        teardown: function(){
1196
            $( this ).unbind( "resize", handler );
1196
            $( this ).unbind( "resize", handler );
1197
        }
1197
        }
1198
    };
1198
    };
1199
 
1199
 
1200
    var throttle = 250,
1200
    var throttle = 250,
1201
        handler = function(){
1201
        handler = function(){
1202
            curr = ( new Date() ).getTime();
1202
            curr = ( new Date() ).getTime();
1203
            diff = curr - lastCall;
1203
            diff = curr - lastCall;
1204
            if( diff >= throttle ){
1204
            if( diff >= throttle ){
1205
                lastCall = curr;
1205
                lastCall = curr;
1206
                $( this ).trigger( "throttledresize" );
1206
                $( this ).trigger( "throttledresize" );
1207
            }
1207
            }
1208
            else{
1208
            else{
1209
                if( heldCall ){
1209
                if( heldCall ){
1210
                    clearTimeout( heldCall );
1210
                    clearTimeout( heldCall );
1211
                }
1211
                }
1212
                //promise a held call will still execute
1212
                //promise a held call will still execute
1213
                heldCall = setTimeout( handler, throttle - diff );
1213
                heldCall = setTimeout( handler, throttle - diff );
1214
            }
1214
            }
1215
        },
1215
        },
1216
        lastCall = 0,
1216
        lastCall = 0,
1217
        heldCall,
1217
        heldCall,
1218
        curr,
1218
        curr,
1219
        diff;
1219
        diff;
1220
})();
1220
})();
1221
 
1221
 
1222
 
1222
 
1223
$.each({
1223
$.each({
1224
    scrollstop: "scrollstart",
1224
    scrollstop: "scrollstart",
1225
    taphold: "tap",
1225
    taphold: "tap",
1226
    swipeleft: "swipe",
1226
    swipeleft: "swipe",
1227
    swiperight: "swipe"
1227
    swiperight: "swipe"
1228
}, function( event, sourceEvent ) {
1228
}, function( event, sourceEvent ) {
1229
    $.event.special[ event ] = {
1229
    $.event.special[ event ] = {
1230
        setup: function() {
1230
        setup: function() {
1231
            $( this ).bind( sourceEvent, $.noop );
1231
            $( this ).bind( sourceEvent, $.noop );
1232
        }
1232
        }
1233
    };
1233
    };
1234
});
1234
});
1235
 
1235
 
1236
})( jQuery );
1236
})( jQuery );
1237
/*!
1237
/*!
1238
 * jQuery hashchange event - v1.3 - 7/21/2010
1238
 * jQuery hashchange event - v1.3 - 7/21/2010
1239
 * http://benalman.com/projects/jquery-hashchange-plugin/
1239
 * http://benalman.com/projects/jquery-hashchange-plugin/
1240
 *
1240
 *
1241
 * Copyright (c) 2010 "Cowboy" Ben Alman
1241
 * Copyright (c) 2010 "Cowboy" Ben Alman
1242
 * Dual licensed under the MIT and GPL licenses.
1242
 * Dual licensed under the MIT and GPL licenses.
1243
 * http://benalman.com/about/license/
1243
 * http://benalman.com/about/license/
1244
 */
1244
 */
1245
 
1245
 
1246
// Script: jQuery hashchange event
1246
// Script: jQuery hashchange event
1247
//
1247
//
1248
// *Version: 1.3, Last updated: 7/21/2010*
1248
// *Version: 1.3, Last updated: 7/21/2010*
1249
// 
1249
// 
1250
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
1250
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
1251
// GitHub       - http://github.com/cowboy/jquery-hashchange/
1251
// GitHub       - http://github.com/cowboy/jquery-hashchange/
1252
// Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
1252
// Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
1253
// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
1253
// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
1254
// 
1254
// 
1255
// About: License
1255
// About: License
1256
// 
1256
// 
1257
// Copyright (c) 2010 "Cowboy" Ben Alman,
1257
// Copyright (c) 2010 "Cowboy" Ben Alman,
1258
// Dual licensed under the MIT and GPL licenses.
1258
// Dual licensed under the MIT and GPL licenses.
1259
// http://benalman.com/about/license/
1259
// http://benalman.com/about/license/
1260
// 
1260
// 
1261
// About: Examples
1261
// About: Examples
1262
// 
1262
// 
1263
// These working examples, complete with fully commented code, illustrate a few
1263
// These working examples, complete with fully commented code, illustrate a few
1264
// ways in which this plugin can be used.
1264
// ways in which this plugin can be used.
1265
// 
1265
// 
1266
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
1266
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
1267
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
1267
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
1268
// 
1268
// 
1269
// About: Support and Testing
1269
// About: Support and Testing
1270
// 
1270
// 
1271
// Information about what version or versions of jQuery this plugin has been
1271
// Information about what version or versions of jQuery this plugin has been
1272
// tested with, what browsers it has been tested in, and where the unit tests
1272
// tested with, what browsers it has been tested in, and where the unit tests
1273
// reside (so you can test it yourself).
1273
// reside (so you can test it yourself).
1274
// 
1274
// 
1275
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
1275
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
1276
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
1276
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
1277
//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
1277
//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
1278
// Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
1278
// Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
1279
// 
1279
// 
1280
// About: Known issues
1280
// About: Known issues
1281
// 
1281
// 
1282
// While this jQuery hashchange event implementation is quite stable and
1282
// While this jQuery hashchange event implementation is quite stable and
1283
// robust, there are a few unfortunate browser bugs surrounding expected
1283
// robust, there are a few unfortunate browser bugs surrounding expected
1284
// hashchange event-based behaviors, independent of any JavaScript
1284
// hashchange event-based behaviors, independent of any JavaScript
1285
// window.onhashchange abstraction. See the following examples for more
1285
// window.onhashchange abstraction. See the following examples for more
1286
// information:
1286
// information:
1287
// 
1287
// 
1288
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
1288
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
1289
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
1289
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
1290
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
1290
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
1291
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
1291
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
1292
// 
1292
// 
1293
// Also note that should a browser natively support the window.onhashchange 
1293
// Also note that should a browser natively support the window.onhashchange 
1294
// event, but not report that it does, the fallback polling loop will be used.
1294
// event, but not report that it does, the fallback polling loop will be used.
1295
// 
1295
// 
1296
// About: Release History
1296
// About: Release History
1297
// 
1297
// 
1298
// 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
1298
// 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
1299
//         "removable" for mobile-only development. Added IE6/7 document.title
1299
//         "removable" for mobile-only development. Added IE6/7 document.title
1300
//         support. Attempted to make Iframe as hidden as possible by using
1300
//         support. Attempted to make Iframe as hidden as possible by using
1301
//         techniques from http://www.paciellogroup.com/blog/?p=604. Added 
1301
//         techniques from http://www.paciellogroup.com/blog/?p=604. Added 
1302
//         support for the "shortcut" format $(window).hashchange( fn ) and
1302
//         support for the "shortcut" format $(window).hashchange( fn ) and
1303
//         $(window).hashchange() like jQuery provides for built-in events.
1303
//         $(window).hashchange() like jQuery provides for built-in events.
1304
//         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
1304
//         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
1305
//         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
1305
//         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
1306
//         and <jQuery.fn.hashchange.src> properties plus document-domain.html
1306
//         and <jQuery.fn.hashchange.src> properties plus document-domain.html
1307
//         file to address access denied issues when setting document.domain in
1307
//         file to address access denied issues when setting document.domain in
1308
//         IE6/7.
1308
//         IE6/7.
1309
// 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
1309
// 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
1310
//         from a page on another domain would cause an error in Safari 4. Also,
1310
//         from a page on another domain would cause an error in Safari 4. Also,
1311
//         IE6/7 Iframe is now inserted after the body (this actually works),
1311
//         IE6/7 Iframe is now inserted after the body (this actually works),
1312
//         which prevents the page from scrolling when the event is first bound.
1312
//         which prevents the page from scrolling when the event is first bound.
1313
//         Event can also now be bound before DOM ready, but it won't be usable
1313
//         Event can also now be bound before DOM ready, but it won't be usable
1314
//         before then in IE6/7.
1314
//         before then in IE6/7.
1315
// 1.1   - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
1315
// 1.1   - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
1316
//         where browser version is incorrectly reported as 8.0, despite
1316
//         where browser version is incorrectly reported as 8.0, despite
1317
//         inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
1317
//         inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
1318
// 1.0   - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
1318
// 1.0   - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
1319
//         window.onhashchange functionality into a separate plugin for users
1319
//         window.onhashchange functionality into a separate plugin for users
1320
//         who want just the basic event & back button support, without all the
1320
//         who want just the basic event & back button support, without all the
1321
//         extra awesomeness that BBQ provides. This plugin will be included as
1321
//         extra awesomeness that BBQ provides. This plugin will be included as
1322
//         part of jQuery BBQ, but also be available separately.
1322
//         part of jQuery BBQ, but also be available separately.
1323
 
1323
 
1324
(function($,window,undefined){
1324
(function($,window,undefined){
1325
  '$:nomunge'; // Used by YUI compressor.
1325
  '$:nomunge'; // Used by YUI compressor.
1326
 
1326
 
1327
  // Reused string.
1327
  // Reused string.
1328
  var str_hashchange = 'hashchange',
1328
  var str_hashchange = 'hashchange',
1329
   
1329
   
1330
    // Method / object references.
1330
    // Method / object references.
1331
    doc = document,
1331
    doc = document,
1332
    fake_onhashchange,
1332
    fake_onhashchange,
1333
    special = $.event.special,
1333
    special = $.event.special,
1334
   
1334
   
1335
    // Does the browser support window.onhashchange? Note that IE8 running in
1335
    // Does the browser support window.onhashchange? Note that IE8 running in
1336
    // IE7 compatibility mode reports true for 'onhashchange' in window, even
1336
    // IE7 compatibility mode reports true for 'onhashchange' in window, even
1337
    // though the event isn't supported, so also test document.documentMode.
1337
    // though the event isn't supported, so also test document.documentMode.
1338
    doc_mode = doc.documentMode,
1338
    doc_mode = doc.documentMode,
1339
    supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
1339
    supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
1340
 
1340
 
1341
  // Get location.hash (or what you'd expect location.hash to be) sans any
1341
  // Get location.hash (or what you'd expect location.hash to be) sans any
1342
  // leading #. Thanks for making this necessary, Firefox!
1342
  // leading #. Thanks for making this necessary, Firefox!
1343
  function get_fragment( url ) {
1343
  function get_fragment( url ) {
1344
    url = url || location.href;
1344
    url = url || location.href;
1345
    return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
1345
    return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
1346
  };
1346
  };
1347
 
1347
 
1348
  // Method: jQuery.fn.hashchange
1348
  // Method: jQuery.fn.hashchange
1349
  // 
1349
  // 
1350
  // Bind a handler to the window.onhashchange event or trigger all bound
1350
  // Bind a handler to the window.onhashchange event or trigger all bound
1351
  // window.onhashchange event handlers. This behavior is consistent with
1351
  // window.onhashchange event handlers. This behavior is consistent with
1352
  // jQuery's built-in event handlers.
1352
  // jQuery's built-in event handlers.
1353
  // 
1353
  // 
1354
  // Usage:
1354
  // Usage:
1355
  // 
1355
  // 
1356
  // > jQuery(window).hashchange( [ handler ] );
1356
  // > jQuery(window).hashchange( [ handler ] );
1357
  // 
1357
  // 
1358
  // Arguments:
1358
  // Arguments:
1359
  // 
1359
  // 
1360
  //  handler - (Function) Optional handler to be bound to the hashchange
1360
  //  handler - (Function) Optional handler to be bound to the hashchange
1361
  //    event. This is a "shortcut" for the more verbose form:
1361
  //    event. This is a "shortcut" for the more verbose form:
1362
  //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
1362
  //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
1363
  //    all bound window.onhashchange event handlers will be triggered. This
1363
  //    all bound window.onhashchange event handlers will be triggered. This
1364
  //    is a shortcut for the more verbose
1364
  //    is a shortcut for the more verbose
1365
  //    jQuery(window).trigger( 'hashchange' ). These forms are described in
1365
  //    jQuery(window).trigger( 'hashchange' ). These forms are described in
1366
  //    the <hashchange event> section.
1366
  //    the <hashchange event> section.
1367
  // 
1367
  // 
1368
  // Returns:
1368
  // Returns:
1369
  // 
1369
  // 
1370
  //  (jQuery) The initial jQuery collection of elements.
1370
  //  (jQuery) The initial jQuery collection of elements.
1371
 
1371
 
1372
  // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
1372
  // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
1373
  // $(elem).hashchange() for triggering, like jQuery does for built-in events.
1373
  // $(elem).hashchange() for triggering, like jQuery does for built-in events.
1374
  $.fn[ str_hashchange ] = function( fn ) {
1374
  $.fn[ str_hashchange ] = function( fn ) {
1375
    return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
1375
    return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
1376
  };
1376
  };
1377
 
1377
 
1378
  // Property: jQuery.fn.hashchange.delay
1378
  // Property: jQuery.fn.hashchange.delay
1379
  // 
1379
  // 
1380
  // The numeric interval (in milliseconds) at which the <hashchange event>
1380
  // The numeric interval (in milliseconds) at which the <hashchange event>
1381
  // polling loop executes. Defaults to 50.
1381
  // polling loop executes. Defaults to 50.
1382
 
1382
 
1383
  // Property: jQuery.fn.hashchange.domain
1383
  // Property: jQuery.fn.hashchange.domain
1384
  // 
1384
  // 
1385
  // If you're setting document.domain in your JavaScript, and you want hash
1385
  // If you're setting document.domain in your JavaScript, and you want hash
1386
  // history to work in IE6/7, not only must this property be set, but you must
1386
  // history to work in IE6/7, not only must this property be set, but you must
1387
  // also set document.domain BEFORE jQuery is loaded into the page. This
1387
  // also set document.domain BEFORE jQuery is loaded into the page. This
1388
  // property is only applicable if you are supporting IE6/7 (or IE8 operating
1388
  // property is only applicable if you are supporting IE6/7 (or IE8 operating
1389
  // in "IE7 compatibility" mode).
1389
  // in "IE7 compatibility" mode).
1390
  // 
1390
  // 
1391
  // In addition, the <jQuery.fn.hashchange.src> property must be set to the
1391
  // In addition, the <jQuery.fn.hashchange.src> property must be set to the
1392
  // path of the included "document-domain.html" file, which can be renamed or
1392
  // path of the included "document-domain.html" file, which can be renamed or
1393
  // modified if necessary (note that the document.domain specified must be the
1393
  // modified if necessary (note that the document.domain specified must be the
1394
  // same in both your main JavaScript as well as in this file).
1394
  // same in both your main JavaScript as well as in this file).
1395
  // 
1395
  // 
1396
  // Usage:
1396
  // Usage:
1397
  // 
1397
  // 
1398
  // jQuery.fn.hashchange.domain = document.domain;
1398
  // jQuery.fn.hashchange.domain = document.domain;
1399
 
1399
 
1400
  // Property: jQuery.fn.hashchange.src
1400
  // Property: jQuery.fn.hashchange.src
1401
  // 
1401
  // 
1402
  // If, for some reason, you need to specify an Iframe src file (for example,
1402
  // If, for some reason, you need to specify an Iframe src file (for example,
1403
  // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
1403
  // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
1404
  // do so using this property. Note that when using this property, history
1404
  // do so using this property. Note that when using this property, history
1405
  // won't be recorded in IE6/7 until the Iframe src file loads. This property
1405
  // won't be recorded in IE6/7 until the Iframe src file loads. This property
1406
  // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
1406
  // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
1407
  // compatibility" mode).
1407
  // compatibility" mode).
1408
  // 
1408
  // 
1409
  // Usage:
1409
  // Usage:
1410
  // 
1410
  // 
1411
  // jQuery.fn.hashchange.src = 'path/to/file.html';
1411
  // jQuery.fn.hashchange.src = 'path/to/file.html';
1412
 
1412
 
1413
  $.fn[ str_hashchange ].delay = 50;
1413
  $.fn[ str_hashchange ].delay = 50;
1414
  /*
1414
  /*
1415
  $.fn[ str_hashchange ].domain = null;
1415
  $.fn[ str_hashchange ].domain = null;
1416
  $.fn[ str_hashchange ].src = null;
1416
  $.fn[ str_hashchange ].src = null;
1417
  */
1417
  */
1418
 
1418
 
1419
  // Event: hashchange event
1419
  // Event: hashchange event
1420
  // 
1420
  // 
1421
  // Fired when location.hash changes. In browsers that support it, the native
1421
  // Fired when location.hash changes. In browsers that support it, the native
1422
  // HTML5 window.onhashchange event is used, otherwise a polling loop is
1422
  // HTML5 window.onhashchange event is used, otherwise a polling loop is
1423
  // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
1423
  // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
1424
  // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
1424
  // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
1425
  // compatibility" mode), a hidden Iframe is created to allow the back button
1425
  // compatibility" mode), a hidden Iframe is created to allow the back button
1426
  // and hash-based history to work.
1426
  // and hash-based history to work.
1427
  // 
1427
  // 
1428
  // Usage as described in <jQuery.fn.hashchange>:
1428
  // Usage as described in <jQuery.fn.hashchange>:
1429
  // 
1429
  // 
1430
  // > // Bind an event handler.
1430
  // > // Bind an event handler.
1431
  // > jQuery(window).hashchange( function(e) {
1431
  // > jQuery(window).hashchange( function(e) {
1432
  // >   var hash = location.hash;
1432
  // >   var hash = location.hash;
1433
  // >   ...
1433
  // >   ...
1434
  // > });
1434
  // > });
1435
  // > 
1435
  // > 
1436
  // > // Manually trigger the event handler.
1436
  // > // Manually trigger the event handler.
1437
  // > jQuery(window).hashchange();
1437
  // > jQuery(window).hashchange();
1438
  // 
1438
  // 
1439
  // A more verbose usage that allows for event namespacing:
1439
  // A more verbose usage that allows for event namespacing:
1440
  // 
1440
  // 
1441
  // > // Bind an event handler.
1441
  // > // Bind an event handler.
1442
  // > jQuery(window).bind( 'hashchange', function(e) {
1442
  // > jQuery(window).bind( 'hashchange', function(e) {
1443
  // >   var hash = location.hash;
1443
  // >   var hash = location.hash;
1444
  // >   ...
1444
  // >   ...
1445
  // > });
1445
  // > });
1446
  // > 
1446
  // > 
1447
  // > // Manually trigger the event handler.
1447
  // > // Manually trigger the event handler.
1448
  // > jQuery(window).trigger( 'hashchange' );
1448
  // > jQuery(window).trigger( 'hashchange' );
1449
  // 
1449
  // 
1450
  // Additional Notes:
1450
  // Additional Notes:
1451
  // 
1451
  // 
1452
  // * The polling loop and Iframe are not created until at least one handler
1452
  // * The polling loop and Iframe are not created until at least one handler
1453
  //   is actually bound to the 'hashchange' event.
1453
  //   is actually bound to the 'hashchange' event.
1454
  // * If you need the bound handler(s) to execute immediately, in cases where
1454
  // * If you need the bound handler(s) to execute immediately, in cases where
1455
  //   a location.hash exists on page load, via bookmark or page refresh for
1455
  //   a location.hash exists on page load, via bookmark or page refresh for
1456
  //   example, use jQuery(window).hashchange() or the more verbose 
1456
  //   example, use jQuery(window).hashchange() or the more verbose 
1457
  //   jQuery(window).trigger( 'hashchange' ).
1457
  //   jQuery(window).trigger( 'hashchange' ).
1458
  // * The event can be bound before DOM ready, but since it won't be usable
1458
  // * The event can be bound before DOM ready, but since it won't be usable
1459
  //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
1459
  //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
1460
  //   to bind it inside a DOM ready handler.
1460
  //   to bind it inside a DOM ready handler.
1461
 
1461
 
1462
  // Override existing $.event.special.hashchange methods (allowing this plugin
1462
  // Override existing $.event.special.hashchange methods (allowing this plugin
1463
  // to be defined after jQuery BBQ in BBQ's source code).
1463
  // to be defined after jQuery BBQ in BBQ's source code).
1464
  special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
1464
  special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
1465
   
1465
   
1466
    // Called only when the first 'hashchange' event is bound to window.
1466
    // Called only when the first 'hashchange' event is bound to window.
1467
    setup: function() {
1467
    setup: function() {
1468
      // If window.onhashchange is supported natively, there's nothing to do..
1468
      // If window.onhashchange is supported natively, there's nothing to do..
1469
      if ( supports_onhashchange ) { return false; }
1469
      if ( supports_onhashchange ) { return false; }
1470
     
1470
     
1471
      // Otherwise, we need to create our own. And we don't want to call this
1471
      // Otherwise, we need to create our own. And we don't want to call this
1472
      // until the user binds to the event, just in case they never do, since it
1472
      // until the user binds to the event, just in case they never do, since it
1473
      // will create a polling loop and possibly even a hidden Iframe.
1473
      // will create a polling loop and possibly even a hidden Iframe.
1474
      $( fake_onhashchange.start );
1474
      $( fake_onhashchange.start );
1475
    },
1475
    },
1476
   
1476
   
1477
    // Called only when the last 'hashchange' event is unbound from window.
1477
    // Called only when the last 'hashchange' event is unbound from window.
1478
    teardown: function() {
1478
    teardown: function() {
1479
      // If window.onhashchange is supported natively, there's nothing to do..
1479
      // If window.onhashchange is supported natively, there's nothing to do..
1480
      if ( supports_onhashchange ) { return false; }
1480
      if ( supports_onhashchange ) { return false; }
1481
     
1481
     
1482
      // Otherwise, we need to stop ours (if possible).
1482
      // Otherwise, we need to stop ours (if possible).
1483
      $( fake_onhashchange.stop );
1483
      $( fake_onhashchange.stop );
1484
    }
1484
    }
1485
   
1485
   
1486
  });
1486
  });
1487
 
1487
 
1488
  // fake_onhashchange does all the work of triggering the window.onhashchange
1488
  // fake_onhashchange does all the work of triggering the window.onhashchange
1489
  // event for browsers that don't natively support it, including creating a
1489
  // event for browsers that don't natively support it, including creating a
1490
  // polling loop to watch for hash changes and in IE 6/7 creating a hidden
1490
  // polling loop to watch for hash changes and in IE 6/7 creating a hidden
1491
  // Iframe to enable back and forward.
1491
  // Iframe to enable back and forward.
1492
  fake_onhashchange = (function(){
1492
  fake_onhashchange = (function(){
1493
    var self = {},
1493
    var self = {},
1494
      timeout_id,
1494
      timeout_id,
1495
     
1495
     
1496
      // Remember the initial hash so it doesn't get triggered immediately.
1496
      // Remember the initial hash so it doesn't get triggered immediately.
1497
      last_hash = get_fragment(),
1497
      last_hash = get_fragment(),
1498
     
1498
     
1499
      fn_retval = function(val){ return val; },
1499
      fn_retval = function(val){ return val; },
1500
      history_set = fn_retval,
1500
      history_set = fn_retval,
1501
      history_get = fn_retval;
1501
      history_get = fn_retval;
1502
   
1502
   
1503
    // Start the polling loop.
1503
    // Start the polling loop.
1504
    self.start = function() {
1504
    self.start = function() {
1505
      timeout_id || poll();
1505
      timeout_id || poll();
1506
    };
1506
    };
1507
   
1507
   
1508
    // Stop the polling loop.
1508
    // Stop the polling loop.
1509
    self.stop = function() {
1509
    self.stop = function() {
1510
      timeout_id && clearTimeout( timeout_id );
1510
      timeout_id && clearTimeout( timeout_id );
1511
      timeout_id = undefined;
1511
      timeout_id = undefined;
1512
    };
1512
    };
1513
   
1513
   
1514
    // This polling loop checks every $.fn.hashchange.delay milliseconds to see
1514
    // This polling loop checks every $.fn.hashchange.delay milliseconds to see
1515
    // if location.hash has changed, and triggers the 'hashchange' event on
1515
    // if location.hash has changed, and triggers the 'hashchange' event on
1516
    // window when necessary.
1516
    // window when necessary.
1517
    function poll() {
1517
    function poll() {
1518
      var hash = get_fragment(),
1518
      var hash = get_fragment(),
1519
        history_hash = history_get( last_hash );
1519
        history_hash = history_get( last_hash );
1520
     
1520
     
1521
      if ( hash !== last_hash ) {
1521
      if ( hash !== last_hash ) {
1522
        history_set( last_hash = hash, history_hash );
1522
        history_set( last_hash = hash, history_hash );
1523
       
1523
       
1524
        $(window).trigger( str_hashchange );
1524
        $(window).trigger( str_hashchange );
1525
       
1525
       
1526
      } else if ( history_hash !== last_hash ) {
1526
      } else if ( history_hash !== last_hash ) {
1527
        location.href = location.href.replace( /#.*/, '' ) + history_hash;
1527
        location.href = location.href.replace( /#.*/, '' ) + history_hash;
1528
      }
1528
      }
1529
     
1529
     
1530
      timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
1530
      timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
1531
    };
1531
    };
1532
   
1532
   
1533
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
1533
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
1534
    // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
1534
    // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
1535
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
1535
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
1536
    $.browser.msie && !supports_onhashchange && (function(){
1536
    $.browser.msie && !supports_onhashchange && (function(){
1537
      // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
1537
      // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
1538
      // when running in "IE7 compatibility" mode.
1538
      // when running in "IE7 compatibility" mode.
1539
     
1539
     
1540
      var iframe,
1540
      var iframe,
1541
        iframe_src;
1541
        iframe_src;
1542
     
1542
     
1543
      // When the event is bound and polling starts in IE 6/7, create a hidden
1543
      // When the event is bound and polling starts in IE 6/7, create a hidden
1544
      // Iframe for history handling.
1544
      // Iframe for history handling.
1545
      self.start = function(){
1545
      self.start = function(){
1546
        if ( !iframe ) {
1546
        if ( !iframe ) {
1547
          iframe_src = $.fn[ str_hashchange ].src;
1547
          iframe_src = $.fn[ str_hashchange ].src;
1548
          iframe_src = iframe_src && iframe_src + get_fragment();
1548
          iframe_src = iframe_src && iframe_src + get_fragment();
1549
         
1549
         
1550
          // Create hidden Iframe. Attempt to make Iframe as hidden as possible
1550
          // Create hidden Iframe. Attempt to make Iframe as hidden as possible
1551
          // by using techniques from http://www.paciellogroup.com/blog/?p=604.
1551
          // by using techniques from http://www.paciellogroup.com/blog/?p=604.
1552
          iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
1552
          iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
1553
           
1553
           
1554
            // When Iframe has completely loaded, initialize the history and
1554
            // When Iframe has completely loaded, initialize the history and
1555
            // start polling.
1555
            // start polling.
1556
            .one( 'load', function(){
1556
            .one( 'load', function(){
1557
              iframe_src || history_set( get_fragment() );
1557
              iframe_src || history_set( get_fragment() );
1558
              poll();
1558
              poll();
1559
            })
1559
            })
1560
           
1560
           
1561
            // Load Iframe src if specified, otherwise nothing.
1561
            // Load Iframe src if specified, otherwise nothing.
1562
            .attr( 'src', iframe_src || 'javascript:0' )
1562
            .attr( 'src', iframe_src || 'javascript:0' )
1563
           
1563
           
1564
            // Append Iframe after the end of the body to prevent unnecessary
1564
            // Append Iframe after the end of the body to prevent unnecessary
1565
            // initial page scrolling (yes, this works).
1565
            // initial page scrolling (yes, this works).
1566
            .insertAfter( 'body' )[0].contentWindow;
1566
            .insertAfter( 'body' )[0].contentWindow;
1567
         
1567
         
1568
          // Whenever `document.title` changes, update the Iframe's title to
1568
          // Whenever `document.title` changes, update the Iframe's title to
1569
          // prettify the back/next history menu entries. Since IE sometimes
1569
          // prettify the back/next history menu entries. Since IE sometimes
1570
          // errors with "Unspecified error" the very first time this is set
1570
          // errors with "Unspecified error" the very first time this is set
1571
          // (yes, very useful) wrap this with a try/catch block.
1571
          // (yes, very useful) wrap this with a try/catch block.
1572
          doc.onpropertychange = function(){
1572
          doc.onpropertychange = function(){
1573
            try {
1573
            try {
1574
              if ( event.propertyName === 'title' ) {
1574
              if ( event.propertyName === 'title' ) {
1575
                iframe.document.title = doc.title;
1575
                iframe.document.title = doc.title;
1576
              }
1576
              }
1577
            } catch(e) {}
1577
            } catch(e) {}
1578
          };
1578
          };
1579
         
1579
         
1580
        }
1580
        }
1581
      };
1581
      };
1582
     
1582
     
1583
      // Override the "stop" method since an IE6/7 Iframe was created. Even
1583
      // Override the "stop" method since an IE6/7 Iframe was created. Even
1584
      // if there are no longer any bound event handlers, the polling loop
1584
      // if there are no longer any bound event handlers, the polling loop
1585
      // is still necessary for back/next to work at all!
1585
      // is still necessary for back/next to work at all!
1586
      self.stop = fn_retval;
1586
      self.stop = fn_retval;
1587
     
1587
     
1588
      // Get history by looking at the hidden Iframe's location.hash.
1588
      // Get history by looking at the hidden Iframe's location.hash.
1589
      history_get = function() {
1589
      history_get = function() {
1590
        return get_fragment( iframe.location.href );
1590
        return get_fragment( iframe.location.href );
1591
      };
1591
      };
1592
     
1592
     
1593
      // Set a new history item by opening and then closing the Iframe
1593
      // Set a new history item by opening and then closing the Iframe
1594
      // document, *then* setting its location.hash. If document.domain has
1594
      // document, *then* setting its location.hash. If document.domain has
1595
      // been set, update that as well.
1595
      // been set, update that as well.
1596
      history_set = function( hash, history_hash ) {
1596
      history_set = function( hash, history_hash ) {
1597
        var iframe_doc = iframe.document,
1597
        var iframe_doc = iframe.document,
1598
          domain = $.fn[ str_hashchange ].domain;
1598
          domain = $.fn[ str_hashchange ].domain;
1599
       
1599
       
1600
        if ( hash !== history_hash ) {
1600
        if ( hash !== history_hash ) {
1601
          // Update Iframe with any initial `document.title` that might be set.
1601
          // Update Iframe with any initial `document.title` that might be set.
1602
          iframe_doc.title = doc.title;
1602
          iframe_doc.title = doc.title;
1603
         
1603
         
1604
          // Opening the Iframe's document after it has been closed is what
1604
          // Opening the Iframe's document after it has been closed is what
1605
          // actually adds a history entry.
1605
          // actually adds a history entry.
1606
          iframe_doc.open();
1606
          iframe_doc.open();
1607
         
1607
         
1608
          // Set document.domain for the Iframe document as well, if necessary.
1608
          // Set document.domain for the Iframe document as well, if necessary.
1609
          domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
1609
          domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
1610
         
1610
         
1611
          iframe_doc.close();
1611
          iframe_doc.close();
1612
         
1612
         
1613
          // Update the Iframe's hash, for great justice.
1613
          // Update the Iframe's hash, for great justice.
1614
          iframe.location.hash = hash;
1614
          iframe.location.hash = hash;
1615
        }
1615
        }
1616
      };
1616
      };
1617
     
1617
     
1618
    })();
1618
    })();
1619
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1619
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1620
    // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
1620
    // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
1621
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1621
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1622
   
1622
   
1623
    return self;
1623
    return self;
1624
  })();
1624
  })();
1625
 
1625
 
1626
})(jQuery,this);
1626
})(jQuery,this);
1627
/*
1627
/*
1628
* jQuery Mobile Framework : "page" plugin
1628
* jQuery Mobile Framework : "page" plugin
1629
* Copyright (c) jQuery Project
1629
* Copyright (c) jQuery Project
1630
* Dual licensed under the MIT or GPL Version 2 licenses.
1630
* Dual licensed under the MIT or GPL Version 2 licenses.
1631
* http://jquery.org/license
1631
* http://jquery.org/license
1632
*/
1632
*/
1633
(function($, undefined ) {
1633
(function($, undefined ) {
1634
 
1634
 
1635
$.widget( "mobile.page", $.mobile.widget, {
1635
$.widget( "mobile.page", $.mobile.widget, {
1636
    options: {
1636
    options: {
1637
        backBtnText: "Back",
1637
        backBtnText: "Back",
1638
        addBackBtn: false,
1638
        addBackBtn: false,
1639
        backBtnTheme: null,
1639
        backBtnTheme: null,
1640
        degradeInputs: {
1640
        degradeInputs: {
1641
            color: false,
1641
            color: false,
1642
            date: false,
1642
            date: false,
1643
            datetime: false,
1643
            datetime: false,
1644
            "datetime-local": false,
1644
            "datetime-local": false,
1645
            email: false,
1645
            email: false,
1646
            month: false,
1646
            month: false,
1647
            number: false,
1647
            number: false,
1648
            range: "number",
1648
            range: "number",
1649
            search: true,
1649
            search: true,
1650
            tel: false,
1650
            tel: false,
1651
            time: false,
1651
            time: false,
1652
            url: false,
1652
            url: false,
1653
            week: false
1653
            week: false
1654
        },
1654
        },
1655
        keepNative: null
1655
        keepNative: null
1656
    },
1656
    },
1657
 
1657
 
1658
    _create: function() {
1658
    _create: function() {
1659
        var $elem = this.element,
1659
        var $elem = this.element,
1660
            o = this.options;
1660
            o = this.options;
1661
 
1661
 
1662
        this.keepNative = ":jqmData(role='none'), :jqmData(role='nojs')" + (o.keepNative ? ", " + o.keepNative : "");
1662
        this.keepNative = ":jqmData(role='none'), :jqmData(role='nojs')" + (o.keepNative ? ", " + o.keepNative : "");
1663
 
1663
 
1664
        if ( this._trigger( "beforeCreate" ) === false ) {
1664
        if ( this._trigger( "beforeCreate" ) === false ) {
1665
            return;
1665
            return;
1666
        }
1666
        }
1667
 
1667
 
1668
        //some of the form elements currently rely on the presence of ui-page and ui-content
1668
        //some of the form elements currently rely on the presence of ui-page and ui-content
1669
        // classes so we'll handle page and content roles outside of the main role processing
1669
        // classes so we'll handle page and content roles outside of the main role processing
1670
        // loop below.
1670
        // loop below.
1671
        $elem.find( ":jqmData(role='page'), :jqmData(role='content')" ).andSelf().each(function() {
1671
        $elem.find( ":jqmData(role='page'), :jqmData(role='content')" ).andSelf().each(function() {
1672
            $(this).addClass( "ui-" + $(this).jqmData( "role" ) );
1672
            $(this).addClass( "ui-" + $(this).jqmData( "role" ) );
1673
        });
1673
        });
1674
 
1674
 
1675
        $elem.find( ":jqmData(role='nojs')" ).addClass( "ui-nojs" );
1675
        $elem.find( ":jqmData(role='nojs')" ).addClass( "ui-nojs" );
1676
 
1676
 
1677
        // pre-find data els
1677
        // pre-find data els
1678
        var $dataEls = $elem.find( ":jqmData(role)" ).andSelf().each(function() {
1678
        var $dataEls = $elem.find( ":jqmData(role)" ).andSelf().each(function() {
1679
            var $this = $( this ),
1679
            var $this = $( this ),
1680
                role = $this.jqmData( "role" ),
1680
                role = $this.jqmData( "role" ),
1681
                theme = $this.jqmData( "theme" );
1681
                theme = $this.jqmData( "theme" );
1682
 
1682
 
1683
            //apply theming and markup modifications to page,header,content,footer
1683
            //apply theming and markup modifications to page,header,content,footer
1684
            if ( role === "header" || role === "footer" ) {
1684
            if ( role === "header" || role === "footer" ) {
1685
                $this.addClass( "ui-bar-" + (theme || $this.parent( ":jqmData(role='page')" ).jqmData( "theme" ) || "a") );
1685
                $this.addClass( "ui-bar-" + (theme || $this.parent( ":jqmData(role='page')" ).jqmData( "theme" ) || "a") );
1686
 
1686
 
1687
                // add ARIA role
1687
                // add ARIA role
1688
                $this.attr( "role", role === "header" ? "banner" : "contentinfo" );
1688
                $this.attr( "role", role === "header" ? "banner" : "contentinfo" );
1689
 
1689
 
1690
                //right,left buttons
1690
                //right,left buttons
1691
                var $headeranchors = $this.children( "a" ),
1691
                var $headeranchors = $this.children( "a" ),
1692
                    leftbtn = $headeranchors.hasClass( "ui-btn-left" ),
1692
                    leftbtn = $headeranchors.hasClass( "ui-btn-left" ),
1693
                    rightbtn = $headeranchors.hasClass( "ui-btn-right" );
1693
                    rightbtn = $headeranchors.hasClass( "ui-btn-right" );
1694
 
1694
 
1695
                if ( !leftbtn ) {
1695
                if ( !leftbtn ) {
1696
                    leftbtn = $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
1696
                    leftbtn = $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
1697
                }
1697
                }
1698
 
1698
 
1699
                if ( !rightbtn ) {
1699
                if ( !rightbtn ) {
1700
                    rightbtn = $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
1700
                    rightbtn = $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
1701
                }
1701
                }
1702
 
1702
 
1703
                // auto-add back btn on pages beyond first view
1703
                // auto-add back btn on pages beyond first view
1704
                if ( o.addBackBtn && role === "header" &&
1704
                if ( o.addBackBtn && role === "header" &&
1705
                        $( ".ui-page" ).length > 1 &&
1705
                        $( ".ui-page" ).length > 1 &&
1706
                        $elem.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
1706
                        $elem.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
1707
                        !leftbtn && $this.jqmData( "backbtn" ) !== false ) {
1707
                        !leftbtn && $this.jqmData( "backbtn" ) !== false ) {
1708
 
1708
 
1709
                    var backBtn = $( "<a href='#' class='ui-btn-left' data-"+ $.mobile.ns +"rel='back' data-"+ $.mobile.ns +"icon='arrow-l'>"+ o.backBtnText +"</a>" ).prependTo( $this );
1709
                    var backBtn = $( "<a href='#' class='ui-btn-left' data-"+ $.mobile.ns +"rel='back' data-"+ $.mobile.ns +"icon='arrow-l'>"+ o.backBtnText +"</a>" ).prependTo( $this );
1710
                   
1710
                   
1711
                    //if theme is provided, override default inheritance
1711
                    //if theme is provided, override default inheritance
1712
                    if( o.backBtnTheme ){
1712
                    if( o.backBtnTheme ){
1713
                        backBtn.attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme );
1713
                        backBtn.attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme );
1714
                    }
1714
                    }
1715
                }
1715
                }
1716
 
1716
 
1717
                //page title
1717
                //page title
1718
                $this.children( "h1, h2, h3, h4, h5, h6" )
1718
                $this.children( "h1, h2, h3, h4, h5, h6" )
1719
                    .addClass( "ui-title" )
1719
                    .addClass( "ui-title" )
1720
                    //regardless of h element number in src, it becomes h1 for the enhanced page
1720
                    //regardless of h element number in src, it becomes h1 for the enhanced page
1721
                    .attr({ "tabindex": "0", "role": "heading", "aria-level": "1" });
1721
                    .attr({ "tabindex": "0", "role": "heading", "aria-level": "1" });
1722
 
1722
 
1723
            } else if ( role === "content" ) {
1723
            } else if ( role === "content" ) {
1724
                if ( theme ) {
1724
                if ( theme ) {
1725
                    $this.addClass( "ui-body-" + theme );
1725
                    $this.addClass( "ui-body-" + theme );
1726
                }
1726
                }
1727
 
1727
 
1728
                // add ARIA role
1728
                // add ARIA role
1729
                $this.attr( "role", "main" );
1729
                $this.attr( "role", "main" );
1730
 
1730
 
1731
            } else if ( role === "page" ) {
1731
            } else if ( role === "page" ) {
1732
                $this.addClass( "ui-body-" + (theme || "c") );
1732
                $this.addClass( "ui-body-" + (theme || "c") );
1733
            }
1733
            }
1734
 
1734
 
1735
            switch(role) {
1735
            switch(role) {
1736
                case "header":
1736
                case "header":
1737
                case "footer":
1737
                case "footer":
1738
                case "page":
1738
                case "page":
1739
                case "content":
1739
                case "content":
1740
                    $this.addClass( "ui-" + role );
1740
                    $this.addClass( "ui-" + role );
1741
                    break;
1741
                    break;
1742
                case "collapsible":
1742
                case "collapsible":
1743
                case "fieldcontain":
1743
                case "fieldcontain":
1744
                case "navbar":
1744
                case "navbar":
1745
                case "listview":
1745
                case "listview":
1746
                case "dialog":
1746
                case "dialog":
1747
                    $this[ role ]();
1747
                    $this[ role ]();
1748
                    break;
1748
                    break;
1749
            }
1749
            }
1750
        });
1750
        });
1751
 
1751
 
1752
        //enhance form controls
1752
        //enhance form controls
1753
    this._enhanceControls();
1753
    this._enhanceControls();
1754
 
1754
 
1755
        //links in bars, or those with  data-role become buttons
1755
        //links in bars, or those with  data-role become buttons
1756
        $elem.find( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a" )
1756
        $elem.find( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a" )
1757
            .not( ".ui-btn" )
1757
            .not( ".ui-btn" )
1758
            .not(this.keepNative)
1758
            .not(this.keepNative)
1759
            .buttonMarkup();
1759
            .buttonMarkup();
1760
 
1760
 
1761
        $elem
1761
        $elem
1762
            .find(":jqmData(role='controlgroup')")
1762
            .find(":jqmData(role='controlgroup')")
1763
            .controlgroup();
1763
            .controlgroup();
1764
 
1764
 
1765
        //links within content areas
1765
        //links within content areas
1766
        $elem.find( "a:not(.ui-btn):not(.ui-link-inherit)" )
1766
        $elem.find( "a:not(.ui-btn):not(.ui-link-inherit)" )
1767
            .not(this.keepNative)
1767
            .not(this.keepNative)
1768
            .addClass( "ui-link" );
1768
            .addClass( "ui-link" );
1769
 
1769
 
1770
        //fix toolbars
1770
        //fix toolbars
1771
        $elem.fixHeaderFooter();
1771
        $elem.fixHeaderFooter();
1772
    },
1772
    },
1773
 
1773
 
1774
    _typeAttributeRegex: /\s+type=["']?\w+['"]?/,
1774
    _typeAttributeRegex: /\s+type=["']?\w+['"]?/,
1775
 
1775
 
1776
    _enhanceControls: function() {
1776
    _enhanceControls: function() {
1777
        var o = this.options, self = this;
1777
        var o = this.options, self = this;
1778
 
1778
 
1779
        // degrade inputs to avoid poorly implemented native functionality
1779
        // degrade inputs to avoid poorly implemented native functionality
1780
        this.element.find( "input" ).not(this.keepNative).each(function() {
1780
        this.element.find( "input" ).not(this.keepNative).each(function() {
1781
            var type = this.getAttribute( "type" ),
1781
            var type = this.getAttribute( "type" ),
1782
                optType = o.degradeInputs[ type ] || "text";
1782
                optType = o.degradeInputs[ type ] || "text";
1783
 
1783
 
1784
            if ( o.degradeInputs[ type ] ) {
1784
            if ( o.degradeInputs[ type ] ) {
1785
                $( this ).replaceWith(
1785
                $( this ).replaceWith(
1786
                    $( "<div>" ).html( $(this).clone() ).html()
1786
                    $( "<div>" ).html( $(this).clone() ).html()
1787
                        .replace( self._typeAttributeRegex, " type=\""+ optType +"\" data-" + $.mobile.ns + "type=\""+type+"\" " ) );
1787
                        .replace( self._typeAttributeRegex, " type=\""+ optType +"\" data-" + $.mobile.ns + "type=\""+type+"\" " ) );
1788
            }
1788
            }
1789
        });
1789
        });
1790
 
1790
 
1791
        // We re-find form elements since the degredation code above
1791
        // We re-find form elements since the degredation code above
1792
        // may have injected new elements. We cache the non-native control
1792
        // may have injected new elements. We cache the non-native control
1793
        // query to reduce the number of times we search through the entire page.
1793
        // query to reduce the number of times we search through the entire page.
1794
 
1794
 
1795
        var allControls = this.element.find("input, textarea, select, button"),
1795
        var allControls = this.element.find("input, textarea, select, button"),
1796
            nonNativeControls = allControls.not(this.keepNative);
1796
            nonNativeControls = allControls.not(this.keepNative);
1797
 
1797
 
1798
        // XXX: Temporary workaround for issue 785. Turn off autocorrect and
1798
        // XXX: Temporary workaround for issue 785. Turn off autocorrect and
1799
        //      autocomplete since the popup they use can't be dismissed by
1799
        //      autocomplete since the popup they use can't be dismissed by
1800
        //      the user. Note that we test for the presence of the feature
1800
        //      the user. Note that we test for the presence of the feature
1801
        //      by looking for the autocorrect property on the input element.
1801
        //      by looking for the autocorrect property on the input element.
1802
 
1802
 
1803
        var textInputs = allControls.filter( "input[type=text]" );
1803
        var textInputs = allControls.filter( "input[type=text]" );
1804
        if (textInputs.length && typeof textInputs[0].autocorrect !== "undefined") {
1804
        if (textInputs.length && typeof textInputs[0].autocorrect !== "undefined") {
1805
            textInputs.each(function(){
1805
            textInputs.each(function(){
1806
                // Set the attribute instead of the property just in case there
1806
                // Set the attribute instead of the property just in case there
1807
                // is code that attempts to make modifications via HTML.
1807
                // is code that attempts to make modifications via HTML.
1808
                this.setAttribute("autocorrect", "off");
1808
                this.setAttribute("autocorrect", "off");
1809
                this.setAttribute("autocomplete", "off");
1809
                this.setAttribute("autocomplete", "off");
1810
            });
1810
            });
1811
        }
1811
        }
1812
 
1812
 
1813
        // enchance form controls
1813
        // enchance form controls
1814
        nonNativeControls
1814
        nonNativeControls
1815
            .filter( "[type='radio'], [type='checkbox']" )
1815
            .filter( "[type='radio'], [type='checkbox']" )
1816
            .checkboxradio();
1816
            .checkboxradio();
1817
 
1817
 
1818
        nonNativeControls
1818
        nonNativeControls
1819
            .filter( "button, [type='button'], [type='submit'], [type='reset'], [type='image']" )
1819
            .filter( "button, [type='button'], [type='submit'], [type='reset'], [type='image']" )
1820
            .button();
1820
            .button();
1821
 
1821
 
1822
        nonNativeControls
1822
        nonNativeControls
1823
            .filter( "input, textarea" )
1823
            .filter( "input, textarea" )
1824
            .not( "[type='radio'], [type='checkbox'], [type='button'], [type='submit'], [type='reset'], [type='image'], [type='hidden']" )
1824
            .not( "[type='radio'], [type='checkbox'], [type='button'], [type='submit'], [type='reset'], [type='image'], [type='hidden']" )
1825
            .textinput();
1825
            .textinput();
1826
 
1826
 
1827
        nonNativeControls
1827
        nonNativeControls
1828
            .filter( "input, select" )
1828
            .filter( "input, select" )
1829
            .filter( ":jqmData(role='slider'), :jqmData(type='range')" )
1829
            .filter( ":jqmData(role='slider'), :jqmData(type='range')" )
1830
            .slider();
1830
            .slider();
1831
 
1831
 
1832
        nonNativeControls
1832
        nonNativeControls
1833
            .filter( "select:not(:jqmData(role='slider'))" )
1833
            .filter( "select:not(:jqmData(role='slider'))" )
1834
            .selectmenu();
1834
            .selectmenu();
1835
    }
1835
    }
1836
});
1836
});
1837
 
1837
 
1838
})( jQuery );
1838
})( jQuery );
1839
/*!
1839
/*!
1840
 * jQuery Mobile v@VERSION
1840
 * jQuery Mobile v@VERSION
1841
 * http://jquerymobile.com/
1841
 * http://jquerymobile.com/
1842
 *
1842
 *
1843
 * Copyright 2010, jQuery Project
1843
 * Copyright 2010, jQuery Project
1844
 * Dual licensed under the MIT or GPL Version 2 licenses.
1844
 * Dual licensed under the MIT or GPL Version 2 licenses.
1845
 * http://jquery.org/license
1845
 * http://jquery.org/license
1846
 */
1846
 */
1847
 
1847
 
1848
(function( $, window, undefined ) {
1848
(function( $, window, undefined ) {
1849
 
1849
 
1850
    //jQuery.mobile configurable options
1850
    //jQuery.mobile configurable options
1851
    $.extend( $.mobile, {
1851
    $.extend( $.mobile, {
1852
 
1852
 
1853
        //namespace used framework-wide for data-attrs. Default is no namespace
1853
        //namespace used framework-wide for data-attrs. Default is no namespace
1854
        ns: "",
1854
        ns: "",
1855
 
1855
 
1856
        //define the url parameter used for referencing widget-generated sub-pages.
1856
        //define the url parameter used for referencing widget-generated sub-pages.
1857
        //Translates to to example.html&ui-page=subpageIdentifier
1857
        //Translates to to example.html&ui-page=subpageIdentifier
1858
        //hash segment before &ui-page= is used to make Ajax request
1858
        //hash segment before &ui-page= is used to make Ajax request
1859
        subPageUrlKey: "ui-page",
1859
        subPageUrlKey: "ui-page",
1860
 
1860
 
1861
        //anchor links with a data-rel, or pages with a  data-role, that match these selectors will be untrackable in history
1861
        //anchor links with a data-rel, or pages with a  data-role, that match these selectors will be untrackable in history
1862
        //(no change in URL, not bookmarkable)
1862
        //(no change in URL, not bookmarkable)
1863
        nonHistorySelectors: "dialog",
1863
        nonHistorySelectors: "dialog",
1864
 
1864
 
1865
        //class assigned to page currently in view, and during transitions
1865
        //class assigned to page currently in view, and during transitions
1866
        activePageClass: "ui-page-active",
1866
        activePageClass: "ui-page-active",
1867
 
1867
 
1868
        //class used for "active" button state, from CSS framework
1868
        //class used for "active" button state, from CSS framework
1869
        activeBtnClass: "ui-btn-active",
1869
        activeBtnClass: "ui-btn-active",
1870
 
1870
 
1871
        //automatically handle clicks and form submissions through Ajax, when same-domain
1871
        //automatically handle clicks and form submissions through Ajax, when same-domain
1872
        ajaxEnabled: true,
1872
        ajaxEnabled: true,
1873
       
1873
       
1874
        //When enabled, clicks and taps that result in Ajax page changes will happen slightly sooner on touch devices.
1874
        //When enabled, clicks and taps that result in Ajax page changes will happen slightly sooner on touch devices.
1875
        //Also, it will prevent the address bar from appearing on platforms like iOS during page transitions.
1875
        //Also, it will prevent the address bar from appearing on platforms like iOS during page transitions.
1876
        //This option has no effect on non-touch devices, but enabling it may interfere with jQuery plugins that bind to click events
1876
        //This option has no effect on non-touch devices, but enabling it may interfere with jQuery plugins that bind to click events
1877
        useFastClick: true,
1877
        useFastClick: true,
1878
 
1878
 
1879
        //automatically load and show pages based on location.hash
1879
        //automatically load and show pages based on location.hash
1880
        hashListeningEnabled: true,
1880
        hashListeningEnabled: true,
1881
 
1881
 
1882
        //set default page transition - 'none' for no transitions
1882
        //set default page transition - 'none' for no transitions
1883
        defaultPageTransition: "slide",
1883
        defaultPageTransition: "slide",
1884
       
1884
       
1885
        //minimum scroll distance that will be remembered when returning to a page
1885
        //minimum scroll distance that will be remembered when returning to a page
1886
        minScrollBack: screen.height / 2,
1886
        minScrollBack: screen.height / 2,
1887
 
1887
 
1888
        //set default dialog transition - 'none' for no transitions
1888
        //set default dialog transition - 'none' for no transitions
1889
        defaultDialogTransition: "pop",
1889
        defaultDialogTransition: "pop",
1890
 
1890
 
1891
        //show loading message during Ajax requests
1891
        //show loading message during Ajax requests
1892
        //if false, message will not appear, but loading classes will still be toggled on html el
1892
        //if false, message will not appear, but loading classes will still be toggled on html el
1893
        loadingMessage: "loading",
1893
        loadingMessage: "loading",
1894
 
1894
 
1895
        //error response message - appears when an Ajax page request fails
1895
        //error response message - appears when an Ajax page request fails
1896
        pageLoadErrorMessage: "Error Loading Page",
1896
        pageLoadErrorMessage: "Error Loading Page",
1897
 
1897
 
1898
        //support conditions that must be met in order to proceed
1898
        //support conditions that must be met in order to proceed
1899
        //default enhanced qualifications are media query support OR IE 7+
1899
        //default enhanced qualifications are media query support OR IE 7+
1900
        gradeA: function(){
1900
        gradeA: function(){
1901
            return $.support.mediaquery || $.mobile.browser.ie && $.mobile.browser.ie >= 7;
1901
            return $.support.mediaquery || $.mobile.browser.ie && $.mobile.browser.ie >= 7;
1902
        },
1902
        },
1903
 
1903
 
1904
        //TODO might be useful upstream in jquery itself ?
1904
        //TODO might be useful upstream in jquery itself ?
1905
        keyCode: {
1905
        keyCode: {
1906
            ALT: 18,
1906
            ALT: 18,
1907
            BACKSPACE: 8,
1907
            BACKSPACE: 8,
1908
            CAPS_LOCK: 20,
1908
            CAPS_LOCK: 20,
1909
            COMMA: 188,
1909
            COMMA: 188,
1910
            COMMAND: 91,
1910
            COMMAND: 91,
1911
            COMMAND_LEFT: 91, // COMMAND
1911
            COMMAND_LEFT: 91, // COMMAND
1912
            COMMAND_RIGHT: 93,
1912
            COMMAND_RIGHT: 93,
1913
            CONTROL: 17,
1913
            CONTROL: 17,
1914
            DELETE: 46,
1914
            DELETE: 46,
1915
            DOWN: 40,
1915
            DOWN: 40,
1916
            END: 35,
1916
            END: 35,
1917
            ENTER: 13,
1917
            ENTER: 13,
1918
            ESCAPE: 27,
1918
            ESCAPE: 27,
1919
            HOME: 36,
1919
            HOME: 36,
1920
            INSERT: 45,
1920
            INSERT: 45,
1921
            LEFT: 37,
1921
            LEFT: 37,
1922
            MENU: 93, // COMMAND_RIGHT
1922
            MENU: 93, // COMMAND_RIGHT
1923
            NUMPAD_ADD: 107,
1923
            NUMPAD_ADD: 107,
1924
            NUMPAD_DECIMAL: 110,
1924
            NUMPAD_DECIMAL: 110,
1925
            NUMPAD_DIVIDE: 111,
1925
            NUMPAD_DIVIDE: 111,
1926
            NUMPAD_ENTER: 108,
1926
            NUMPAD_ENTER: 108,
1927
            NUMPAD_MULTIPLY: 106,
1927
            NUMPAD_MULTIPLY: 106,
1928
            NUMPAD_SUBTRACT: 109,
1928
            NUMPAD_SUBTRACT: 109,
1929
            PAGE_DOWN: 34,
1929
            PAGE_DOWN: 34,
1930
            PAGE_UP: 33,
1930
            PAGE_UP: 33,
1931
            PERIOD: 190,
1931
            PERIOD: 190,
1932
            RIGHT: 39,
1932
            RIGHT: 39,
1933
            SHIFT: 16,
1933
            SHIFT: 16,
1934
            SPACE: 32,
1934
            SPACE: 32,
1935
            TAB: 9,
1935
            TAB: 9,
1936
            UP: 38,
1936
            UP: 38,
1937
            WINDOWS: 91 // COMMAND
1937
            WINDOWS: 91 // COMMAND
1938
        },
1938
        },
1939
 
1939
 
1940
        //scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
1940
        //scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
1941
        silentScroll: function( ypos ) {
1941
        silentScroll: function( ypos ) {
1942
            if( $.type( ypos ) !== "number" ){
1942
            if( $.type( ypos ) !== "number" ){
1943
                ypos = $.mobile.defaultHomeScroll;
1943
                ypos = $.mobile.defaultHomeScroll;
1944
            }
1944
            }
1945
 
1945
 
1946
            // prevent scrollstart and scrollstop events
1946
            // prevent scrollstart and scrollstop events
1947
            $.event.special.scrollstart.enabled = false;
1947
            $.event.special.scrollstart.enabled = false;
1948
 
1948
 
1949
            setTimeout(function() {
1949
            setTimeout(function() {
1950
                window.scrollTo( 0, ypos );
1950
                window.scrollTo( 0, ypos );
1951
                $(document).trigger( "silentscroll", { x: 0, y: ypos });
1951
                $(document).trigger( "silentscroll", { x: 0, y: ypos });
1952
            },20);
1952
            },20);
1953
 
1953
 
1954
            setTimeout(function() {
1954
            setTimeout(function() {
1955
                $.event.special.scrollstart.enabled = true;
1955
                $.event.special.scrollstart.enabled = true;
1956
            }, 150 );
1956
            }, 150 );
1957
        },
1957
        },
1958
 
1958
 
1959
        // compile the namespace normalization regex once
1959
        // compile the namespace normalization regex once
1960
        normalizeRegex: /-([a-z])/g,
1960
        normalizeRegex: /-([a-z])/g,
1961
 
1961
 
1962
        // take a data attribute property, prepend the namespace
1962
        // take a data attribute property, prepend the namespace
1963
        // and then camel case the attribute string
1963
        // and then camel case the attribute string
1964
        nsNormalize: function(prop){
1964
        nsNormalize: function(prop){
1965
            if(!prop) return;
1965
            if(!prop) return;
1966
 
1966
 
1967
            return $.camelCase( $.mobile.ns + prop );
1967
            return $.camelCase( $.mobile.ns + prop );
1968
        }
1968
        }
1969
    });
1969
    });
1970
 
1970
 
1971
    //mobile version of data and removeData and hasData methods
1971
    //mobile version of data and removeData and hasData methods
1972
    //ensures all data is set and retrieved using jQuery Mobile's data namespace
1972
    //ensures all data is set and retrieved using jQuery Mobile's data namespace
1973
    $.fn.jqmData = function( prop, value ){
1973
    $.fn.jqmData = function( prop, value ){
1974
        return this.data( prop ? $.mobile.nsNormalize(prop) : prop, value );
1974
        return this.data( prop ? $.mobile.nsNormalize(prop) : prop, value );
1975
    };
1975
    };
1976
 
1976
 
1977
    $.jqmData = function( elem, prop, value ){
1977
    $.jqmData = function( elem, prop, value ){
1978
        return $.data( elem, $.mobile.nsNormalize(prop), value );
1978
        return $.data( elem, $.mobile.nsNormalize(prop), value );
1979
    };
1979
    };
1980
 
1980
 
1981
    $.fn.jqmRemoveData = function( prop ){
1981
    $.fn.jqmRemoveData = function( prop ){
1982
        return this.removeData( $.mobile.nsNormalize(prop) );
1982
        return this.removeData( $.mobile.nsNormalize(prop) );
1983
    };
1983
    };
1984
 
1984
 
1985
    $.jqmRemoveData = function( elem, prop ){
1985
    $.jqmRemoveData = function( elem, prop ){
1986
        return $.removeData( elem, $.mobile.nsNormalize(prop) );
1986
        return $.removeData( elem, $.mobile.nsNormalize(prop) );
1987
    };
1987
    };
1988
 
1988
 
1989
    $.jqmHasData = function( elem, prop ){
1989
    $.jqmHasData = function( elem, prop ){
1990
        return $.hasData( elem, $.mobile.nsNormalize(prop) );
1990
        return $.hasData( elem, $.mobile.nsNormalize(prop) );
1991
    };
1991
    };
1992
 
1992
 
1993
    // Monkey-patching Sizzle to filter the :jqmData selector
1993
    // Monkey-patching Sizzle to filter the :jqmData selector
1994
    var oldFind = $.find;
1994
    var oldFind = $.find;
1995
 
1995
 
1996
    $.find = function( selector, context, ret, extra ) {
1996
    $.find = function( selector, context, ret, extra ) {
1997
        selector = selector.replace(/:jqmData\(([^)]*)\)/g, "[data-" + ($.mobile.ns || "") + "$1]");
1997
        selector = selector.replace(/:jqmData\(([^)]*)\)/g, "[data-" + ($.mobile.ns || "") + "$1]");
1998
 
1998
 
1999
        return oldFind.call( this, selector, context, ret, extra );
1999
        return oldFind.call( this, selector, context, ret, extra );
2000
    };
2000
    };
2001
 
2001
 
2002
    $.extend( $.find, oldFind );
2002
    $.extend( $.find, oldFind );
2003
 
2003
 
2004
    $.find.matches = function( expr, set ) {
2004
    $.find.matches = function( expr, set ) {
2005
        return $.find( expr, null, null, set );
2005
        return $.find( expr, null, null, set );
2006
    };
2006
    };
2007
 
2007
 
2008
    $.find.matchesSelector = function( node, expr ) {
2008
    $.find.matchesSelector = function( node, expr ) {
2009
        return $.find( expr, null, null, [node] ).length > 0;
2009
        return $.find( expr, null, null, [node] ).length > 0;
2010
    };
2010
    };
2011
})( jQuery, this );
2011
})( jQuery, this );
2012
/*
2012
/*
2013
* jQuery Mobile Framework : core utilities for auto ajax navigation, base tag mgmt,
2013
* jQuery Mobile Framework : core utilities for auto ajax navigation, base tag mgmt,
2014
* Copyright (c) jQuery Project
2014
* Copyright (c) jQuery Project
2015
* Dual licensed under the MIT or GPL Version 2 licenses.
2015
* Dual licensed under the MIT or GPL Version 2 licenses.
2016
* http://jquery.org/license
2016
* http://jquery.org/license
2017
*/
2017
*/
2018
( function( $, undefined ) {
2018
( function( $, undefined ) {
2019
 
2019
 
2020
    //define vars for interal use
2020
    //define vars for interal use
2021
    var $window = $( window ),
2021
    var $window = $( window ),
2022
        $html = $( 'html' ),
2022
        $html = $( 'html' ),
2023
        $head = $( 'head' ),
2023
        $head = $( 'head' ),
2024
 
2024
 
2025
        //url path helpers for use in relative url management
2025
        //url path helpers for use in relative url management
2026
        path = {
2026
        path = {
2027
 
2027
 
2028
            // This scary looking regular expression parses an absolute URL or its relative
2028
            // This scary looking regular expression parses an absolute URL or its relative
2029
            // variants (protocol, site, document, query, and hash), into the various
2029
            // variants (protocol, site, document, query, and hash), into the various
2030
            // components (protocol, host, path, query, fragment, etc that make up the
2030
            // components (protocol, host, path, query, fragment, etc that make up the
2031
            // URL as well as some other commonly used sub-parts. When used with RegExp.exec()
2031
            // URL as well as some other commonly used sub-parts. When used with RegExp.exec()
2032
            // or String.match, it parses the URL into a results array that looks like this:
2032
            // or String.match, it parses the URL into a results array that looks like this:
2033
            //
2033
            //
2034
            //     [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
2034
            //     [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
2035
            //     [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
2035
            //     [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
2036
            //     [2]: http://jblas:password@mycompany.com:8080/mail/inbox
2036
            //     [2]: http://jblas:password@mycompany.com:8080/mail/inbox
2037
            //     [3]: http://jblas:password@mycompany.com:8080
2037
            //     [3]: http://jblas:password@mycompany.com:8080
2038
            //     [4]: http:
2038
            //     [4]: http:
2039
            //     [5]: jblas:password@mycompany.com:8080
2039
            //     [5]: jblas:password@mycompany.com:8080
2040
            //     [6]: jblas:password
2040
            //     [6]: jblas:password
2041
            //     [7]: jblas
2041
            //     [7]: jblas
2042
            //     [8]: password
2042
            //     [8]: password
2043
            //     [9]: mycompany.com:8080
2043
            //     [9]: mycompany.com:8080
2044
            //    [10]: mycompany.com
2044
            //    [10]: mycompany.com
2045
            //    [11]: 8080
2045
            //    [11]: 8080
2046
            //    [12]: /mail/inbox
2046
            //    [12]: /mail/inbox
2047
            //    [13]: /mail/
2047
            //    [13]: /mail/
2048
            //    [14]: inbox
2048
            //    [14]: inbox
2049
            //    [15]: ?msg=1234&type=unread
2049
            //    [15]: ?msg=1234&type=unread
2050
            //    [16]: #msg-content
2050
            //    [16]: #msg-content
2051
            //
2051
            //
2052
            urlParseRE: /^(((([^:\/#\?]+:)?(?:\/\/((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?]+)(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
2052
            urlParseRE: /^(((([^:\/#\?]+:)?(?:\/\/((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?]+)(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
2053
 
2053
 
2054
            //Parse a URL into a structure that allows easy access to
2054
            //Parse a URL into a structure that allows easy access to
2055
            //all of the URL components by name.
2055
            //all of the URL components by name.
2056
            parseUrl: function( url ) {
2056
            parseUrl: function( url ) {
2057
                // If we're passed an object, we'll assume that it is
2057
                // If we're passed an object, we'll assume that it is
2058
                // a parsed url object and just return it back to the caller.
2058
                // a parsed url object and just return it back to the caller.
2059
                if ( typeof url === "object" ) {
2059
                if ( typeof url === "object" ) {
2060
                    return url;
2060
                    return url;
2061
                }
2061
                }
2062
 
2062
 
2063
                var u = url || "",
2063
                var u = url || "",
2064
                    matches = path.urlParseRE.exec( url ),
2064
                    matches = path.urlParseRE.exec( url ),
2065
                    results;
2065
                    results;
2066
                if ( matches ) {
2066
                if ( matches ) {
2067
                    // Create an object that allows the caller to access the sub-matches
2067
                    // Create an object that allows the caller to access the sub-matches
2068
                    // by name. Note that IE returns an empty string instead of undefined,
2068
                    // by name. Note that IE returns an empty string instead of undefined,
2069
                    // like all other browsers do, so we normalize everything so its consistent
2069
                    // like all other browsers do, so we normalize everything so its consistent
2070
                    // no matter what browser we're running on.
2070
                    // no matter what browser we're running on.
2071
                    results = {
2071
                    results = {
2072
                        href:         matches[0] || "",
2072
                        href:         matches[0] || "",
2073
                        hrefNoHash:   matches[1] || "",
2073
                        hrefNoHash:   matches[1] || "",
2074
                        hrefNoSearch: matches[2] || "",
2074
                        hrefNoSearch: matches[2] || "",
2075
                        domain:       matches[3] || "",
2075
                        domain:       matches[3] || "",
2076
                        protocol:     matches[4] || "",
2076
                        protocol:     matches[4] || "",
2077
                        authority:    matches[5] || "",
2077
                        authority:    matches[5] || "",
2078
                        username:     matches[7] || "",
2078
                        username:     matches[7] || "",
2079
                        password:     matches[8] || "",
2079
                        password:     matches[8] || "",
2080
                        host:         matches[9] || "",
2080
                        host:         matches[9] || "",
2081
                        hostname:     matches[10] || "",
2081
                        hostname:     matches[10] || "",
2082
                        port:         matches[11] || "",
2082
                        port:         matches[11] || "",
2083
                        pathname:     matches[12] || "",
2083
                        pathname:     matches[12] || "",
2084
                        directory:    matches[13] || "",
2084
                        directory:    matches[13] || "",
2085
                        filename:     matches[14] || "",
2085
                        filename:     matches[14] || "",
2086
                        search:       matches[15] || "",
2086
                        search:       matches[15] || "",
2087
                        hash:         matches[16] || ""
2087
                        hash:         matches[16] || ""
2088
                    };
2088
                    };
2089
                }
2089
                }
2090
                return results || {};
2090
                return results || {};
2091
            },
2091
            },
2092
 
2092
 
2093
            //Turn relPath into an asbolute path. absPath is
2093
            //Turn relPath into an asbolute path. absPath is
2094
            //an optional absolute path which describes what
2094
            //an optional absolute path which describes what
2095
            //relPath is relative to.
2095
            //relPath is relative to.
2096
            makePathAbsolute: function( relPath, absPath ) {
2096
            makePathAbsolute: function( relPath, absPath ) {
2097
                if ( relPath && relPath.charAt( 0 ) === "/" ) {
2097
                if ( relPath && relPath.charAt( 0 ) === "/" ) {
2098
                    return relPath;
2098
                    return relPath;
2099
                }
2099
                }
2100
       
2100
       
2101
                relPath = relPath || "";
2101
                relPath = relPath || "";
2102
                absPath = absPath ? absPath.replace( /^\/|\/?[^\/]*$/g, "" ) : "";
2102
                absPath = absPath ? absPath.replace( /^\/|\/?[^\/]*$/g, "" ) : "";
2103
       
2103
       
2104
                var absStack = absPath ? absPath.split( "/" ) : [],
2104
                var absStack = absPath ? absPath.split( "/" ) : [],
2105
                    relStack = relPath.split( "/" );
2105
                    relStack = relPath.split( "/" );
2106
                for ( var i = 0; i < relStack.length; i++ ) {
2106
                for ( var i = 0; i < relStack.length; i++ ) {
2107
                    var d = relStack[ i ];
2107
                    var d = relStack[ i ];
2108
                    switch ( d ) {
2108
                    switch ( d ) {
2109
                        case ".":
2109
                        case ".":
2110
                            break;
2110
                            break;
2111
                        case "..":
2111
                        case "..":
2112
                            if ( absStack.length ) {
2112
                            if ( absStack.length ) {
2113
                                absStack.pop();
2113
                                absStack.pop();
2114
                            }
2114
                            }
2115
                            break;
2115
                            break;
2116
                        default:
2116
                        default:
2117
                            absStack.push( d );
2117
                            absStack.push( d );
2118
                            break;
2118
                            break;
2119
                    }
2119
                    }
2120
                }
2120
                }
2121
                return "/" + absStack.join( "/" );
2121
                return "/" + absStack.join( "/" );
2122
            },
2122
            },
2123
 
2123
 
2124
            //Returns true if both urls have the same domain.
2124
            //Returns true if both urls have the same domain.
2125
            isSameDomain: function( absUrl1, absUrl2 ) {
2125
            isSameDomain: function( absUrl1, absUrl2 ) {
2126
                return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
2126
                return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
2127
            },
2127
            },
2128
 
2128
 
2129
            //Returns true for any relative variant.
2129
            //Returns true for any relative variant.
2130
            isRelativeUrl: function( url ) {
2130
            isRelativeUrl: function( url ) {
2131
                // All relative Url variants have one thing in common, no protocol.
2131
                // All relative Url variants have one thing in common, no protocol.
2132
                return path.parseUrl( url ).protocol === "";
2132
                return path.parseUrl( url ).protocol === "";
2133
            },
2133
            },
2134
 
2134
 
2135
            //Returns true for an absolute url.
2135
            //Returns true for an absolute url.
2136
            isAbsoluteUrl: function( url ) {
2136
            isAbsoluteUrl: function( url ) {
2137
                return path.parseUrl( url ).protocol !== "";
2137
                return path.parseUrl( url ).protocol !== "";
2138
            },
2138
            },
2139
 
2139
 
2140
            //Turn the specified realtive URL into an absolute one. This function
2140
            //Turn the specified realtive URL into an absolute one. This function
2141
            //can handle all relative variants (protocol, site, document, query, fragment).
2141
            //can handle all relative variants (protocol, site, document, query, fragment).
2142
            makeUrlAbsolute: function( relUrl, absUrl ) {
2142
            makeUrlAbsolute: function( relUrl, absUrl ) {
2143
                if ( !path.isRelativeUrl( relUrl ) ) {
2143
                if ( !path.isRelativeUrl( relUrl ) ) {
2144
                    return relUrl;
2144
                    return relUrl;
2145
                }
2145
                }
2146
       
2146
       
2147
                var relObj = path.parseUrl( relUrl ),
2147
                var relObj = path.parseUrl( relUrl ),
2148
                    absObj = path.parseUrl( absUrl ),
2148
                    absObj = path.parseUrl( absUrl ),
2149
                    protocol = relObj.protocol || absObj.protocol,
2149
                    protocol = relObj.protocol || absObj.protocol,
2150
                    authority = relObj.authority || absObj.authority,
2150
                    authority = relObj.authority || absObj.authority,
2151
                    hasPath = relObj.pathname !== "",
2151
                    hasPath = relObj.pathname !== "",
2152
                    pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
2152
                    pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
2153
                    search = relObj.search || ( !hasPath && absObj.search ) || "",
2153
                    search = relObj.search || ( !hasPath && absObj.search ) || "",
2154
                    hash = relObj.hash;
2154
                    hash = relObj.hash;
2155
       
2155
       
2156
                return protocol + "//" + authority + pathname + search + hash;
2156
                return protocol + "//" + authority + pathname + search + hash;
2157
            },
2157
            },
2158
 
2158
 
2159
            //Add search (aka query) params to the specified url.
2159
            //Add search (aka query) params to the specified url.
2160
            addSearchParams: function( url, params ) {
2160
            addSearchParams: function( url, params ) {
2161
                var u = path.parseUrl( url ),
2161
                var u = path.parseUrl( url ),
2162
                    p = ( typeof params === "object" ) ? $.param( params ) : params,
2162
                    p = ( typeof params === "object" ) ? $.param( params ) : params,
2163
                    s = u.search || "?";
2163
                    s = u.search || "?";
2164
                return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
2164
                return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
2165
            },
2165
            },
2166
 
2166
 
2167
            convertUrlToDataUrl: function( absUrl ) {
2167
            convertUrlToDataUrl: function( absUrl ) {
2168
                var u = path.parseUrl( absUrl );
2168
                var u = path.parseUrl( absUrl );
2169
                if ( path.isEmbeddedPage( u ) ) {
2169
                if ( path.isEmbeddedPage( u ) ) {
2170
                    return u.hash.replace( /^#/, "" );
2170
                    return u.hash.replace( /^#/, "" );
2171
                } else if ( path.isSameDomain( u, documentBase ) ) {
2171
                } else if ( path.isSameDomain( u, documentBase ) ) {
2172
                    return u.hrefNoHash.replace( documentBase.domain, "" );
2172
                    return u.hrefNoHash.replace( documentBase.domain, "" );
2173
                }
2173
                }
2174
                return absUrl;
2174
                return absUrl;
2175
            },
2175
            },
2176
 
2176
 
2177
            //get path from current hash, or from a file path
2177
            //get path from current hash, or from a file path
2178
            get: function( newPath ) {
2178
            get: function( newPath ) {
2179
                if( newPath === undefined ) {
2179
                if( newPath === undefined ) {
2180
                    newPath = location.hash;
2180
                    newPath = location.hash;
2181
                }
2181
                }
2182
                return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
2182
                return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
2183
            },
2183
            },
2184
 
2184
 
2185
            //return the substring of a filepath before the sub-page key, for making a server request
2185
            //return the substring of a filepath before the sub-page key, for making a server request
2186
            getFilePath: function( path ) {
2186
            getFilePath: function( path ) {
2187
                var splitkey = '&' + $.mobile.subPageUrlKey;
2187
                var splitkey = '&' + $.mobile.subPageUrlKey;
2188
                return path && path.split( splitkey )[0].split( dialogHashKey )[0];
2188
                return path && path.split( splitkey )[0].split( dialogHashKey )[0];
2189
            },
2189
            },
2190
 
2190
 
2191
            //set location hash to path
2191
            //set location hash to path
2192
            set: function( path ) {
2192
            set: function( path ) {
2193
                location.hash = path;
2193
                location.hash = path;
2194
            },
2194
            },
2195
 
2195
 
2196
            //test if a given url (string) is a path
2196
            //test if a given url (string) is a path
2197
            //NOTE might be exceptionally naive
2197
            //NOTE might be exceptionally naive
2198
            isPath: function( url ) {
2198
            isPath: function( url ) {
2199
                return ( /\// ).test( url );
2199
                return ( /\// ).test( url );
2200
            },
2200
            },
2201
 
2201
 
2202
            //return a url path with the window's location protocol/hostname/pathname removed
2202
            //return a url path with the window's location protocol/hostname/pathname removed
2203
            clean: function( url ) {
2203
            clean: function( url ) {
2204
                return url.replace( documentBase.domain, "" );
2204
                return url.replace( documentBase.domain, "" );
2205
            },
2205
            },
2206
 
2206
 
2207
            //just return the url without an initial #
2207
            //just return the url without an initial #
2208
            stripHash: function( url ) {
2208
            stripHash: function( url ) {
2209
                return url.replace( /^#/, "" );
2209
                return url.replace( /^#/, "" );
2210
            },
2210
            },
2211
 
2211
 
2212
            //remove the preceding hash, any query params, and dialog notations
2212
            //remove the preceding hash, any query params, and dialog notations
2213
            cleanHash: function( hash ) {
2213
            cleanHash: function( hash ) {
2214
                return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
2214
                return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
2215
            },
2215
            },
2216
 
2216
 
2217
            //check whether a url is referencing the same domain, or an external domain or different protocol
2217
            //check whether a url is referencing the same domain, or an external domain or different protocol
2218
            //could be mailto, etc
2218
            //could be mailto, etc
2219
            isExternal: function( url ) {
2219
            isExternal: function( url ) {
2220
                var u = path.parseUrl( url );
2220
                var u = path.parseUrl( url );
2221
                return u.protocol && u.domain !== documentUrl.domain ? true : false;
2221
                return u.protocol && u.domain !== documentUrl.domain ? true : false;
2222
            },
2222
            },
2223
 
2223
 
2224
            hasProtocol: function( url ) {
2224
            hasProtocol: function( url ) {
2225
                return ( /^(:?\w+:)/ ).test( url );
2225
                return ( /^(:?\w+:)/ ).test( url );
2226
            },
2226
            },
2227
 
2227
 
2228
            isEmbeddedPage: function( url ) {
2228
            isEmbeddedPage: function( url ) {
2229
                var u = path.parseUrl( url );
2229
                var u = path.parseUrl( url );
2230
 
2230
 
2231
                //if the path is absolute, then we need to compare the url against
2231
                //if the path is absolute, then we need to compare the url against
2232
                //both the documentUrl and the documentBase. The main reason for this
2232
                //both the documentUrl and the documentBase. The main reason for this
2233
                //is that links embedded within external documents will refer to the
2233
                //is that links embedded within external documents will refer to the
2234
                //application document, whereas links embedded within the application
2234
                //application document, whereas links embedded within the application
2235
                //document will be resolved against the document base.
2235
                //document will be resolved against the document base.
2236
                if ( u.protocol !== "" ) {
2236
                if ( u.protocol !== "" ) {
2237
                    return ( u.hash && ( u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ) ) );
2237
                    return ( u.hash && ( u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ) ) );
2238
                }
2238
                }
2239
                return (/^#/).test( u.href );
2239
                return (/^#/).test( u.href );
2240
            }
2240
            }
2241
        },
2241
        },
2242
 
2242
 
2243
        //will be defined when a link is clicked and given an active class
2243
        //will be defined when a link is clicked and given an active class
2244
        $activeClickedLink = null,
2244
        $activeClickedLink = null,
2245
 
2245
 
2246
        //urlHistory is purely here to make guesses at whether the back or forward button was clicked
2246
        //urlHistory is purely here to make guesses at whether the back or forward button was clicked
2247
        //and provide an appropriate transition
2247
        //and provide an appropriate transition
2248
        urlHistory = {
2248
        urlHistory = {
2249
            //array of pages that are visited during a single page load. each has a url and optional transition
2249
            //array of pages that are visited during a single page load. each has a url and optional transition
2250
            stack: [],
2250
            stack: [],
2251
 
2251
 
2252
            //maintain an index number for the active page in the stack
2252
            //maintain an index number for the active page in the stack
2253
            activeIndex: 0,
2253
            activeIndex: 0,
2254
 
2254
 
2255
            //get active
2255
            //get active
2256
            getActive: function() {
2256
            getActive: function() {
2257
                return urlHistory.stack[ urlHistory.activeIndex ];
2257
                return urlHistory.stack[ urlHistory.activeIndex ];
2258
            },
2258
            },
2259
 
2259
 
2260
            getPrev: function() {
2260
            getPrev: function() {
2261
                return urlHistory.stack[ urlHistory.activeIndex - 1 ];
2261
                return urlHistory.stack[ urlHistory.activeIndex - 1 ];
2262
            },
2262
            },
2263
 
2263
 
2264
            getNext: function() {
2264
            getNext: function() {
2265
                return urlHistory.stack[ urlHistory.activeIndex + 1 ];
2265
                return urlHistory.stack[ urlHistory.activeIndex + 1 ];
2266
            },
2266
            },
2267
 
2267
 
2268
            // addNew is used whenever a new page is added
2268
            // addNew is used whenever a new page is added
2269
            addNew: function( url, transition, title, storedTo ) {
2269
            addNew: function( url, transition, title, storedTo ) {
2270
                //if there's forward history, wipe it
2270
                //if there's forward history, wipe it
2271
                if( urlHistory.getNext() ) {
2271
                if( urlHistory.getNext() ) {
2272
                    urlHistory.clearForward();
2272
                    urlHistory.clearForward();
2273
                }
2273
                }
2274
 
2274
 
2275
                urlHistory.stack.push( {url : url, transition: transition, title: title, page: storedTo } );
2275
                urlHistory.stack.push( {url : url, transition: transition, title: title, page: storedTo } );
2276
 
2276
 
2277
                urlHistory.activeIndex = urlHistory.stack.length - 1;
2277
                urlHistory.activeIndex = urlHistory.stack.length - 1;
2278
            },
2278
            },
2279
 
2279
 
2280
            //wipe urls ahead of active index
2280
            //wipe urls ahead of active index
2281
            clearForward: function() {
2281
            clearForward: function() {
2282
                urlHistory.stack = urlHistory.stack.slice( 0, urlHistory.activeIndex + 1 );
2282
                urlHistory.stack = urlHistory.stack.slice( 0, urlHistory.activeIndex + 1 );
2283
            },
2283
            },
2284
 
2284
 
2285
            directHashChange: function( opts ) {
2285
            directHashChange: function( opts ) {
2286
                var back , forward, newActiveIndex;
2286
                var back , forward, newActiveIndex;
2287
 
2287
 
2288
                // check if url isp in history and if it's ahead or behind current page
2288
                // check if url isp in history and if it's ahead or behind current page
2289
                $.each( urlHistory.stack, function( i, historyEntry ) {
2289
                $.each( urlHistory.stack, function( i, historyEntry ) {
2290
 
2290
 
2291
                    //if the url is in the stack, it's a forward or a back
2291
                    //if the url is in the stack, it's a forward or a back
2292
                    if( opts.currentUrl === historyEntry.url ) {
2292
                    if( opts.currentUrl === historyEntry.url ) {
2293
                        //define back and forward by whether url is older or newer than current page
2293
                        //define back and forward by whether url is older or newer than current page
2294
                        back = i < urlHistory.activeIndex;
2294
                        back = i < urlHistory.activeIndex;
2295
                        forward = !back;
2295
                        forward = !back;
2296
                        newActiveIndex = i;
2296
                        newActiveIndex = i;
2297
                    }
2297
                    }
2298
                });
2298
                });
2299
 
2299
 
2300
                // save new page index, null check to prevent falsey 0 result
2300
                // save new page index, null check to prevent falsey 0 result
2301
                this.activeIndex = newActiveIndex !== undefined ? newActiveIndex : this.activeIndex;
2301
                this.activeIndex = newActiveIndex !== undefined ? newActiveIndex : this.activeIndex;
2302
 
2302
 
2303
                if( back ) {
2303
                if( back ) {
2304
                    opts.isBack();
2304
                    opts.isBack();
2305
                } else if( forward ) {
2305
                } else if( forward ) {
2306
                    opts.isForward();
2306
                    opts.isForward();
2307
                }
2307
                }
2308
            },
2308
            },
2309
 
2309
 
2310
            //disable hashchange event listener internally to ignore one change
2310
            //disable hashchange event listener internally to ignore one change
2311
            //toggled internally when location.hash is updated to match the url of a successful page load
2311
            //toggled internally when location.hash is updated to match the url of a successful page load
2312
            ignoreNextHashChange: false
2312
            ignoreNextHashChange: false
2313
        },
2313
        },
2314
 
2314
 
2315
        //define first selector to receive focus when a page is shown
2315
        //define first selector to receive focus when a page is shown
2316
        focusable = "[tabindex],a,button:visible,select:visible,input",
2316
        focusable = "[tabindex],a,button:visible,select:visible,input",
2317
 
2317
 
2318
        //queue to hold simultanious page transitions
2318
        //queue to hold simultanious page transitions
2319
        pageTransitionQueue = [],
2319
        pageTransitionQueue = [],
2320
 
2320
 
2321
        //indicates whether or not page is in process of transitioning
2321
        //indicates whether or not page is in process of transitioning
2322
        isPageTransitioning = false,
2322
        isPageTransitioning = false,
2323
 
2323
 
2324
        //nonsense hash change key for dialogs, so they create a history entry
2324
        //nonsense hash change key for dialogs, so they create a history entry
2325
        dialogHashKey = "&ui-state=dialog",
2325
        dialogHashKey = "&ui-state=dialog",
2326
 
2326
 
2327
        //existing base tag?
2327
        //existing base tag?
2328
        $base = $head.children( "base" ),
2328
        $base = $head.children( "base" ),
2329
 
2329
 
2330
        //tuck away the original document URL minus any fragment.
2330
        //tuck away the original document URL minus any fragment.
2331
        documentUrl = path.parseUrl( location.href ),
2331
        documentUrl = path.parseUrl( location.href ),
2332
 
2332
 
2333
        //if the document has an embedded base tag, documentBase is set to its
2333
        //if the document has an embedded base tag, documentBase is set to its
2334
        //initial value. If a base tag does not exist, then we default to the documentUrl.
2334
        //initial value. If a base tag does not exist, then we default to the documentUrl.
2335
        documentBase = $base.length ? path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), documentUrl.href ) ) : documentUrl,
2335
        documentBase = $base.length ? path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), documentUrl.href ) ) : documentUrl,
2336
 
2336
 
2337
        //cache the comparison once.
2337
        //cache the comparison once.
2338
        documentBaseDiffers = ( documentUrl.hrefNoHash !== documentBase.hrefNoHash );
2338
        documentBaseDiffers = ( documentUrl.hrefNoHash !== documentBase.hrefNoHash );
2339
 
2339
 
2340
        //base element management, defined depending on dynamic base tag support
2340
        //base element management, defined depending on dynamic base tag support
2341
        var base = $.support.dynamicBaseTag ? {
2341
        var base = $.support.dynamicBaseTag ? {
2342
 
2342
 
2343
            //define base element, for use in routing asset urls that are referenced in Ajax-requested markup
2343
            //define base element, for use in routing asset urls that are referenced in Ajax-requested markup
2344
            element: ( $base.length ? $base : $( "<base>", { href: documentBase.hrefNoHash } ).prependTo( $head ) ),
2344
            element: ( $base.length ? $base : $( "<base>", { href: documentBase.hrefNoHash } ).prependTo( $head ) ),
2345
 
2345
 
2346
            //set the generated BASE element's href attribute to a new page's base path
2346
            //set the generated BASE element's href attribute to a new page's base path
2347
            set: function( href ) {
2347
            set: function( href ) {
2348
                base.element.attr( "href", path.makeUrlAbsolute( href, documentBase ) );
2348
                base.element.attr( "href", path.makeUrlAbsolute( href, documentBase ) );
2349
            },
2349
            },
2350
 
2350
 
2351
            //set the generated BASE element's href attribute to a new page's base path
2351
            //set the generated BASE element's href attribute to a new page's base path
2352
            reset: function() {
2352
            reset: function() {
2353
                base.element.attr( "href", documentBase.hrefNoHash );
2353
                base.element.attr( "href", documentBase.hrefNoHash );
2354
            }
2354
            }
2355
 
2355
 
2356
        } : undefined;
2356
        } : undefined;
2357
 
2357
 
2358
/*
2358
/*
2359
    internal utility functions
2359
    internal utility functions
2360
--------------------------------------*/
2360
--------------------------------------*/
2361
 
2361
 
2362
 
2362
 
2363
    //direct focus to the page title, or otherwise first focusable element
2363
    //direct focus to the page title, or otherwise first focusable element
2364
    function reFocus( page ) {
2364
    function reFocus( page ) {
2365
        var lastClicked = page.jqmData( "lastClicked" );
2365
        var lastClicked = page.jqmData( "lastClicked" );
2366
 
2366
 
2367
        if( lastClicked && lastClicked.length ) {
2367
        if( lastClicked && lastClicked.length ) {
2368
            lastClicked.focus();
2368
            lastClicked.focus();
2369
        }
2369
        }
2370
        else {
2370
        else {
2371
            var pageTitle = page.find( ".ui-title:eq(0)" );
2371
            var pageTitle = page.find( ".ui-title:eq(0)" );
2372
 
2372
 
2373
            if( pageTitle.length ) {
2373
            if( pageTitle.length ) {
2374
                pageTitle.focus();
2374
                pageTitle.focus();
2375
            }
2375
            }
2376
            else{
2376
            else{
2377
                page.find( focusable ).eq( 0 ).focus();
2377
                page.find( focusable ).eq( 0 ).focus();
2378
            }
2378
            }
2379
        }
2379
        }
2380
    }
2380
    }
2381
 
2381
 
2382
    //remove active classes after page transition or error
2382
    //remove active classes after page transition or error
2383
    function removeActiveLinkClass( forceRemoval ) {
2383
    function removeActiveLinkClass( forceRemoval ) {
2384
        if( !!$activeClickedLink && ( !$activeClickedLink.closest( '.ui-page-active' ).length || forceRemoval ) ) {
2384
        if( !!$activeClickedLink && ( !$activeClickedLink.closest( '.ui-page-active' ).length || forceRemoval ) ) {
2385
            $activeClickedLink.removeClass( $.mobile.activeBtnClass );
2385
            $activeClickedLink.removeClass( $.mobile.activeBtnClass );
2386
        }
2386
        }
2387
        $activeClickedLink = null;
2387
        $activeClickedLink = null;
2388
    }
2388
    }
2389
 
2389
 
2390
    function releasePageTransitionLock() {
2390
    function releasePageTransitionLock() {
2391
        isPageTransitioning = false;
2391
        isPageTransitioning = false;
2392
        if( pageTransitionQueue.length > 0 ) {
2392
        if( pageTransitionQueue.length > 0 ) {
2393
            $.mobile.changePage.apply( null, pageTransitionQueue.pop() );
2393
            $.mobile.changePage.apply( null, pageTransitionQueue.pop() );
2394
        }
2394
        }
2395
    }
2395
    }
2396
 
2396
 
2397
    //function for transitioning between two existing pages
2397
    //function for transitioning between two existing pages
2398
    function transitionPages( toPage, fromPage, transition, reverse ) {
2398
    function transitionPages( toPage, fromPage, transition, reverse ) {
2399
       
2399
       
2400
        //get current scroll distance
2400
        //get current scroll distance
2401
        var currScroll = $.support.scrollTop ? $window.scrollTop() : true,
2401
        var currScroll = $.support.scrollTop ? $window.scrollTop() : true,
2402
            toScroll    = toPage.data( "lastScroll" ) || $.mobile.defaultHomeScroll,
2402
            toScroll    = toPage.data( "lastScroll" ) || $.mobile.defaultHomeScroll,
2403
            screenHeight = getScreenHeight();
2403
            screenHeight = getScreenHeight();
2404
       
2404
       
2405
        //if scrolled down, scroll to top
2405
        //if scrolled down, scroll to top
2406
        if( currScroll ){
2406
        if( currScroll ){
2407
            window.scrollTo( 0, $.mobile.defaultHomeScroll );
2407
            window.scrollTo( 0, $.mobile.defaultHomeScroll );
2408
        }
2408
        }
2409
       
2409
       
2410
        //if the Y location we're scrolling to is less than 10px, let it go for sake of smoothness
2410
        //if the Y location we're scrolling to is less than 10px, let it go for sake of smoothness
2411
        if( toScroll < $.mobile.minScrollBack ){
2411
        if( toScroll < $.mobile.minScrollBack ){
2412
            toScroll = 0;
2412
            toScroll = 0;
2413
        }
2413
        }
2414
       
2414
       
2415
        if( fromPage ) {
2415
        if( fromPage ) {
2416
            //set as data for returning to that spot
2416
            //set as data for returning to that spot
2417
            fromPage
2417
            fromPage
2418
                .height( screenHeight + currScroll )
2418
                .height( screenHeight + currScroll )
2419
                .jqmData( "lastScroll", currScroll )
2419
                .jqmData( "lastScroll", currScroll )
2420
                .jqmData( "lastClicked", $activeClickedLink );
2420
                .jqmData( "lastClicked", $activeClickedLink );
2421
               
2421
               
2422
            //trigger before show/hide events
2422
            //trigger before show/hide events
2423
            fromPage.data( "page" )._trigger( "beforehide", null, { nextPage: toPage } );
2423
            fromPage.data( "page" )._trigger( "beforehide", null, { nextPage: toPage } );
2424
        }
2424
        }
2425
        toPage
2425
        toPage
2426
            .height( screenHeight + toScroll )
2426
            .height( screenHeight + toScroll )
2427
            .data( "page" )._trigger( "beforeshow", null, { prevPage: fromPage || $( "" ) } );
2427
            .data( "page" )._trigger( "beforeshow", null, { prevPage: fromPage || $( "" ) } );
2428
 
2428
 
2429
        //clear page loader
2429
        //clear page loader
2430
        $.mobile.hidePageLoadingMsg();
2430
        $.mobile.hidePageLoadingMsg();
2431
 
2431
 
2432
        //find the transition handler for the specified transition. If there
2432
        //find the transition handler for the specified transition. If there
2433
        //isn't one in our transitionHandlers dictionary, use the default one.
2433
        //isn't one in our transitionHandlers dictionary, use the default one.
2434
        //call the handler immediately to kick-off the transition.
2434
        //call the handler immediately to kick-off the transition.
2435
        var th = $.mobile.transitionHandlers[transition || "none"] || $.mobile.defaultTransitionHandler,
2435
        var th = $.mobile.transitionHandlers[transition || "none"] || $.mobile.defaultTransitionHandler,
2436
            promise = th( transition, reverse, toPage, fromPage );
2436
            promise = th( transition, reverse, toPage, fromPage );
2437
 
2437
 
2438
        promise.done(function() {
2438
        promise.done(function() {
2439
            //reset toPage height bac
2439
            //reset toPage height bac
2440
            toPage.height( "" );
2440
            toPage.height( "" );
2441
           
2441
           
2442
            //jump to top or prev scroll, sometimes on iOS the page has not rendered yet.
2442
            //jump to top or prev scroll, sometimes on iOS the page has not rendered yet.
2443
            if( toScroll ){
2443
            if( toScroll ){
2444
                $.mobile.silentScroll( toScroll );
2444
                $.mobile.silentScroll( toScroll );
2445
                $( document ).one( "silentscroll", function() { reFocus( toPage ); } );
2445
                $( document ).one( "silentscroll", function() { reFocus( toPage ); } );
2446
            }
2446
            }
2447
            else{
2447
            else{
2448
                reFocus( toPage );
2448
                reFocus( toPage );
2449
            }
2449
            }
2450
 
2450
 
2451
            //trigger show/hide events
2451
            //trigger show/hide events
2452
            if( fromPage ) {
2452
            if( fromPage ) {
2453
                fromPage.height("").data( "page" )._trigger( "hide", null, { nextPage: toPage } );
2453
                fromPage.height("").data( "page" )._trigger( "hide", null, { nextPage: toPage } );
2454
            }
2454
            }
2455
           
2455
           
2456
            //trigger pageshow, define prevPage as either fromPage or empty jQuery obj
2456
            //trigger pageshow, define prevPage as either fromPage or empty jQuery obj
2457
            toPage.data( "page" )._trigger( "show", null, { prevPage: fromPage || $( "" ) } );
2457
            toPage.data( "page" )._trigger( "show", null, { prevPage: fromPage || $( "" ) } );
2458
        });
2458
        });
2459
 
2459
 
2460
        return promise;
2460
        return promise;
2461
    }
2461
    }
2462
   
2462
   
2463
    //simply set the active page's minimum height to screen height, depending on orientation
2463
    //simply set the active page's minimum height to screen height, depending on orientation
2464
    function getScreenHeight(){
2464
    function getScreenHeight(){
2465
        var orientation     = jQuery.event.special.orientationchange.orientation(),
2465
        var orientation     = jQuery.event.special.orientationchange.orientation(),
2466
            port            = orientation === "portrait",
2466
            port            = orientation === "portrait",
2467
            winMin          = port ? 480 : 320,
2467
            winMin          = port ? 480 : 320,
2468
            screenHeight    = port ? screen.availHeight : screen.availWidth,
2468
            screenHeight    = port ? screen.availHeight : screen.availWidth,
2469
            winHeight       = Math.max( winMin, $( window ).height() ),
2469
            winHeight       = Math.max( winMin, $( window ).height() ),
2470
            pageMin         = Math.min( screenHeight, winHeight );
2470
            pageMin         = Math.min( screenHeight, winHeight );
2471
 
2471
 
2472
        return pageMin;
2472
        return pageMin;
2473
    }
2473
    }
2474
   
2474
   
2475
    //simply set the active page's minimum height to screen height, depending on orientation
2475
    //simply set the active page's minimum height to screen height, depending on orientation
2476
    function resetActivePageHeight(){
2476
    function resetActivePageHeight(){
2477
        $( "." + $.mobile.activePageClass ).css( "min-height", getScreenHeight() );
2477
        $( "." + $.mobile.activePageClass ).css( "min-height", getScreenHeight() );
2478
    }
2478
    }
2479
 
2479
 
2480
    //shared page enhancements
2480
    //shared page enhancements
2481
    function enhancePage( $page, role ) {
2481
    function enhancePage( $page, role ) {
2482
        // If a role was specified, make sure the data-role attribute
2482
        // If a role was specified, make sure the data-role attribute
2483
        // on the page element is in sync.
2483
        // on the page element is in sync.
2484
        if( role ) {
2484
        if( role ) {
2485
            $page.attr( "data-" + $.mobile.ns + "role", role );
2485
            $page.attr( "data-" + $.mobile.ns + "role", role );
2486
        }
2486
        }
2487
 
2487
 
2488
        //run page plugin
2488
        //run page plugin
2489
        $page.page();
2489
        $page.page();
2490
    }
2490
    }
2491
 
2491
 
2492
/* exposed $.mobile methods  */
2492
/* exposed $.mobile methods  */
2493
 
2493
 
2494
    //animation complete callback
2494
    //animation complete callback
2495
    $.fn.animationComplete = function( callback ) {
2495
    $.fn.animationComplete = function( callback ) {
2496
        if( $.support.cssTransitions ) {
2496
        if( $.support.cssTransitions ) {
2497
            return $( this ).one( 'webkitAnimationEnd', callback );
2497
            return $( this ).one( 'webkitAnimationEnd', callback );
2498
        }
2498
        }
2499
        else{
2499
        else{
2500
            // defer execution for consistency between webkit/non webkit
2500
            // defer execution for consistency between webkit/non webkit
2501
            setTimeout( callback, 0 );
2501
            setTimeout( callback, 0 );
2502
            return $( this );
2502
            return $( this );
2503
        }
2503
        }
2504
    };
2504
    };
2505
 
2505
 
2506
    //update location.hash, with or without triggering hashchange event
2506
    //update location.hash, with or without triggering hashchange event
2507
    //TODO - deprecate this one at 1.0
2507
    //TODO - deprecate this one at 1.0
2508
    $.mobile.updateHash = path.set;
2508
    $.mobile.updateHash = path.set;
2509
 
2509
 
2510
    //expose path object on $.mobile
2510
    //expose path object on $.mobile
2511
    $.mobile.path = path;
2511
    $.mobile.path = path;
2512
 
2512
 
2513
    //expose base object on $.mobile
2513
    //expose base object on $.mobile
2514
    $.mobile.base = base;
2514
    $.mobile.base = base;
2515
 
2515
 
2516
    //url stack, useful when plugins need to be aware of previous pages viewed
2516
    //url stack, useful when plugins need to be aware of previous pages viewed
2517
    //TODO: deprecate this one at 1.0
2517
    //TODO: deprecate this one at 1.0
2518
    $.mobile.urlstack = urlHistory.stack;
2518
    $.mobile.urlstack = urlHistory.stack;
2519
 
2519
 
2520
    //history stack
2520
    //history stack
2521
    $.mobile.urlHistory = urlHistory;
2521
    $.mobile.urlHistory = urlHistory;
2522
 
2522
 
2523
    //default non-animation transition handler
2523
    //default non-animation transition handler
2524
    $.mobile.noneTransitionHandler = function( name, reverse, $toPage, $fromPage ) {
2524
    $.mobile.noneTransitionHandler = function( name, reverse, $toPage, $fromPage ) {
2525
        if ( $fromPage ) {
2525
        if ( $fromPage ) {
2526
            $fromPage.removeClass( $.mobile.activePageClass );
2526
            $fromPage.removeClass( $.mobile.activePageClass );
2527
        }
2527
        }
2528
        $toPage.addClass( $.mobile.activePageClass );
2528
        $toPage.addClass( $.mobile.activePageClass );
2529
 
2529
 
2530
        return $.Deferred().resolve( name, reverse, $toPage, $fromPage ).promise();
2530
        return $.Deferred().resolve( name, reverse, $toPage, $fromPage ).promise();
2531
    };
2531
    };
2532
 
2532
 
2533
    //default handler for unknown transitions
2533
    //default handler for unknown transitions
2534
    $.mobile.defaultTransitionHandler = $.mobile.noneTransitionHandler;
2534
    $.mobile.defaultTransitionHandler = $.mobile.noneTransitionHandler;
2535
 
2535
 
2536
    //transition handler dictionary for 3rd party transitions
2536
    //transition handler dictionary for 3rd party transitions
2537
    $.mobile.transitionHandlers = {
2537
    $.mobile.transitionHandlers = {
2538
        none: $.mobile.defaultTransitionHandler
2538
        none: $.mobile.defaultTransitionHandler
2539
    };
2539
    };
2540
 
2540
 
2541
    //enable cross-domain page support
2541
    //enable cross-domain page support
2542
    $.mobile.allowCrossDomainPages = false;
2542
    $.mobile.allowCrossDomainPages = false;
2543
 
2543
 
2544
    //return the original document url
2544
    //return the original document url
2545
    $.mobile.getDocumentUrl = function(asParsedObject) {
2545
    $.mobile.getDocumentUrl = function(asParsedObject) {
2546
        return asParsedObject ? $.extend( {}, documentUrl ) : documentUrl.href;
2546
        return asParsedObject ? $.extend( {}, documentUrl ) : documentUrl.href;
2547
    };
2547
    };
2548
 
2548
 
2549
    //return the original document base url
2549
    //return the original document base url
2550
    $.mobile.getDocumentBase = function(asParsedObject) {
2550
    $.mobile.getDocumentBase = function(asParsedObject) {
2551
        return asParsedObject ? $.extend( {}, documentBase ) : documentBase.href;
2551
        return asParsedObject ? $.extend( {}, documentBase ) : documentBase.href;
2552
    };
2552
    };
2553
 
2553
 
2554
    // Load a page into the DOM.
2554
    // Load a page into the DOM.
2555
    $.mobile.loadPage = function( url, options ) {
2555
    $.mobile.loadPage = function( url, options ) {
2556
        // This function uses deferred notifications to let callers
2556
        // This function uses deferred notifications to let callers
2557
        // know when the page is done loading, or if an error has occurred.
2557
        // know when the page is done loading, or if an error has occurred.
2558
        var deferred = $.Deferred(),
2558
        var deferred = $.Deferred(),
2559
 
2559
 
2560
            // The default loadPage options with overrides specified by
2560
            // The default loadPage options with overrides specified by
2561
            // the caller.
2561
            // the caller.
2562
            settings = $.extend( {}, $.mobile.loadPage.defaults, options ),
2562
            settings = $.extend( {}, $.mobile.loadPage.defaults, options ),
2563
 
2563
 
2564
            // The DOM element for the page after it has been loaded.
2564
            // The DOM element for the page after it has been loaded.
2565
            page = null,
2565
            page = null,
2566
 
2566
 
2567
            // If the reloadPage option is true, and the page is already
2567
            // If the reloadPage option is true, and the page is already
2568
            // in the DOM, dupCachedPage will be set to the page element
2568
            // in the DOM, dupCachedPage will be set to the page element
2569
            // so that it can be removed after the new version of the
2569
            // so that it can be removed after the new version of the
2570
            // page is loaded off the network.
2570
            // page is loaded off the network.
2571
            dupCachedPage = null,
2571
            dupCachedPage = null,
2572
 
2572
 
2573
            // The absolute version of the URL passed into the function. This
2573
            // The absolute version of the URL passed into the function. This
2574
            // version of the URL may contain dialog/subpage params in it.
2574
            // version of the URL may contain dialog/subpage params in it.
2575
            absUrl = path.makeUrlAbsolute( url, documentBase.hrefNoHash );
2575
            absUrl = path.makeUrlAbsolute( url, documentBase.hrefNoHash );
2576
 
2576
 
2577
 
2577
 
2578
        // If the caller provided data, and we're using "get" request,
2578
        // If the caller provided data, and we're using "get" request,
2579
        // append the data to the URL.
2579
        // append the data to the URL.
2580
        if ( settings.data && settings.type === "get" ) {
2580
        if ( settings.data && settings.type === "get" ) {
2581
            absUrl = path.addSearchParams( absUrl, settings.data );
2581
            absUrl = path.addSearchParams( absUrl, settings.data );
2582
            settings.data = undefined;
2582
            settings.data = undefined;
2583
        }
2583
        }
2584
 
2584
 
2585
            // The absolute version of the URL minus any dialog/subpage params.
2585
            // The absolute version of the URL minus any dialog/subpage params.
2586
            // In otherwords the real URL of the page to be loaded.
2586
            // In otherwords the real URL of the page to be loaded.
2587
        var fileUrl = path.getFilePath( absUrl ),
2587
        var fileUrl = path.getFilePath( absUrl ),
2588
 
2588
 
2589
            // The version of the Url actually stored in the data-url attribute of
2589
            // The version of the Url actually stored in the data-url attribute of
2590
            // the page. For embedded pages, it is just the id of the page. For pages
2590
            // the page. For embedded pages, it is just the id of the page. For pages
2591
            // within the same domain as the document base, it is the site relative
2591
            // within the same domain as the document base, it is the site relative
2592
            // path. For cross-domain pages (Phone Gap only) the entire absolute Url
2592
            // path. For cross-domain pages (Phone Gap only) the entire absolute Url
2593
            // used to load the page.
2593
            // used to load the page.
2594
            dataUrl = path.convertUrlToDataUrl( absUrl );
2594
            dataUrl = path.convertUrlToDataUrl( absUrl );
2595
 
2595
 
2596
        // Make sure we have a pageContainer to work with.
2596
        // Make sure we have a pageContainer to work with.
2597
        settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
2597
        settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
2598
 
2598
 
2599
        // Check to see if the page already exists in the DOM.
2599
        // Check to see if the page already exists in the DOM.
2600
        page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
2600
        page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
2601
 
2601
 
2602
        // Reset base to the default document base.
2602
        // Reset base to the default document base.
2603
        if ( base ) {
2603
        if ( base ) {
2604
            base.reset();
2604
            base.reset();
2605
        }
2605
        }
2606
 
2606
 
2607
        // If the page we are interested in is already in the DOM,
2607
        // If the page we are interested in is already in the DOM,
2608
        // and the caller did not indicate that we should force a
2608
        // and the caller did not indicate that we should force a
2609
        // reload of the file, we are done. Otherwise, track the
2609
        // reload of the file, we are done. Otherwise, track the
2610
        // existing page as a duplicated.
2610
        // existing page as a duplicated.
2611
        if ( page.length ) {
2611
        if ( page.length ) {
2612
            if ( !settings.reloadPage ) {
2612
            if ( !settings.reloadPage ) {
2613
                enhancePage( page, settings.role );
2613
                enhancePage( page, settings.role );
2614
                deferred.resolve( absUrl, options, page );
2614
                deferred.resolve( absUrl, options, page );
2615
                return deferred.promise();
2615
                return deferred.promise();
2616
            }
2616
            }
2617
            dupCachedPage = page;
2617
            dupCachedPage = page;
2618
        }
2618
        }
2619
 
2619
 
2620
        if ( settings.showLoadMsg ) {
2620
        if ( settings.showLoadMsg ) {
2621
            $.mobile.showPageLoadingMsg();
2621
            $.mobile.showPageLoadingMsg();
2622
        }
2622
        }
2623
 
2623
 
2624
        // Load the new page.
2624
        // Load the new page.
2625
        $.ajax({
2625
        $.ajax({
2626
            url: fileUrl,
2626
            url: fileUrl,
2627
            type: settings.type,
2627
            type: settings.type,
2628
            data: settings.data,
2628
            data: settings.data,
2629
            dataType: "html",
2629
            dataType: "html",
2630
            success: function( html ) {
2630
            success: function( html ) {
2631
                //pre-parse html to check for a data-url,
2631
                //pre-parse html to check for a data-url,
2632
                //use it as the new fileUrl, base path, etc
2632
                //use it as the new fileUrl, base path, etc
2633
                var all = $( "<div></div>" ),
2633
                var all = $( "<div></div>" ),
2634
 
2634
 
2635
                        //page title regexp
2635
                        //page title regexp
2636
                        newPageTitle = html.match( /<title[^>]*>([^<]*)/ ) && RegExp.$1,
2636
                        newPageTitle = html.match( /<title[^>]*>([^<]*)/ ) && RegExp.$1,
2637
 
2637
 
2638
                        // TODO handle dialogs again
2638
                        // TODO handle dialogs again
2639
                        pageElemRegex = new RegExp( ".*(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>).*" ),
2639
                        pageElemRegex = new RegExp( ".*(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>).*" ),
2640
                        dataUrlRegex = new RegExp( "\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?" );
2640
                        dataUrlRegex = new RegExp( "\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?" );
2641
 
2641
 
2642
 
2642
 
2643
                // data-url must be provided for the base tag so resource requests can be directed to the
2643
                // data-url must be provided for the base tag so resource requests can be directed to the
2644
                // correct url. loading into a temprorary element makes these requests immediately
2644
                // correct url. loading into a temprorary element makes these requests immediately
2645
                if( pageElemRegex.test( html )
2645
                if( pageElemRegex.test( html )
2646
                        && RegExp.$1
2646
                        && RegExp.$1
2647
                        && dataUrlRegex.test( RegExp.$1 )
2647
                        && dataUrlRegex.test( RegExp.$1 )
2648
                        && RegExp.$1 ) {
2648
                        && RegExp.$1 ) {
2649
                    url = fileUrl = path.getFilePath( RegExp.$1 );
2649
                    url = fileUrl = path.getFilePath( RegExp.$1 );
2650
                }
2650
                }
2651
 
2651
 
2652
                if ( base ) {
2652
                if ( base ) {
2653
                    base.set( fileUrl );
2653
                    base.set( fileUrl );
2654
                }
2654
                }
2655
 
2655
 
2656
                //workaround to allow scripts to execute when included in page divs
2656
                //workaround to allow scripts to execute when included in page divs
2657
                all.get( 0 ).innerHTML = html;
2657
                all.get( 0 ).innerHTML = html;
2658
                page = all.find( ":jqmData(role='page'), :jqmData(role='dialog')" ).first();
2658
                page = all.find( ":jqmData(role='page'), :jqmData(role='dialog')" ).first();
2659
 
2659
 
2660
                if ( newPageTitle && !page.jqmData( "title" ) ) {
2660
                if ( newPageTitle && !page.jqmData( "title" ) ) {
2661
                    page.jqmData( "title", newPageTitle );
2661
                    page.jqmData( "title", newPageTitle );
2662
                }
2662
                }
2663
 
2663
 
2664
                //rewrite src and href attrs to use a base url
2664
                //rewrite src and href attrs to use a base url
2665
                if( !$.support.dynamicBaseTag ) {
2665
                if( !$.support.dynamicBaseTag ) {
2666
                    var newPath = path.get( fileUrl );
2666
                    var newPath = path.get( fileUrl );
2667
                    page.find( "[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]" ).each(function() {
2667
                    page.find( "[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]" ).each(function() {
2668
                        var thisAttr = $( this ).is( '[href]' ) ? 'href' :
2668
                        var thisAttr = $( this ).is( '[href]' ) ? 'href' :
2669
                                $(this).is('[src]') ? 'src' : 'action',
2669
                                $(this).is('[src]') ? 'src' : 'action',
2670
                            thisUrl = $( this ).attr( thisAttr );
2670
                            thisUrl = $( this ).attr( thisAttr );
2671
 
2671
 
2672
                        // XXX_jblas: We need to fix this so that it removes the document
2672
                        // XXX_jblas: We need to fix this so that it removes the document
2673
                        //            base URL, and then prepends with the new page URL.
2673
                        //            base URL, and then prepends with the new page URL.
2674
                        //if full path exists and is same, chop it - helps IE out
2674
                        //if full path exists and is same, chop it - helps IE out
2675
                        thisUrl = thisUrl.replace( location.protocol + '//' + location.host + location.pathname, '' );
2675
                        thisUrl = thisUrl.replace( location.protocol + '//' + location.host + location.pathname, '' );
2676
 
2676
 
2677
                        if( !/^(\w+:|#|\/)/.test( thisUrl ) ) {
2677
                        if( !/^(\w+:|#|\/)/.test( thisUrl ) ) {
2678
                            $( this ).attr( thisAttr, newPath + thisUrl );
2678
                            $( this ).attr( thisAttr, newPath + thisUrl );
2679
                        }
2679
                        }
2680
                    });
2680
                    });
2681
                }
2681
                }
2682
 
2682
 
2683
                //append to page and enhance
2683
                //append to page and enhance
2684
                page
2684
                page
2685
                    .attr( "data-" + $.mobile.ns + "url", path.convertUrlToDataUrl( fileUrl ) )
2685
                    .attr( "data-" + $.mobile.ns + "url", path.convertUrlToDataUrl( fileUrl ) )
2686
                    .appendTo( settings.pageContainer );
2686
                    .appendTo( settings.pageContainer );
2687
 
2687
 
2688
                enhancePage( page, settings.role );
2688
                enhancePage( page, settings.role );
2689
 
2689
 
2690
                // Enhancing the page may result in new dialogs/sub pages being inserted
2690
                // Enhancing the page may result in new dialogs/sub pages being inserted
2691
                // into the DOM. If the original absUrl refers to a sub-page, that is the
2691
                // into the DOM. If the original absUrl refers to a sub-page, that is the
2692
                // real page we are interested in.
2692
                // real page we are interested in.
2693
                if ( absUrl.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ) {
2693
                if ( absUrl.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ) {
2694
                    page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
2694
                    page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
2695
                }
2695
                }
2696
 
2696
 
2697
                // Remove loading message.
2697
                // Remove loading message.
2698
                if ( settings.showLoadMsg ) {
2698
                if ( settings.showLoadMsg ) {
2699
                    $.mobile.hidePageLoadingMsg();
2699
                    $.mobile.hidePageLoadingMsg();
2700
                }
2700
                }
2701
 
2701
 
2702
                deferred.resolve( absUrl, options, page, dupCachedPage );
2702
                deferred.resolve( absUrl, options, page, dupCachedPage );
2703
            },
2703
            },
2704
            error: function() {
2704
            error: function() {
2705
                //set base back to current path
2705
                //set base back to current path
2706
                if( base ) {
2706
                if( base ) {
2707
                    base.set( path.get() );
2707
                    base.set( path.get() );
2708
                }
2708
                }
2709
 
2709
 
2710
                // Remove loading message.
2710
                // Remove loading message.
2711
                if ( settings.showLoadMsg ) {
2711
                if ( settings.showLoadMsg ) {
2712
                    $.mobile.hidePageLoadingMsg();
2712
                    $.mobile.hidePageLoadingMsg();
2713
 
2713
 
2714
                    //show error message
2714
                    //show error message
2715
                    $( "<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>"+ $.mobile.pageLoadErrorMessage +"</h1></div>" )
2715
                    $( "<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>"+ $.mobile.pageLoadErrorMessage +"</h1></div>" )
2716
                        .css({ "display": "block", "opacity": 0.96, "top": $window.scrollTop() + 100 })
2716
                        .css({ "display": "block", "opacity": 0.96, "top": $window.scrollTop() + 100 })
2717
                        .appendTo( settings.pageContainer )
2717
                        .appendTo( settings.pageContainer )
2718
                        .delay( 800 )
2718
                        .delay( 800 )
2719
                        .fadeOut( 400, function() {
2719
                        .fadeOut( 400, function() {
2720
                            $( this ).remove();
2720
                            $( this ).remove();
2721
                        });
2721
                        });
2722
                }
2722
                }
2723
 
2723
 
2724
                deferred.reject( absUrl, options );
2724
                deferred.reject( absUrl, options );
2725
            }
2725
            }
2726
        });
2726
        });
2727
 
2727
 
2728
        return deferred.promise();
2728
        return deferred.promise();
2729
    };
2729
    };
2730
 
2730
 
2731
    $.mobile.loadPage.defaults = {
2731
    $.mobile.loadPage.defaults = {
2732
        type: "get",
2732
        type: "get",
2733
        data: undefined,
2733
        data: undefined,
2734
        reloadPage: false,
2734
        reloadPage: false,
2735
        role: undefined, // By default we rely on the role defined by the @data-role attribute.
2735
        role: undefined, // By default we rely on the role defined by the @data-role attribute.
2736
        showLoadMsg: true,
2736
        showLoadMsg: true,
2737
        pageContainer: undefined
2737
        pageContainer: undefined
2738
    };
2738
    };
2739
 
2739
 
2740
    // Show a specific page in the page container.
2740
    // Show a specific page in the page container.
2741
    $.mobile.changePage = function( toPage, options ) {
2741
    $.mobile.changePage = function( toPage, options ) {
2742
        // XXX: REMOVE_BEFORE_SHIPPING_1.0
2742
        // XXX: REMOVE_BEFORE_SHIPPING_1.0
2743
        // This is temporary code that makes changePage() compatible with previous alpha versions.
2743
        // This is temporary code that makes changePage() compatible with previous alpha versions.
2744
        if ( typeof options !== "object" ) {
2744
        if ( typeof options !== "object" ) {
2745
            var opts = null;
2745
            var opts = null;
2746
 
2746
 
2747
            // Map old-style call signature for form submit to the new options object format.
2747
            // Map old-style call signature for form submit to the new options object format.
2748
            if ( typeof toPage === "object" && toPage.url && toPage.type ) {
2748
            if ( typeof toPage === "object" && toPage.url && toPage.type ) {
2749
                opts = {
2749
                opts = {
2750
                    type: toPage.type,
2750
                    type: toPage.type,
2751
                    data: toPage.data,
2751
                    data: toPage.data,
2752
                    forcePageLoad: true
2752
                    forcePageLoad: true
2753
                };
2753
                };
2754
                toPage = toPage.url;
2754
                toPage = toPage.url;
2755
            }
2755
            }
2756
 
2756
 
2757
            // The arguments passed into the function need to be re-mapped
2757
            // The arguments passed into the function need to be re-mapped
2758
            // to the new options object format.
2758
            // to the new options object format.
2759
            var len = arguments.length;
2759
            var len = arguments.length;
2760
            if ( len > 1 ) {
2760
            if ( len > 1 ) {
2761
                var argNames = [ "transition", "reverse", "changeHash", "fromHashChange" ], i;
2761
                var argNames = [ "transition", "reverse", "changeHash", "fromHashChange" ], i;
2762
                for ( i = 1; i < len; i++ ) {
2762
                for ( i = 1; i < len; i++ ) {
2763
                    var a = arguments[ i ];
2763
                    var a = arguments[ i ];
2764
                    if ( typeof a !== "undefined" ) {
2764
                    if ( typeof a !== "undefined" ) {
2765
                        opts = opts || {};
2765
                        opts = opts || {};
2766
                        opts[ argNames[ i - 1 ] ] = a;
2766
                        opts[ argNames[ i - 1 ] ] = a;
2767
                    }
2767
                    }
2768
                }
2768
                }
2769
            }
2769
            }
2770
 
2770
 
2771
            // If an options object was created, then we know changePage() was called
2771
            // If an options object was created, then we know changePage() was called
2772
            // with an old signature.
2772
            // with an old signature.
2773
            if ( opts ) {
2773
            if ( opts ) {
2774
                return $.mobile.changePage( toPage, opts );
2774
                return $.mobile.changePage( toPage, opts );
2775
            }
2775
            }
2776
        }
2776
        }
2777
        // XXX: REMOVE_BEFORE_SHIPPING_1.0
2777
        // XXX: REMOVE_BEFORE_SHIPPING_1.0
2778
 
2778
 
2779
        // If we are in the midst of a transition, queue the current request.
2779
        // If we are in the midst of a transition, queue the current request.
2780
        // We'll call changePage() once we're done with the current transition to
2780
        // We'll call changePage() once we're done with the current transition to
2781
        // service the request.
2781
        // service the request.
2782
        if( isPageTransitioning ) {
2782
        if( isPageTransitioning ) {
2783
            pageTransitionQueue.unshift( arguments );
2783
            pageTransitionQueue.unshift( arguments );
2784
            return;
2784
            return;
2785
        }
2785
        }
2786
 
2786
 
2787
        // Set the isPageTransitioning flag to prevent any requests from
2787
        // Set the isPageTransitioning flag to prevent any requests from
2788
        // entering this method while we are in the midst of loading a page
2788
        // entering this method while we are in the midst of loading a page
2789
        // or transitioning.
2789
        // or transitioning.
2790
 
2790
 
2791
        isPageTransitioning = true;
2791
        isPageTransitioning = true;
2792
 
2792
 
2793
        var settings = $.extend( {}, $.mobile.changePage.defaults, options );
2793
        var settings = $.extend( {}, $.mobile.changePage.defaults, options );
2794
 
2794
 
2795
        // Make sure we have a pageContainer to work with.
2795
        // Make sure we have a pageContainer to work with.
2796
        settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
2796
        settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
2797
 
2797
 
2798
        // If the caller passed us a url, call loadPage()
2798
        // If the caller passed us a url, call loadPage()
2799
        // to make sure it is loaded into the DOM. We'll listen
2799
        // to make sure it is loaded into the DOM. We'll listen
2800
        // to the promise object it returns so we know when
2800
        // to the promise object it returns so we know when
2801
        // it is done loading or if an error ocurred.
2801
        // it is done loading or if an error ocurred.
2802
        if ( typeof toPage == "string" ) {
2802
        if ( typeof toPage == "string" ) {
2803
            $.mobile.loadPage( toPage, settings )
2803
            $.mobile.loadPage( toPage, settings )
2804
                .done(function( url, options, newPage, dupCachedPage ) {
2804
                .done(function( url, options, newPage, dupCachedPage ) {
2805
                    isPageTransitioning = false;
2805
                    isPageTransitioning = false;
2806
                    options.duplicateCachedPage = dupCachedPage;
2806
                    options.duplicateCachedPage = dupCachedPage;
2807
                    $.mobile.changePage( newPage, options );
2807
                    $.mobile.changePage( newPage, options );
2808
                })
2808
                })
2809
                .fail(function( url, options ) {
2809
                .fail(function( url, options ) {
2810
                    // XXX_jblas: Fire off changepagefailed notificaiton.
2810
                    // XXX_jblas: Fire off changepagefailed notificaiton.
2811
                    isPageTransitioning = false;
2811
                    isPageTransitioning = false;
2812
 
2812
 
2813
                    //clear out the active button state
2813
                    //clear out the active button state
2814
                    removeActiveLinkClass( true );
2814
                    removeActiveLinkClass( true );
2815
 
2815
 
2816
                    //release transition lock so navigation is free again
2816
                    //release transition lock so navigation is free again
2817
                    releasePageTransitionLock();
2817
                    releasePageTransitionLock();
2818
                    settings.pageContainer.trigger("changepagefailed");
2818
                    settings.pageContainer.trigger("changepagefailed");
2819
                });
2819
                });
2820
            return;
2820
            return;
2821
        }
2821
        }
2822
 
2822
 
2823
        // The caller passed us a real page DOM element. Update our
2823
        // The caller passed us a real page DOM element. Update our
2824
        // internal state and then trigger a transition to the page.
2824
        // internal state and then trigger a transition to the page.
2825
        var mpc = settings.pageContainer,
2825
        var mpc = settings.pageContainer,
2826
            fromPage = $.mobile.activePage,
2826
            fromPage = $.mobile.activePage,
2827
            url = toPage.jqmData( "url" ),
2827
            url = toPage.jqmData( "url" ),
2828
            fileUrl = path.getFilePath( url ),
2828
            fileUrl = path.getFilePath( url ),
2829
            active = urlHistory.getActive(),
2829
            active = urlHistory.getActive(),
2830
            activeIsInitialPage = urlHistory.activeIndex === 0,
2830
            activeIsInitialPage = urlHistory.activeIndex === 0,
2831
            historyDir = 0,
2831
            historyDir = 0,
2832
            pageTitle = document.title,
2832
            pageTitle = document.title,
2833
            isDialog = settings.role === "dialog" || toPage.jqmData( "role" ) === "dialog";
2833
            isDialog = settings.role === "dialog" || toPage.jqmData( "role" ) === "dialog";
2834
 
2834
 
2835
        // Let listeners know we're about to change the current page.
2835
        // Let listeners know we're about to change the current page.
2836
        mpc.trigger( "beforechangepage" );
2836
        mpc.trigger( "beforechangepage" );
2837
 
2837
 
2838
        // If we are trying to transition to the same page that we are currently on ignore the request.
2838
        // If we are trying to transition to the same page that we are currently on ignore the request.
2839
        // an illegal same page request is defined by the current page being the same as the url, as long as there's history
2839
        // an illegal same page request is defined by the current page being the same as the url, as long as there's history
2840
        // and toPage is not an array or object (those are allowed to be "same")
2840
        // and toPage is not an array or object (those are allowed to be "same")
2841
        //
2841
        //
2842
        // XXX_jblas: We need to remove this at some point when we allow for transitions
2842
        // XXX_jblas: We need to remove this at some point when we allow for transitions
2843
        //            to the same page.
2843
        //            to the same page.
2844
        if( fromPage && fromPage[0] === toPage[0] ) {
2844
        if( fromPage && fromPage[0] === toPage[0] ) {
2845
            isPageTransitioning = false;
2845
            isPageTransitioning = false;
2846
            mpc.trigger( "changepage" );
2846
            mpc.trigger( "changepage" );
2847
            return;
2847
            return;
2848
        }
2848
        }
2849
 
2849
 
2850
        // We need to make sure the page we are given has already been enhanced.
2850
        // We need to make sure the page we are given has already been enhanced.
2851
        enhancePage( toPage, settings.role );
2851
        enhancePage( toPage, settings.role );
2852
 
2852
 
2853
        // If the changePage request was sent from a hashChange event, check to see if the
2853
        // If the changePage request was sent from a hashChange event, check to see if the
2854
        // page is already within the urlHistory stack. If so, we'll assume the user hit
2854
        // page is already within the urlHistory stack. If so, we'll assume the user hit
2855
        // the forward/back button and will try to match the transition accordingly.
2855
        // the forward/back button and will try to match the transition accordingly.
2856
        if( settings.fromHashChange ) {
2856
        if( settings.fromHashChange ) {
2857
            urlHistory.directHashChange({
2857
            urlHistory.directHashChange({
2858
                currentUrl: url,
2858
                currentUrl: url,
2859
                isBack:     function() { historyDir = -1; },
2859
                isBack:     function() { historyDir = -1; },
2860
                isForward:  function() { historyDir = 1; }
2860
                isForward:  function() { historyDir = 1; }
2861
            });
2861
            });
2862
        }
2862
        }
2863
 
2863
 
2864
        // Kill the keyboard.
2864
        // Kill the keyboard.
2865
        // XXX_jblas: We need to stop crawling the entire document to kill focus. Instead,
2865
        // XXX_jblas: We need to stop crawling the entire document to kill focus. Instead,
2866
        //            we should be tracking focus with a live() handler so we already have
2866
        //            we should be tracking focus with a live() handler so we already have
2867
        //            the element in hand at this point.
2867
        //            the element in hand at this point.
2868
        $( document.activeElement || "" ).add( "input:focus, textarea:focus, select:focus" ).blur();
2868
        $( document.activeElement || "" ).add( "input:focus, textarea:focus, select:focus" ).blur();
2869
 
2869
 
2870
        // If we're displaying the page as a dialog, we don't want the url
2870
        // If we're displaying the page as a dialog, we don't want the url
2871
        // for the dialog content to be used in the hash. Instead, we want
2871
        // for the dialog content to be used in the hash. Instead, we want
2872
        // to append the dialogHashKey to the url of the current page.
2872
        // to append the dialogHashKey to the url of the current page.
2873
        if ( isDialog && active ) {
2873
        if ( isDialog && active ) {
2874
            url = active.url + dialogHashKey;
2874
            url = active.url + dialogHashKey;
2875
        }
2875
        }
2876
 
2876
 
2877
        // Set the location hash.
2877
        // Set the location hash.
2878
        if( settings.changeHash !== false && url ) {
2878
        if( settings.changeHash !== false && url ) {
2879
            //disable hash listening temporarily
2879
            //disable hash listening temporarily
2880
            urlHistory.ignoreNextHashChange = true;
2880
            urlHistory.ignoreNextHashChange = true;
2881
            //update hash and history
2881
            //update hash and history
2882
            path.set( url );
2882
            path.set( url );
2883
        }
2883
        }
2884
 
2884
 
2885
        //if title element wasn't found, try the page div data attr too
2885
        //if title element wasn't found, try the page div data attr too
2886
        var newPageTitle = toPage.jqmData( "title" ) || toPage.children(":jqmData(role='header')").find(".ui-title" ).text();
2886
        var newPageTitle = toPage.jqmData( "title" ) || toPage.children(":jqmData(role='header')").find(".ui-title" ).text();
2887
        if( !!newPageTitle && pageTitle == document.title ) {
2887
        if( !!newPageTitle && pageTitle == document.title ) {
2888
            pageTitle = newPageTitle;
2888
            pageTitle = newPageTitle;
2889
        }
2889
        }
2890
 
2890
 
2891
        //add page to history stack if it's not back or forward
2891
        //add page to history stack if it's not back or forward
2892
        if( !historyDir ) {
2892
        if( !historyDir ) {
2893
            urlHistory.addNew( url, settings.transition, pageTitle, toPage );
2893
            urlHistory.addNew( url, settings.transition, pageTitle, toPage );
2894
        }
2894
        }
2895
 
2895
 
2896
        //set page title
2896
        //set page title
2897
        document.title = urlHistory.getActive().title;
2897
        document.title = urlHistory.getActive().title;
2898
 
2898
 
2899
        //set "toPage" as activePage
2899
        //set "toPage" as activePage
2900
        $.mobile.activePage = toPage;
2900
        $.mobile.activePage = toPage;
2901
 
2901
 
2902
        // Make sure we have a transition defined.
2902
        // Make sure we have a transition defined.
2903
        settings.transition = settings.transition
2903
        settings.transition = settings.transition
2904
            || ( ( historyDir && !activeIsInitialPage ) ? active.transition : undefined )
2904
            || ( ( historyDir && !activeIsInitialPage ) ? active.transition : undefined )
2905
            || ( settings.role === "dialog" ? $.mobile.defaultDialogTransition : $.mobile.defaultPageTransition );
2905
            || ( settings.role === "dialog" ? $.mobile.defaultDialogTransition : $.mobile.defaultPageTransition );
2906
 
2906
 
2907
        // If we're navigating back in the URL history, set reverse accordingly.
2907
        // If we're navigating back in the URL history, set reverse accordingly.
2908
        settings.reverse = settings.reverse || historyDir < 0;
2908
        settings.reverse = settings.reverse || historyDir < 0;
2909
 
2909
 
2910
        transitionPages( toPage, fromPage, settings.transition, settings.reverse )
2910
        transitionPages( toPage, fromPage, settings.transition, settings.reverse )
2911
            .done(function() {
2911
            .done(function() {
2912
                removeActiveLinkClass();
2912
                removeActiveLinkClass();
2913
   
2913
   
2914
                //if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
2914
                //if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
2915
                if ( settings.duplicateCachedPage ) {
2915
                if ( settings.duplicateCachedPage ) {
2916
                    settings.duplicateCachedPage.remove();
2916
                    settings.duplicateCachedPage.remove();
2917
                }
2917
                }
2918
   
2918
   
2919
                //remove initial build class (only present on first pageshow)
2919
                //remove initial build class (only present on first pageshow)
2920
                $html.removeClass( "ui-mobile-rendering" );
2920
                $html.removeClass( "ui-mobile-rendering" );
2921
   
2921
   
2922
                releasePageTransitionLock();
2922
                releasePageTransitionLock();
2923
   
2923
   
2924
                // Let listeners know we're all done changing the current page.
2924
                // Let listeners know we're all done changing the current page.
2925
                mpc.trigger( "changepage" );
2925
                mpc.trigger( "changepage" );
2926
            });
2926
            });
2927
    };
2927
    };
2928
 
2928
 
2929
    $.mobile.changePage.defaults = {
2929
    $.mobile.changePage.defaults = {
2930
        transition: undefined,
2930
        transition: undefined,
2931
        reverse: false,
2931
        reverse: false,
2932
        changeHash: true,
2932
        changeHash: true,
2933
        fromHashChange: false,
2933
        fromHashChange: false,
2934
        role: undefined, // By default we rely on the role defined by the @data-role attribute.
2934
        role: undefined, // By default we rely on the role defined by the @data-role attribute.
2935
        duplicateCachedPage: undefined,
2935
        duplicateCachedPage: undefined,
2936
        pageContainer: undefined
2936
        pageContainer: undefined
2937
    };
2937
    };
2938
 
2938
 
2939
/* Event Bindings - hashchange, submit, and click */
2939
/* Event Bindings - hashchange, submit, and click */
2940
 
2940
 
2941
    //bind to form submit events, handle with Ajax
2941
    //bind to form submit events, handle with Ajax
2942
    $( "form" ).live('submit', function( event ) {
2942
    $( "form" ).live('submit', function( event ) {
2943
        var $this = $( this );
2943
        var $this = $( this );
2944
        if( !$.mobile.ajaxEnabled ||
2944
        if( !$.mobile.ajaxEnabled ||
2945
            $this.is( ":jqmData(ajax='false')" ) ) {
2945
            $this.is( ":jqmData(ajax='false')" ) ) {
2946
                return;
2946
                return;
2947
            }
2947
            }
2948
 
2948
 
2949
        var type = $this.attr( "method" ),
2949
        var type = $this.attr( "method" ),
2950
            url = path.makeUrlAbsolute( $this.attr( "action" ), getClosestBaseUrl($this) ),
2950
            url = path.makeUrlAbsolute( $this.attr( "action" ), getClosestBaseUrl($this) ),
2951
            target = $this.attr( "target" );
2951
            target = $this.attr( "target" );
2952
 
2952
 
2953
        //external submits use regular HTTP
2953
        //external submits use regular HTTP
2954
        if( path.isExternal( url ) || target ) {
2954
        if( path.isExternal( url ) || target ) {
2955
            return;
2955
            return;
2956
        }
2956
        }
2957
 
2957
 
2958
        $.mobile.changePage(
2958
        $.mobile.changePage(
2959
            url,
2959
            url,
2960
            {
2960
            {
2961
                type:       type.length && type.toLowerCase() || "get",
2961
                type:       type.length && type.toLowerCase() || "get",
2962
                data:       $this.serialize(),
2962
                data:       $this.serialize(),
2963
                transition: $this.jqmData( "transition" ),
2963
                transition: $this.jqmData( "transition" ),
2964
                direction:  $this.jqmData( "direction" ),
2964
                direction:  $this.jqmData( "direction" ),
2965
                reloadPage: true
2965
                reloadPage: true
2966
            }
2966
            }
2967
        );
2967
        );
2968
        event.preventDefault();
2968
        event.preventDefault();
2969
    });
2969
    });
2970
 
2970
 
2971
    function findClosestLink( ele )
2971
    function findClosestLink( ele )
2972
    {
2972
    {
2973
        while ( ele ) {
2973
        while ( ele ) {
2974
            if ( ele.nodeName.toLowerCase() == "a" ) {
2974
            if ( ele.nodeName.toLowerCase() == "a" ) {
2975
                break;
2975
                break;
2976
            }
2976
            }
2977
            ele = ele.parentNode;
2977
            ele = ele.parentNode;
2978
        }
2978
        }
2979
        return ele;
2979
        return ele;
2980
    }
2980
    }
2981
 
2981
 
2982
    // The base URL for any given element depends on the page it resides in.
2982
    // The base URL for any given element depends on the page it resides in.
2983
    function getClosestBaseUrl( ele )
2983
    function getClosestBaseUrl( ele )
2984
    {
2984
    {
2985
        // Find the closest page and extract out its url.
2985
        // Find the closest page and extract out its url.
2986
        var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ),
2986
        var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ),
2987
            base = documentBase.hrefNoHash;
2987
            base = documentBase.hrefNoHash;
2988
 
2988
 
2989
        if ( !url || !path.isPath( url ) ) {
2989
        if ( !url || !path.isPath( url ) ) {
2990
            url = base;
2990
            url = base;
2991
        }
2991
        }
2992
 
2992
 
2993
        return path.makeUrlAbsolute( url, base);
2993
        return path.makeUrlAbsolute( url, base);
2994
    }
2994
    }
2995
 
2995
 
2996
    //add active state on vclick
2996
    //add active state on vclick
2997
    $( document ).bind( "vclick", function( event ) {
2997
    $( document ).bind( "vclick", function( event ) {
2998
        var link = findClosestLink( event.target );
2998
        var link = findClosestLink( event.target );
2999
        if ( link ) {
2999
        if ( link ) {
3000
            if ( path.parseUrl( link.getAttribute( "href" ) || "#" ).hash !== "#" ) {
3000
            if ( path.parseUrl( link.getAttribute( "href" ) || "#" ).hash !== "#" ) {
3001
                $( link ).closest( ".ui-btn" ).not( ".ui-disabled" ).addClass( $.mobile.activeBtnClass );
3001
                $( link ).closest( ".ui-btn" ).not( ".ui-disabled" ).addClass( $.mobile.activeBtnClass );
3002
                $( "." + $.mobile.activePageClass + " .ui-btn" ).not( link ).blur();
3002
                $( "." + $.mobile.activePageClass + " .ui-btn" ).not( link ).blur();
3003
            }
3003
            }
3004
        }
3004
        }
3005
    });
3005
    });
3006
 
3006
 
3007
    // click routing - direct to HTTP or Ajax, accordingly
3007
    // click routing - direct to HTTP or Ajax, accordingly
3008
    // TODO: most of the time, vclick will be all we need for fastClick bulletproofing.
3008
    // TODO: most of the time, vclick will be all we need for fastClick bulletproofing.
3009
    // However, it seems that in Android 2.1, a click event
3009
    // However, it seems that in Android 2.1, a click event
3010
    // will occasionally arrive independently of the bound vclick
3010
    // will occasionally arrive independently of the bound vclick
3011
    // binding to click as well seems to help in this edge case
3011
    // binding to click as well seems to help in this edge case
3012
    // we'll dig into this further in the next release cycle
3012
    // we'll dig into this further in the next release cycle
3013
    $( document ).bind( $.mobile.useFastClick ? "vclick click" : "click", function( event ) {
3013
    $( document ).bind( $.mobile.useFastClick ? "vclick click" : "click", function( event ) {
3014
        var link = findClosestLink( event.target );
3014
        var link = findClosestLink( event.target );
3015
        if ( !link ) {
3015
        if ( !link ) {
3016
            return;
3016
            return;
3017
        }
3017
        }
3018
 
3018
 
3019
        var $link = $( link ),
3019
        var $link = $( link ),
3020
            //remove active link class if external (then it won't be there if you come back)
3020
            //remove active link class if external (then it won't be there if you come back)
3021
            httpCleanup = function(){
3021
            httpCleanup = function(){
3022
                window.setTimeout( function() { removeActiveLinkClass( true ); }, 200 );
3022
                window.setTimeout( function() { removeActiveLinkClass( true ); }, 200 );
3023
            };
3023
            };
3024
 
3024
 
3025
        //if there's a data-rel=back attr, go back in history
3025
        //if there's a data-rel=back attr, go back in history
3026
        if( $link.is( ":jqmData(rel='back')" ) ) {
3026
        if( $link.is( ":jqmData(rel='back')" ) ) {
3027
            window.history.back();
3027
            window.history.back();
3028
            return false;
3028
            return false;
3029
        }
3029
        }
3030
       
3030
       
3031
        //if ajax is disabled, exit early
3031
        //if ajax is disabled, exit early
3032
        if( !$.mobile.ajaxEnabled ){
3032
        if( !$.mobile.ajaxEnabled ){
3033
            httpCleanup();
3033
            httpCleanup();
3034
            //use default click handling
3034
            //use default click handling
3035
            return;
3035
            return;
3036
        }
3036
        }
3037
       
3037
       
3038
        var baseUrl = getClosestBaseUrl( $link ),
3038
        var baseUrl = getClosestBaseUrl( $link ),
3039
 
3039
 
3040
            //get href, if defined, otherwise default to empty hash
3040
            //get href, if defined, otherwise default to empty hash
3041
            href = path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl );
3041
            href = path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl );
3042
 
3042
 
3043
        // XXX_jblas: Ideally links to application pages should be specified as
3043
        // XXX_jblas: Ideally links to application pages should be specified as
3044
        //            an url to the application document with a hash that is either
3044
        //            an url to the application document with a hash that is either
3045
        //            the site relative path or id to the page. But some of the
3045
        //            the site relative path or id to the page. But some of the
3046
        //            internal code that dynamically generates sub-pages for nested
3046
        //            internal code that dynamically generates sub-pages for nested
3047
        //            lists and select dialogs, just write a hash in the link they
3047
        //            lists and select dialogs, just write a hash in the link they
3048
        //            create. This means the actual URL path is based on whatever
3048
        //            create. This means the actual URL path is based on whatever
3049
        //            the current value of the base tag is at the time this code
3049
        //            the current value of the base tag is at the time this code
3050
        //            is called. For now we are just assuming that any url with a
3050
        //            is called. For now we are just assuming that any url with a
3051
        //            hash in it is an application page reference.
3051
        //            hash in it is an application page reference.
3052
        if ( href.search( "#" ) != -1 ) {
3052
        if ( href.search( "#" ) != -1 ) {
3053
            href = href.replace( /[^#]*#/, "" );
3053
            href = href.replace( /[^#]*#/, "" );
3054
            if ( !href ) {
3054
            if ( !href ) {
3055
                //link was an empty hash meant purely
3055
                //link was an empty hash meant purely
3056
                //for interaction, so we ignore it.
3056
                //for interaction, so we ignore it.
3057
                event.preventDefault();
3057
                event.preventDefault();
3058
                return;
3058
                return;
3059
            } else if ( path.isPath( href ) ) {
3059
            } else if ( path.isPath( href ) ) {
3060
                //we have apath so make it the href we want to load.
3060
                //we have apath so make it the href we want to load.
3061
                href = path.makeUrlAbsolute( href, baseUrl );
3061
                href = path.makeUrlAbsolute( href, baseUrl );
3062
            } else {
3062
            } else {
3063
                //we have a simple id so use the documentUrl as its base.
3063
                //we have a simple id so use the documentUrl as its base.
3064
                href = path.makeUrlAbsolute( "#" + href, documentUrl.hrefNoHash );
3064
                href = path.makeUrlAbsolute( "#" + href, documentUrl.hrefNoHash );
3065
            }
3065
            }
3066
        }
3066
        }
3067
 
3067
 
3068
            // Should we handle this link, or let the browser deal with it?
3068
            // Should we handle this link, or let the browser deal with it?
3069
        var useDefaultUrlHandling = $link.is( "[rel='external']" ) || $link.is( ":jqmData(ajax='false')" ) || $link.is( "[target]" ),
3069
        var useDefaultUrlHandling = $link.is( "[rel='external']" ) || $link.is( ":jqmData(ajax='false')" ) || $link.is( "[target]" ),
3070
 
3070
 
3071
            // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
3071
            // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
3072
            // requests if the document doing the request was loaded via the file:// protocol.
3072
            // requests if the document doing the request was loaded via the file:// protocol.
3073
            // This is usually to allow the application to "phone home" and fetch app specific
3073
            // This is usually to allow the application to "phone home" and fetch app specific
3074
            // data. We normally let the browser handle external/cross-domain urls, but if the
3074
            // data. We normally let the browser handle external/cross-domain urls, but if the
3075
            // allowCrossDomainPages option is true, we will allow cross-domain http/https
3075
            // allowCrossDomainPages option is true, we will allow cross-domain http/https
3076
            // requests to go through our page loading logic.
3076
            // requests to go through our page loading logic.
3077
            isCrossDomainPageLoad = ( $.mobile.allowCrossDomainPages && documentUrl.protocol === "file:" && href.search( /^https?:/ ) != -1 ),
3077
            isCrossDomainPageLoad = ( $.mobile.allowCrossDomainPages && documentUrl.protocol === "file:" && href.search( /^https?:/ ) != -1 ),
3078
 
3078
 
3079
            //check for protocol or rel and its not an embedded page
3079
            //check for protocol or rel and its not an embedded page
3080
            //TODO overlap in logic from isExternal, rel=external check should be
3080
            //TODO overlap in logic from isExternal, rel=external check should be
3081
            //     moved into more comprehensive isExternalLink
3081
            //     moved into more comprehensive isExternalLink
3082
            isExternal = useDefaultUrlHandling || ( path.isExternal( href ) && !isCrossDomainPageLoad );
3082
            isExternal = useDefaultUrlHandling || ( path.isExternal( href ) && !isCrossDomainPageLoad );
3083
 
3083
 
3084
        $activeClickedLink = $link.closest( ".ui-btn" );
3084
        $activeClickedLink = $link.closest( ".ui-btn" );
3085
 
3085
 
3086
        if( isExternal ) {
3086
        if( isExternal ) {
3087
            httpCleanup();
3087
            httpCleanup();
3088
            //use default click handling
3088
            //use default click handling
3089
            return;
3089
            return;
3090
        }
3090
        }
3091
 
3091
 
3092
        //use ajax
3092
        //use ajax
3093
        var transition = $link.jqmData( "transition" ),
3093
        var transition = $link.jqmData( "transition" ),
3094
            direction = $link.jqmData( "direction" ),
3094
            direction = $link.jqmData( "direction" ),
3095
            reverse = ( direction && direction === "reverse" ) ||
3095
            reverse = ( direction && direction === "reverse" ) ||
3096
                        // deprecated - remove by 1.0
3096
                        // deprecated - remove by 1.0
3097
                        $link.jqmData( "back" ),
3097
                        $link.jqmData( "back" ),
3098
 
3098
 
3099
            //this may need to be more specific as we use data-rel more
3099
            //this may need to be more specific as we use data-rel more
3100
            role = $link.attr( "data-" + $.mobile.ns + "rel" ) || undefined;
3100
            role = $link.attr( "data-" + $.mobile.ns + "rel" ) || undefined;
3101
 
3101
 
3102
        $.mobile.changePage( href, { transition: transition, reverse: reverse, role: role } );
3102
        $.mobile.changePage( href, { transition: transition, reverse: reverse, role: role } );
3103
        event.preventDefault();
3103
        event.preventDefault();
3104
    });
3104
    });
3105
 
3105
 
3106
    //hashchange event handler
3106
    //hashchange event handler
3107
    $window.bind( "hashchange", function( e, triggered ) {
3107
    $window.bind( "hashchange", function( e, triggered ) {
3108
        //find first page via hash
3108
        //find first page via hash
3109
        var to = path.stripHash( location.hash ),
3109
        var to = path.stripHash( location.hash ),
3110
            //transition is false if it's the first page, undefined otherwise (and may be overridden by default)
3110
            //transition is false if it's the first page, undefined otherwise (and may be overridden by default)
3111
            transition = $.mobile.urlHistory.stack.length === 0 ? "none" : undefined;
3111
            transition = $.mobile.urlHistory.stack.length === 0 ? "none" : undefined;
3112
 
3112
 
3113
        //if listening is disabled (either globally or temporarily), or it's a dialog hash
3113
        //if listening is disabled (either globally or temporarily), or it's a dialog hash
3114
        if( !$.mobile.hashListeningEnabled || urlHistory.ignoreNextHashChange ) {
3114
        if( !$.mobile.hashListeningEnabled || urlHistory.ignoreNextHashChange ) {
3115
            urlHistory.ignoreNextHashChange = false;
3115
            urlHistory.ignoreNextHashChange = false;
3116
            return;
3116
            return;
3117
        }
3117
        }
3118
 
3118
 
3119
        // special case for dialogs
3119
        // special case for dialogs
3120
        if( urlHistory.stack.length > 1 &&
3120
        if( urlHistory.stack.length > 1 &&
3121
                to.indexOf( dialogHashKey ) > -1 ) {
3121
                to.indexOf( dialogHashKey ) > -1 ) {
3122
 
3122
 
3123
            // If current active page is not a dialog skip the dialog and continue
3123
            // If current active page is not a dialog skip the dialog and continue
3124
            // in the same direction
3124
            // in the same direction
3125
            if(!$.mobile.activePage.is( ".ui-dialog" )) {
3125
            if(!$.mobile.activePage.is( ".ui-dialog" )) {
3126
                //determine if we're heading forward or backward and continue accordingly past
3126
                //determine if we're heading forward or backward and continue accordingly past
3127
                //the current dialog
3127
                //the current dialog
3128
                urlHistory.directHashChange({
3128
                urlHistory.directHashChange({
3129
                    currentUrl: to,
3129
                    currentUrl: to,
3130
                    isBack: function() { window.history.back(); },
3130
                    isBack: function() { window.history.back(); },
3131
                    isForward: function() { window.history.forward(); }
3131
                    isForward: function() { window.history.forward(); }
3132
                });
3132
                });
3133
 
3133
 
3134
                // prevent changepage
3134
                // prevent changepage
3135
                return;
3135
                return;
3136
            } else {
3136
            } else {
3137
                var setTo = function() { to = $.mobile.urlHistory.getActive().page; };
3137
                var setTo = function() { to = $.mobile.urlHistory.getActive().page; };
3138
                // if the current active page is a dialog and we're navigating
3138
                // if the current active page is a dialog and we're navigating
3139
                // to a dialog use the dialog objected saved in the stack
3139
                // to a dialog use the dialog objected saved in the stack
3140
                urlHistory.directHashChange({   currentUrl: to, isBack: setTo, isForward: setTo });
3140
                urlHistory.directHashChange({   currentUrl: to, isBack: setTo, isForward: setTo });
3141
            }
3141
            }
3142
        }
3142
        }
3143
 
3143
 
3144
        //if to is defined, load it
3144
        //if to is defined, load it
3145
        if ( to ) {
3145
        if ( to ) {
3146
            to = ( typeof to === "string" && !path.isPath( to ) ) ? ( '#' + to ) : to;
3146
            to = ( typeof to === "string" && !path.isPath( to ) ) ? ( '#' + to ) : to;
3147
            $.mobile.changePage( to, { transition: transition, changeHash: false, fromHashChange: true } );
3147
            $.mobile.changePage( to, { transition: transition, changeHash: false, fromHashChange: true } );
3148
        }
3148
        }
3149
        //there's no hash, go to the first page in the dom
3149
        //there's no hash, go to the first page in the dom
3150
        else {
3150
        else {
3151
            $.mobile.changePage( $.mobile.firstPage, { transition: transition, changeHash: false, fromHashChange: true } );
3151
            $.mobile.changePage( $.mobile.firstPage, { transition: transition, changeHash: false, fromHashChange: true } );
3152
        }
3152
        }
3153
    });
3153
    });
3154
   
3154
   
3155
    //set page min-heights to be device specific
3155
    //set page min-heights to be device specific
3156
    $( document ).bind( "pageshow", resetActivePageHeight );
3156
    $( document ).bind( "pageshow", resetActivePageHeight );
3157
    $( window ).bind( "throttledresize", resetActivePageHeight );
3157
    $( window ).bind( "throttledresize", resetActivePageHeight );
3158
 
3158
 
3159
})( jQuery );
3159
})( jQuery );
3160
/*!
3160
/*!
3161
 * jQuery Mobile v@VERSION
3161
 * jQuery Mobile v@VERSION
3162
 * http://jquerymobile.com/
3162
 * http://jquerymobile.com/
3163
 *
3163
 *
3164
 * Copyright 2010, jQuery Project
3164
 * Copyright 2010, jQuery Project
3165
 * Dual licensed under the MIT or GPL Version 2 licenses.
3165
 * Dual licensed under the MIT or GPL Version 2 licenses.
3166
 * http://jquery.org/license
3166
 * http://jquery.org/license
3167
 */
3167
 */
3168
 
3168
 
3169
( function( $, window, undefined ) {
3169
( function( $, window, undefined ) {
3170
 
3170
 
3171
function css3TransitionHandler( name, reverse, $to, $from )
3171
function css3TransitionHandler( name, reverse, $to, $from )
3172
{
3172
{
3173
    var deferred = new $.Deferred(),
3173
    var deferred = new $.Deferred(),
3174
        reverseClass = reverse ? " reverse" : "",
3174
        reverseClass = reverse ? " reverse" : "",
3175
        viewportClass = "ui-mobile-viewport-transitioning viewport-" + name,
3175
        viewportClass = "ui-mobile-viewport-transitioning viewport-" + name,
3176
        doneFunc = function() {
3176
        doneFunc = function() {
3177
            $to.add( $from ).removeClass( "out in reverse " + name );
3177
            $to.add( $from ).removeClass( "out in reverse " + name );
3178
            if ( $from ) {
3178
            if ( $from ) {
3179
                $from.removeClass( $.mobile.activePageClass );
3179
                $from.removeClass( $.mobile.activePageClass );
3180
            }
3180
            }
3181
            $to.parent().removeClass( viewportClass );
3181
            $to.parent().removeClass( viewportClass );
3182
   
3182
   
3183
            deferred.resolve( name, reverse, $to, $from );
3183
            deferred.resolve( name, reverse, $to, $from );
3184
        };
3184
        };
3185
   
3185
   
3186
    $to.animationComplete( doneFunc );
3186
    $to.animationComplete( doneFunc );
3187
   
3187
   
3188
    $to.parent().addClass( viewportClass );
3188
    $to.parent().addClass( viewportClass );
3189
    if ( $from ) {
3189
    if ( $from ) {
3190
        $from.addClass( name + " out" + reverseClass );
3190
        $from.addClass( name + " out" + reverseClass );
3191
    }
3191
    }
3192
    $to.addClass( $.mobile.activePageClass + " " + name + " in" + reverseClass );
3192
    $to.addClass( $.mobile.activePageClass + " " + name + " in" + reverseClass );
3193
 
3193
 
3194
    return deferred.promise();
3194
    return deferred.promise();
3195
}
3195
}
3196
 
3196
 
3197
// Make our transition handler public.
3197
// Make our transition handler public.
3198
$.mobile.css3TransitionHandler = css3TransitionHandler;
3198
$.mobile.css3TransitionHandler = css3TransitionHandler;
3199
 
3199
 
3200
// If the default transition handler is the 'none' handler, replace it with our handler.
3200
// If the default transition handler is the 'none' handler, replace it with our handler.
3201
if ( $.mobile.defaultTransitionHandler === $.mobile.noneTransitionHandler ) {
3201
if ( $.mobile.defaultTransitionHandler === $.mobile.noneTransitionHandler ) {
3202
    $.mobile.defaultTransitionHandler = css3TransitionHandler;
3202
    $.mobile.defaultTransitionHandler = css3TransitionHandler;
3203
}
3203
}
3204
 
3204
 
3205
})( jQuery, this );
3205
})( jQuery, this );
3206
/*
3206
/*
3207
* jQuery Mobile Framework : "fixHeaderFooter" plugin - on-demand positioning for headers,footers
3207
* jQuery Mobile Framework : "fixHeaderFooter" plugin - on-demand positioning for headers,footers
3208
* Copyright (c) jQuery Project
3208
* Copyright (c) jQuery Project
3209
* Dual licensed under the MIT or GPL Version 2 licenses.
3209
* Dual licensed under the MIT or GPL Version 2 licenses.
3210
* http://jquery.org/license
3210
* http://jquery.org/license
3211
*/
3211
*/
3212
(function($, undefined ) {
3212
(function($, undefined ) {
3213
$.fn.fixHeaderFooter = function(options){
3213
$.fn.fixHeaderFooter = function(options){
3214
    if( !$.support.scrollTop ){ return this; }
3214
    if( !$.support.scrollTop ){ return this; }
3215
   
3215
   
3216
    return this.each(function(){
3216
    return this.each(function(){
3217
        var $this = $(this);
3217
        var $this = $(this);
3218
       
3218
       
3219
        if( $this.jqmData('fullscreen') ){ $this.addClass('ui-page-fullscreen'); }
3219
        if( $this.jqmData('fullscreen') ){ $this.addClass('ui-page-fullscreen'); }
3220
        $this.find( ".ui-header:jqmData(position='fixed')" ).addClass('ui-header-fixed ui-fixed-inline fade'); //should be slidedown
3220
        $this.find( ".ui-header:jqmData(position='fixed')" ).addClass('ui-header-fixed ui-fixed-inline fade'); //should be slidedown
3221
        $this.find( ".ui-footer:jqmData(position='fixed')" ).addClass('ui-footer-fixed ui-fixed-inline fade'); //should be slideup      
3221
        $this.find( ".ui-footer:jqmData(position='fixed')" ).addClass('ui-footer-fixed ui-fixed-inline fade'); //should be slideup      
3222
    });
3222
    });
3223
};
3223
};
3224
 
3224
 
3225
//single controller for all showing,hiding,toggling     
3225
//single controller for all showing,hiding,toggling     
3226
$.fixedToolbars = (function(){
3226
$.fixedToolbars = (function(){
3227
    if( !$.support.scrollTop ){ return; }
3227
    if( !$.support.scrollTop ){ return; }
3228
    var currentstate = 'inline',
3228
    var currentstate = 'inline',
3229
        autoHideMode = false,
3229
        autoHideMode = false,
3230
        showDelay = 100,
3230
        showDelay = 100,
3231
        delayTimer,
3231
        delayTimer,
3232
        ignoreTargets = 'a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed',
3232
        ignoreTargets = 'a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed',
3233
        toolbarSelector = '.ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last',
3233
        toolbarSelector = '.ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last',
3234
        stickyFooter, //for storing quick references to duplicate footers
3234
        stickyFooter, //for storing quick references to duplicate footers
3235
        supportTouch = $.support.touch,
3235
        supportTouch = $.support.touch,
3236
        touchStartEvent = supportTouch ? "touchstart" : "mousedown",
3236
        touchStartEvent = supportTouch ? "touchstart" : "mousedown",
3237
        touchStopEvent = supportTouch ? "touchend" : "mouseup",
3237
        touchStopEvent = supportTouch ? "touchend" : "mouseup",
3238
        stateBefore = null,
3238
        stateBefore = null,
3239
        scrollTriggered = false,
3239
        scrollTriggered = false,
3240
        touchToggleEnabled = true;
3240
        touchToggleEnabled = true;
3241
 
3241
 
3242
    function showEventCallback(event)
3242
    function showEventCallback(event)
3243
    {
3243
    {
3244
        // An event that affects the dimensions of the visual viewport has
3244
        // An event that affects the dimensions of the visual viewport has
3245
        // been triggered. If the header and/or footer for the current page are in overlay
3245
        // been triggered. If the header and/or footer for the current page are in overlay
3246
        // mode, we want to hide them, and then fire off a timer to show them at a later
3246
        // mode, we want to hide them, and then fire off a timer to show them at a later
3247
        // point. Events like a resize can be triggered continuously during a scroll, on
3247
        // point. Events like a resize can be triggered continuously during a scroll, on
3248
        // some platforms, so the timer is used to delay the actual positioning until the
3248
        // some platforms, so the timer is used to delay the actual positioning until the
3249
        // flood of events have subsided.
3249
        // flood of events have subsided.
3250
        //
3250
        //
3251
        // If we are in autoHideMode, we don't do anything because we know the scroll
3251
        // If we are in autoHideMode, we don't do anything because we know the scroll
3252
        // callbacks for the plugin will fire off a show when the scrolling has stopped.
3252
        // callbacks for the plugin will fire off a show when the scrolling has stopped.
3253
        if (!autoHideMode && currentstate == 'overlay') {
3253
        if (!autoHideMode && currentstate == 'overlay') {
3254
            if (!delayTimer)
3254
            if (!delayTimer)
3255
                $.fixedToolbars.hide(true);
3255
                $.fixedToolbars.hide(true);
3256
            $.fixedToolbars.startShowTimer();
3256
            $.fixedToolbars.startShowTimer();
3257
        }
3257
        }
3258
    }
3258
    }
3259
 
3259
 
3260
    $(function() {
3260
    $(function() {
3261
        $(document)
3261
        $(document)
3262
            .bind( "vmousedown",function(event){
3262
            .bind( "vmousedown",function(event){
3263
                if( touchToggleEnabled ) {
3263
                if( touchToggleEnabled ) {
3264
                    stateBefore = currentstate;
3264
                    stateBefore = currentstate;
3265
                }
3265
                }
3266
            })
3266
            })
3267
            .bind( "vclick",function(event){
3267
            .bind( "vclick",function(event){
3268
                if( touchToggleEnabled ) {
3268
                if( touchToggleEnabled ) {
3269
                    if( $(event.target).closest(ignoreTargets).length ){ return; }
3269
                    if( $(event.target).closest(ignoreTargets).length ){ return; }
3270
                    if( !scrollTriggered ){
3270
                    if( !scrollTriggered ){
3271
                        $.fixedToolbars.toggle(stateBefore);
3271
                        $.fixedToolbars.toggle(stateBefore);
3272
                        stateBefore = null;
3272
                        stateBefore = null;
3273
                    }
3273
                    }
3274
                }
3274
                }
3275
            })
3275
            })
3276
            .bind('silentscroll', showEventCallback);
3276
            .bind('silentscroll', showEventCallback);
3277
 
3277
 
3278
/*     
3278
/*     
3279
        The below checks first for a $(document).scrollTop() value, and if zero, binds scroll events to $(window) instead. If the scrollTop value is actually zero, both will return zero anyway.
3279
        The below checks first for a $(document).scrollTop() value, and if zero, binds scroll events to $(window) instead. If the scrollTop value is actually zero, both will return zero anyway.
3280
 
3280
 
3281
        Works with $(document), not $(window) : Opera Mobile (WinMO phone; kinda broken anyway)
3281
        Works with $(document), not $(window) : Opera Mobile (WinMO phone; kinda broken anyway)
3282
        Works with $(window), not $(document) : IE 7/8
3282
        Works with $(window), not $(document) : IE 7/8
3283
        Works with either $(window) or $(document) : Chrome, FF 3.6/4, Android 1.6/2.1, iOS
3283
        Works with either $(window) or $(document) : Chrome, FF 3.6/4, Android 1.6/2.1, iOS
3284
        Needs work either way : BB5, Opera Mobile (iOS)
3284
        Needs work either way : BB5, Opera Mobile (iOS)
3285
 
3285
 
3286
*/
3286
*/
3287
 
3287
 
3288
        (( $(document).scrollTop() == 0 ) ? $(window) : $(document))
3288
        (( $(document).scrollTop() == 0 ) ? $(window) : $(document))
3289
            .bind('scrollstart',function(event){
3289
            .bind('scrollstart',function(event){
3290
                scrollTriggered = true;
3290
                scrollTriggered = true;
3291
                if(stateBefore == null){ stateBefore = currentstate; }
3291
                if(stateBefore == null){ stateBefore = currentstate; }
3292
 
3292
 
3293
                // We only enter autoHideMode if the headers/footers are in
3293
                // We only enter autoHideMode if the headers/footers are in
3294
                // an overlay state or the show timer was started. If the
3294
                // an overlay state or the show timer was started. If the
3295
                // show timer is set, clear it so the headers/footers don't
3295
                // show timer is set, clear it so the headers/footers don't
3296
                // show up until after we're done scrolling.
3296
                // show up until after we're done scrolling.
3297
                var isOverlayState = stateBefore == 'overlay';
3297
                var isOverlayState = stateBefore == 'overlay';
3298
                autoHideMode = isOverlayState || !!delayTimer;
3298
                autoHideMode = isOverlayState || !!delayTimer;
3299
                if (autoHideMode){
3299
                if (autoHideMode){
3300
                    $.fixedToolbars.clearShowTimer();
3300
                    $.fixedToolbars.clearShowTimer();
3301
                    if (isOverlayState) {
3301
                    if (isOverlayState) {
3302
                        $.fixedToolbars.hide(true);
3302
                        $.fixedToolbars.hide(true);
3303
                    }
3303
                    }
3304
                }
3304
                }
3305
            })
3305
            })
3306
            .bind('scrollstop',function(event){
3306
            .bind('scrollstop',function(event){
3307
                if( $(event.target).closest(ignoreTargets).length ){ return; }
3307
                if( $(event.target).closest(ignoreTargets).length ){ return; }
3308
                scrollTriggered = false;
3308
                scrollTriggered = false;
3309
                if (autoHideMode) {
3309
                if (autoHideMode) {
3310
                    autoHideMode = false;
3310
                    autoHideMode = false;
3311
                    $.fixedToolbars.startShowTimer();
3311
                    $.fixedToolbars.startShowTimer();
3312
                }
3312
                }
3313
                stateBefore = null;
3313
                stateBefore = null;
3314
            });
3314
            });
3315
 
3315
 
3316
            $(window).bind('resize', showEventCallback);
3316
            $(window).bind('resize', showEventCallback);
3317
    });
3317
    });
3318
       
3318
       
3319
    //before page is shown, check for duplicate footer
3319
    //before page is shown, check for duplicate footer
3320
    $('.ui-page').live('pagebeforeshow', function(event, ui){
3320
    $('.ui-page').live('pagebeforeshow', function(event, ui){
3321
        var page = $(event.target),
3321
        var page = $(event.target),
3322
            footer = page.find( ":jqmData(role='footer')" ),
3322
            footer = page.find( ":jqmData(role='footer')" ),
3323
            id = footer.data('id'),
3323
            id = footer.data('id'),
3324
            prevPage = ui.prevPage,
3324
            prevPage = ui.prevPage,
3325
            prevFooter = prevPage && prevPage.find( ":jqmData(role='footer')" ),
3325
            prevFooter = prevPage && prevPage.find( ":jqmData(role='footer')" ),
3326
            prevFooterMatches = prevFooter.length && prevFooter.jqmData( "id" ) === id;
3326
            prevFooterMatches = prevFooter.length && prevFooter.jqmData( "id" ) === id;
3327
       
3327
       
3328
        if( id && prevFooterMatches ){
3328
        if( id && prevFooterMatches ){
3329
            stickyFooter = footer;
3329
            stickyFooter = footer;
3330
            setTop( stickyFooter.removeClass( "fade in out" ).appendTo( $.mobile.pageContainer ) );
3330
            setTop( stickyFooter.removeClass( "fade in out" ).appendTo( $.mobile.pageContainer ) );
3331
        }
3331
        }
3332
    });
3332
    });
3333
 
3333
 
3334
    //after page is shown, append footer to new page
3334
    //after page is shown, append footer to new page
3335
    $('.ui-page').live('pageshow', function(event, ui){
3335
    $('.ui-page').live('pageshow', function(event, ui){
3336
        var $this = $(this);
3336
        var $this = $(this);
3337
       
3337
       
3338
        if( stickyFooter && stickyFooter.length ){ 
3338
        if( stickyFooter && stickyFooter.length ){ 
3339
           
3339
           
3340
            setTimeout(function(){
3340
            setTimeout(function(){
3341
                setTop( stickyFooter.appendTo( $this ).addClass("fade") );
3341
                setTop( stickyFooter.appendTo( $this ).addClass("fade") );
3342
                stickyFooter = null;
3342
                stickyFooter = null;
3343
            }, 500);   
3343
            }, 500);   
3344
        }
3344
        }
3345
       
3345
       
3346
        $.fixedToolbars.show(true, this);  
3346
        $.fixedToolbars.show(true, this);  
3347
    });
3347
    });
3348
   
3348
   
3349
    //When a collapsiable is hidden or shown we need to trigger the fixed toolbar to reposition itself (#1635)
3349
    //When a collapsiable is hidden or shown we need to trigger the fixed toolbar to reposition itself (#1635)
3350
    $( ".ui-collapsible-contain" ).live( "collapse expand", showEventCallback );
3350
    $( ".ui-collapsible-contain" ).live( "collapse expand", showEventCallback );
3351
 
3351
 
3352
    // element.getBoundingClientRect() is broken in iOS 3.2.1 on the iPad. The
3352
    // element.getBoundingClientRect() is broken in iOS 3.2.1 on the iPad. The
3353
    // coordinates inside of the rect it returns don't have the page scroll position
3353
    // coordinates inside of the rect it returns don't have the page scroll position
3354
    // factored out of it like the other platforms do. To get around this,
3354
    // factored out of it like the other platforms do. To get around this,
3355
    // we'll just calculate the top offset the old fashioned way until core has
3355
    // we'll just calculate the top offset the old fashioned way until core has
3356
    // a chance to figure out how to handle this situation.
3356
    // a chance to figure out how to handle this situation.
3357
    //
3357
    //
3358
    // TODO: We'll need to get rid of getOffsetTop() once a fix gets folded into core.
3358
    // TODO: We'll need to get rid of getOffsetTop() once a fix gets folded into core.
3359
 
3359
 
3360
    function getOffsetTop(ele)
3360
    function getOffsetTop(ele)
3361
    {
3361
    {
3362
        var top = 0;
3362
        var top = 0;
3363
        if (ele)
3363
        if (ele)
3364
        {
3364
        {
3365
            var op = ele.offsetParent, body = document.body;
3365
            var op = ele.offsetParent, body = document.body;
3366
            top = ele.offsetTop;
3366
            top = ele.offsetTop;
3367
            while (ele && ele != body)
3367
            while (ele && ele != body)
3368
            {
3368
            {
3369
                top += ele.scrollTop || 0;
3369
                top += ele.scrollTop || 0;
3370
                if (ele == op)
3370
                if (ele == op)
3371
                {
3371
                {
3372
                    top += op.offsetTop;
3372
                    top += op.offsetTop;
3373
                    op = ele.offsetParent;
3373
                    op = ele.offsetParent;
3374
                }
3374
                }
3375
                ele = ele.parentNode;
3375
                ele = ele.parentNode;
3376
            }
3376
            }
3377
        }
3377
        }
3378
        return top;
3378
        return top;
3379
    }
3379
    }
3380
 
3380
 
3381
    function setTop(el){
3381
    function setTop(el){
3382
        var fromTop = $(window).scrollTop(),
3382
        var fromTop = $(window).scrollTop(),
3383
            thisTop = getOffsetTop(el[0]), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
3383
            thisTop = getOffsetTop(el[0]), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
3384
            thisCSStop = el.css('top') == 'auto' ? 0 : parseFloat(el.css('top')),
3384
            thisCSStop = el.css('top') == 'auto' ? 0 : parseFloat(el.css('top')),
3385
            screenHeight = window.innerHeight,
3385
            screenHeight = window.innerHeight,
3386
            thisHeight = el.outerHeight(),
3386
            thisHeight = el.outerHeight(),
3387
            useRelative = el.parents('.ui-page:not(.ui-page-fullscreen)').length,
3387
            useRelative = el.parents('.ui-page:not(.ui-page-fullscreen)').length,
3388
            relval;
3388
            relval;
3389
        if( el.is('.ui-header-fixed') ){
3389
        if( el.is('.ui-header-fixed') ){
3390
            relval = fromTop - thisTop + thisCSStop;
3390
            relval = fromTop - thisTop + thisCSStop;
3391
            if( relval < thisTop){ relval = 0; }
3391
            if( relval < thisTop){ relval = 0; }
3392
            return el.css('top', ( useRelative ) ? relval : fromTop);
3392
            return el.css('top', ( useRelative ) ? relval : fromTop);
3393
        }
3393
        }
3394
        else{
3394
        else{
3395
            //relval = -1 * (thisTop - (fromTop + screenHeight) + thisCSStop + thisHeight);
3395
            //relval = -1 * (thisTop - (fromTop + screenHeight) + thisCSStop + thisHeight);
3396
            //if( relval > thisTop ){ relval = 0; }
3396
            //if( relval > thisTop ){ relval = 0; }
3397
            relval = fromTop + screenHeight - thisHeight - (thisTop - thisCSStop);
3397
            relval = fromTop + screenHeight - thisHeight - (thisTop - thisCSStop);
3398
            return el.css('top', ( useRelative ) ? relval : fromTop + screenHeight - thisHeight );
3398
            return el.css('top', ( useRelative ) ? relval : fromTop + screenHeight - thisHeight );
3399
        }
3399
        }
3400
    }
3400
    }
3401
 
3401
 
3402
    //exposed methods
3402
    //exposed methods
3403
    return {
3403
    return {
3404
        show: function(immediately, page){
3404
        show: function(immediately, page){
3405
            $.fixedToolbars.clearShowTimer();
3405
            $.fixedToolbars.clearShowTimer();
3406
            currentstate = 'overlay';
3406
            currentstate = 'overlay';
3407
            var $ap = page ? $(page) : ($.mobile.activePage ? $.mobile.activePage : $(".ui-page-active"));
3407
            var $ap = page ? $(page) : ($.mobile.activePage ? $.mobile.activePage : $(".ui-page-active"));
3408
            return $ap.children( toolbarSelector ).each(function(){
3408
            return $ap.children( toolbarSelector ).each(function(){
3409
                var el = $(this),
3409
                var el = $(this),
3410
                    fromTop = $(window).scrollTop(),
3410
                    fromTop = $(window).scrollTop(),
3411
                    thisTop = getOffsetTop(el[0]), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
3411
                    thisTop = getOffsetTop(el[0]), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
3412
                    screenHeight = window.innerHeight,
3412
                    screenHeight = window.innerHeight,
3413
                    thisHeight = el.outerHeight(),
3413
                    thisHeight = el.outerHeight(),
3414
                    alreadyVisible = (el.is('.ui-header-fixed') && fromTop <= thisTop + thisHeight) || (el.is('.ui-footer-fixed') && thisTop <= fromTop + screenHeight);   
3414
                    alreadyVisible = (el.is('.ui-header-fixed') && fromTop <= thisTop + thisHeight) || (el.is('.ui-footer-fixed') && thisTop <= fromTop + screenHeight);   
3415
               
3415
               
3416
                //add state class
3416
                //add state class
3417
                el.addClass('ui-fixed-overlay').removeClass('ui-fixed-inline');
3417
                el.addClass('ui-fixed-overlay').removeClass('ui-fixed-inline');
3418
                   
3418
                   
3419
                if( !alreadyVisible && !immediately ){
3419
                if( !alreadyVisible && !immediately ){
3420
                    el.animationComplete(function(){
3420
                    el.animationComplete(function(){
3421
                        el.removeClass('in');
3421
                        el.removeClass('in');
3422
                    }).addClass('in');
3422
                    }).addClass('in');
3423
                }
3423
                }
3424
                setTop(el);
3424
                setTop(el);
3425
            });
3425
            });
3426
        },
3426
        },
3427
        hide: function(immediately){
3427
        hide: function(immediately){
3428
            currentstate = 'inline';
3428
            currentstate = 'inline';
3429
            var $ap = $.mobile.activePage ? $.mobile.activePage : $(".ui-page-active");
3429
            var $ap = $.mobile.activePage ? $.mobile.activePage : $(".ui-page-active");
3430
            return $ap.children( toolbarSelector ).each(function(){
3430
            return $ap.children( toolbarSelector ).each(function(){
3431
                var el = $(this);
3431
                var el = $(this);
3432
 
3432
 
3433
                var thisCSStop = el.css('top'); thisCSStop = thisCSStop == 'auto' ? 0 : parseFloat(thisCSStop);
3433
                var thisCSStop = el.css('top'); thisCSStop = thisCSStop == 'auto' ? 0 : parseFloat(thisCSStop);
3434
               
3434
               
3435
                //add state class
3435
                //add state class
3436
                el.addClass('ui-fixed-inline').removeClass('ui-fixed-overlay');
3436
                el.addClass('ui-fixed-inline').removeClass('ui-fixed-overlay');
3437
               
3437
               
3438
                if (thisCSStop < 0 || (el.is('.ui-header-fixed') && thisCSStop != 0))
3438
                if (thisCSStop < 0 || (el.is('.ui-header-fixed') && thisCSStop != 0))
3439
                {
3439
                {
3440
                    if(immediately){
3440
                    if(immediately){
3441
                        el.css('top',0);
3441
                        el.css('top',0);
3442
                    }
3442
                    }
3443
                    else{
3443
                    else{
3444
                        if( el.css('top') !== 'auto' && parseFloat(el.css('top')) !== 0 ){
3444
                        if( el.css('top') !== 'auto' && parseFloat(el.css('top')) !== 0 ){
3445
                            var classes = 'out reverse';
3445
                            var classes = 'out reverse';
3446
                            el.animationComplete(function(){
3446
                            el.animationComplete(function(){
3447
                                el.removeClass(classes);
3447
                                el.removeClass(classes);
3448
                                el.css('top',0);
3448
                                el.css('top',0);
3449
                            }).addClass(classes);  
3449
                            }).addClass(classes);  
3450
                        }
3450
                        }
3451
                    }
3451
                    }
3452
                }
3452
                }
3453
            });
3453
            });
3454
        },
3454
        },
3455
        startShowTimer: function(){
3455
        startShowTimer: function(){
3456
            $.fixedToolbars.clearShowTimer();
3456
            $.fixedToolbars.clearShowTimer();
3457
            var args = $.makeArray(arguments);
3457
            var args = $.makeArray(arguments);
3458
            delayTimer = setTimeout(function(){
3458
            delayTimer = setTimeout(function(){
3459
                delayTimer = undefined;
3459
                delayTimer = undefined;
3460
                $.fixedToolbars.show.apply(null, args);
3460
                $.fixedToolbars.show.apply(null, args);
3461
            }, showDelay);
3461
            }, showDelay);
3462
        },
3462
        },
3463
        clearShowTimer: function() {
3463
        clearShowTimer: function() {
3464
            if (delayTimer) {
3464
            if (delayTimer) {
3465
                clearTimeout(delayTimer);
3465
                clearTimeout(delayTimer);
3466
            }
3466
            }
3467
            delayTimer = undefined;
3467
            delayTimer = undefined;
3468
        },
3468
        },
3469
        toggle: function(from){
3469
        toggle: function(from){
3470
            if(from){ currentstate = from; }
3470
            if(from){ currentstate = from; }
3471
            return (currentstate == 'overlay') ? $.fixedToolbars.hide() : $.fixedToolbars.show();
3471
            return (currentstate == 'overlay') ? $.fixedToolbars.hide() : $.fixedToolbars.show();
3472
        },
3472
        },
3473
        setTouchToggleEnabled: function(enabled) {
3473
        setTouchToggleEnabled: function(enabled) {
3474
            touchToggleEnabled = enabled;
3474
            touchToggleEnabled = enabled;
3475
        }
3475
        }
3476
    };
3476
    };
3477
})();
3477
})();
3478
 
3478
 
3479
})(jQuery);
3479
})(jQuery);
3480
/*
3480
/*
3481
* jQuery Mobile Framework : "checkboxradio" plugin
3481
* jQuery Mobile Framework : "checkboxradio" plugin
3482
* Copyright (c) jQuery Project
3482
* Copyright (c) jQuery Project
3483
* Dual licensed under the MIT or GPL Version 2 licenses.
3483
* Dual licensed under the MIT or GPL Version 2 licenses.
3484
* http://jquery.org/license
3484
* http://jquery.org/license
3485
*/
3485
*/
3486
(function($, undefined ) {
3486
(function($, undefined ) {
3487
$.widget( "mobile.checkboxradio", $.mobile.widget, {
3487
$.widget( "mobile.checkboxradio", $.mobile.widget, {
3488
    options: {
3488
    options: {
3489
        theme: null
3489
        theme: null
3490
    },
3490
    },
3491
    _create: function(){
3491
    _create: function(){
3492
        var self = this,
3492
        var self = this,
3493
            input = this.element,
3493
            input = this.element,
3494
            //NOTE: Windows Phone could not find the label through a selector
3494
            //NOTE: Windows Phone could not find the label through a selector
3495
            //filter works though.
3495
            //filter works though.
3496
            label = input.closest("form,fieldset,:jqmData(role='page')").find("label").filter('[for="' + input[0].id + '"]'),
3496
            label = input.closest("form,fieldset,:jqmData(role='page')").find("label").filter('[for="' + input[0].id + '"]'),
3497
            inputtype = input.attr( "type" ),
3497
            inputtype = input.attr( "type" ),
3498
            checkedicon = "ui-icon-" + inputtype + "-on",
3498
            checkedicon = "ui-icon-" + inputtype + "-on",
3499
            uncheckedicon = "ui-icon-" + inputtype + "-off";
3499
            uncheckedicon = "ui-icon-" + inputtype + "-off";
3500
 
3500
 
3501
        if ( inputtype != "checkbox" && inputtype != "radio" ) { return; }
3501
        if ( inputtype != "checkbox" && inputtype != "radio" ) { return; }
3502
 
3502
 
3503
        //expose for other methods
3503
        //expose for other methods
3504
        $.extend( this,{
3504
        $.extend( this,{
3505
            label           : label,
3505
            label           : label,
3506
            inputtype       : inputtype,
3506
            inputtype       : inputtype,
3507
            checkedicon     : checkedicon,
3507
            checkedicon     : checkedicon,
3508
            uncheckedicon   : uncheckedicon
3508
            uncheckedicon   : uncheckedicon
3509
        });
3509
        });
3510
 
3510
 
3511
        // If there's no selected theme...
3511
        // If there's no selected theme...
3512
        if( !this.options.theme ) {
3512
        if( !this.options.theme ) {
3513
            this.options.theme = this.element.jqmData( "theme" );
3513
            this.options.theme = this.element.jqmData( "theme" );
3514
        }
3514
        }
3515
 
3515
 
3516
        label
3516
        label
3517
            .buttonMarkup({
3517
            .buttonMarkup({
3518
                theme: this.options.theme,
3518
                theme: this.options.theme,
3519
                icon: this.element.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedicon,
3519
                icon: this.element.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedicon,
3520
                shadow: false
3520
                shadow: false
3521
            });
3521
            });
3522
 
3522
 
3523
        // wrap the input + label in a div
3523
        // wrap the input + label in a div
3524
        input
3524
        input
3525
            .add( label )
3525
            .add( label )
3526
            .wrapAll( "<div class='ui-" + inputtype +"'></div>" );
3526
            .wrapAll( "<div class='ui-" + inputtype +"'></div>" );
3527
 
3527
 
3528
        label.bind({
3528
        label.bind({
3529
            vmouseover: function() {
3529
            vmouseover: function() {
3530
                if( $(this).parent().is('.ui-disabled') ){ return false; }
3530
                if( $(this).parent().is('.ui-disabled') ){ return false; }
3531
            },
3531
            },
3532
 
3532
 
3533
            vclick: function( event ){
3533
            vclick: function( event ){
3534
                if ( input.is( ":disabled" ) ){
3534
                if ( input.is( ":disabled" ) ){
3535
                    event.preventDefault();
3535
                    event.preventDefault();
3536
                    return;
3536
                    return;
3537
                }
3537
                }
3538
 
3538
 
3539
                self._cacheVals();
3539
                self._cacheVals();
3540
       
3540
       
3541
                input.prop( "checked", inputtype === "radio" && true || !(input.prop("checked")) );
3541
                input.prop( "checked", inputtype === "radio" && true || !(input.prop("checked")) );
3542
 
3542
 
3543
                // input set for common radio buttons will contain all the radio
3543
                // input set for common radio buttons will contain all the radio
3544
                // buttons, but will not for checkboxes. clearing the checked status
3544
                // buttons, but will not for checkboxes. clearing the checked status
3545
                // of other radios ensures the active button state is applied properly
3545
                // of other radios ensures the active button state is applied properly
3546
                self._getInputSet().not(input).prop('checked', false);
3546
                self._getInputSet().not(input).prop('checked', false);
3547
 
3547
 
3548
                self._updateAll();
3548
                self._updateAll();
3549
                return false;
3549
                return false;
3550
            }
3550
            }
3551
 
3551
 
3552
        });
3552
        });
3553
 
3553
 
3554
        input
3554
        input
3555
            .bind({
3555
            .bind({
3556
                vmousedown: function(){
3556
                vmousedown: function(){
3557
                    this._cacheVals();
3557
                    this._cacheVals();
3558
                },
3558
                },
3559
 
3559
 
3560
                vclick: function(){
3560
                vclick: function(){
3561
          // adds checked attribute to checked input when keyboard is used
3561
          // adds checked attribute to checked input when keyboard is used
3562
          if ($(this).is(":checked")) {
3562
          if ($(this).is(":checked")) {
3563
             $(this).prop( "checked", true);  
3563
             $(this).prop( "checked", true);  
3564
             self._getInputSet().not($(this)).prop('checked', false);
3564
             self._getInputSet().not($(this)).prop('checked', false);
3565
          } else {
3565
          } else {
3566
             $(this).prop("checked", false);
3566
             $(this).prop("checked", false);
3567
          }
3567
          }
3568
                    self._updateAll();
3568
                    self._updateAll();
3569
                },
3569
                },
3570
 
3570
 
3571
                focus: function() {
3571
                focus: function() {
3572
                    label.addClass( "ui-focus" );
3572
                    label.addClass( "ui-focus" );
3573
                },
3573
                },
3574
 
3574
 
3575
                blur: function() {
3575
                blur: function() {
3576
                    label.removeClass( "ui-focus" );
3576
                    label.removeClass( "ui-focus" );
3577
                }
3577
                }
3578
            });
3578
            });
3579
 
3579
 
3580
        this.refresh();
3580
        this.refresh();
3581
 
3581
 
3582
    },
3582
    },
3583
 
3583
 
3584
    _cacheVals: function(){
3584
    _cacheVals: function(){
3585
        this._getInputSet().each(function(){
3585
        this._getInputSet().each(function(){
3586
            $(this).jqmData("cacheVal", $(this).is(":checked") );
3586
            $(this).jqmData("cacheVal", $(this).is(":checked") );
3587
        });
3587
        });
3588
    },
3588
    },
3589
 
3589
 
3590
    //returns either a set of radios with the same name attribute, or a single checkbox
3590
    //returns either a set of radios with the same name attribute, or a single checkbox
3591
    _getInputSet: function(){
3591
    _getInputSet: function(){
3592
        return this.element.closest( "form,fieldset,:jqmData(role='page')" )
3592
        return this.element.closest( "form,fieldset,:jqmData(role='page')" )
3593
                .find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.inputtype +"']" );
3593
                .find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.inputtype +"']" );
3594
    },
3594
    },
3595
 
3595
 
3596
    _updateAll: function(){
3596
    _updateAll: function(){
3597
        var self = this;
3597
        var self = this;
3598
 
3598
 
3599
        this._getInputSet().each(function(){
3599
        this._getInputSet().each(function(){
3600
            if( $(this).is(":checked") || self.inputtype === "checkbox" ){
3600
            if( $(this).is(":checked") || self.inputtype === "checkbox" ){
3601
                $(this).trigger("change");
3601
                $(this).trigger("change");
3602
            }
3602
            }
3603
        })
3603
        })
3604
        .checkboxradio( "refresh" );
3604
        .checkboxradio( "refresh" );
3605
    },
3605
    },
3606
 
3606
 
3607
    refresh: function( ){
3607
    refresh: function( ){
3608
        var input = this.element,
3608
        var input = this.element,
3609
            label = this.label,
3609
            label = this.label,
3610
            icon = label.find( ".ui-icon" );
3610
            icon = label.find( ".ui-icon" );
3611
 
3611
 
3612
        // input[0].checked expando doesn't always report the proper value
3612
        // input[0].checked expando doesn't always report the proper value
3613
        // for checked='checked'
3613
        // for checked='checked'
3614
        if ( $(input[0]).prop('checked') ) {
3614
        if ( $(input[0]).prop('checked') ) {
3615
            label.addClass( $.mobile.activeBtnClass );
3615
            label.addClass( $.mobile.activeBtnClass );
3616
            icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
3616
            icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
3617
 
3617
 
3618
        } else {
3618
        } else {
3619
            label.removeClass( $.mobile.activeBtnClass );
3619
            label.removeClass( $.mobile.activeBtnClass );
3620
            icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
3620
            icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
3621
        }
3621
        }
3622
 
3622
 
3623
        if( input.is( ":disabled" ) ){
3623
        if( input.is( ":disabled" ) ){
3624
            this.disable();
3624
            this.disable();
3625
        }
3625
        }
3626
        else {
3626
        else {
3627
            this.enable();
3627
            this.enable();
3628
        }
3628
        }
3629
    },
3629
    },
3630
 
3630
 
3631
    disable: function(){
3631
    disable: function(){
3632
        this.element.prop("disabled",true).parent().addClass("ui-disabled");
3632
        this.element.prop("disabled",true).parent().addClass("ui-disabled");
3633
    },
3633
    },
3634
 
3634
 
3635
    enable: function(){
3635
    enable: function(){
3636
        this.element.prop("disabled",false).parent().removeClass("ui-disabled");
3636
        this.element.prop("disabled",false).parent().removeClass("ui-disabled");
3637
    }
3637
    }
3638
});
3638
});
3639
})( jQuery );
3639
})( jQuery );
3640
/*
3640
/*
3641
* jQuery Mobile Framework : "textinput" plugin for text inputs, textareas
3641
* jQuery Mobile Framework : "textinput" plugin for text inputs, textareas
3642
* Copyright (c) jQuery Project
3642
* Copyright (c) jQuery Project
3643
* Dual licensed under the MIT or GPL Version 2 licenses.
3643
* Dual licensed under the MIT or GPL Version 2 licenses.
3644
* http://jquery.org/license
3644
* http://jquery.org/license
3645
*/
3645
*/
3646
(function($, undefined ) {
3646
(function($, undefined ) {
3647
$.widget( "mobile.textinput", $.mobile.widget, {
3647
$.widget( "mobile.textinput", $.mobile.widget, {
3648
    options: {
3648
    options: {
3649
        theme: null
3649
        theme: null
3650
    },
3650
    },
3651
    _create: function(){
3651
    _create: function(){
3652
        var input = this.element,
3652
        var input = this.element,
3653
            o = this.options,
3653
            o = this.options,
3654
            theme = o.theme,
3654
            theme = o.theme,
3655
            themeclass;
3655
            themeclass;
3656
           
3656
           
3657
        if ( !theme ) {
3657
        if ( !theme ) {
3658
            var themedParent = this.element.closest("[class*='ui-bar-'],[class*='ui-body-']"),
3658
            var themedParent = this.element.closest("[class*='ui-bar-'],[class*='ui-body-']"),
3659
                themeLetter = themedParent.length && /ui-(bar|body)-([a-z])/.exec( themedParent.attr("class") ),
3659
                themeLetter = themedParent.length && /ui-(bar|body)-([a-z])/.exec( themedParent.attr("class") ),
3660
                theme = themeLetter && themeLetter[2] || "c";
3660
                theme = themeLetter && themeLetter[2] || "c";
3661
        }  
3661
        }  
3662
       
3662
       
3663
        themeclass = " ui-body-" + theme;
3663
        themeclass = " ui-body-" + theme;
3664
       
3664
       
3665
        $('label[for="'+input.attr('id')+'"]').addClass('ui-input-text');
3665
        $('label[for="'+input.attr('id')+'"]').addClass('ui-input-text');
3666
       
3666
       
3667
        input.addClass('ui-input-text ui-body-'+ o.theme);
3667
        input.addClass('ui-input-text ui-body-'+ o.theme);
3668
       
3668
       
3669
        var focusedEl = input;
3669
        var focusedEl = input;
3670
       
3670
       
3671
        //"search" input widget
3671
        //"search" input widget
3672
        if( input.is( "[type='search'],:jqmData(type='search')" ) ){
3672
        if( input.is( "[type='search'],:jqmData(type='search')" ) ){
3673
            focusedEl = input.wrap('<div class="ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield'+ themeclass +'"></div>').parent();
3673
            focusedEl = input.wrap('<div class="ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield'+ themeclass +'"></div>').parent();
3674
            var clearbtn = $('<a href="#" class="ui-input-clear" title="clear text">clear text</a>')
3674
            var clearbtn = $('<a href="#" class="ui-input-clear" title="clear text">clear text</a>')
3675
                .tap(function( e ){
3675
                .tap(function( e ){
3676
                    input.val('').focus();
3676
                    input.val('').focus();
3677
                    input.trigger('change');
3677
                    input.trigger('change');
3678
                    clearbtn.addClass('ui-input-clear-hidden');
3678
                    clearbtn.addClass('ui-input-clear-hidden');
3679
                    e.preventDefault();
3679
                    e.preventDefault();
3680
                })
3680
                })
3681
                .appendTo(focusedEl)
3681
                .appendTo(focusedEl)
3682
                .buttonMarkup({icon: 'delete', iconpos: 'notext', corners:true, shadow:true});
3682
                .buttonMarkup({icon: 'delete', iconpos: 'notext', corners:true, shadow:true});
3683
           
3683
           
3684
            function toggleClear(){
3684
            function toggleClear(){
3685
                if(input.val() == ''){
3685
                if(input.val() == ''){
3686
                    clearbtn.addClass('ui-input-clear-hidden');
3686
                    clearbtn.addClass('ui-input-clear-hidden');
3687
                }
3687
                }
3688
                else{
3688
                else{
3689
                    clearbtn.removeClass('ui-input-clear-hidden');
3689
                    clearbtn.removeClass('ui-input-clear-hidden');
3690
                }
3690
                }
3691
            }
3691
            }
3692
           
3692
           
3693
            toggleClear();
3693
            toggleClear();
3694
            input.keyup(toggleClear);
3694
            input.keyup(toggleClear);
3695
                    input.focus(toggleClear);  
3695
                    input.focus(toggleClear);  
3696
        }
3696
        }
3697
        else{
3697
        else{
3698
            input.addClass('ui-corner-all ui-shadow-inset' + themeclass);
3698
            input.addClass('ui-corner-all ui-shadow-inset' + themeclass);
3699
        }
3699
        }
3700
               
3700
               
3701
        input
3701
        input
3702
            .focus(function(){
3702
            .focus(function(){
3703
                focusedEl.addClass('ui-focus');
3703
                focusedEl.addClass('ui-focus');
3704
            })
3704
            })
3705
            .blur(function(){
3705
            .blur(function(){
3706
                focusedEl.removeClass('ui-focus');
3706
                focusedEl.removeClass('ui-focus');
3707
            });
3707
            });
3708
           
3708
           
3709
        //autogrow
3709
        //autogrow
3710
        if ( input.is('textarea') ) {
3710
        if ( input.is('textarea') ) {
3711
            var extraLineHeight = 15,
3711
            var extraLineHeight = 15,
3712
                keyupTimeoutBuffer = 100,
3712
                keyupTimeoutBuffer = 100,
3713
                keyup = function() {
3713
                keyup = function() {
3714
                    var scrollHeight = input[0].scrollHeight,
3714
                    var scrollHeight = input[0].scrollHeight,
3715
                        clientHeight = input[0].clientHeight;
3715
                        clientHeight = input[0].clientHeight;
3716
                    if ( clientHeight < scrollHeight ) {
3716
                    if ( clientHeight < scrollHeight ) {
3717
                        input.css({ height: (scrollHeight + extraLineHeight) });
3717
                        input.css({ height: (scrollHeight + extraLineHeight) });
3718
                    }
3718
                    }
3719
                },
3719
                },
3720
                keyupTimeout;
3720
                keyupTimeout;
3721
            input.keyup(function() {
3721
            input.keyup(function() {
3722
                clearTimeout( keyupTimeout );
3722
                clearTimeout( keyupTimeout );
3723
                keyupTimeout = setTimeout( keyup, keyupTimeoutBuffer );
3723
                keyupTimeout = setTimeout( keyup, keyupTimeoutBuffer );
3724
            });
3724
            });
3725
        }
3725
        }
3726
    },
3726
    },
3727
   
3727
   
3728
    disable: function(){
3728
    disable: function(){
3729
        ( this.element.attr("disabled",true).is( "[type='search'],:jqmData(type='search')" ) ? this.element.parent() : this.element ).addClass("ui-disabled");
3729
        ( this.element.attr("disabled",true).is( "[type='search'],:jqmData(type='search')" ) ? this.element.parent() : this.element ).addClass("ui-disabled");
3730
    },
3730
    },
3731
   
3731
   
3732
    enable: function(){
3732
    enable: function(){
3733
        ( this.element.attr("disabled", false).is( "[type='search'],:jqmData(type='search')" ) ? this.element.parent() : this.element ).removeClass("ui-disabled");
3733
        ( this.element.attr("disabled", false).is( "[type='search'],:jqmData(type='search')" ) ? this.element.parent() : this.element ).removeClass("ui-disabled");
3734
    }
3734
    }
3735
});
3735
});
3736
})( jQuery );
3736
})( jQuery );
3737
/*
3737
/*
3738
* jQuery Mobile Framework : "selectmenu" plugin
3738
* jQuery Mobile Framework : "selectmenu" plugin
3739
* Copyright (c) jQuery Project
3739
* Copyright (c) jQuery Project
3740
* Dual licensed under the MIT or GPL Version 2 licenses.
3740
* Dual licensed under the MIT or GPL Version 2 licenses.
3741
* http://jquery.org/license
3741
* http://jquery.org/license
3742
*/
3742
*/
3743
(function($, undefined ) {
3743
(function($, undefined ) {
3744
$.widget( "mobile.selectmenu", $.mobile.widget, {
3744
$.widget( "mobile.selectmenu", $.mobile.widget, {
3745
    options: {
3745
    options: {
3746
        theme: null,
3746
        theme: null,
3747
        disabled: false,
3747
        disabled: false,
3748
        icon: 'arrow-d',
3748
        icon: 'arrow-d',
3749
        iconpos: 'right',
3749
        iconpos: 'right',
3750
        inline: null,
3750
        inline: null,
3751
        corners: true,
3751
        corners: true,
3752
        shadow: true,
3752
        shadow: true,
3753
        iconshadow: true,
3753
        iconshadow: true,
3754
        menuPageTheme: 'b',
3754
        menuPageTheme: 'b',
3755
        overlayTheme: 'a',
3755
        overlayTheme: 'a',
3756
        hidePlaceholderMenuItems: true,
3756
        hidePlaceholderMenuItems: true,
3757
        closeText: 'Close',
3757
        closeText: 'Close',
3758
        nativeMenu: true
3758
        nativeMenu: true
3759
    },
3759
    },
3760
    _create: function(){
3760
    _create: function(){
3761
 
3761
 
3762
        var self = this,
3762
        var self = this,
3763
 
3763
 
3764
            o = this.options,
3764
            o = this.options,
3765
 
3765
 
3766
            select = this.element
3766
            select = this.element
3767
                        .wrap( "<div class='ui-select'>" ),
3767
                        .wrap( "<div class='ui-select'>" ),
3768
 
3768
 
3769
            selectID = select.attr( "id" ),
3769
            selectID = select.attr( "id" ),
3770
 
3770
 
3771
            label = $( 'label[for="'+ selectID +'"]' ).addClass( "ui-select" ),
3771
            label = $( 'label[for="'+ selectID +'"]' ).addClass( "ui-select" ),
3772
 
3772
 
3773
            //IE throws an exception at options.item() function when
3773
            //IE throws an exception at options.item() function when
3774
            //there is no selected item
3774
            //there is no selected item
3775
            //select first in this case
3775
            //select first in this case
3776
            selectedIndex = select[0].selectedIndex == -1 ? 0 : select[0].selectedIndex,
3776
            selectedIndex = select[0].selectedIndex == -1 ? 0 : select[0].selectedIndex,
3777
 
3777
 
3778
            button = ( self.options.nativeMenu ? $( "<div/>" ) : $( "<a>", {
3778
            button = ( self.options.nativeMenu ? $( "<div/>" ) : $( "<a>", {
3779
                    "href": "#",
3779
                    "href": "#",
3780
                    "role": "button",
3780
                    "role": "button",
3781
                    "id": buttonId,
3781
                    "id": buttonId,
3782
                    "aria-haspopup": "true",
3782
                    "aria-haspopup": "true",
3783
                    "aria-owns": menuId
3783
                    "aria-owns": menuId
3784
                }) )
3784
                }) )
3785
                .text( $( select[0].options.item( selectedIndex ) ).text() )
3785
                .text( $( select[0].options.item( selectedIndex ) ).text() )
3786
                .insertBefore( select )
3786
                .insertBefore( select )
3787
                .buttonMarkup({
3787
                .buttonMarkup({
3788
                    theme: o.theme,
3788
                    theme: o.theme,
3789
                    icon: o.icon,
3789
                    icon: o.icon,
3790
                    iconpos: o.iconpos,
3790
                    iconpos: o.iconpos,
3791
                    inline: o.inline,
3791
                    inline: o.inline,
3792
                    corners: o.corners,
3792
                    corners: o.corners,
3793
                    shadow: o.shadow,
3793
                    shadow: o.shadow,
3794
                    iconshadow: o.iconshadow
3794
                    iconshadow: o.iconshadow
3795
                }),
3795
                }),
3796
 
3796
 
3797
            //multi select or not
3797
            //multi select or not
3798
            isMultiple = self.isMultiple = select[0].multiple;
3798
            isMultiple = self.isMultiple = select[0].multiple;
3799
 
3799
 
3800
        //Opera does not properly support opacity on select elements
3800
        //Opera does not properly support opacity on select elements
3801
        //In Mini, it hides the element, but not its text
3801
        //In Mini, it hides the element, but not its text
3802
        //On the desktop,it seems to do the opposite
3802
        //On the desktop,it seems to do the opposite
3803
        //for these reasons, using the nativeMenu option results in a full native select in Opera
3803
        //for these reasons, using the nativeMenu option results in a full native select in Opera
3804
        if( o.nativeMenu && window.opera && window.opera.version ){
3804
        if( o.nativeMenu && window.opera && window.opera.version ){
3805
            select.addClass( "ui-select-nativeonly" );
3805
            select.addClass( "ui-select-nativeonly" );
3806
        }
3806
        }
3807
 
3807
 
3808
        //vars for non-native menus
3808
        //vars for non-native menus
3809
        if( !o.nativeMenu ){
3809
        if( !o.nativeMenu ){
3810
            var options = select.find("option"),
3810
            var options = select.find("option"),
3811
 
3811
 
3812
                buttonId = selectID + "-button",
3812
                buttonId = selectID + "-button",
3813
 
3813
 
3814
                menuId = selectID + "-menu",
3814
                menuId = selectID + "-menu",
3815
 
3815
 
3816
                thisPage = select.closest( ".ui-page" ),
3816
                thisPage = select.closest( ".ui-page" ),
3817
 
3817
 
3818
                //button theme
3818
                //button theme
3819
                theme = /ui-btn-up-([a-z])/.exec( button.attr("class") )[1],
3819
                theme = /ui-btn-up-([a-z])/.exec( button.attr("class") )[1],
3820
 
3820
 
3821
                menuPage = $( "<div data-" + $.mobile.ns + "role='dialog' data-" +$.mobile.ns + "theme='"+ o.menuPageTheme +"'>" +
3821
                menuPage = $( "<div data-" + $.mobile.ns + "role='dialog' data-" +$.mobile.ns + "theme='"+ o.menuPageTheme +"'>" +
3822
                            "<div data-" + $.mobile.ns + "role='header'>" +
3822
                            "<div data-" + $.mobile.ns + "role='header'>" +
3823
                                "<div class='ui-title'>" + label.text() + "</div>"+
3823
                                "<div class='ui-title'>" + label.text() + "</div>"+
3824
                            "</div>"+
3824
                            "</div>"+
3825
                            "<div data-" + $.mobile.ns + "role='content'></div>"+
3825
                            "<div data-" + $.mobile.ns + "role='content'></div>"+
3826
                        "</div>" )
3826
                        "</div>" )
3827
                        .appendTo( $.mobile.pageContainer )
3827
                        .appendTo( $.mobile.pageContainer )
3828
                        .page(),
3828
                        .page(),
3829
 
3829
 
3830
                menuPageContent = menuPage.find( ".ui-content" ),
3830
                menuPageContent = menuPage.find( ".ui-content" ),
3831
 
3831
 
3832
                menuPageClose = menuPage.find( ".ui-header a" ),
3832
                menuPageClose = menuPage.find( ".ui-header a" ),
3833
 
3833
 
3834
                screen = $( "<div>", {"class": "ui-selectmenu-screen ui-screen-hidden"})
3834
                screen = $( "<div>", {"class": "ui-selectmenu-screen ui-screen-hidden"})
3835
                            .appendTo( thisPage ),
3835
                            .appendTo( thisPage ),
3836
 
3836
 
3837
                listbox = $( "<div>", { "class": "ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all pop ui-body-" + o.overlayTheme } )
3837
                listbox = $( "<div>", { "class": "ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all pop ui-body-" + o.overlayTheme } )
3838
                        .insertAfter(screen),
3838
                        .insertAfter(screen),
3839
 
3839
 
3840
                list = $( "<ul>", {
3840
                list = $( "<ul>", {
3841
                        "class": "ui-selectmenu-list",
3841
                        "class": "ui-selectmenu-list",
3842
                        "id": menuId,
3842
                        "id": menuId,
3843
                        "role": "listbox",
3843
                        "role": "listbox",
3844
                        "aria-labelledby": buttonId
3844
                        "aria-labelledby": buttonId
3845
                    })
3845
                    })
3846
                    .attr( "data-" + $.mobile.ns + "theme", theme )
3846
                    .attr( "data-" + $.mobile.ns + "theme", theme )
3847
                    .appendTo( listbox ),
3847
                    .appendTo( listbox ),
3848
 
3848
 
3849
                header = $( "<div>", {
3849
                header = $( "<div>", {
3850
                        "class": "ui-header ui-bar-" + theme
3850
                        "class": "ui-header ui-bar-" + theme
3851
                    })
3851
                    })
3852
                    .prependTo( listbox ),
3852
                    .prependTo( listbox ),
3853
 
3853
 
3854
                headerTitle = $( "<h1>", {
3854
                headerTitle = $( "<h1>", {
3855
                        "class": "ui-title"
3855
                        "class": "ui-title"
3856
                    })
3856
                    })
3857
                    .appendTo( header ),
3857
                    .appendTo( header ),
3858
 
3858
 
3859
                headerClose = $( "<a>", {
3859
                headerClose = $( "<a>", {
3860
                        "text": o.closeText,
3860
                        "text": o.closeText,
3861
                        "href": "#",
3861
                        "href": "#",
3862
                        "class": "ui-btn-left"
3862
                        "class": "ui-btn-left"
3863
                    })
3863
                    })
3864
                    .attr( "data-" + $.mobile.ns + "iconpos", "notext" )
3864
                    .attr( "data-" + $.mobile.ns + "iconpos", "notext" )
3865
                    .attr( "data-" + $.mobile.ns + "icon", "delete" )
3865
                    .attr( "data-" + $.mobile.ns + "icon", "delete" )
3866
                    .appendTo( header )
3866
                    .appendTo( header )
3867
                    .buttonMarkup(),
3867
                    .buttonMarkup(),
3868
 
3868
 
3869
                menuType;
3869
                menuType;
3870
        } //end non native vars
3870
        } //end non native vars
3871
 
3871
 
3872
        // add counter for multi selects
3872
        // add counter for multi selects
3873
        if( isMultiple ){
3873
        if( isMultiple ){
3874
            self.buttonCount = $('<span>')
3874
            self.buttonCount = $('<span>')
3875
                .addClass( 'ui-li-count ui-btn-up-c ui-btn-corner-all' )
3875
                .addClass( 'ui-li-count ui-btn-up-c ui-btn-corner-all' )
3876
                .hide()
3876
                .hide()
3877
                .appendTo( button );
3877
                .appendTo( button );
3878
        }
3878
        }
3879
 
3879
 
3880
        //disable if specified
3880
        //disable if specified
3881
        if( o.disabled ){ this.disable(); }
3881
        if( o.disabled ){ this.disable(); }
3882
 
3882
 
3883
        //events on native select
3883
        //events on native select
3884
        select
3884
        select
3885
            .change(function(){
3885
            .change(function(){
3886
                self.refresh();
3886
                self.refresh();
3887
            });
3887
            });
3888
 
3888
 
3889
        //expose to other methods
3889
        //expose to other methods
3890
        $.extend(self, {
3890
        $.extend(self, {
3891
            select: select,
3891
            select: select,
3892
            optionElems: options,
3892
            optionElems: options,
3893
            selectID: selectID,
3893
            selectID: selectID,
3894
            label: label,
3894
            label: label,
3895
            buttonId:buttonId,
3895
            buttonId:buttonId,
3896
            menuId:menuId,
3896
            menuId:menuId,
3897
            thisPage:thisPage,
3897
            thisPage:thisPage,
3898
            button:button,
3898
            button:button,
3899
            menuPage:menuPage,
3899
            menuPage:menuPage,
3900
            menuPageContent:menuPageContent,
3900
            menuPageContent:menuPageContent,
3901
            screen:screen,
3901
            screen:screen,
3902
            listbox:listbox,
3902
            listbox:listbox,
3903
            list:list,
3903
            list:list,
3904
            menuType:menuType,
3904
            menuType:menuType,
3905
            header:header,
3905
            header:header,
3906
            headerClose:headerClose,
3906
            headerClose:headerClose,
3907
            headerTitle:headerTitle,
3907
            headerTitle:headerTitle,
3908
            placeholder: ''
3908
            placeholder: ''
3909
        });
3909
        });
3910
 
3910
 
3911
        //support for using the native select menu with a custom button
3911
        //support for using the native select menu with a custom button
3912
        if( o.nativeMenu ){
3912
        if( o.nativeMenu ){
3913
 
3913
 
3914
            select
3914
            select
3915
                .appendTo(button)
3915
                .appendTo(button)
3916
                .bind( "vmousedown", function( e ){
3916
                .bind( "vmousedown", function( e ){
3917
                    //add active class to button
3917
                    //add active class to button
3918
                    button.addClass( $.mobile.activeBtnClass );
3918
                    button.addClass( $.mobile.activeBtnClass );
3919
                })
3919
                })
3920
                .bind( "focus vmouseover", function(){
3920
                .bind( "focus vmouseover", function(){
3921
                    button.trigger( "vmouseover" );
3921
                    button.trigger( "vmouseover" );
3922
                })
3922
                })
3923
                .bind( "vmousemove", function(){
3923
                .bind( "vmousemove", function(){
3924
                    //remove active class on scroll/touchmove
3924
                    //remove active class on scroll/touchmove
3925
                    button.removeClass( $.mobile.activeBtnClass );
3925
                    button.removeClass( $.mobile.activeBtnClass );
3926
                })
3926
                })
3927
                .bind( "change blur vmouseout", function(){
3927
                .bind( "change blur vmouseout", function(){
3928
                    button
3928
                    button
3929
                        .trigger( "vmouseout" )
3929
                        .trigger( "vmouseout" )
3930
                        .removeClass( $.mobile.activeBtnClass );
3930
                        .removeClass( $.mobile.activeBtnClass );
3931
                });
3931
                });
3932
 
3932
 
3933
 
3933
 
3934
        } else {
3934
        } else {
3935
 
3935
 
3936
            //create list from select, update state
3936
            //create list from select, update state
3937
            self.refresh();
3937
            self.refresh();
3938
 
3938
 
3939
            select
3939
            select
3940
                .attr( "tabindex", "-1" )
3940
                .attr( "tabindex", "-1" )
3941
                .focus(function(){
3941
                .focus(function(){
3942
                    $(this).blur();
3942
                    $(this).blur();
3943
                    button.focus();
3943
                    button.focus();
3944
                });
3944
                });
3945
 
3945
 
3946
            //button events
3946
            //button events
3947
            button
3947
            button
3948
                .bind( "vclick keydown" , function( event ){
3948
                .bind( "vclick keydown" , function( event ){
3949
                    if( event.type == "vclick" ||
3949
                    if( event.type == "vclick" ||
3950
                        event.keyCode && ( event.keyCode === $.mobile.keyCode.ENTER || event.keyCode === $.mobile.keyCode.SPACE ) ){
3950
                        event.keyCode && ( event.keyCode === $.mobile.keyCode.ENTER || event.keyCode === $.mobile.keyCode.SPACE ) ){
3951
                        self.open();
3951
                        self.open();
3952
                        event.preventDefault();
3952
                        event.preventDefault();
3953
                    }
3953
                    }
3954
                });
3954
                });
3955
 
3955
 
3956
            //events for list items
3956
            //events for list items
3957
            list
3957
            list
3958
            .attr( "role", "listbox" )
3958
            .attr( "role", "listbox" )
3959
            .delegate( ".ui-li>a", "focusin", function() {
3959
            .delegate( ".ui-li>a", "focusin", function() {
3960
                $( this ).attr( "tabindex", "0" );
3960
                $( this ).attr( "tabindex", "0" );
3961
            })
3961
            })
3962
            .delegate( ".ui-li>a", "focusout", function() {
3962
            .delegate( ".ui-li>a", "focusout", function() {
3963
                $( this ).attr( "tabindex", "-1" );
3963
                $( this ).attr( "tabindex", "-1" );
3964
            })
3964
            })
3965
            .delegate("li:not(.ui-disabled, .ui-li-divider)", "vclick", function(event){
3965
            .delegate("li:not(.ui-disabled, .ui-li-divider)", "vclick", function(event){
3966
 
3966
 
3967
                // index of option tag to be selected
3967
                // index of option tag to be selected
3968
                var oldIndex = select[0].selectedIndex,
3968
                var oldIndex = select[0].selectedIndex,
3969
                    newIndex = list.find( "li:not(.ui-li-divider)" ).index( this ),
3969
                    newIndex = list.find( "li:not(.ui-li-divider)" ).index( this ),
3970
                    option = self.optionElems.eq( newIndex )[0];
3970
                    option = self.optionElems.eq( newIndex )[0];
3971
 
3971
 
3972
                // toggle selected status on the tag for multi selects
3972
                // toggle selected status on the tag for multi selects
3973
                option.selected = isMultiple ? !option.selected : true;
3973
                option.selected = isMultiple ? !option.selected : true;
3974
 
3974
 
3975
                // toggle checkbox class for multiple selects
3975
                // toggle checkbox class for multiple selects
3976
                if( isMultiple ){
3976
                if( isMultiple ){
3977
                    $(this)
3977
                    $(this)
3978
                        .find('.ui-icon')
3978
                        .find('.ui-icon')
3979
                        .toggleClass('ui-icon-checkbox-on', option.selected)
3979
                        .toggleClass('ui-icon-checkbox-on', option.selected)
3980
                        .toggleClass('ui-icon-checkbox-off', !option.selected);
3980
                        .toggleClass('ui-icon-checkbox-off', !option.selected);
3981
                }
3981
                }
3982
 
3982
 
3983
                // trigger change if value changed
3983
                // trigger change if value changed
3984
                if( isMultiple || oldIndex !== newIndex ){
3984
                if( isMultiple || oldIndex !== newIndex ){
3985
                    select.trigger( "change" );
3985
                    select.trigger( "change" );
3986
                }
3986
                }
3987
 
3987
 
3988
                //hide custom select for single selects only
3988
                //hide custom select for single selects only
3989
                if( !isMultiple ){
3989
                if( !isMultiple ){
3990
                    self.close();
3990
                    self.close();
3991
                }
3991
                }
3992
 
3992
 
3993
                event.preventDefault();
3993
                event.preventDefault();
3994
            })
3994
            })
3995
            //keyboard events for menu items
3995
            //keyboard events for menu items
3996
            .keydown(function( e ) {
3996
            .keydown(function( e ) {
3997
                var target = $( e.target ),
3997
                var target = $( e.target ),
3998
                    li = target.closest( "li" );
3998
                    li = target.closest( "li" );
3999
 
3999
 
4000
                // switch logic based on which key was pressed
4000
                // switch logic based on which key was pressed
4001
                switch ( e.keyCode ) {
4001
                switch ( e.keyCode ) {
4002
                    // up or left arrow keys
4002
                    // up or left arrow keys
4003
                    case 38:
4003
                    case 38:
4004
                        var prev = li.prev();
4004
                        var prev = li.prev();
4005
 
4005
 
4006
                        // if there's a previous option, focus it
4006
                        // if there's a previous option, focus it
4007
                        if ( prev.length ) {
4007
                        if ( prev.length ) {
4008
                            target
4008
                            target
4009
                                .blur()
4009
                                .blur()
4010
                                .attr( "tabindex", "-1" );
4010
                                .attr( "tabindex", "-1" );
4011
 
4011
 
4012
                            prev.find( "a" ).first().focus();
4012
                            prev.find( "a" ).first().focus();
4013
                        }
4013
                        }
4014
 
4014
 
4015
                        return false;
4015
                        return false;
4016
                    break;
4016
                    break;
4017
 
4017
 
4018
                    // down or right arrow keys
4018
                    // down or right arrow keys
4019
                    case 40:
4019
                    case 40:
4020
                        var next = li.next();
4020
                        var next = li.next();
4021
 
4021
 
4022
                        // if there's a next option, focus it
4022
                        // if there's a next option, focus it
4023
                        if ( next.length ) {
4023
                        if ( next.length ) {
4024
                            target
4024
                            target
4025
                                .blur()
4025
                                .blur()
4026
                                .attr( "tabindex", "-1" );
4026
                                .attr( "tabindex", "-1" );
4027
 
4027
 
4028
                            next.find( "a" ).first().focus();
4028
                            next.find( "a" ).first().focus();
4029
                        }
4029
                        }
4030
 
4030
 
4031
                        return false;
4031
                        return false;
4032
                    break;
4032
                    break;
4033
 
4033
 
4034
                    // if enter or space is pressed, trigger click
4034
                    // if enter or space is pressed, trigger click
4035
                    case 13:
4035
                    case 13:
4036
                    case 32:
4036
                    case 32:
4037
                         target.trigger( "vclick" );
4037
                         target.trigger( "vclick" );
4038
 
4038
 
4039
                         return false;
4039
                         return false;
4040
                    break;
4040
                    break;
4041
                }
4041
                }
4042
            });
4042
            });
4043
 
4043
 
4044
            //events on "screen" overlay
4044
            //events on "screen" overlay
4045
            screen.bind("vclick", function( event ){
4045
            screen.bind("vclick", function( event ){
4046
                self.close();
4046
                self.close();
4047
            });
4047
            });
4048
 
4048
 
4049
            //close button on small overlays
4049
            //close button on small overlays
4050
            self.headerClose.click(function(){
4050
            self.headerClose.click(function(){
4051
                if( self.menuType == "overlay" ){
4051
                if( self.menuType == "overlay" ){
4052
                    self.close();
4052
                    self.close();
4053
                    return false;
4053
                    return false;
4054
                }
4054
                }
4055
            })
4055
            })
4056
        }
4056
        }
4057
    },
4057
    },
4058
 
4058
 
4059
    _buildList: function(){
4059
    _buildList: function(){
4060
        var self = this,
4060
        var self = this,
4061
            o = this.options,
4061
            o = this.options,
4062
            placeholder = this.placeholder,
4062
            placeholder = this.placeholder,
4063
            optgroups = [],
4063
            optgroups = [],
4064
            lis = [],
4064
            lis = [],
4065
            dataIcon = self.isMultiple ? "checkbox-off" : "false";
4065
            dataIcon = self.isMultiple ? "checkbox-off" : "false";
4066
 
4066
 
4067
        self.list.empty().filter('.ui-listview').listview('destroy');
4067
        self.list.empty().filter('.ui-listview').listview('destroy');
4068
 
4068
 
4069
        //populate menu with options from select element
4069
        //populate menu with options from select element
4070
        self.select.find( "option" ).each(function( i ){
4070
        self.select.find( "option" ).each(function( i ){
4071
            var $this = $(this),
4071
            var $this = $(this),
4072
                $parent = $this.parent(),
4072
                $parent = $this.parent(),
4073
                text = $this.text(),
4073
                text = $this.text(),
4074
                anchor = "<a href='#'>"+ text +"</a>",
4074
                anchor = "<a href='#'>"+ text +"</a>",
4075
                classes = [],
4075
                classes = [],
4076
                extraAttrs = [];
4076
                extraAttrs = [];
4077
 
4077
 
4078
            // are we inside an optgroup?
4078
            // are we inside an optgroup?
4079
            if( $parent.is("optgroup") ){
4079
            if( $parent.is("optgroup") ){
4080
                var optLabel = $parent.attr("label");
4080
                var optLabel = $parent.attr("label");
4081
 
4081
 
4082
                // has this optgroup already been built yet?
4082
                // has this optgroup already been built yet?
4083
                if( $.inArray(optLabel, optgroups) === -1 ){
4083
                if( $.inArray(optLabel, optgroups) === -1 ){
4084
                    lis.push( "<li data-" + $.mobile.ns + "role='list-divider'>"+ optLabel +"</li>" );
4084
                    lis.push( "<li data-" + $.mobile.ns + "role='list-divider'>"+ optLabel +"</li>" );
4085
                    optgroups.push( optLabel );
4085
                    optgroups.push( optLabel );
4086
                }
4086
                }
4087
            }
4087
            }
4088
 
4088
 
4089
            //find placeholder text
4089
            //find placeholder text
4090
            if( !this.getAttribute('value') || text.length == 0 || $this.jqmData('placeholder') ){
4090
            if( !this.getAttribute('value') || text.length == 0 || $this.jqmData('placeholder') ){
4091
                if( o.hidePlaceholderMenuItems ){
4091
                if( o.hidePlaceholderMenuItems ){
4092
                    classes.push( "ui-selectmenu-placeholder" );
4092
                    classes.push( "ui-selectmenu-placeholder" );
4093
                }
4093
                }
4094
                placeholder = self.placeholder = text;
4094
                placeholder = self.placeholder = text;
4095
            }
4095
            }
4096
 
4096
 
4097
            // support disabled option tags
4097
            // support disabled option tags
4098
            if( this.disabled ){
4098
            if( this.disabled ){
4099
                classes.push( "ui-disabled" );
4099
                classes.push( "ui-disabled" );
4100
                extraAttrs.push( "aria-disabled='true'" );
4100
                extraAttrs.push( "aria-disabled='true'" );
4101
            }
4101
            }
4102
 
4102
 
4103
            lis.push( "<li data-" + $.mobile.ns + "icon='"+ dataIcon +"' class='"+ classes.join(" ") + "' " + extraAttrs.join(" ") +">"+ anchor +"</li>" )
4103
            lis.push( "<li data-" + $.mobile.ns + "icon='"+ dataIcon +"' class='"+ classes.join(" ") + "' " + extraAttrs.join(" ") +">"+ anchor +"</li>" )
4104
        });
4104
        });
4105
 
4105
 
4106
        self.list.html( lis.join(" ") );
4106
        self.list.html( lis.join(" ") );
4107
 
4107
 
4108
        self.list.find( "li" )
4108
        self.list.find( "li" )
4109
            .attr({ "role": "option", "tabindex": "-1" })
4109
            .attr({ "role": "option", "tabindex": "-1" })
4110
            .first().attr( "tabindex", "0" );
4110
            .first().attr( "tabindex", "0" );
4111
 
4111
 
4112
        // hide header close link for single selects
4112
        // hide header close link for single selects
4113
        if( !this.isMultiple ){
4113
        if( !this.isMultiple ){
4114
            this.headerClose.hide();
4114
            this.headerClose.hide();
4115
        }
4115
        }
4116
 
4116
 
4117
        // hide header if it's not a multiselect and there's no placeholder
4117
        // hide header if it's not a multiselect and there's no placeholder
4118
        if( !this.isMultiple && !placeholder.length ){
4118
        if( !this.isMultiple && !placeholder.length ){
4119
            this.header.hide();
4119
            this.header.hide();
4120
        } else {
4120
        } else {
4121
            this.headerTitle.text( this.placeholder );
4121
            this.headerTitle.text( this.placeholder );
4122
        }
4122
        }
4123
 
4123
 
4124
        //now populated, create listview
4124
        //now populated, create listview
4125
        self.list.listview();
4125
        self.list.listview();
4126
    },
4126
    },
4127
 
4127
 
4128
    refresh: function( forceRebuild ){
4128
    refresh: function( forceRebuild ){
4129
        var self = this,
4129
        var self = this,
4130
            select = this.element,
4130
            select = this.element,
4131
            isMultiple = this.isMultiple,
4131
            isMultiple = this.isMultiple,
4132
            options = this.optionElems = select.find("option"),
4132
            options = this.optionElems = select.find("option"),
4133
            selected = options.filter(":selected"),
4133
            selected = options.filter(":selected"),
4134
 
4134
 
4135
            // return an array of all selected index's
4135
            // return an array of all selected index's
4136
            indicies = selected.map(function(){
4136
            indicies = selected.map(function(){
4137
                return options.index( this );
4137
                return options.index( this );
4138
            }).get();
4138
            }).get();
4139
 
4139
 
4140
        if( !self.options.nativeMenu && ( forceRebuild || select[0].options.length != self.list.find('li').length )){
4140
        if( !self.options.nativeMenu && ( forceRebuild || select[0].options.length != self.list.find('li').length )){
4141
            self._buildList();
4141
            self._buildList();
4142
        }
4142
        }
4143
 
4143
 
4144
        self.button
4144
        self.button
4145
            .find( ".ui-btn-text" )
4145
            .find( ".ui-btn-text" )
4146
            .text(function(){
4146
            .text(function(){
4147
                if( !isMultiple ){
4147
                if( !isMultiple ){
4148
                    return selected.text();
4148
                    return selected.text();
4149
                }
4149
                }
4150
 
4150
 
4151
                return selected.length ?
4151
                return selected.length ?
4152
                    selected.map(function(){ return $(this).text(); }).get().join(', ') :
4152
                    selected.map(function(){ return $(this).text(); }).get().join(', ') :
4153
                    self.placeholder;
4153
                    self.placeholder;
4154
            });
4154
            });
4155
 
4155
 
4156
        // multiple count inside button
4156
        // multiple count inside button
4157
        if( isMultiple ){
4157
        if( isMultiple ){
4158
            self.buttonCount[ selected.length > 1 ? 'show' : 'hide' ]().text( selected.length );
4158
            self.buttonCount[ selected.length > 1 ? 'show' : 'hide' ]().text( selected.length );
4159
        }
4159
        }
4160
 
4160
 
4161
        if( !self.options.nativeMenu ){
4161
        if( !self.options.nativeMenu ){
4162
            self.list
4162
            self.list
4163
                .find( 'li:not(.ui-li-divider)' )
4163
                .find( 'li:not(.ui-li-divider)' )
4164
                .removeClass( $.mobile.activeBtnClass )
4164
                .removeClass( $.mobile.activeBtnClass )
4165
                .attr( 'aria-selected', false )
4165
                .attr( 'aria-selected', false )
4166
                .each(function( i ){
4166
                .each(function( i ){
4167
                    if( $.inArray(i, indicies) > -1 ){
4167
                    if( $.inArray(i, indicies) > -1 ){
4168
                        var item = $(this).addClass( $.mobile.activeBtnClass );
4168
                        var item = $(this).addClass( $.mobile.activeBtnClass );
4169
 
4169
 
4170
                        // aria selected attr
4170
                        // aria selected attr
4171
                        item.find( 'a' ).attr( 'aria-selected', true );
4171
                        item.find( 'a' ).attr( 'aria-selected', true );
4172
 
4172
 
4173
                        // multiple selects: add the "on" checkbox state to the icon
4173
                        // multiple selects: add the "on" checkbox state to the icon
4174
                        if( isMultiple ){
4174
                        if( isMultiple ){
4175
                            item.find('.ui-icon').removeClass('ui-icon-checkbox-off').addClass('ui-icon-checkbox-on');
4175
                            item.find('.ui-icon').removeClass('ui-icon-checkbox-off').addClass('ui-icon-checkbox-on');
4176
                        }
4176
                        }
4177
                    }
4177
                    }
4178
                });
4178
                });
4179
        }
4179
        }
4180
    },
4180
    },
4181
 
4181
 
4182
    open: function(){
4182
    open: function(){
4183
        if( this.options.disabled || this.options.nativeMenu ){ return; }
4183
        if( this.options.disabled || this.options.nativeMenu ){ return; }
4184
 
4184
 
4185
        var self = this,
4185
        var self = this,
4186
            menuHeight = self.list.parent().outerHeight(),
4186
            menuHeight = self.list.parent().outerHeight(),
4187
            menuWidth = self.list.parent().outerWidth(),
4187
            menuWidth = self.list.parent().outerWidth(),
4188
            scrollTop = $(window).scrollTop(),
4188
            scrollTop = $(window).scrollTop(),
4189
            btnOffset = self.button.offset().top,
4189
            btnOffset = self.button.offset().top,
4190
            screenHeight = window.innerHeight,
4190
            screenHeight = window.innerHeight,
4191
            screenWidth = window.innerWidth;
4191
            screenWidth = window.innerWidth;
4192
 
4192
 
4193
        //add active class to button
4193
        //add active class to button
4194
        self.button.addClass( $.mobile.activeBtnClass );
4194
        self.button.addClass( $.mobile.activeBtnClass );
4195
 
4195
 
4196
        //remove after delay
4196
        //remove after delay
4197
        setTimeout(function(){
4197
        setTimeout(function(){
4198
            self.button.removeClass( $.mobile.activeBtnClass );
4198
            self.button.removeClass( $.mobile.activeBtnClass );
4199
        }, 300);
4199
        }, 300);
4200
 
4200
 
4201
        function focusMenuItem(){
4201
        function focusMenuItem(){
4202
            self.list.find( ".ui-btn-active" ).focus();
4202
            self.list.find( ".ui-btn-active" ).focus();
4203
        }
4203
        }
4204
 
4204
 
4205
        if( menuHeight > screenHeight - 80 || !$.support.scrollTop ){
4205
        if( menuHeight > screenHeight - 80 || !$.support.scrollTop ){
4206
 
4206
 
4207
            //for webos (set lastscroll using button offset)
4207
            //for webos (set lastscroll using button offset)
4208
            if( scrollTop == 0 && btnOffset > screenHeight ){
4208
            if( scrollTop == 0 && btnOffset > screenHeight ){
4209
                self.thisPage.one('pagehide',function(){
4209
                self.thisPage.one('pagehide',function(){
4210
                    $(this).jqmData('lastScroll', btnOffset);
4210
                    $(this).jqmData('lastScroll', btnOffset);
4211
                });
4211
                });
4212
            }
4212
            }
4213
 
4213
 
4214
            self.menuPage.one('pageshow', function() {
4214
            self.menuPage.one('pageshow', function() {
4215
                // silentScroll() is called whenever a page is shown to restore
4215
                // silentScroll() is called whenever a page is shown to restore
4216
                // any previous scroll position the page may have had. We need to
4216
                // any previous scroll position the page may have had. We need to
4217
                // wait for the "silentscroll" event before setting focus to avoid
4217
                // wait for the "silentscroll" event before setting focus to avoid
4218
                // the browser's "feature" which offsets rendering to make sure
4218
                // the browser's "feature" which offsets rendering to make sure
4219
                // whatever has focus is in view.
4219
                // whatever has focus is in view.
4220
                $(window).one("silentscroll", function(){ focusMenuItem(); });
4220
                $(window).one("silentscroll", function(){ focusMenuItem(); });
4221
            });
4221
            });
4222
 
4222
 
4223
            self.menuType = "page";
4223
            self.menuType = "page";
4224
            self.menuPageContent.append( self.list );
4224
            self.menuPageContent.append( self.list );
4225
            $.mobile.changePage( self.menuPage, { transition: 'pop' } );
4225
            $.mobile.changePage( self.menuPage, { transition: 'pop' } );
4226
        }
4226
        }
4227
        else {
4227
        else {
4228
            self.menuType = "overlay";
4228
            self.menuType = "overlay";
4229
 
4229
 
4230
            self.screen
4230
            self.screen
4231
                .height( $(document).height() )
4231
                .height( $(document).height() )
4232
                .removeClass('ui-screen-hidden');
4232
                .removeClass('ui-screen-hidden');
4233
 
4233
 
4234
            //try and center the overlay over the button
4234
            //try and center the overlay over the button
4235
            var roomtop = btnOffset - scrollTop,
4235
            var roomtop = btnOffset - scrollTop,
4236
                roombot = scrollTop + screenHeight - btnOffset,
4236
                roombot = scrollTop + screenHeight - btnOffset,
4237
                halfheight = menuHeight / 2,
4237
                halfheight = menuHeight / 2,
4238
                maxwidth = parseFloat(self.list.parent().css('max-width')),
4238
                maxwidth = parseFloat(self.list.parent().css('max-width')),
4239
                newtop, newleft;
4239
                newtop, newleft;
4240
 
4240
 
4241
            if( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ){
4241
            if( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ){
4242
                newtop = btnOffset + ( self.button.outerHeight() / 2 ) - halfheight;
4242
                newtop = btnOffset + ( self.button.outerHeight() / 2 ) - halfheight;
4243
            }
4243
            }
4244
            else{
4244
            else{
4245
                //30px tolerance off the edges
4245
                //30px tolerance off the edges
4246
                newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
4246
                newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
4247
            }
4247
            }
4248
 
4248
 
4249
            // if the menuwidth is smaller than the screen center is
4249
            // if the menuwidth is smaller than the screen center is
4250
            if (menuWidth < maxwidth) {
4250
            if (menuWidth < maxwidth) {
4251
                newleft = (screenWidth - menuWidth) / 2;
4251
                newleft = (screenWidth - menuWidth) / 2;
4252
            } else { //otherwise insure a >= 30px offset from the left
4252
            } else { //otherwise insure a >= 30px offset from the left
4253
                newleft = self.button.offset().left + self.button.outerWidth() / 2 - menuWidth / 2;
4253
                newleft = self.button.offset().left + self.button.outerWidth() / 2 - menuWidth / 2;
4254
                // 30px tolerance off the edges
4254
                // 30px tolerance off the edges
4255
                if (newleft < 30) {
4255
                if (newleft < 30) {
4256
                    newleft = 30;
4256
                    newleft = 30;
4257
                } else if ((newleft + menuWidth) > screenWidth) {
4257
                } else if ((newleft + menuWidth) > screenWidth) {
4258
                    newleft = screenWidth - menuWidth - 30;
4258
                    newleft = screenWidth - menuWidth - 30;
4259
                }
4259
                }
4260
            }
4260
            }
4261
 
4261
 
4262
            self.listbox
4262
            self.listbox
4263
                .append( self.list )
4263
                .append( self.list )
4264
                .removeClass( "ui-selectmenu-hidden" )
4264
                .removeClass( "ui-selectmenu-hidden" )
4265
                .css({
4265
                .css({
4266
                    top: newtop,
4266
                    top: newtop,
4267
                    left: newleft
4267
                    left: newleft
4268
                })
4268
                })
4269
                .addClass("in");
4269
                .addClass("in");
4270
 
4270
 
4271
            focusMenuItem();
4271
            focusMenuItem();
4272
        }
4272
        }
4273
 
4273
 
4274
        // wait before the dialog can be closed
4274
        // wait before the dialog can be closed
4275
        setTimeout(function(){
4275
        setTimeout(function(){
4276
            self.isOpen = true;
4276
            self.isOpen = true;
4277
        }, 400);
4277
        }, 400);
4278
    },
4278
    },
4279
 
4279
 
4280
    close: function(){
4280
    close: function(){
4281
        if( this.options.disabled || !this.isOpen || this.options.nativeMenu ){ return; }
4281
        if( this.options.disabled || !this.isOpen || this.options.nativeMenu ){ return; }
4282
        var self = this;
4282
        var self = this;
4283
 
4283
 
4284
        function focusButton(){
4284
        function focusButton(){
4285
            setTimeout(function(){
4285
            setTimeout(function(){
4286
                self.button.focus();
4286
                self.button.focus();
4287
            }, 40);
4287
            }, 40);
4288
 
4288
 
4289
            self.listbox.removeAttr('style').append( self.list );
4289
            self.listbox.removeAttr('style').append( self.list );
4290
        }
4290
        }
4291
 
4291
 
4292
        if(self.menuType == "page"){
4292
        if(self.menuType == "page"){
4293
            // button refocus ensures proper height calculation
4293
            // button refocus ensures proper height calculation
4294
            // by removing the inline style and ensuring page inclusion
4294
            // by removing the inline style and ensuring page inclusion
4295
            self.menuPage.one("pagehide", focusButton);
4295
            self.menuPage.one("pagehide", focusButton);
4296
 
4296
 
4297
            // doesn't solve the possible issue with calling change page
4297
            // doesn't solve the possible issue with calling change page
4298
            // where the objects don't define data urls which prevents dialog key
4298
            // where the objects don't define data urls which prevents dialog key
4299
            // stripping - changePage has incoming refactor
4299
            // stripping - changePage has incoming refactor
4300
            window.history.back();
4300
            window.history.back();
4301
        }
4301
        }
4302
        else{
4302
        else{
4303
            self.screen.addClass( "ui-screen-hidden" );
4303
            self.screen.addClass( "ui-screen-hidden" );
4304
            self.listbox.addClass( "ui-selectmenu-hidden" ).removeAttr( "style" ).removeClass("in");
4304
            self.listbox.addClass( "ui-selectmenu-hidden" ).removeAttr( "style" ).removeClass("in");
4305
            focusButton();
4305
            focusButton();
4306
        }
4306
        }
4307
 
4307
 
4308
        // allow the dialog to be closed again
4308
        // allow the dialog to be closed again
4309
        this.isOpen = false;
4309
        this.isOpen = false;
4310
    },
4310
    },
4311
 
4311
 
4312
    disable: function(){
4312
    disable: function(){
4313
        this.element.attr("disabled",true);
4313
        this.element.attr("disabled",true);
4314
        this.button.addClass('ui-disabled').attr("aria-disabled", true);
4314
        this.button.addClass('ui-disabled').attr("aria-disabled", true);
4315
        return this._setOption( "disabled", true );
4315
        return this._setOption( "disabled", true );
4316
    },
4316
    },
4317
 
4317
 
4318
    enable: function(){
4318
    enable: function(){
4319
        this.element.attr("disabled",false);
4319
        this.element.attr("disabled",false);
4320
        this.button.removeClass('ui-disabled').attr("aria-disabled", false);
4320
        this.button.removeClass('ui-disabled').attr("aria-disabled", false);
4321
        return this._setOption( "disabled", false );
4321
        return this._setOption( "disabled", false );
4322
    }
4322
    }
4323
});
4323
});
4324
})( jQuery );
4324
})( jQuery );
4325
 
4325
 
4326
/*
4326
/*
4327
* jQuery Mobile Framework : plugin for making button-like links
4327
* jQuery Mobile Framework : plugin for making button-like links
4328
* Copyright (c) jQuery Project
4328
* Copyright (c) jQuery Project
4329
* Dual licensed under the MIT or GPL Version 2 licenses.
4329
* Dual licensed under the MIT or GPL Version 2 licenses.
4330
* http://jquery.org/license
4330
* http://jquery.org/license
4331
*/
4331
*/
4332
( function( $, undefined ) {
4332
( function( $, undefined ) {
4333
 
4333
 
4334
$.fn.buttonMarkup = function( options ) {
4334
$.fn.buttonMarkup = function( options ) {
4335
    return this.each( function() {
4335
    return this.each( function() {
4336
        var el = $( this ),
4336
        var el = $( this ),
4337
            o = $.extend( {}, $.fn.buttonMarkup.defaults, el.jqmData(), options ),
4337
            o = $.extend( {}, $.fn.buttonMarkup.defaults, el.jqmData(), options ),
4338
 
4338
 
4339
            // Classes Defined
4339
            // Classes Defined
4340
            buttonClass,
4340
            buttonClass,
4341
            innerClass = "ui-btn-inner",
4341
            innerClass = "ui-btn-inner",
4342
            iconClass;
4342
            iconClass;
4343
 
4343
 
4344
        if ( attachEvents ) {
4344
        if ( attachEvents ) {
4345
            attachEvents();
4345
            attachEvents();
4346
        }
4346
        }
4347
 
4347
 
4348
        // if not, try to find closest theme container
4348
        // if not, try to find closest theme container
4349
        if ( !o.theme ) {
4349
        if ( !o.theme ) {
4350
            var themedParent = el.closest( "[class*='ui-bar-'],[class*='ui-body-']" );
4350
            var themedParent = el.closest( "[class*='ui-bar-'],[class*='ui-body-']" );
4351
            o.theme = themedParent.length ?
4351
            o.theme = themedParent.length ?
4352
                /ui-(bar|body)-([a-z])/.exec( themedParent.attr( "class" ) )[2] :
4352
                /ui-(bar|body)-([a-z])/.exec( themedParent.attr( "class" ) )[2] :
4353
                "c";
4353
                "c";
4354
        }
4354
        }
4355
 
4355
 
4356
        buttonClass = "ui-btn ui-btn-up-" + o.theme;
4356
        buttonClass = "ui-btn ui-btn-up-" + o.theme;
4357
 
4357
 
4358
        if ( o.inline ) {
4358
        if ( o.inline ) {
4359
            buttonClass += " ui-btn-inline";
4359
            buttonClass += " ui-btn-inline";
4360
        }
4360
        }
4361
 
4361
 
4362
        if ( o.icon ) {
4362
        if ( o.icon ) {
4363
            o.icon = "ui-icon-" + o.icon;
4363
            o.icon = "ui-icon-" + o.icon;
4364
            o.iconpos = o.iconpos || "left";
4364
            o.iconpos = o.iconpos || "left";
4365
 
4365
 
4366
            iconClass = "ui-icon " + o.icon;
4366
            iconClass = "ui-icon " + o.icon;
4367
 
4367
 
4368
            if ( o.shadow ) {
4368
            if ( o.shadow ) {
4369
                iconClass += " ui-icon-shadow";
4369
                iconClass += " ui-icon-shadow";
4370
            }
4370
            }
4371
        }
4371
        }
4372
 
4372
 
4373
        if ( o.iconpos ) {
4373
        if ( o.iconpos ) {
4374
            buttonClass += " ui-btn-icon-" + o.iconpos;
4374
            buttonClass += " ui-btn-icon-" + o.iconpos;
4375
 
4375
 
4376
            if ( o.iconpos == "notext" && !el.attr( "title" ) ) {
4376
            if ( o.iconpos == "notext" && !el.attr( "title" ) ) {
4377
                el.attr( "title", el.text() );
4377
                el.attr( "title", el.text() );
4378
            }
4378
            }
4379
        }
4379
        }
4380
 
4380
 
4381
        if ( o.corners ) {
4381
        if ( o.corners ) {
4382
            buttonClass += " ui-btn-corner-all";
4382
            buttonClass += " ui-btn-corner-all";
4383
            innerClass += " ui-btn-corner-all";
4383
            innerClass += " ui-btn-corner-all";
4384
        }
4384
        }
4385
 
4385
 
4386
        if ( o.shadow ) {
4386
        if ( o.shadow ) {
4387
            buttonClass += " ui-shadow";
4387
            buttonClass += " ui-shadow";
4388
        }
4388
        }
4389
 
4389
 
4390
        el
4390
        el
4391
            .attr( "data-" + $.mobile.ns + "theme", o.theme )
4391
            .attr( "data-" + $.mobile.ns + "theme", o.theme )
4392
            .addClass( buttonClass );
4392
            .addClass( buttonClass );
4393
 
4393
 
4394
        var wrap = ( "<D class='" + innerClass + "'><D class='ui-btn-text'></D>" +
4394
        var wrap = ( "<D class='" + innerClass + "'><D class='ui-btn-text'></D>" +
4395
            ( o.icon ? "<span class='" + iconClass + "'></span>" : "" ) +
4395
            ( o.icon ? "<span class='" + iconClass + "'></span>" : "" ) +
4396
            "</D>" ).replace( /D/g, o.wrapperEls );
4396
            "</D>" ).replace( /D/g, o.wrapperEls );
4397
 
4397
 
4398
        el.wrapInner( wrap );
4398
        el.wrapInner( wrap );
4399
    });
4399
    });
4400
};
4400
};
4401
 
4401
 
4402
$.fn.buttonMarkup.defaults = {
4402
$.fn.buttonMarkup.defaults = {
4403
    corners: true,
4403
    corners: true,
4404
    shadow: true,
4404
    shadow: true,
4405
    iconshadow: true,
4405
    iconshadow: true,
4406
    wrapperEls: "span"
4406
    wrapperEls: "span"
4407
};
4407
};
4408
 
4408
 
4409
function closestEnabledButton( element )
4409
function closestEnabledButton( element )
4410
{
4410
{
4411
    while ( element ) {
4411
    while ( element ) {
4412
        var $ele = $( element );
4412
        var $ele = $( element );
4413
        if ( $ele.hasClass( "ui-btn" ) && !$ele.hasClass( "ui-disabled" ) ) {
4413
        if ( $ele.hasClass( "ui-btn" ) && !$ele.hasClass( "ui-disabled" ) ) {
4414
            break;
4414
            break;
4415
        }
4415
        }
4416
        element = element.parentNode;
4416
        element = element.parentNode;
4417
    }
4417
    }
4418
    return element;
4418
    return element;
4419
}
4419
}
4420
 
4420
 
4421
var attachEvents = function() {
4421
var attachEvents = function() {
4422
    $( document ).bind( {
4422
    $( document ).bind( {
4423
        "vmousedown": function( event ) {
4423
        "vmousedown": function( event ) {
4424
            var btn = closestEnabledButton( event.target );
4424
            var btn = closestEnabledButton( event.target );
4425
            if ( btn ) {
4425
            if ( btn ) {
4426
                var $btn = $( btn ),
4426
                var $btn = $( btn ),
4427
                    theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
4427
                    theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
4428
                $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
4428
                $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
4429
            }
4429
            }
4430
        },
4430
        },
4431
        "vmousecancel vmouseup": function( event ) {
4431
        "vmousecancel vmouseup": function( event ) {
4432
            var btn = closestEnabledButton( event.target );
4432
            var btn = closestEnabledButton( event.target );
4433
            if ( btn ) {
4433
            if ( btn ) {
4434
                var $btn = $( btn ),
4434
                var $btn = $( btn ),
4435
                    theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
4435
                    theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
4436
                $btn.removeClass( "ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
4436
                $btn.removeClass( "ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
4437
            }
4437
            }
4438
        },
4438
        },
4439
        "vmouseover focus": function( event ) {
4439
        "vmouseover focus": function( event ) {
4440
            var btn = closestEnabledButton( event.target );
4440
            var btn = closestEnabledButton( event.target );
4441
            if ( btn ) {
4441
            if ( btn ) {
4442
                var $btn = $( btn ),
4442
                var $btn = $( btn ),
4443
                    theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
4443
                    theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
4444
                $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
4444
                $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
4445
            }
4445
            }
4446
        },
4446
        },
4447
        "vmouseout blur": function( event ) {
4447
        "vmouseout blur": function( event ) {
4448
            var btn = closestEnabledButton( event.target );
4448
            var btn = closestEnabledButton( event.target );
4449
            if ( btn ) {
4449
            if ( btn ) {
4450
                var $btn = $( btn ),
4450
                var $btn = $( btn ),
4451
                    theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
4451
                    theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
4452
                $btn.removeClass( "ui-btn-hover-" + theme ).addClass( "ui-btn-up-" + theme );
4452
                $btn.removeClass( "ui-btn-hover-" + theme ).addClass( "ui-btn-up-" + theme );
4453
            }
4453
            }
4454
        }
4454
        }
4455
    });
4455
    });
4456
 
4456
 
4457
    attachEvents = null;
4457
    attachEvents = null;
4458
};
4458
};
4459
 
4459
 
4460
})( jQuery );
4460
})( jQuery );
4461
/*
4461
/*
4462
* jQuery Mobile Framework : "button" plugin - links that proxy to native input/buttons
4462
* jQuery Mobile Framework : "button" plugin - links that proxy to native input/buttons
4463
* Copyright (c) jQuery Project
4463
* Copyright (c) jQuery Project
4464
* Dual licensed under the MIT or GPL Version 2 licenses.
4464
* Dual licensed under the MIT or GPL Version 2 licenses.
4465
* http://jquery.org/license
4465
* http://jquery.org/license
4466
*/
4466
*/
4467
(function($, undefined ) {
4467
(function($, undefined ) {
4468
$.widget( "mobile.button", $.mobile.widget, {
4468
$.widget( "mobile.button", $.mobile.widget, {
4469
    options: {
4469
    options: {
4470
        theme: null,
4470
        theme: null,
4471
        icon: null,
4471
        icon: null,
4472
        iconpos: null,
4472
        iconpos: null,
4473
        inline: null,
4473
        inline: null,
4474
        corners: true,
4474
        corners: true,
4475
        shadow: true,
4475
        shadow: true,
4476
        iconshadow: true
4476
        iconshadow: true
4477
    },
4477
    },
4478
    _create: function(){
4478
    _create: function(){
4479
        var $el = this.element,
4479
        var $el = this.element,
4480
            o = this.options;
4480
            o = this.options;
4481
       
4481
       
4482
        //add ARIA role
4482
        //add ARIA role
4483
        this.button = $( "<div></div>" )
4483
        this.button = $( "<div></div>" )
4484
            .text( $el.text() || $el.val() )
4484
            .text( $el.text() || $el.val() )
4485
            .buttonMarkup({
4485
            .buttonMarkup({
4486
                theme: o.theme,
4486
                theme: o.theme,
4487
                icon: o.icon,
4487
                icon: o.icon,
4488
                iconpos: o.iconpos,
4488
                iconpos: o.iconpos,
4489
                inline: o.inline,
4489
                inline: o.inline,
4490
                corners: o.corners,
4490
                corners: o.corners,
4491
                shadow: o.shadow,
4491
                shadow: o.shadow,
4492
                iconshadow: o.iconshadow
4492
                iconshadow: o.iconshadow
4493
            })
4493
            })
4494
            .insertBefore( $el )
4494
            .insertBefore( $el )
4495
            .append( $el.addClass('ui-btn-hidden') );
4495
            .append( $el.addClass('ui-btn-hidden') );
4496
       
4496
       
4497
        //add hidden input during submit
4497
        //add hidden input during submit
4498
        var type = $el.attr('type');
4498
        var type = $el.attr('type');
4499
        if( type !== 'button' && type !== 'reset' ){
4499
        if( type !== 'button' && type !== 'reset' ){
4500
            $el.bind("vclick", function(){
4500
            $el.bind("vclick", function(){
4501
                var $buttonPlaceholder = $("<input>",
4501
                var $buttonPlaceholder = $("<input>",
4502
                        {type: "hidden", name: $el.attr("name"), value: $el.attr("value")})
4502
                        {type: "hidden", name: $el.attr("name"), value: $el.attr("value")})
4503
                        .insertBefore($el);
4503
                        .insertBefore($el);
4504
                       
4504
                       
4505
                //bind to doc to remove after submit handling   
4505
                //bind to doc to remove after submit handling   
4506
                $(document).submit(function(){
4506
                $(document).submit(function(){
4507
                     $buttonPlaceholder.remove();
4507
                     $buttonPlaceholder.remove();
4508
                });
4508
                });
4509
            });
4509
            });
4510
        }
4510
        }
4511
        this.refresh();
4511
        this.refresh();
4512
           
4512
           
4513
    },
4513
    },
4514
 
4514
 
4515
    enable: function(){
4515
    enable: function(){
4516
        this.element.attr("disabled", false);
4516
        this.element.attr("disabled", false);
4517
        this.button.removeClass("ui-disabled").attr("aria-disabled", false);
4517
        this.button.removeClass("ui-disabled").attr("aria-disabled", false);
4518
        return this._setOption("disabled", false);
4518
        return this._setOption("disabled", false);
4519
    },
4519
    },
4520
 
4520
 
4521
    disable: function(){
4521
    disable: function(){
4522
        this.element.attr("disabled", true);
4522
        this.element.attr("disabled", true);
4523
        this.button.addClass("ui-disabled").attr("aria-disabled", true);
4523
        this.button.addClass("ui-disabled").attr("aria-disabled", true);
4524
        return this._setOption("disabled", true);
4524
        return this._setOption("disabled", true);
4525
    },
4525
    },
4526
 
4526
 
4527
    refresh: function(){
4527
    refresh: function(){
4528
        if( this.element.attr('disabled') ){
4528
        if( this.element.attr('disabled') ){
4529
            this.disable();
4529
            this.disable();
4530
        }
4530
        }
4531
        else{
4531
        else{
4532
            this.enable();
4532
            this.enable();
4533
        }
4533
        }
4534
    }
4534
    }
4535
});
4535
});
4536
})( jQuery );/*
4536
})( jQuery );/*
4537
* jQuery Mobile Framework : "slider" plugin
4537
* jQuery Mobile Framework : "slider" plugin
4538
* Copyright (c) jQuery Project
4538
* Copyright (c) jQuery Project
4539
* Dual licensed under the MIT or GPL Version 2 licenses.
4539
* Dual licensed under the MIT or GPL Version 2 licenses.
4540
* http://jquery.org/license
4540
* http://jquery.org/license
4541
*/
4541
*/
4542
(function($, undefined ) {
4542
(function($, undefined ) {
4543
$.widget( "mobile.slider", $.mobile.widget, {
4543
$.widget( "mobile.slider", $.mobile.widget, {
4544
    options: {
4544
    options: {
4545
        theme: null,
4545
        theme: null,
4546
        trackTheme: null,
4546
        trackTheme: null,
4547
        disabled: false
4547
        disabled: false
4548
    },
4548
    },
4549
    _create: function(){
4549
    _create: function(){
4550
        var self = this,
4550
        var self = this,
4551
 
4551
 
4552
            control = this.element,
4552
            control = this.element,
4553
 
4553
 
4554
            parentTheme = control.parents('[class*=ui-bar-],[class*=ui-body-]').eq(0),
4554
            parentTheme = control.parents('[class*=ui-bar-],[class*=ui-body-]').eq(0),
4555
 
4555
 
4556
            parentTheme = parentTheme.length ? parentTheme.attr('class').match(/ui-(bar|body)-([a-z])/)[2] : 'c',
4556
            parentTheme = parentTheme.length ? parentTheme.attr('class').match(/ui-(bar|body)-([a-z])/)[2] : 'c',
4557
 
4557
 
4558
            theme = this.options.theme ? this.options.theme : parentTheme,
4558
            theme = this.options.theme ? this.options.theme : parentTheme,
4559
 
4559
 
4560
            trackTheme = this.options.trackTheme ? this.options.trackTheme : parentTheme,
4560
            trackTheme = this.options.trackTheme ? this.options.trackTheme : parentTheme,
4561
 
4561
 
4562
            cType = control[0].nodeName.toLowerCase(),
4562
            cType = control[0].nodeName.toLowerCase(),
4563
            selectClass = (cType == 'select') ? 'ui-slider-switch' : '',
4563
            selectClass = (cType == 'select') ? 'ui-slider-switch' : '',
4564
            controlID = control.attr('id'),
4564
            controlID = control.attr('id'),
4565
            labelID = controlID + '-label',
4565
            labelID = controlID + '-label',
4566
            label = $('[for="'+ controlID +'"]').attr('id',labelID),
4566
            label = $('[for="'+ controlID +'"]').attr('id',labelID),
4567
            val = function(){
4567
            val = function(){
4568
                return (cType == 'input') ? parseFloat(control.val()) : control[0].selectedIndex;
4568
                return (cType == 'input') ? parseFloat(control.val()) : control[0].selectedIndex;
4569
            },
4569
            },
4570
            min = (cType == 'input') ? parseFloat(control.attr('min')) : 0,
4570
            min = (cType == 'input') ? parseFloat(control.attr('min')) : 0,
4571
            max = (cType == 'input') ? parseFloat(control.attr('max')) : control.find('option').length-1,
4571
            max = (cType == 'input') ? parseFloat(control.attr('max')) : control.find('option').length-1,
4572
            step = window.parseFloat(control.attr('step') || 1),
4572
            step = window.parseFloat(control.attr('step') || 1),
4573
            slider = $('<div class="ui-slider '+ selectClass +' ui-btn-down-'+ trackTheme+' ui-btn-corner-all" role="application"></div>'),
4573
            slider = $('<div class="ui-slider '+ selectClass +' ui-btn-down-'+ trackTheme+' ui-btn-corner-all" role="application"></div>'),
4574
            handle = $('<a href="#" class="ui-slider-handle"></a>')
4574
            handle = $('<a href="#" class="ui-slider-handle"></a>')
4575
                .appendTo(slider)
4575
                .appendTo(slider)
4576
                .buttonMarkup({corners: true, theme: theme, shadow: true})
4576
                .buttonMarkup({corners: true, theme: theme, shadow: true})
4577
                .attr({
4577
                .attr({
4578
                    'role': 'slider',
4578
                    'role': 'slider',
4579
                    'aria-valuemin': min,
4579
                    'aria-valuemin': min,
4580
                    'aria-valuemax': max,
4580
                    'aria-valuemax': max,
4581
                    'aria-valuenow': val(),
4581
                    'aria-valuenow': val(),
4582
                    'aria-valuetext': val(),
4582
                    'aria-valuetext': val(),
4583
                    'title': val(),
4583
                    'title': val(),
4584
                    'aria-labelledby': labelID
4584
                    'aria-labelledby': labelID
4585
                });
4585
                });
4586
 
4586
 
4587
        $.extend(this, {
4587
        $.extend(this, {
4588
            slider: slider,
4588
            slider: slider,
4589
            handle: handle,
4589
            handle: handle,
4590
            dragging: false,
4590
            dragging: false,
4591
            beforeStart: null
4591
            beforeStart: null
4592
        });
4592
        });
4593
 
4593
 
4594
        if(cType == 'select'){
4594
        if(cType == 'select'){
4595
            slider.wrapInner('<div class="ui-slider-inneroffset"></div>');
4595
            slider.wrapInner('<div class="ui-slider-inneroffset"></div>');
4596
            var options = control.find('option');
4596
            var options = control.find('option');
4597
 
4597
 
4598
            control.find('option').each(function(i){
4598
            control.find('option').each(function(i){
4599
                var side = (i==0) ?'b':'a',
4599
                var side = (i==0) ?'b':'a',
4600
                    corners = (i==0) ? 'right' :'left',
4600
                    corners = (i==0) ? 'right' :'left',
4601
                    theme = (i==0) ? ' ui-btn-down-' + trackTheme :' ui-btn-active';
4601
                    theme = (i==0) ? ' ui-btn-down-' + trackTheme :' ui-btn-active';
4602
                $('<div class="ui-slider-labelbg ui-slider-labelbg-'+ side + theme +' ui-btn-corner-'+ corners+'"></div>').prependTo(slider);
4602
                $('<div class="ui-slider-labelbg ui-slider-labelbg-'+ side + theme +' ui-btn-corner-'+ corners+'"></div>').prependTo(slider);
4603
                $('<span class="ui-slider-label ui-slider-label-'+ side + theme +' ui-btn-corner-'+ corners+'" role="img">'+$(this).text()+'</span>').prependTo(handle);
4603
                $('<span class="ui-slider-label ui-slider-label-'+ side + theme +' ui-btn-corner-'+ corners+'" role="img">'+$(this).text()+'</span>').prependTo(handle);
4604
            });
4604
            });
4605
 
4605
 
4606
        }
4606
        }
4607
 
4607
 
4608
        label.addClass('ui-slider');
4608
        label.addClass('ui-slider');
4609
 
4609
 
4610
        // monitor the input for updated values
4610
        // monitor the input for updated values
4611
        control
4611
        control
4612
            .addClass((cType == 'input') ? 'ui-slider-input' : 'ui-slider-switch')
4612
            .addClass((cType == 'input') ? 'ui-slider-input' : 'ui-slider-switch')
4613
            .change(function(){
4613
            .change(function(){
4614
                self.refresh( val(), true );
4614
                self.refresh( val(), true );
4615
            })
4615
            })
4616
            .keyup(function(){ // necessary?
4616
            .keyup(function(){ // necessary?
4617
                self.refresh( val(), true, true );
4617
                self.refresh( val(), true, true );
4618
            })
4618
            })
4619
            .blur(function(){
4619
            .blur(function(){
4620
                self.refresh( val(), true );
4620
                self.refresh( val(), true );
4621
            });
4621
            });
4622
 
4622
 
4623
        // prevent screen drag when slider activated
4623
        // prevent screen drag when slider activated
4624
        $(document).bind( "vmousemove", function(event){
4624
        $(document).bind( "vmousemove", function(event){
4625
            if ( self.dragging ) {
4625
            if ( self.dragging ) {
4626
                self.refresh( event );
4626
                self.refresh( event );
4627
                return false;
4627
                return false;
4628
            }
4628
            }
4629
        });
4629
        });
4630
 
4630
 
4631
        slider
4631
        slider
4632
            .bind( "vmousedown", function(event){
4632
            .bind( "vmousedown", function(event){
4633
                self.dragging = true;
4633
                self.dragging = true;
4634
                if ( cType === "select" ) {
4634
                if ( cType === "select" ) {
4635
                    self.beforeStart = control[0].selectedIndex;
4635
                    self.beforeStart = control[0].selectedIndex;
4636
                }
4636
                }
4637
                self.refresh( event );
4637
                self.refresh( event );
4638
                return false;
4638
                return false;
4639
            });
4639
            });
4640
 
4640
 
4641
        slider
4641
        slider
4642
            .add(document)
4642
            .add(document)
4643
            .bind( "vmouseup", function(){
4643
            .bind( "vmouseup", function(){
4644
                if ( self.dragging ) {
4644
                if ( self.dragging ) {
4645
                    self.dragging = false;
4645
                    self.dragging = false;
4646
                    if ( cType === "select" ) {
4646
                    if ( cType === "select" ) {
4647
                        if ( self.beforeStart === control[0].selectedIndex ) {
4647
                        if ( self.beforeStart === control[0].selectedIndex ) {
4648
                            //tap occurred, but value didn't change. flip it!
4648
                            //tap occurred, but value didn't change. flip it!
4649
                            self.refresh( self.beforeStart === 0 ? 1 : 0 );
4649
                            self.refresh( self.beforeStart === 0 ? 1 : 0 );
4650
                        }
4650
                        }
4651
                        var curval = val();
4651
                        var curval = val();
4652
                        var snapped = Math.round( curval / (max - min) * 100 );
4652
                        var snapped = Math.round( curval / (max - min) * 100 );
4653
                        handle
4653
                        handle
4654
                            .addClass("ui-slider-handle-snapping")
4654
                            .addClass("ui-slider-handle-snapping")
4655
                            .css("left", snapped + "%")
4655
                            .css("left", snapped + "%")
4656
                            .animationComplete(function(){
4656
                            .animationComplete(function(){
4657
                                handle.removeClass("ui-slider-handle-snapping");
4657
                                handle.removeClass("ui-slider-handle-snapping");
4658
                            });
4658
                            });
4659
                    }
4659
                    }
4660
                    return false;
4660
                    return false;
4661
                }
4661
                }
4662
            });
4662
            });
4663
 
4663
 
4664
        slider.insertAfter(control);
4664
        slider.insertAfter(control);
4665
 
4665
 
4666
        // NOTE force focus on handle
4666
        // NOTE force focus on handle
4667
        this.handle
4667
        this.handle
4668
            .bind( "vmousedown", function(){
4668
            .bind( "vmousedown", function(){
4669
                $(this).focus();
4669
                $(this).focus();
4670
            })
4670
            })
4671
            .bind( "vclick", false );
4671
            .bind( "vclick", false );
4672
 
4672
 
4673
        this.handle
4673
        this.handle
4674
            .bind( "keydown", function( event ) {
4674
            .bind( "keydown", function( event ) {
4675
                var index = val();
4675
                var index = val();
4676
 
4676
 
4677
                if ( self.options.disabled ) {
4677
                if ( self.options.disabled ) {
4678
                    return;
4678
                    return;
4679
                }
4679
                }
4680
 
4680
 
4681
                // In all cases prevent the default and mark the handle as active
4681
                // In all cases prevent the default and mark the handle as active
4682
                switch ( event.keyCode ) {
4682
                switch ( event.keyCode ) {
4683
                 case $.mobile.keyCode.HOME:
4683
                 case $.mobile.keyCode.HOME:
4684
                 case $.mobile.keyCode.END:
4684
                 case $.mobile.keyCode.END:
4685
                 case $.mobile.keyCode.PAGE_UP:
4685
                 case $.mobile.keyCode.PAGE_UP:
4686
                 case $.mobile.keyCode.PAGE_DOWN:
4686
                 case $.mobile.keyCode.PAGE_DOWN:
4687
                 case $.mobile.keyCode.UP:
4687
                 case $.mobile.keyCode.UP:
4688
                 case $.mobile.keyCode.RIGHT:
4688
                 case $.mobile.keyCode.RIGHT:
4689
                 case $.mobile.keyCode.DOWN:
4689
                 case $.mobile.keyCode.DOWN:
4690
                 case $.mobile.keyCode.LEFT:
4690
                 case $.mobile.keyCode.LEFT:
4691
                    event.preventDefault();
4691
                    event.preventDefault();
4692
 
4692
 
4693
                    if ( !self._keySliding ) {
4693
                    if ( !self._keySliding ) {
4694
                        self._keySliding = true;
4694
                        self._keySliding = true;
4695
                        $( this ).addClass( "ui-state-active" );
4695
                        $( this ).addClass( "ui-state-active" );
4696
                    }
4696
                    }
4697
                    break;
4697
                    break;
4698
                }
4698
                }
4699
 
4699
 
4700
                // move the slider according to the keypress
4700
                // move the slider according to the keypress
4701
                switch ( event.keyCode ) {
4701
                switch ( event.keyCode ) {
4702
                 case $.mobile.keyCode.HOME:
4702
                 case $.mobile.keyCode.HOME:
4703
                    self.refresh(min);
4703
                    self.refresh(min);
4704
                    break;
4704
                    break;
4705
                 case $.mobile.keyCode.END:
4705
                 case $.mobile.keyCode.END:
4706
                    self.refresh(max);
4706
                    self.refresh(max);
4707
                    break;
4707
                    break;
4708
                 case $.mobile.keyCode.PAGE_UP:
4708
                 case $.mobile.keyCode.PAGE_UP:
4709
                 case $.mobile.keyCode.UP:
4709
                 case $.mobile.keyCode.UP:
4710
                 case $.mobile.keyCode.RIGHT:
4710
                 case $.mobile.keyCode.RIGHT:
4711
                    self.refresh(index + step);
4711
                    self.refresh(index + step);
4712
                    break;
4712
                    break;
4713
                 case $.mobile.keyCode.PAGE_DOWN:
4713
                 case $.mobile.keyCode.PAGE_DOWN:
4714
                 case $.mobile.keyCode.DOWN:
4714
                 case $.mobile.keyCode.DOWN:
4715
                 case $.mobile.keyCode.LEFT:
4715
                 case $.mobile.keyCode.LEFT:
4716
                    self.refresh(index - step);
4716
                    self.refresh(index - step);
4717
                    break;
4717
                    break;
4718
                }
4718
                }
4719
            }) // remove active mark
4719
            }) // remove active mark
4720
            .keyup(function( event ) {
4720
            .keyup(function( event ) {
4721
                if ( self._keySliding ) {
4721
                if ( self._keySliding ) {
4722
                    self._keySliding = false;
4722
                    self._keySliding = false;
4723
                    $( this ).removeClass( "ui-state-active" );
4723
                    $( this ).removeClass( "ui-state-active" );
4724
                }
4724
                }
4725
            });
4725
            });
4726
 
4726
 
4727
        this.refresh();
4727
        this.refresh();
4728
    },
4728
    },
4729
 
4729
 
4730
    refresh: function(val, isfromControl, preventInputUpdate){
4730
    refresh: function(val, isfromControl, preventInputUpdate){
4731
        if ( this.options.disabled ) { return; }
4731
        if ( this.options.disabled ) { return; }
4732
 
4732
 
4733
        var control = this.element, percent,
4733
        var control = this.element, percent,
4734
            cType = control[0].nodeName.toLowerCase(),
4734
            cType = control[0].nodeName.toLowerCase(),
4735
            min = (cType === "input") ? parseFloat(control.attr("min")) : 0,
4735
            min = (cType === "input") ? parseFloat(control.attr("min")) : 0,
4736
            max = (cType === "input") ? parseFloat(control.attr("max")) : control.find("option").length - 1;
4736
            max = (cType === "input") ? parseFloat(control.attr("max")) : control.find("option").length - 1;
4737
 
4737
 
4738
        if ( typeof val === "object" ) {
4738
        if ( typeof val === "object" ) {
4739
            var data = val,
4739
            var data = val,
4740
                // a slight tolerance helped get to the ends of the slider
4740
                // a slight tolerance helped get to the ends of the slider
4741
                tol = 8;
4741
                tol = 8;
4742
            if ( !this.dragging
4742
            if ( !this.dragging
4743
                    || data.pageX < this.slider.offset().left - tol
4743
                    || data.pageX < this.slider.offset().left - tol
4744
                    || data.pageX > this.slider.offset().left + this.slider.width() + tol ) {
4744
                    || data.pageX > this.slider.offset().left + this.slider.width() + tol ) {
4745
                return;
4745
                return;
4746
            }
4746
            }
4747
            percent = Math.round( ((data.pageX - this.slider.offset().left) / this.slider.width() ) * 100 );
4747
            percent = Math.round( ((data.pageX - this.slider.offset().left) / this.slider.width() ) * 100 );
4748
        } else {
4748
        } else {
4749
            if ( val == null ) {
4749
            if ( val == null ) {
4750
                val = (cType === "input") ? parseFloat(control.val()) : control[0].selectedIndex;
4750
                val = (cType === "input") ? parseFloat(control.val()) : control[0].selectedIndex;
4751
            }
4751
            }
4752
            percent = (parseFloat(val) - min) / (max - min) * 100;
4752
            percent = (parseFloat(val) - min) / (max - min) * 100;
4753
        }
4753
        }
4754
 
4754
 
4755
        if ( isNaN(percent) ) { return; }
4755
        if ( isNaN(percent) ) { return; }
4756
        if ( percent < 0 ) { percent = 0; }
4756
        if ( percent < 0 ) { percent = 0; }
4757
        if ( percent > 100 ) { percent = 100; }
4757
        if ( percent > 100 ) { percent = 100; }
4758
 
4758
 
4759
        var newval = Math.round( (percent / 100) * (max - min) ) + min;
4759
        var newval = Math.round( (percent / 100) * (max - min) ) + min;
4760
        if ( newval < min ) { newval = min; }
4760
        if ( newval < min ) { newval = min; }
4761
        if ( newval > max ) { newval = max; }
4761
        if ( newval > max ) { newval = max; }
4762
 
4762
 
4763
        //flip the stack of the bg colors
4763
        //flip the stack of the bg colors
4764
        if ( percent > 60 && cType === "select" ) {
4764
        if ( percent > 60 && cType === "select" ) {
4765
 
4765
 
4766
        }
4766
        }
4767
        this.handle.css("left", percent + "%");
4767
        this.handle.css("left", percent + "%");
4768
        this.handle.attr({
4768
        this.handle.attr({
4769
                "aria-valuenow": (cType === "input") ? newval : control.find("option").eq(newval).attr("value"),
4769
                "aria-valuenow": (cType === "input") ? newval : control.find("option").eq(newval).attr("value"),
4770
                "aria-valuetext": (cType === "input") ? newval : control.find("option").eq(newval).text(),
4770
                "aria-valuetext": (cType === "input") ? newval : control.find("option").eq(newval).text(),
4771
                title: newval
4771
                title: newval
4772
            });
4772
            });
4773
 
4773
 
4774
        // add/remove classes for flip toggle switch
4774
        // add/remove classes for flip toggle switch
4775
        if ( cType === "select" ) {
4775
        if ( cType === "select" ) {
4776
            if ( newval === 0 ) {
4776
            if ( newval === 0 ) {
4777
                this.slider.addClass("ui-slider-switch-a")
4777
                this.slider.addClass("ui-slider-switch-a")
4778
                    .removeClass("ui-slider-switch-b");
4778
                    .removeClass("ui-slider-switch-b");
4779
            } else {
4779
            } else {
4780
                this.slider.addClass("ui-slider-switch-b")
4780
                this.slider.addClass("ui-slider-switch-b")
4781
                    .removeClass("ui-slider-switch-a");
4781
                    .removeClass("ui-slider-switch-a");
4782
            }
4782
            }
4783
        }
4783
        }
4784
 
4784
 
4785
        if(!preventInputUpdate){
4785
        if(!preventInputUpdate){
4786
            // update control's value
4786
            // update control's value
4787
            if ( cType === "input" ) {
4787
            if ( cType === "input" ) {
4788
                control.val(newval);
4788
                control.val(newval);
4789
            } else {
4789
            } else {
4790
                control[ 0 ].selectedIndex = newval;
4790
                control[ 0 ].selectedIndex = newval;
4791
            }
4791
            }
4792
            if (!isfromControl) { control.trigger("change"); }
4792
            if (!isfromControl) { control.trigger("change"); }
4793
        }
4793
        }
4794
    },
4794
    },
4795
 
4795
 
4796
    enable: function(){
4796
    enable: function(){
4797
        this.element.attr("disabled", false);
4797
        this.element.attr("disabled", false);
4798
        this.slider.removeClass("ui-disabled").attr("aria-disabled", false);
4798
        this.slider.removeClass("ui-disabled").attr("aria-disabled", false);
4799
        return this._setOption("disabled", false);
4799
        return this._setOption("disabled", false);
4800
    },
4800
    },
4801
 
4801
 
4802
    disable: function(){
4802
    disable: function(){
4803
        this.element.attr("disabled", true);
4803
        this.element.attr("disabled", true);
4804
        this.slider.addClass("ui-disabled").attr("aria-disabled", true);
4804
        this.slider.addClass("ui-disabled").attr("aria-disabled", true);
4805
        return this._setOption("disabled", true);
4805
        return this._setOption("disabled", true);
4806
    }
4806
    }
4807
 
4807
 
4808
});
4808
});
4809
})( jQuery );
4809
})( jQuery );
4810
 
4810
 
4811
/*
4811
/*
4812
* jQuery Mobile Framework : "collapsible" plugin
4812
* jQuery Mobile Framework : "collapsible" plugin
4813
* Copyright (c) jQuery Project
4813
* Copyright (c) jQuery Project
4814
* Dual licensed under the MIT or GPL Version 2 licenses.
4814
* Dual licensed under the MIT or GPL Version 2 licenses.
4815
* http://jquery.org/license
4815
* http://jquery.org/license
4816
*/
4816
*/
4817
( function( $, undefined ) {
4817
( function( $, undefined ) {
4818
$.widget( "mobile.collapsible", $.mobile.widget, {
4818
$.widget( "mobile.collapsible", $.mobile.widget, {
4819
    options: {
4819
    options: {
4820
        expandCueText: " click to expand contents",
4820
        expandCueText: " click to expand contents",
4821
        collapseCueText: " click to collapse contents",
4821
        collapseCueText: " click to collapse contents",
4822
        collapsed: false,
4822
        collapsed: false,
4823
        heading: ">:header,>legend",
4823
        heading: ">:header,>legend",
4824
        theme: null,
4824
        theme: null,
4825
        iconTheme: "d"
4825
        iconTheme: "d"
4826
    },
4826
    },
4827
    _create: function() {
4827
    _create: function() {
4828
 
4828
 
4829
        var $el = this.element,
4829
        var $el = this.element,
4830
            o = this.options,
4830
            o = this.options,
4831
            collapsibleContain = $el.addClass( "ui-collapsible-contain" ),
4831
            collapsibleContain = $el.addClass( "ui-collapsible-contain" ),
4832
            collapsibleHeading = $el.find( o.heading ).eq( 0 ),
4832
            collapsibleHeading = $el.find( o.heading ).eq( 0 ),
4833
            collapsibleContent = collapsibleContain.wrapInner( '<div class="ui-collapsible-content"></div>' ).find( ".ui-collapsible-content" ),
4833
            collapsibleContent = collapsibleContain.wrapInner( '<div class="ui-collapsible-content"></div>' ).find( ".ui-collapsible-content" ),
4834
            collapsibleParent = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" );
4834
            collapsibleParent = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" );
4835
 
4835
 
4836
        //replace collapsibleHeading if it's a legend
4836
        //replace collapsibleHeading if it's a legend
4837
        if ( collapsibleHeading.is( "legend" ) ) {
4837
        if ( collapsibleHeading.is( "legend" ) ) {
4838
            collapsibleHeading = $( '<div role="heading">'+ collapsibleHeading.html() +"</div>" ).insertBefore( collapsibleHeading );
4838
            collapsibleHeading = $( '<div role="heading">'+ collapsibleHeading.html() +"</div>" ).insertBefore( collapsibleHeading );
4839
            collapsibleHeading.next().remove();
4839
            collapsibleHeading.next().remove();
4840
        }
4840
        }
4841
 
4841
 
4842
        collapsibleHeading
4842
        collapsibleHeading
4843
            //drop heading in before content
4843
            //drop heading in before content
4844
            .insertBefore( collapsibleContent )
4844
            .insertBefore( collapsibleContent )
4845
            //modify markup & attributes
4845
            //modify markup & attributes
4846
            .addClass( "ui-collapsible-heading" )
4846
            .addClass( "ui-collapsible-heading" )
4847
            .append( '<span class="ui-collapsible-heading-status"></span>' )
4847
            .append( '<span class="ui-collapsible-heading-status"></span>' )
4848
            .wrapInner( '<a href="#" class="ui-collapsible-heading-toggle"></a>' )
4848
            .wrapInner( '<a href="#" class="ui-collapsible-heading-toggle"></a>' )
4849
            .find( "a:eq(0)" )
4849
            .find( "a:eq(0)" )
4850
                .buttonMarkup( {
4850
                .buttonMarkup( {
4851
                    shadow: !collapsibleParent.length,
4851
                    shadow: !collapsibleParent.length,
4852
                    corners: false,
4852
                    corners: false,
4853
                    iconPos: "left",
4853
                    iconPos: "left",
4854
                    icon: "plus",
4854
                    icon: "plus",
4855
                    theme: o.theme
4855
                    theme: o.theme
4856
                } )
4856
                } )
4857
                .find( ".ui-icon" )
4857
                .find( ".ui-icon" )
4858
                    .removeAttr( "class" )
4858
                    .removeAttr( "class" )
4859
                    .buttonMarkup( {
4859
                    .buttonMarkup( {
4860
                        shadow: true,
4860
                        shadow: true,
4861
                        corners: true,
4861
                        corners: true,
4862
                        iconPos: "notext",
4862
                        iconPos: "notext",
4863
                        icon: "plus",
4863
                        icon: "plus",
4864
                        theme: o.iconTheme
4864
                        theme: o.iconTheme
4865
                    } );
4865
                    } );
4866
 
4866
 
4867
            if ( ! collapsibleParent.length ) {
4867
            if ( ! collapsibleParent.length ) {
4868
                collapsibleHeading
4868
                collapsibleHeading
4869
                    .find( "a:eq(0)" )
4869
                    .find( "a:eq(0)" )
4870
                        .addClass( "ui-corner-all" )
4870
                        .addClass( "ui-corner-all" )
4871
                        .find( ".ui-btn-inner" )
4871
                        .find( ".ui-btn-inner" )
4872
                            .addClass( "ui-corner-all" );
4872
                            .addClass( "ui-corner-all" );
4873
            }
4873
            }
4874
            else {
4874
            else {
4875
                if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
4875
                if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
4876
                    collapsibleHeading
4876
                    collapsibleHeading
4877
                        .find( "a:eq(0), .ui-btn-inner" )
4877
                        .find( "a:eq(0), .ui-btn-inner" )
4878
                            .addClass( "ui-corner-bottom" );
4878
                            .addClass( "ui-corner-bottom" );
4879
                }
4879
                }
4880
            }
4880
            }
4881
 
4881
 
4882
        //events
4882
        //events
4883
        collapsibleContain
4883
        collapsibleContain
4884
            .bind( "collapse", function( event ) {
4884
            .bind( "collapse", function( event ) {
4885
                if ( ! event.isDefaultPrevented() && $( event.target ).closest( ".ui-collapsible-contain" ).is( collapsibleContain ) ) {
4885
                if ( ! event.isDefaultPrevented() && $( event.target ).closest( ".ui-collapsible-contain" ).is( collapsibleContain ) ) {
4886
                    event.preventDefault();
4886
                    event.preventDefault();
4887
                    collapsibleHeading
4887
                    collapsibleHeading
4888
                        .addClass( "ui-collapsible-heading-collapsed" )
4888
                        .addClass( "ui-collapsible-heading-collapsed" )
4889
                        .find( ".ui-collapsible-heading-status" )
4889
                        .find( ".ui-collapsible-heading-status" )
4890
                            .text( o.expandCueText )
4890
                            .text( o.expandCueText )
4891
                        .end()
4891
                        .end()
4892
                        .find( ".ui-icon" )
4892
                        .find( ".ui-icon" )
4893
                            .removeClass( "ui-icon-minus" )
4893
                            .removeClass( "ui-icon-minus" )
4894
                            .addClass( "ui-icon-plus" );
4894
                            .addClass( "ui-icon-plus" );
4895
                    collapsibleContent.addClass( "ui-collapsible-content-collapsed" ).attr( "aria-hidden", true );
4895
                    collapsibleContent.addClass( "ui-collapsible-content-collapsed" ).attr( "aria-hidden", true );
4896
 
4896
 
4897
                    if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
4897
                    if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
4898
                        collapsibleHeading
4898
                        collapsibleHeading
4899
                            .find( "a:eq(0), .ui-btn-inner" )
4899
                            .find( "a:eq(0), .ui-btn-inner" )
4900
                            .addClass( "ui-corner-bottom" );
4900
                            .addClass( "ui-corner-bottom" );
4901
                    }
4901
                    }
4902
                }
4902
                }
4903
 
4903
 
4904
            } )
4904
            } )
4905
            .bind( "expand", function( event ) {   
4905
            .bind( "expand", function( event ) {   
4906
                if ( ! event.isDefaultPrevented() ) {
4906
                if ( ! event.isDefaultPrevented() ) {
4907
                    event.preventDefault();
4907
                    event.preventDefault();
4908
                    collapsibleHeading
4908
                    collapsibleHeading
4909
                        .removeClass( "ui-collapsible-heading-collapsed" )
4909
                        .removeClass( "ui-collapsible-heading-collapsed" )
4910
                        .find( ".ui-collapsible-heading-status" ).text( o.collapseCueText );
4910
                        .find( ".ui-collapsible-heading-status" ).text( o.collapseCueText );
4911
 
4911
 
4912
                    collapsibleHeading.find( ".ui-icon" ).removeClass( "ui-icon-plus" ).addClass( "ui-icon-minus" );
4912
                    collapsibleHeading.find( ".ui-icon" ).removeClass( "ui-icon-plus" ).addClass( "ui-icon-minus" );
4913
                    collapsibleContent.removeClass( "ui-collapsible-content-collapsed" ).attr( "aria-hidden", false );
4913
                    collapsibleContent.removeClass( "ui-collapsible-content-collapsed" ).attr( "aria-hidden", false );
4914
 
4914
 
4915
                    if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
4915
                    if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
4916
                        collapsibleHeading
4916
                        collapsibleHeading
4917
                            .find( "a:eq(0), .ui-btn-inner" )
4917
                            .find( "a:eq(0), .ui-btn-inner" )
4918
                            .removeClass( "ui-corner-bottom" );
4918
                            .removeClass( "ui-corner-bottom" );
4919
                    }
4919
                    }
4920
                }
4920
                }
4921
            } )
4921
            } )
4922
            .trigger( o.collapsed ? "collapse" : "expand" );
4922
            .trigger( o.collapsed ? "collapse" : "expand" );
4923
 
4923
 
4924
 
4924
 
4925
        //close others in a set
4925
        //close others in a set
4926
        if ( collapsibleParent.length && !collapsibleParent.jqmData( "collapsiblebound" ) ) {
4926
        if ( collapsibleParent.length && !collapsibleParent.jqmData( "collapsiblebound" ) ) {
4927
            collapsibleParent
4927
            collapsibleParent
4928
                .jqmData( "collapsiblebound", true )
4928
                .jqmData( "collapsiblebound", true )
4929
                .bind( "expand", function( event ){
4929
                .bind( "expand", function( event ){
4930
                   
4930
                   
4931
                    $( event.target )
4931
                    $( event.target )
4932
                        .closest( ".ui-collapsible-contain" )
4932
                        .closest( ".ui-collapsible-contain" )
4933
                        .siblings( ".ui-collapsible-contain" )
4933
                        .siblings( ".ui-collapsible-contain" )
4934
                        .trigger( "collapse" );
4934
                        .trigger( "collapse" );
4935
                   
4935
                   
4936
                } );
4936
                } );
4937
 
4937
 
4938
 
4938
 
4939
            var set = collapsibleParent.find( ":jqmData(role='collapsible'):first" );
4939
            var set = collapsibleParent.find( ":jqmData(role='collapsible'):first" );
4940
 
4940
 
4941
            set.first()
4941
            set.first()
4942
                .find( "a:eq(0)" )
4942
                .find( "a:eq(0)" )
4943
                    .addClass( "ui-corner-top" )
4943
                    .addClass( "ui-corner-top" )
4944
                        .find( ".ui-btn-inner" )
4944
                        .find( ".ui-btn-inner" )
4945
                            .addClass( "ui-corner-top" );
4945
                            .addClass( "ui-corner-top" );
4946
 
4946
 
4947
            set.last().jqmData( "collapsible-last", true );
4947
            set.last().jqmData( "collapsible-last", true );
4948
        }
4948
        }
4949
 
4949
 
4950
        collapsibleHeading
4950
        collapsibleHeading
4951
            .bind( "vclick", function( e ) {
4951
            .bind( "vclick", function( e ) {
4952
                if ( collapsibleHeading.is( ".ui-collapsible-heading-collapsed" ) ) {
4952
                if ( collapsibleHeading.is( ".ui-collapsible-heading-collapsed" ) ) {
4953
                    collapsibleContain.trigger( "expand" );
4953
                    collapsibleContain.trigger( "expand" );
4954
                }
4954
                }
4955
                else {
4955
                else {
4956
                    collapsibleContain.trigger( "collapse" );
4956
                    collapsibleContain.trigger( "collapse" );
4957
                }
4957
                }
4958
                e.preventDefault();
4958
                e.preventDefault();
4959
            } );
4959
            } );
4960
    }
4960
    }
4961
} );
4961
} );
4962
} )( jQuery );
4962
} )( jQuery );
4963
/*
4963
/*
4964
* jQuery Mobile Framework: "controlgroup" plugin - corner-rounding for groups of buttons, checks, radios, etc
4964
* jQuery Mobile Framework: "controlgroup" plugin - corner-rounding for groups of buttons, checks, radios, etc
4965
* Copyright (c) jQuery Project
4965
* Copyright (c) jQuery Project
4966
* Dual licensed under the MIT or GPL Version 2 licenses.
4966
* Dual licensed under the MIT or GPL Version 2 licenses.
4967
* http://jquery.org/license
4967
* http://jquery.org/license
4968
*/
4968
*/
4969
(function($, undefined ) {
4969
(function($, undefined ) {
4970
$.fn.controlgroup = function(options){
4970
$.fn.controlgroup = function(options){
4971
       
4971
       
4972
    return this.each(function(){
4972
    return this.each(function(){
4973
        var o = $.extend({
4973
        var o = $.extend({
4974
            direction: $( this ).jqmData( "type" ) || "vertical",
4974
            direction: $( this ).jqmData( "type" ) || "vertical",
4975
            shadow: false
4975
            shadow: false
4976
        },options);
4976
        },options);
4977
        var groupheading = $(this).find('>legend'),
4977
        var groupheading = $(this).find('>legend'),
4978
            flCorners = o.direction == 'horizontal' ? ['ui-corner-left', 'ui-corner-right'] : ['ui-corner-top', 'ui-corner-bottom'],
4978
            flCorners = o.direction == 'horizontal' ? ['ui-corner-left', 'ui-corner-right'] : ['ui-corner-top', 'ui-corner-bottom'],
4979
            type = $(this).find('input:eq(0)').attr('type');
4979
            type = $(this).find('input:eq(0)').attr('type');
4980
       
4980
       
4981
        //replace legend with more stylable replacement div 
4981
        //replace legend with more stylable replacement div 
4982
        if( groupheading.length ){
4982
        if( groupheading.length ){
4983
            $(this).wrapInner('<div class="ui-controlgroup-controls"></div>'); 
4983
            $(this).wrapInner('<div class="ui-controlgroup-controls"></div>'); 
4984
            $('<div role="heading" class="ui-controlgroup-label">'+ groupheading.html() +'</div>').insertBefore( $(this).children(0) );
4984
            $('<div role="heading" class="ui-controlgroup-label">'+ groupheading.html() +'</div>').insertBefore( $(this).children(0) );
4985
            groupheading.remove(); 
4985
            groupheading.remove(); 
4986
        }
4986
        }
4987
 
4987
 
4988
        $(this).addClass('ui-corner-all ui-controlgroup ui-controlgroup-'+o.direction);
4988
        $(this).addClass('ui-corner-all ui-controlgroup ui-controlgroup-'+o.direction);
4989
       
4989
       
4990
        function flipClasses(els){
4990
        function flipClasses(els){
4991
            els
4991
            els
4992
                .removeClass('ui-btn-corner-all ui-shadow')
4992
                .removeClass('ui-btn-corner-all ui-shadow')
4993
                .eq(0).addClass(flCorners[0])
4993
                .eq(0).addClass(flCorners[0])
4994
                .end()
4994
                .end()
4995
                .filter(':last').addClass(flCorners[1]).addClass('ui-controlgroup-last');
4995
                .filter(':last').addClass(flCorners[1]).addClass('ui-controlgroup-last');
4996
        }
4996
        }
4997
        flipClasses($(this).find('.ui-btn'));
4997
        flipClasses($(this).find('.ui-btn'));
4998
        flipClasses($(this).find('.ui-btn-inner'));
4998
        flipClasses($(this).find('.ui-btn-inner'));
4999
        if(o.shadow){
4999
        if(o.shadow){
5000
            $(this).addClass('ui-shadow');
5000
            $(this).addClass('ui-shadow');
5001
        }
5001
        }
5002
    });
5002
    });
5003
};
5003
};
5004
})(jQuery);/*
5004
})(jQuery);/*
5005
* jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
5005
* jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
5006
* Copyright (c) jQuery Project
5006
* Copyright (c) jQuery Project
5007
* Dual licensed under the MIT or GPL Version 2 licenses.
5007
* Dual licensed under the MIT or GPL Version 2 licenses.
5008
* http://jquery.org/license
5008
* http://jquery.org/license
5009
*/
5009
*/
5010
(function($, undefined ) {
5010
(function($, undefined ) {
5011
$.fn.fieldcontain = function(options){
5011
$.fn.fieldcontain = function(options){
5012
    return this.addClass('ui-field-contain ui-body ui-br');
5012
    return this.addClass('ui-field-contain ui-body ui-br');
5013
};
5013
};
5014
})(jQuery);/*
5014
})(jQuery);/*
5015
* jQuery Mobile Framework : "listview" plugin
5015
* jQuery Mobile Framework : "listview" plugin
5016
* Copyright (c) jQuery Project
5016
* Copyright (c) jQuery Project
5017
* Dual licensed under the MIT or GPL Version 2 licenses.
5017
* Dual licensed under the MIT or GPL Version 2 licenses.
5018
* http://jquery.org/license
5018
* http://jquery.org/license
5019
*/
5019
*/
5020
(function($, undefined ) {
5020
(function($, undefined ) {
5021
//Keeps track of the number of lists per page UID
5021
//Keeps track of the number of lists per page UID
5022
//This allows support for multiple nested list in the same page
5022
//This allows support for multiple nested list in the same page
5023
//https://github.com/jquery/jquery-mobile/issues/1617
5023
//https://github.com/jquery/jquery-mobile/issues/1617
5024
var listCountPerPage = {};
5024
var listCountPerPage = {};
5025
 
5025
 
5026
$.widget( "mobile.listview", $.mobile.widget, {
5026
$.widget( "mobile.listview", $.mobile.widget, {
5027
    options: {
5027
    options: {
5028
        theme: "c",
5028
        theme: "c",
5029
        countTheme: "c",
5029
        countTheme: "c",
5030
        headerTheme: "b",
5030
        headerTheme: "b",
5031
        dividerTheme: "b",
5031
        dividerTheme: "b",
5032
        splitIcon: "arrow-r",
5032
        splitIcon: "arrow-r",
5033
        splitTheme: "b",
5033
        splitTheme: "b",
5034
        inset: false
5034
        inset: false
5035
    },
5035
    },
5036
   
5036
   
5037
    _create: function() {
5037
    _create: function() {
5038
        var t = this;
5038
        var t = this;
5039
 
5039
 
5040
        // create listview markup 
5040
        // create listview markup 
5041
        t.element.addClass(function( i, orig ) {
5041
        t.element.addClass(function( i, orig ) {
5042
            return orig + " ui-listview " + ( t.options.inset ? " ui-listview-inset ui-corner-all ui-shadow " : "" );
5042
            return orig + " ui-listview " + ( t.options.inset ? " ui-listview-inset ui-corner-all ui-shadow " : "" );
5043
        });
5043
        });
5044
 
5044
 
5045
        t.refresh();
5045
        t.refresh();
5046
    },
5046
    },
5047
 
5047
 
5048
    _itemApply: function( $list, item ) {
5048
    _itemApply: function( $list, item ) {
5049
        // TODO class has to be defined in markup
5049
        // TODO class has to be defined in markup
5050
        item.find( ".ui-li-count" )
5050
        item.find( ".ui-li-count" )
5051
            .addClass( "ui-btn-up-" + ($list.jqmData( "counttheme" ) || this.options.countTheme) + " ui-btn-corner-all" ).end()
5051
            .addClass( "ui-btn-up-" + ($list.jqmData( "counttheme" ) || this.options.countTheme) + " ui-btn-corner-all" ).end()
5052
        .find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" ).end()
5052
        .find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" ).end()
5053
        .find( "p, dl" ).addClass( "ui-li-desc" ).end()
5053
        .find( "p, dl" ).addClass( "ui-li-desc" ).end()
5054
        .find( ">img:eq(0), .ui-link-inherit>img:eq(0)" ).addClass( "ui-li-thumb" ).each(function() {
5054
        .find( ">img:eq(0), .ui-link-inherit>img:eq(0)" ).addClass( "ui-li-thumb" ).each(function() {
5055
            item.addClass( $(this).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
5055
            item.addClass( $(this).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
5056
        }).end()
5056
        }).end()
5057
        .find( ".ui-li-aside" ).each(function() {
5057
        .find( ".ui-li-aside" ).each(function() {
5058
            var $this = $(this);
5058
            var $this = $(this);
5059
            $this.prependTo( $this.parent() ); //shift aside to front for css float
5059
            $this.prependTo( $this.parent() ); //shift aside to front for css float
5060
        });
5060
        });
5061
    },
5061
    },
5062
   
5062
   
5063
    _removeCorners: function( li ) {
5063
    _removeCorners: function( li ) {
5064
        li
5064
        li
5065
            .add( li.find(".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb") )
5065
            .add( li.find(".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb") )
5066
            .removeClass( "ui-corner-top ui-corner-bottom ui-corner-br ui-corner-bl ui-corner-tr ui-corner-tl" );
5066
            .removeClass( "ui-corner-top ui-corner-bottom ui-corner-br ui-corner-bl ui-corner-tr ui-corner-tl" );
5067
    },
5067
    },
5068
   
5068
   
5069
    refresh: function( create ) {
5069
    refresh: function( create ) {
5070
        this._createSubPages();
5070
        this._createSubPages();
5071
       
5071
       
5072
        var o = this.options,
5072
        var o = this.options,
5073
            $list = this.element,
5073
            $list = this.element,
5074
            self = this,
5074
            self = this,
5075
            dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
5075
            dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
5076
            listsplittheme = $list.jqmData( "splittheme" ),
5076
            listsplittheme = $list.jqmData( "splittheme" ),
5077
            listspliticon = $list.jqmData( "spliticon" ),
5077
            listspliticon = $list.jqmData( "spliticon" ),
5078
            li = $list.children( "li" ),
5078
            li = $list.children( "li" ),
5079
            counter = $.support.cssPseudoElement || !$.nodeName( $list[0], "ol" ) ? 0 : 1;
5079
            counter = $.support.cssPseudoElement || !$.nodeName( $list[0], "ol" ) ? 0 : 1;
5080
 
5080
 
5081
        if ( counter ) {
5081
        if ( counter ) {
5082
            $list.find( ".ui-li-dec" ).remove();
5082
            $list.find( ".ui-li-dec" ).remove();
5083
        }
5083
        }
5084
 
5084
 
5085
        for (var pos = 0, numli = li.length; pos < numli; pos++) {
5085
        for (var pos = 0, numli = li.length; pos < numli; pos++) {
5086
            var item = li.eq(pos),
5086
            var item = li.eq(pos),
5087
                itemClass = "ui-li";
5087
                itemClass = "ui-li";
5088
 
5088
 
5089
            // If we're creating the element, we update it regardless
5089
            // If we're creating the element, we update it regardless
5090
            if ( create || !item.hasClass( "ui-li" ) ) {
5090
            if ( create || !item.hasClass( "ui-li" ) ) {
5091
                var itemTheme = item.jqmData("theme") || o.theme,
5091
                var itemTheme = item.jqmData("theme") || o.theme,
5092
                    a = item.children( "a" );
5092
                    a = item.children( "a" );
5093
 
5093
 
5094
                if ( a.length ) {
5094
                if ( a.length ) {
5095
                    var icon = item.jqmData("icon");
5095
                    var icon = item.jqmData("icon");
5096
 
5096
 
5097
                    item
5097
                    item
5098
                        .buttonMarkup({
5098
                        .buttonMarkup({
5099
                            wrapperEls: "div",
5099
                            wrapperEls: "div",
5100
                            shadow: false,
5100
                            shadow: false,
5101
                            corners: false,
5101
                            corners: false,
5102
                            iconpos: "right",
5102
                            iconpos: "right",
5103
                            icon: a.length > 1 || icon === false ? false : icon || "arrow-r",
5103
                            icon: a.length > 1 || icon === false ? false : icon || "arrow-r",
5104
                            theme: itemTheme
5104
                            theme: itemTheme
5105
                        });
5105
                        });
5106
 
5106
 
5107
                    a.first().addClass( "ui-link-inherit" );
5107
                    a.first().addClass( "ui-link-inherit" );
5108
 
5108
 
5109
                    if ( a.length > 1 ) {
5109
                    if ( a.length > 1 ) {
5110
                        itemClass += " ui-li-has-alt";
5110
                        itemClass += " ui-li-has-alt";
5111
 
5111
 
5112
                        var last = a.last(),
5112
                        var last = a.last(),
5113
                            splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;
5113
                            splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;
5114
 
5114
 
5115
                        last
5115
                        last
5116
                            .appendTo(item)
5116
                            .appendTo(item)
5117
                            .attr( "title", last.text() )
5117
                            .attr( "title", last.text() )
5118
                            .addClass( "ui-li-link-alt" )
5118
                            .addClass( "ui-li-link-alt" )
5119
                            .empty()
5119
                            .empty()
5120
                            .buttonMarkup({
5120
                            .buttonMarkup({
5121
                                shadow: false,
5121
                                shadow: false,
5122
                                corners: false,
5122
                                corners: false,
5123
                                theme: itemTheme,
5123
                                theme: itemTheme,
5124
                                icon: false,
5124
                                icon: false,
5125
                                iconpos: false
5125
                                iconpos: false
5126
                            })
5126
                            })
5127
                            .find( ".ui-btn-inner" )
5127
                            .find( ".ui-btn-inner" )
5128
                                .append( $( "<span />" ).buttonMarkup({
5128
                                .append( $( "<span />" ).buttonMarkup({
5129
                                    shadow: true,
5129
                                    shadow: true,
5130
                                    corners: true,
5130
                                    corners: true,
5131
                                    theme: splittheme,
5131
                                    theme: splittheme,
5132
                                    iconpos: "notext",
5132
                                    iconpos: "notext",
5133
                                    icon: listspliticon || last.jqmData( "icon" ) ||  o.splitIcon
5133
                                    icon: listspliticon || last.jqmData( "icon" ) ||  o.splitIcon
5134
                                } ) );
5134
                                } ) );
5135
                    }
5135
                    }
5136
 
5136
 
5137
                } else if ( item.jqmData( "role" ) === "list-divider" ) {
5137
                } else if ( item.jqmData( "role" ) === "list-divider" ) {
5138
                    itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
5138
                    itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
5139
                    item.attr( "role", "heading" );
5139
                    item.attr( "role", "heading" );
5140
 
5140
 
5141
                    //reset counter when a divider heading is encountered
5141
                    //reset counter when a divider heading is encountered
5142
                    if ( counter ) {
5142
                    if ( counter ) {
5143
                        counter = 1;
5143
                        counter = 1;
5144
                    }
5144
                    }
5145
 
5145
 
5146
                } else {
5146
                } else {
5147
                    itemClass += " ui-li-static ui-body-" + itemTheme;
5147
                    itemClass += " ui-li-static ui-body-" + itemTheme;
5148
                }
5148
                }
5149
            }
5149
            }
5150
           
5150
           
5151
           
5151
           
5152
            if( o.inset ){ 
5152
            if( o.inset ){ 
5153
                if ( pos === 0 ) {
5153
                if ( pos === 0 ) {
5154
                        itemClass += " ui-corner-top";
5154
                        itemClass += " ui-corner-top";
5155
   
5155
   
5156
                        item
5156
                        item
5157
                            .add( item.find( ".ui-btn-inner" ) )
5157
                            .add( item.find( ".ui-btn-inner" ) )
5158
                            .find( ".ui-li-link-alt" )
5158
                            .find( ".ui-li-link-alt" )
5159
                                .addClass( "ui-corner-tr" )
5159
                                .addClass( "ui-corner-tr" )
5160
                            .end()
5160
                            .end()
5161
                            .find( ".ui-li-thumb" )
5161
                            .find( ".ui-li-thumb" )
5162
                                .addClass( "ui-corner-tl" );
5162
                                .addClass( "ui-corner-tl" );
5163
                        if(item.next().next().length){
5163
                        if(item.next().next().length){
5164
                            self._removeCorners( item.next() );    
5164
                            self._removeCorners( item.next() );    
5165
                        }
5165
                        }
5166
   
5166
   
5167
                }
5167
                }
5168
                if ( pos === li.length - 1 ) {
5168
                if ( pos === li.length - 1 ) {
5169
                        itemClass += " ui-corner-bottom";
5169
                        itemClass += " ui-corner-bottom";
5170
   
5170
   
5171
                        item
5171
                        item
5172
                            .add( item.find( ".ui-btn-inner" ) )
5172
                            .add( item.find( ".ui-btn-inner" ) )
5173
                            .find( ".ui-li-link-alt" )
5173
                            .find( ".ui-li-link-alt" )
5174
                                .addClass( "ui-corner-br" )
5174
                                .addClass( "ui-corner-br" )
5175
                            .end()
5175
                            .end()
5176
                            .find( ".ui-li-thumb" )
5176
                            .find( ".ui-li-thumb" )
5177
                                .addClass( "ui-corner-bl" );
5177
                                .addClass( "ui-corner-bl" );
5178
                       
5178
                       
5179
                        if(item.prev().prev().length){
5179
                        if(item.prev().prev().length){
5180
                            self._removeCorners( item.prev() );    
5180
                            self._removeCorners( item.prev() );    
5181
                        }  
5181
                        }  
5182
                }
5182
                }
5183
            }
5183
            }
5184
 
5184
 
5185
 
5185
 
5186
            if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
5186
            if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
5187
           
5187
           
5188
                var countParent = item.is(".ui-li-static:first") ? item : item.find( ".ui-link-inherit" );
5188
                var countParent = item.is(".ui-li-static:first") ? item : item.find( ".ui-link-inherit" );
5189
               
5189
               
5190
                countParent
5190
                countParent
5191
                    .addClass( "ui-li-jsnumbering" )
5191
                    .addClass( "ui-li-jsnumbering" )
5192
                    .prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );
5192
                    .prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );
5193
            }
5193
            }
5194
 
5194
 
5195
            item.add( item.children( ".ui-btn-inner" ) ).addClass( itemClass );
5195
            item.add( item.children( ".ui-btn-inner" ) ).addClass( itemClass );
5196
 
5196
 
5197
            if ( !create ) {
5197
            if ( !create ) {
5198
                self._itemApply( $list, item );
5198
                self._itemApply( $list, item );
5199
            }
5199
            }
5200
        }
5200
        }
5201
    },
5201
    },
5202
   
5202
   
5203
    //create a string for ID/subpage url creation
5203
    //create a string for ID/subpage url creation
5204
    _idStringEscape: function( str ){
5204
    _idStringEscape: function( str ){
5205
        return str.replace(/[^a-zA-Z0-9]/g, '-');
5205
        return str.replace(/[^a-zA-Z0-9]/g, '-');
5206
    },
5206
    },
5207
 
5207
 
5208
    _createSubPages: function() {
5208
    _createSubPages: function() {
5209
        var parentList = this.element,
5209
        var parentList = this.element,
5210
            parentPage = parentList.closest( ".ui-page" ),
5210
            parentPage = parentList.closest( ".ui-page" ),
5211
            parentUrl = parentPage.jqmData( "url" ),
5211
            parentUrl = parentPage.jqmData( "url" ),
5212
            parentId  = parentUrl || parentPage[ 0 ][ $.expando ],
5212
            parentId  = parentUrl || parentPage[ 0 ][ $.expando ],
5213
            parentListId = parentList.attr( "id" ),
5213
            parentListId = parentList.attr( "id" ),
5214
            o = this.options,
5214
            o = this.options,
5215
            dns = "data-" + $.mobile.ns,
5215
            dns = "data-" + $.mobile.ns,
5216
            self = this,
5216
            self = this,
5217
            persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" );
5217
            persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" );
5218
 
5218
 
5219
        if ( typeof( listCountPerPage[ parentId ] ) === 'undefined' ) {
5219
        if ( typeof( listCountPerPage[ parentId ] ) === 'undefined' ) {
5220
            listCountPerPage[ parentId ] = -1;
5220
            listCountPerPage[ parentId ] = -1;
5221
        }
5221
        }
5222
        parentListId = parentListId || ++listCountPerPage[ parentId ];
5222
        parentListId = parentListId || ++listCountPerPage[ parentId ];
5223
 
5223
 
5224
        $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function( i ) {
5224
        $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function( i ) {
5225
            var list = $( this ),
5225
            var list = $( this ),
5226
                listId = list.attr( "id" ) || parentListId + "-" + i,
5226
                listId = list.attr( "id" ) || parentListId + "-" + i,
5227
                parent = list.parent(),
5227
                parent = list.parent(),
5228
                nodeEls = $( list.prevAll().toArray().reverse() ),
5228
                nodeEls = $( list.prevAll().toArray().reverse() ),
5229
                nodeEls = nodeEls.length ? nodeEls : $( "<span>" + $.trim(parent.contents()[ 0 ].nodeValue) + "</span>" ),
5229
                nodeEls = nodeEls.length ? nodeEls : $( "<span>" + $.trim(parent.contents()[ 0 ].nodeValue) + "</span>" ),
5230
                title = nodeEls.first().text(),//url limits to first 30 chars of text
5230
                title = nodeEls.first().text(),//url limits to first 30 chars of text
5231
                id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId;
5231
                id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId;
5232
                theme = list.jqmData( "theme" ) || o.theme,
5232
                theme = list.jqmData( "theme" ) || o.theme,
5233
                countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
5233
                countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
5234
                newPage = list.detach()
5234
                newPage = list.detach()
5235
                            .wrap( "<div " + dns + "role='page' " +  dns + "url='" + id + "' " + dns + "theme='" + theme + "' " + dns + "count-theme='" + countTheme + "'><div " + dns + "role='content'></div></div>" )
5235
                            .wrap( "<div " + dns + "role='page' " +  dns + "url='" + id + "' " + dns + "theme='" + theme + "' " + dns + "count-theme='" + countTheme + "'><div " + dns + "role='content'></div></div>" )
5236
                            .parent()
5236
                            .parent()
5237
                                .before( "<div " + dns + "role='header' " + dns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
5237
                                .before( "<div " + dns + "role='header' " + dns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
5238
                                .after( persistentFooterID ? $( "<div " + dns + "role='footer' " + dns + "id='"+ persistentFooterID +"'>") : "" )
5238
                                .after( persistentFooterID ? $( "<div " + dns + "role='footer' " + dns + "id='"+ persistentFooterID +"'>") : "" )
5239
                                .parent()
5239
                                .parent()
5240
                                    .appendTo( $.mobile.pageContainer );
5240
                                    .appendTo( $.mobile.pageContainer );
5241
 
5241
 
5242
                newPage.page();    
5242
                newPage.page();    
5243
            var anchor = parent.find('a:first');
5243
            var anchor = parent.find('a:first');
5244
            if ( !anchor.length ) {
5244
            if ( !anchor.length ) {
5245
                anchor = $("<a />").html( nodeEls || title ).prependTo( parent.empty() );
5245
                anchor = $("<a />").html( nodeEls || title ).prependTo( parent.empty() );
5246
            }
5246
            }
5247
            anchor.attr('href','#' + id);
5247
            anchor.attr('href','#' + id);
5248
        }).listview();
5248
        }).listview();
5249
    }
5249
    }
5250
});
5250
});
5251
 
5251
 
5252
})( jQuery );
5252
})( jQuery );
5253
/*
5253
/*
5254
* jQuery Mobile Framework : "listview" filter extension
5254
* jQuery Mobile Framework : "listview" filter extension
5255
* Copyright (c) jQuery Project
5255
* Copyright (c) jQuery Project
5256
* Dual licensed under the MIT or GPL Version 2 licenses.
5256
* Dual licensed under the MIT or GPL Version 2 licenses.
5257
* http://jquery.org/license
5257
* http://jquery.org/license
5258
*/
5258
*/
5259
(function($, undefined ) {
5259
(function($, undefined ) {
5260
 
5260
 
5261
$.mobile.listview.prototype.options.filter = false;
5261
$.mobile.listview.prototype.options.filter = false;
5262
$.mobile.listview.prototype.options.filterPlaceholder = "Filter items...";
5262
$.mobile.listview.prototype.options.filterPlaceholder = "Filter items...";
5263
$.mobile.listview.prototype.options.filterTheme = "c";
5263
$.mobile.listview.prototype.options.filterTheme = "c";
5264
 
5264
 
5265
$( ":jqmData(role='listview')" ).live( "listviewcreate", function() {
5265
$( ":jqmData(role='listview')" ).live( "listviewcreate", function() {
5266
    var list = $( this ),
5266
    var list = $( this ),
5267
        listview = list.data( "listview" );
5267
        listview = list.data( "listview" );
5268
 
5268
 
5269
    if ( !listview.options.filter ) {
5269
    if ( !listview.options.filter ) {
5270
        return;
5270
        return;
5271
    }
5271
    }
5272
 
5272
 
5273
    var wrapper = $( "<form>", { "class": "ui-listview-filter ui-bar-" + listview.options.filterTheme, "role": "search" } ),
5273
    var wrapper = $( "<form>", { "class": "ui-listview-filter ui-bar-" + listview.options.filterTheme, "role": "search" } ),
5274
 
5274
 
5275
        search = $( "<input>", {
5275
        search = $( "<input>", {
5276
                placeholder: listview.options.filterPlaceholder
5276
                placeholder: listview.options.filterPlaceholder
5277
            })
5277
            })
5278
            .attr( "data-" + $.mobile.ns + "type", "search" )
5278
            .attr( "data-" + $.mobile.ns + "type", "search" )
5279
            .jqmData( 'lastval', "" )
5279
            .jqmData( 'lastval', "" )
5280
            .bind( "keyup change", function() {
5280
            .bind( "keyup change", function() {
5281
 
5281
 
5282
                var val = this.value.toLowerCase(),
5282
                var val = this.value.toLowerCase(),
5283
                    listItems=null,
5283
                    listItems=null,
5284
                    lastval = $( this ).jqmData('lastval')+"";
5284
                    lastval = $( this ).jqmData('lastval')+"";
5285
 
5285
 
5286
                //change val as lastval for next execution  
5286
                //change val as lastval for next execution  
5287
                $(this).jqmData( 'lastval' , val );
5287
                $(this).jqmData( 'lastval' , val );
5288
 
5288
 
5289
                change = val.replace( new RegExp( "^" + lastval ) , "" );
5289
                change = val.replace( new RegExp( "^" + lastval ) , "" );
5290
 
5290
 
5291
                if( val.length < lastval.length || change.length != ( val.length - lastval.length ) ){
5291
                if( val.length < lastval.length || change.length != ( val.length - lastval.length ) ){
5292
 
5292
 
5293
                    //removed chars or pasted something totaly different, check all items
5293
                    //removed chars or pasted something totaly different, check all items
5294
                    listItems = list.children();
5294
                    listItems = list.children();
5295
                } else {
5295
                } else {
5296
 
5296
 
5297
                    //only chars added, not removed, only use visible subset
5297
                    //only chars added, not removed, only use visible subset
5298
                    listItems = list.children( ':not(.ui-screen-hidden)' );
5298
                    listItems = list.children( ':not(.ui-screen-hidden)' );
5299
                }
5299
                }
5300
 
5300
 
5301
                if ( val ) {
5301
                if ( val ) {
5302
 
5302
 
5303
                    // This handles hiding regular rows without the text we search for
5303
                    // This handles hiding regular rows without the text we search for
5304
                    // and any list dividers without regular rows shown under it
5304
                    // and any list dividers without regular rows shown under it
5305
                    var item,
5305
                    var item,
5306
                        childItems = false,                        
5306
                        childItems = false,                        
5307
                        itemtext="";
5307
                        itemtext="";
5308
 
5308
 
5309
                    for ( var i = listItems.length - 1; i >= 0; i-- ) {
5309
                    for ( var i = listItems.length - 1; i >= 0; i-- ) {
5310
                        item = $( listItems[i] );
5310
                        item = $( listItems[i] );
5311
                        itemtext = item.jqmData( 'filtertext' ) || item.text();
5311
                        itemtext = item.jqmData( 'filtertext' ) || item.text();
5312
 
5312
 
5313
                        if ( item.is( "li:jqmData(role=list-divider)" ) ) {
5313
                        if ( item.is( "li:jqmData(role=list-divider)" ) ) {
5314
 
5314
 
5315
                            item.toggleClass( 'ui-filter-hidequeue' , !childItems );
5315
                            item.toggleClass( 'ui-filter-hidequeue' , !childItems );
5316
 
5316
 
5317
                            // New bucket!
5317
                            // New bucket!
5318
                            childItems = false;
5318
                            childItems = false;
5319
 
5319
 
5320
                        } else if ( itemtext.toLowerCase().indexOf( val ) === -1) {
5320
                        } else if ( itemtext.toLowerCase().indexOf( val ) === -1) {
5321
 
5321
 
5322
                            //mark to be hidden
5322
                            //mark to be hidden
5323
                            item.toggleClass( 'ui-filter-hidequeue' , true );
5323
                            item.toggleClass( 'ui-filter-hidequeue' , true );
5324
                        } else {
5324
                        } else {
5325
 
5325
 
5326
                            // There's a shown item in the bucket
5326
                            // There's a shown item in the bucket
5327
                            childItems = true;
5327
                            childItems = true;
5328
                        }
5328
                        }
5329
                    }
5329
                    }
5330
 
5330
 
5331
                    // show items, not marked to be hidden
5331
                    // show items, not marked to be hidden
5332
                    listItems
5332
                    listItems
5333
                        .filter( ':not(.ui-filter-hidequeue)' )
5333
                        .filter( ':not(.ui-filter-hidequeue)' )
5334
                        .toggleClass('ui-screen-hidden',false);
5334
                        .toggleClass('ui-screen-hidden',false);
5335
 
5335
 
5336
                    // hide items, marked to be hidden
5336
                    // hide items, marked to be hidden
5337
                    listItems
5337
                    listItems
5338
                        .filter( '.ui-filter-hidequeue' )
5338
                        .filter( '.ui-filter-hidequeue' )
5339
                        .toggleClass('ui-screen-hidden',true)
5339
                        .toggleClass('ui-screen-hidden',true)
5340
                        .toggleClass( 'ui-filter-hidequeue' , false );
5340
                        .toggleClass( 'ui-filter-hidequeue' , false );
5341
 
5341
 
5342
                }else{
5342
                }else{
5343
 
5343
 
5344
                    //filtervalue is empty => show all
5344
                    //filtervalue is empty => show all
5345
                    listItems.toggleClass('ui-screen-hidden',false);
5345
                    listItems.toggleClass('ui-screen-hidden',false);
5346
                }
5346
                }
5347
            })
5347
            })
5348
            .appendTo( wrapper )
5348
            .appendTo( wrapper )
5349
            .textinput();
5349
            .textinput();
5350
 
5350
 
5351
    if ($( this ).jqmData( "inset" ) ) {
5351
    if ($( this ).jqmData( "inset" ) ) {
5352
        wrapper.addClass( "ui-listview-filter-inset" );
5352
        wrapper.addClass( "ui-listview-filter-inset" );
5353
    }
5353
    }
5354
 
5354
 
5355
    wrapper.insertBefore( list );
5355
    wrapper.insertBefore( list );
5356
});
5356
});
5357
 
5357
 
5358
})( jQuery );/*
5358
})( jQuery );/*
5359
* jQuery Mobile Framework : "dialog" plugin.
5359
* jQuery Mobile Framework : "dialog" plugin.
5360
* Copyright (c) jQuery Project
5360
* Copyright (c) jQuery Project
5361
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
5361
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
5362
* Note: Code is in draft form and is subject to change
5362
* Note: Code is in draft form and is subject to change
5363
*/
5363
*/
5364
( function( $, undefined ) {
5364
( function( $, undefined ) {
5365
$.widget( "mobile.dialog", $.mobile.widget, {
5365
$.widget( "mobile.dialog", $.mobile.widget, {
5366
    options: {
5366
    options: {
5367
        closeBtnText: "Close"
5367
        closeBtnText: "Close"
5368
    },
5368
    },
5369
    _create: function() {
5369
    _create: function() {
5370
        var $el = this.element;
5370
        var $el = this.element;
5371
       
5371
       
5372
        /* class the markup for dialog styling */  
5372
        /* class the markup for dialog styling */  
5373
        $el
5373
        $el
5374
            //add ARIA role
5374
            //add ARIA role
5375
            .attr( "role", "dialog" )
5375
            .attr( "role", "dialog" )
5376
            .addClass( "ui-page ui-dialog ui-body-a" )
5376
            .addClass( "ui-page ui-dialog ui-body-a" )
5377
            .find( ":jqmData(role=header)" )
5377
            .find( ":jqmData(role=header)" )
5378
            .addClass( "ui-corner-top ui-overlay-shadow" )
5378
            .addClass( "ui-corner-top ui-overlay-shadow" )
5379
                .prepend( "<a href='#' data-" + $.mobile.ns + "icon='delete' data-" + $.mobile.ns + "rel='back' data-" + $.mobile.ns + "iconpos='notext'>"+ this.options.closeBtnText +"</a>" )
5379
                .prepend( "<a href='#' data-" + $.mobile.ns + "icon='delete' data-" + $.mobile.ns + "rel='back' data-" + $.mobile.ns + "iconpos='notext'>"+ this.options.closeBtnText +"</a>" )
5380
            .end()
5380
            .end()
5381
            .find( '.ui-content:not([class*="ui-body-"])' )
5381
            .find( '.ui-content:not([class*="ui-body-"])' )
5382
                .addClass( 'ui-body-c' )
5382
                .addClass( 'ui-body-c' )
5383
            .end()
5383
            .end()
5384
            .find( ".ui-content,:jqmData(role='footer')" )
5384
            .find( ".ui-content,:jqmData(role='footer')" )
5385
                .last()
5385
                .last()
5386
                .addClass( "ui-corner-bottom ui-overlay-shadow" );
5386
                .addClass( "ui-corner-bottom ui-overlay-shadow" );
5387
       
5387
       
5388
        /* bind events
5388
        /* bind events
5389
            - clicks and submits should use the closing transition that the dialog opened with
5389
            - clicks and submits should use the closing transition that the dialog opened with
5390
              unless a data-transition is specified on the link/form
5390
              unless a data-transition is specified on the link/form
5391
            - if the click was on the close button, or the link has a data-rel="back" it'll go back in history naturally
5391
            - if the click was on the close button, or the link has a data-rel="back" it'll go back in history naturally
5392
        */
5392
        */
5393
        $el
5393
        $el
5394
            .bind( "vclick submit", function( e ) {
5394
            .bind( "vclick submit", function( e ) {
5395
                var $target = $( e.target ).closest( e.type === "vclick" ? "a" : "form" );
5395
                var $target = $( e.target ).closest( e.type === "vclick" ? "a" : "form" );
5396
               
5396
               
5397
                if( $target.length && ! $target.jqmData( "transition" ) ) {
5397
                if( $target.length && ! $target.jqmData( "transition" ) ) {
5398
                    var active = $.mobile.urlHistory.getActive() || {};
5398
                    var active = $.mobile.urlHistory.getActive() || {};
5399
                    $target
5399
                    $target
5400
                        .attr( "data-" + $.mobile.ns + "transition", ( active.transition || $.mobile.defaultDialogTransition ) )
5400
                        .attr( "data-" + $.mobile.ns + "transition", ( active.transition || $.mobile.defaultDialogTransition ) )
5401
                        .attr( "data-" + $.mobile.ns + "direction", "reverse" );
5401
                        .attr( "data-" + $.mobile.ns + "direction", "reverse" );
5402
                }
5402
                }
5403
            })
5403
            })
5404
            .bind( "pagehide", function() {
5404
            .bind( "pagehide", function() {
5405
                $( this ).find( "." + $.mobile.activeBtnClass ).removeClass( $.mobile.activeBtnClass );
5405
                $( this ).find( "." + $.mobile.activeBtnClass ).removeClass( $.mobile.activeBtnClass );
5406
            });
5406
            });
5407
    },
5407
    },
5408
   
5408
   
5409
    //close method goes back in history
5409
    //close method goes back in history
5410
    close: function() {
5410
    close: function() {
5411
        window.history.back();
5411
        window.history.back();
5412
    }
5412
    }
5413
});
5413
});
5414
})( jQuery );
5414
})( jQuery );
5415
/*
5415
/*
5416
* jQuery Mobile Framework : "navbar" plugin
5416
* jQuery Mobile Framework : "navbar" plugin
5417
* Copyright (c) jQuery Project
5417
* Copyright (c) jQuery Project
5418
* Dual licensed under the MIT or GPL Version 2 licenses.
5418
* Dual licensed under the MIT or GPL Version 2 licenses.
5419
* http://jquery.org/license
5419
* http://jquery.org/license
5420
*/
5420
*/
5421
(function($, undefined ) {
5421
(function($, undefined ) {
5422
$.widget( "mobile.navbar", $.mobile.widget, {
5422
$.widget( "mobile.navbar", $.mobile.widget, {
5423
    options: {
5423
    options: {
5424
        iconpos: 'top',
5424
        iconpos: 'top',
5425
        grid: null
5425
        grid: null
5426
    },
5426
    },
5427
    _create: function(){
5427
    _create: function(){
5428
        var $navbar = this.element,
5428
        var $navbar = this.element,
5429
            $navbtns = $navbar.find("a"),
5429
            $navbtns = $navbar.find("a"),
5430
            iconpos = $navbtns.filter( ":jqmData(icon)").length ? this.options.iconpos : undefined;
5430
            iconpos = $navbtns.filter( ":jqmData(icon)").length ? this.options.iconpos : undefined;
5431
       
5431
       
5432
        $navbar
5432
        $navbar
5433
            .addClass('ui-navbar')
5433
            .addClass('ui-navbar')
5434
            .attr("role","navigation")
5434
            .attr("role","navigation")
5435
            .find("ul")
5435
            .find("ul")
5436
                .grid({grid: this.options.grid });     
5436
                .grid({grid: this.options.grid });     
5437
       
5437
       
5438
        if( !iconpos ){
5438
        if( !iconpos ){
5439
            $navbar.addClass("ui-navbar-noicons");
5439
            $navbar.addClass("ui-navbar-noicons");
5440
        }
5440
        }
5441
       
5441
       
5442
        $navbtns
5442
        $navbtns
5443
            .buttonMarkup({
5443
            .buttonMarkup({
5444
                corners:    false,
5444
                corners:    false,
5445
                shadow:     false,
5445
                shadow:     false,
5446
                iconpos:    iconpos
5446
                iconpos:    iconpos
5447
            });
5447
            });
5448
       
5448
       
5449
        $navbar.delegate("a", "vclick",function(event){
5449
        $navbar.delegate("a", "vclick",function(event){
5450
            $navbtns.not( ".ui-state-persist" ).removeClass( $.mobile.activeBtnClass );
5450
            $navbtns.not( ".ui-state-persist" ).removeClass( $.mobile.activeBtnClass );
5451
            $( this ).addClass( $.mobile.activeBtnClass );
5451
            $( this ).addClass( $.mobile.activeBtnClass );
5452
        });
5452
        });
5453
    }
5453
    }
5454
});
5454
});
5455
})( jQuery );
5455
})( jQuery );
5456
/*
5456
/*
5457
* jQuery Mobile Framework : plugin for creating CSS grids
5457
* jQuery Mobile Framework : plugin for creating CSS grids
5458
* Copyright (c) jQuery Project
5458
* Copyright (c) jQuery Project
5459
* Dual licensed under the MIT or GPL Version 2 licenses.
5459
* Dual licensed under the MIT or GPL Version 2 licenses.
5460
* http://jquery.org/license
5460
* http://jquery.org/license
5461
*/
5461
*/
5462
(function($, undefined ) {
5462
(function($, undefined ) {
5463
$.fn.grid = function(options){
5463
$.fn.grid = function(options){
5464
    return this.each(function(){
5464
    return this.each(function(){
5465
        var o = $.extend({
5465
        var o = $.extend({
5466
            grid: null
5466
            grid: null
5467
        },options);
5467
        },options);
5468
   
5468
   
5469
           
5469
           
5470
        var $kids = $(this).children(),
5470
        var $kids = $(this).children(),
5471
            gridCols = {solo:1, a:2, b:3, c:4, d:5},
5471
            gridCols = {solo:1, a:2, b:3, c:4, d:5},
5472
            grid = o.grid,
5472
            grid = o.grid,
5473
            iterator;
5473
            iterator;
5474
           
5474
           
5475
            if( !grid ){
5475
            if( !grid ){
5476
                if( $kids.length <= 5 ){
5476
                if( $kids.length <= 5 ){
5477
                    for(var letter in gridCols){
5477
                    for(var letter in gridCols){
5478
                        if(gridCols[letter] == $kids.length){ grid = letter; }
5478
                        if(gridCols[letter] == $kids.length){ grid = letter; }
5479
                    }
5479
                    }
5480
                }
5480
                }
5481
                else{
5481
                else{
5482
                    grid = 'a';
5482
                    grid = 'a';
5483
                }
5483
                }
5484
            }
5484
            }
5485
            iterator = gridCols[grid];
5485
            iterator = gridCols[grid];
5486
           
5486
           
5487
        $(this).addClass('ui-grid-' + grid);
5487
        $(this).addClass('ui-grid-' + grid);
5488
   
5488
   
5489
        $kids.filter(':nth-child(' + iterator + 'n+1)').addClass('ui-block-a');
5489
        $kids.filter(':nth-child(' + iterator + 'n+1)').addClass('ui-block-a');
5490
        if(iterator > 1){  
5490
        if(iterator > 1){  
5491
            $kids.filter(':nth-child(' + iterator + 'n+2)').addClass('ui-block-b');
5491
            $kids.filter(':nth-child(' + iterator + 'n+2)').addClass('ui-block-b');
5492
        }  
5492
        }  
5493
        if(iterator > 2){  
5493
        if(iterator > 2){  
5494
            $kids.filter(':nth-child(3n+3)').addClass('ui-block-c');
5494
            $kids.filter(':nth-child(3n+3)').addClass('ui-block-c');
5495
        }  
5495
        }  
5496
        if(iterator > 3){  
5496
        if(iterator > 3){  
5497
            $kids.filter(':nth-child(4n+4)').addClass('ui-block-d');
5497
            $kids.filter(':nth-child(4n+4)').addClass('ui-block-d');
5498
        }  
5498
        }  
5499
        if(iterator > 4){  
5499
        if(iterator > 4){  
5500
            $kids.filter(':nth-child(5n+5)').addClass('ui-block-e');
5500
            $kids.filter(':nth-child(5n+5)').addClass('ui-block-e');
5501
        }
5501
        }
5502
               
5502
               
5503
    });
5503
    });
5504
};
5504
};
5505
})(jQuery);/*!
5505
})(jQuery);/*!
5506
 * jQuery Mobile v@VERSION
5506
 * jQuery Mobile v@VERSION
5507
 * http://jquerymobile.com/
5507
 * http://jquerymobile.com/
5508
 *
5508
 *
5509
 * Copyright 2010, jQuery Project
5509
 * Copyright 2010, jQuery Project
5510
 * Dual licensed under the MIT or GPL Version 2 licenses.
5510
 * Dual licensed under the MIT or GPL Version 2 licenses.
5511
 * http://jquery.org/license
5511
 * http://jquery.org/license
5512
 */
5512
 */
5513
 
5513
 
5514
(function( $, window, undefined ) {
5514
(function( $, window, undefined ) {
5515
    var $html = $( "html" ),
5515
    var $html = $( "html" ),
5516
            $head = $( "head" ),
5516
            $head = $( "head" ),
5517
            $window = $( window );
5517
            $window = $( window );
5518
 
5518
 
5519
    //trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
5519
    //trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
5520
    $( window.document ).trigger( "mobileinit" );
5520
    $( window.document ).trigger( "mobileinit" );
5521
 
5521
 
5522
    //support conditions
5522
    //support conditions
5523
    //if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
5523
    //if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
5524
    //otherwise, proceed with the enhancements
5524
    //otherwise, proceed with the enhancements
5525
    if ( !$.mobile.gradeA() ) {
5525
    if ( !$.mobile.gradeA() ) {
5526
        return;
5526
        return;
5527
    }
5527
    }
5528
   
5528
   
5529
    // override ajaxEnabled on platforms that have known conflicts with hash history updates 
5529
    // override ajaxEnabled on platforms that have known conflicts with hash history updates 
5530
    // or generally work better browsing in regular http for full page refreshes (BB5, Opera Mini)
5530
    // or generally work better browsing in regular http for full page refreshes (BB5, Opera Mini)
5531
    if( window.blackberry && !window.WebKitPoint || window.operamini && Object.prototype.toString.call( window.operamini ) === "[object OperaMini]" ){
5531
    if( window.blackberry && !window.WebKitPoint || window.operamini && Object.prototype.toString.call( window.operamini ) === "[object OperaMini]" ){
5532
        $.mobile.ajaxEnabled = false;
5532
        $.mobile.ajaxEnabled = false;
5533
    }
5533
    }
5534
 
5534
 
5535
    //add mobile, initial load "rendering" classes to docEl
5535
    //add mobile, initial load "rendering" classes to docEl
5536
    $html.addClass( "ui-mobile ui-mobile-rendering" );
5536
    $html.addClass( "ui-mobile ui-mobile-rendering" );
5537
 
5537
 
5538
    //loading div which appears during Ajax requests
5538
    //loading div which appears during Ajax requests
5539
    //will not appear if $.mobile.loadingMessage is false
5539
    //will not appear if $.mobile.loadingMessage is false
5540
    var $loader = $.mobile.loadingMessage ?     $( "<div class='ui-loader ui-body-a ui-corner-all'>" + "<span class='ui-icon ui-icon-loading spin'></span>" + "<h1>" + $.mobile.loadingMessage + "</h1>" + "</div>" )   : undefined;
5540
    var $loader = $.mobile.loadingMessage ?     $( "<div class='ui-loader ui-body-a ui-corner-all'>" + "<span class='ui-icon ui-icon-loading spin'></span>" + "<h1>" + $.mobile.loadingMessage + "</h1>" + "</div>" )   : undefined;
5541
 
5541
 
5542
    $.extend($.mobile, {
5542
    $.extend($.mobile, {
5543
        // turn on/off page loading message.
5543
        // turn on/off page loading message.
5544
        showPageLoadingMsg: function() {
5544
        showPageLoadingMsg: function() {
5545
            if( $.mobile.loadingMessage ){
5545
            if( $.mobile.loadingMessage ){
5546
                var activeBtn = $( "." + $.mobile.activeBtnClass ).first();
5546
                var activeBtn = $( "." + $.mobile.activeBtnClass ).first();
5547
           
5547
           
5548
                $loader
5548
                $loader
5549
                    .appendTo( $.mobile.pageContainer )
5549
                    .appendTo( $.mobile.pageContainer )
5550
                    //position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
5550
                    //position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
5551
                    .css( {
5551
                    .css( {
5552
                        top: $.support.scrollTop && $(window).scrollTop() + $(window).height() / 2 ||
5552
                        top: $.support.scrollTop && $(window).scrollTop() + $(window).height() / 2 ||
5553
                        activeBtn.length && activeBtn.offset().top || 100
5553
                        activeBtn.length && activeBtn.offset().top || 100
5554
                    } );
5554
                    } );
5555
            }
5555
            }
5556
           
5556
           
5557
            $html.addClass( "ui-loading" );
5557
            $html.addClass( "ui-loading" );
5558
        },
5558
        },
5559
 
5559
 
5560
        hidePageLoadingMsg: function() {
5560
        hidePageLoadingMsg: function() {
5561
            $html.removeClass( "ui-loading" );
5561
            $html.removeClass( "ui-loading" );
5562
        },
5562
        },
5563
 
5563
 
5564
        // XXX: deprecate for 1.0
5564
        // XXX: deprecate for 1.0
5565
        pageLoading: function ( done ) {
5565
        pageLoading: function ( done ) {
5566
            if ( done ) {
5566
            if ( done ) {
5567
                $.mobile.hidePageLoadingMsg();
5567
                $.mobile.hidePageLoadingMsg();
5568
            } else {
5568
            } else {
5569
                $.mobile.showPageLoadingMsg();
5569
                $.mobile.showPageLoadingMsg();
5570
            }
5570
            }
5571
        },
5571
        },
5572
 
5572
 
5573
        // find and enhance the pages in the dom and transition to the first page.
5573
        // find and enhance the pages in the dom and transition to the first page.
5574
        initializePage: function(){
5574
        initializePage: function(){
5575
            //find present pages
5575
            //find present pages
5576
            var $pages = $( ":jqmData(role='page')" );
5576
            var $pages = $( ":jqmData(role='page')" );
5577
 
5577
 
5578
            //add dialogs, set data-url attrs
5578
            //add dialogs, set data-url attrs
5579
            $pages.add( ":jqmData(role='dialog')" ).each(function(){
5579
            $pages.add( ":jqmData(role='dialog')" ).each(function(){
5580
                var $this = $(this);
5580
                var $this = $(this);
5581
 
5581
 
5582
                // unless the data url is already set set it to the id
5582
                // unless the data url is already set set it to the id
5583
                if( !$this.jqmData('url') ){
5583
                if( !$this.jqmData('url') ){
5584
                    $this.attr( "data-" + $.mobile.ns + "url", $this.attr( "id" ) );
5584
                    $this.attr( "data-" + $.mobile.ns + "url", $this.attr( "id" ) );
5585
                }
5585
                }
5586
            });
5586
            });
5587
 
5587
 
5588
            //define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
5588
            //define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
5589
            $.mobile.firstPage = $pages.first();
5589
            $.mobile.firstPage = $pages.first();
5590
 
5590
 
5591
            //define page container
5591
            //define page container
5592
            $.mobile.pageContainer = $pages.first().parent().addClass( "ui-mobile-viewport" );
5592
            $.mobile.pageContainer = $pages.first().parent().addClass( "ui-mobile-viewport" );
5593
 
5593
 
5594
            //cue page loading message
5594
            //cue page loading message
5595
            $.mobile.showPageLoadingMsg();
5595
            $.mobile.showPageLoadingMsg();
5596
 
5596
 
5597
            // if hashchange listening is disabled or there's no hash deeplink, change to the first page in the DOM
5597
            // if hashchange listening is disabled or there's no hash deeplink, change to the first page in the DOM
5598
            if( !$.mobile.hashListeningEnabled || !$.mobile.path.stripHash( location.hash ) ){
5598
            if( !$.mobile.hashListeningEnabled || !$.mobile.path.stripHash( location.hash ) ){
5599
                $.mobile.changePage( $.mobile.firstPage, { transition: "none", reverse: true, changeHash: false, fromHashChange: true } );
5599
                $.mobile.changePage( $.mobile.firstPage, { transition: "none", reverse: true, changeHash: false, fromHashChange: true } );
5600
            }
5600
            }
5601
            // otherwise, trigger a hashchange to load a deeplink
5601
            // otherwise, trigger a hashchange to load a deeplink
5602
            else {
5602
            else {
5603
                $window.trigger( "hashchange", [ true ] );
5603
                $window.trigger( "hashchange", [ true ] );
5604
            }
5604
            }
5605
        }
5605
        }
5606
    });
5606
    });
5607
   
5607
   
5608
    //check which scrollTop value should be used by scrolling to 1 immediately at domready
5608
    //check which scrollTop value should be used by scrolling to 1 immediately at domready
5609
    //then check what the scroll top is. Android will report 0... others 1
5609
    //then check what the scroll top is. Android will report 0... others 1
5610
    //note that this initial scroll won't hide the address bar. It's just for the check.
5610
    //note that this initial scroll won't hide the address bar. It's just for the check.
5611
    $(function(){
5611
    $(function(){
5612
        window.scrollTo( 0, 1 );
5612
        window.scrollTo( 0, 1 );
5613
   
5613
   
5614
        //if defaultHomeScroll hasn't been set yet, see if scrollTop is 1
5614
        //if defaultHomeScroll hasn't been set yet, see if scrollTop is 1
5615
        //it should be 1 in most browsers, but android treats 1 as 0 (for hiding addr bar)
5615
        //it should be 1 in most browsers, but android treats 1 as 0 (for hiding addr bar)
5616
        //so if it's 1, use 0 from now on
5616
        //so if it's 1, use 0 from now on
5617
        $.mobile.defaultHomeScroll = ( !$.support.scrollTop || $(window).scrollTop() === 1 ) ? 0 : 1;
5617
        $.mobile.defaultHomeScroll = ( !$.support.scrollTop || $(window).scrollTop() === 1 ) ? 0 : 1;
5618
   
5618
   
5619
        //dom-ready inits
5619
        //dom-ready inits
5620
        $( $.mobile.initializePage );
5620
        $( $.mobile.initializePage );
5621
   
5621
   
5622
        //window load event
5622
        //window load event
5623
        //hide iOS browser chrome on load
5623
        //hide iOS browser chrome on load
5624
        $window.load( $.mobile.silentScroll );
5624
        $window.load( $.mobile.silentScroll );
5625
    });
5625
    });
5626
})( jQuery, this );
5626
})( jQuery, this );
5627
 
5627