fume 0.2.6 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1091 @@
1
+ /*!
2
+ * URL Utils - v1.11 - 9/10/2009
3
+ * http://benalman.com/
4
+ *
5
+ * Copyright (c) 2009 "Cowboy" Ben Alman
6
+ * Licensed under the MIT license
7
+ * http://benalman.com/about/license/
8
+ */
9
+
10
+ // Script: URL Utils
11
+ //
12
+ // Version: 1.11, Date: 9/10/2009
13
+ //
14
+ // Tested with jQuery 1.3.2 in Internet Explorer 6-8, Firefox 3-3.6a,
15
+ // Safari 3-4, Chrome, Opera 9.6.
16
+ //
17
+ // Home - http://benalman.com/projects/jquery-url-utils-plugin/
18
+ // Source - http://benalman.com/code/javascript/jquery/jquery.ba-url.js
19
+ // (Minified) - http://benalman.com/code/javascript/jquery/jquery.ba-url.min.js (3.9kb)
20
+ // Unit Tests - http://benalman.com/code/unittest/url.html
21
+ //
22
+ // About: License
23
+ //
24
+ // Copyright (c) 2009 "Cowboy" Ben Alman
25
+ //
26
+ // Licensed under the MIT license
27
+ //
28
+ // http://benalman.com/about/license/
29
+ //
30
+ // About: Revision History
31
+ //
32
+ // 1.11 - Minor bugfix for Firefox 3.0+
33
+ // 1.1 - Added support for onhashchange event
34
+ // 1.0 - Initial release
35
+
36
+ (function($) {
37
+ '$:nomunge'; // Used by YUI compressor.
38
+
39
+ var url_regexp,
40
+ tag_attributes = {},
41
+
42
+ // A few constants.
43
+ undefined,
44
+ window = this,
45
+ TRUE = true,
46
+ FALSE = false,
47
+ has_onhashchange = 'onhashchange' in window,
48
+
49
+ // Some convenient shortcuts.
50
+ aps = Array.prototype.slice,
51
+ loc = document.location,
52
+
53
+ // Internal plugin method references.
54
+ p_urlTagAttrList,
55
+ p_urlInternalHost,
56
+ p_urlInternalRegExp,
57
+ p_isUrlInternal,
58
+ p_isUrlExternal,
59
+ p_urlFilter,
60
+ p_urlFilterSelector,
61
+ p_setFragment,
62
+
63
+ // Reused internal strings.
64
+ str_urlInternal = 'urlInternal',
65
+ str_urlExternal = 'urlExternal',
66
+ str_queryString = 'queryString',
67
+ str_fragment = 'fragment',
68
+ str_update = 'update',
69
+ str_passQueryString = 'passQueryString',
70
+ str_passFragment = 'passFragment',
71
+ str_fragmentChange = 'fragmentChange',
72
+ str_hashchange = 'hashchange.' + str_fragmentChange,
73
+
74
+ // fragmentChange event handler
75
+ timeout_id,
76
+ last_fragment;
77
+
78
+
79
+ // A few commonly used bits, broken out to help reduce minified file size.
80
+
81
+ function is_string( arg ) {
82
+ return typeof arg === 'string';
83
+ };
84
+
85
+ function is_object( arg ) {
86
+ return typeof arg === 'object';
87
+ };
88
+
89
+ function curry() {
90
+ var args = aps.call( arguments ),
91
+ func = args.shift();
92
+
93
+ return function() {
94
+ return func.apply( this, args.concat( aps.call( arguments ) ) );
95
+ };
96
+ };
97
+
98
+ // Work-around for an annoying Firefox bug where document.location.hash gets
99
+ // urldecoded by default.
100
+
101
+ function get_fragment() {
102
+ return loc.href.replace( /^[^#]*#?/, '' );
103
+ };
104
+
105
+
106
+ // Method: jQuery.urlTagAttrList
107
+ //
108
+ // Get the internal "Default URL attribute per tag" list, or augment the list
109
+ // with additional tag-attribute pairs, in case the defaults are insufficient.
110
+ //
111
+ // This list contains the default attributes for the <jQuery.fn.urlInternal>
112
+ // and <jQuery.fn.urlExternal> methods, as well as the <:urlInternal> and
113
+ // <:urlExternal> selector filters, to determine which URL will be tested for
114
+ // internal- or external-ness. In the <jQuery.fn.queryString>,
115
+ // <jQuery.fn.fragment>, <jQuery.fn.passQueryString> and
116
+ // <jQuery.fn.passFragment> methods, this list is used to determine which URL
117
+ // will be modified.
118
+ //
119
+ // Default List:
120
+ //
121
+ // TAG - URL ATTRIBUTE
122
+ // a - href
123
+ // img - src
124
+ // form - action
125
+ // base - href
126
+ // script - src
127
+ // iframe - src
128
+ // link - href
129
+ //
130
+ // Usage:
131
+ //
132
+ // jQuery.urlTagAttrList( [ tag_attr_obj ] ); - -
133
+ //
134
+ // Arguments:
135
+ //
136
+ // tag_attr_obj - (Object) An list of tag names and associated default
137
+ // attribute names in the format { tag: 'attr', tag: 'attr', ... }.
138
+ //
139
+ // Returns:
140
+ //
141
+ // (Object) The current internal "Default URL attribute per tag" list.
142
+
143
+ $.urlTagAttrList = p_urlTagAttrList = function( attr_obj ) {
144
+ return $.extend( tag_attributes, attr_obj );
145
+ };
146
+
147
+ // Initialize the tag_attributes object with some reasonable defaults.
148
+
149
+ p_urlTagAttrList({
150
+ a: 'href',
151
+ img: 'src',
152
+ form: 'action',
153
+ base: 'href',
154
+ script: 'src',
155
+ iframe: 'src',
156
+ link: 'href'
157
+ });
158
+
159
+ // Get the default attribute for the specified DOM element, if it exists.
160
+
161
+ function get_attr( elem ) {
162
+ var n = elem.nodeName;
163
+ return n ? tag_attributes[ n.toLowerCase() ] : '';
164
+ };
165
+
166
+
167
+ // Section: URL Internal / External
168
+ //
169
+ // Method: jQuery.urlInternalHost
170
+ //
171
+ // Constructs the regular expression that matches an absolute-but-internal
172
+ // URL from the current page's protocol, hostname and port, allowing for
173
+ // an optional hostname (if specified). For example, if the current page is
174
+ // http://benalman.com/anything, specifying an alt_hostname of 'www' would
175
+ // yield this pattern:
176
+ //
177
+ // > /^http:\/\/(?:www\.)?benalman.com\//i
178
+ //
179
+ // This pattern will match URLs beginning with both http://benalman.com/ and
180
+ // http://www.benalman.com/. Specifying an empty alt_hostname will disable any
181
+ // alt-hostname matching.
182
+ //
183
+ // Note that the plugin is initialized by default to an alt_hostname of 'www'.
184
+ // Should you need more control, <jQuery.urlInternalRegExp> may be used to
185
+ // completely override this absolute-but-internal matching pattern.
186
+ //
187
+ // Usage:
188
+ //
189
+ // jQuery.urlInternalHost( [ alt_hostname ] ); - -
190
+ //
191
+ // Arguments:
192
+ //
193
+ // alt_hostname - (String) An optional alternate hostname to use when testing
194
+ // URL absolute-but-internal-ness.
195
+ //
196
+ // Returns:
197
+ //
198
+ // (RegExp) The absolute-but-internal pattern, as a RegExp.
199
+
200
+ $.urlInternalHost = p_urlInternalHost = function( alt_hostname ) {
201
+ alt_hostname = alt_hostname
202
+ ? '(?:' + alt_hostname + '\\.)?'
203
+ : '';
204
+
205
+ var re = new RegExp( '^' + alt_hostname + '(.*)', 'i' ),
206
+ pattern = '^' + loc.protocol + '//'
207
+ + loc.hostname.replace(re, alt_hostname + '$1')
208
+ //+ 'benalman.com'.replace(re, alt_hostname + '$1') // For testing on stage.benalman.com
209
+ + (loc.port ? ':' + loc.port : '') + '/';
210
+
211
+ return p_urlInternalRegExp( pattern );
212
+ };
213
+
214
+
215
+ // Method: jQuery.urlInternalRegExp
216
+ //
217
+ // Set or get the regular expression that matches an absolute-but-internal
218
+ // URL.
219
+ //
220
+ // Usage:
221
+ //
222
+ // jQuery.urlInternalRegExp( [ re ] ); - -
223
+ //
224
+ // Arguments:
225
+ //
226
+ // re - (String or RegExp) The regular expression pattern. If not passed,
227
+ // nothing is changed.
228
+ //
229
+ // Returns:
230
+ //
231
+ // (RegExp) The absolute-but-internal pattern, as a RegExp.
232
+
233
+ $.urlInternalRegExp = p_urlInternalRegExp = function( re ) {
234
+ if ( re ) {
235
+ url_regexp = is_string( re )
236
+ ? new RegExp( re, 'i' )
237
+ : re;
238
+ }
239
+
240
+ return url_regexp;
241
+ };
242
+
243
+
244
+ // Initialize url_regexp with a reasonable default.
245
+
246
+ p_urlInternalHost( 'www' );
247
+
248
+
249
+ // Method: jQuery.isUrlInternal
250
+ //
251
+ // Test whether or not a URL is internal. Non-navigating URLs (ie. #anchor,
252
+ // javascript:, mailto:, news:, tel:, im: or non-http/-https protocol://
253
+ // links) are not considered internal.
254
+ //
255
+ // Usage:
256
+ //
257
+ // jQuery.isUrlInternal( url ); - -
258
+ //
259
+ // Arguments:
260
+ //
261
+ // url - (String) a URL to test the internal-ness of.
262
+ //
263
+ // Returns:
264
+ //
265
+ // (Boolean) true if the URL is internal, false if external, or undefined if
266
+ // the URL is non-navigating.
267
+
268
+ $.isUrlInternal = p_isUrlInternal = function( url ) {
269
+
270
+ // non-navigating: url is nonexistent
271
+ if ( !url ) { return undefined; }
272
+
273
+ // internal: url is absolute-but-internal (see $.urlInternalRegExp)
274
+ if ( url_regexp.test(url) ) { return TRUE; }
275
+
276
+ // external: url is absolute (begins with http:// or https://)
277
+ if ( /^https?:\/\//i.test(url) ) { return FALSE; }
278
+
279
+ // non-navigating: url begins with # or scheme:
280
+ if ( /^(?:#|[a-z\d.-]+:)/i.test(url) ) { return undefined; }
281
+
282
+ return TRUE;
283
+ };
284
+
285
+
286
+ // Method: jQuery.isUrlExternal
287
+ //
288
+ // Test whether or not a URL is external. Non-navigating URLs (ie. #anchor,
289
+ // mailto:, javascript:, or non-http/-https protocol:// links) are not
290
+ // considered external.
291
+ //
292
+ // Usage:
293
+ //
294
+ // jQuery.isUrlExternal( url ); - -
295
+ //
296
+ // Arguments:
297
+ //
298
+ // url - (String) a URL to test the external-ness of.
299
+ //
300
+ // Returns:
301
+ //
302
+ // (Boolean) true if the URL is external, false if internal, or undefined if
303
+ // the URL is non-navigating.
304
+
305
+ $.isUrlExternal = p_isUrlExternal = function( url ) {
306
+ var result = p_isUrlInternal( url );
307
+
308
+ return typeof result === 'boolean'
309
+ ? !result
310
+ : result;
311
+ };
312
+
313
+
314
+ // Method: jQuery.fn.urlInternal
315
+ //
316
+ // Filter a jQuery collection of elements, returning only elements that have
317
+ // an internal URL (as determined by <jQuery.isUrlInternal>). If URL cannot
318
+ // be determined, remove the element from the collection.
319
+ //
320
+ // Usage:
321
+ //
322
+ // jQuery('selector').urlInternal( [ attr ] ); - -
323
+ //
324
+ // Arguments:
325
+ //
326
+ // attr - (String) Optional name of an attribute that will contain a URL to
327
+ // test internal-ness against. See <jQuery.urlTagAttrList> for a list of
328
+ // default attributes.
329
+ //
330
+ // Returns:
331
+ //
332
+ // (jQuery) A filtered jQuery collection of elements.
333
+
334
+ // Method: jQuery.fn.urlExternal
335
+ //
336
+ // Filter a jQuery collection of elements, returning only elements that have
337
+ // an external URL (as determined by <jQuery.isUrlExternal>). If URL cannot
338
+ // be determined, remove the element from the collection.
339
+ //
340
+ // Usage:
341
+ //
342
+ // jQuery('selector').urlExternal( [ attr ] ); - -
343
+ //
344
+ // Arguments:
345
+ //
346
+ // attr - (String) Optional name of an attribute that will contain a URL to
347
+ // test external-ness against. See <jQuery.urlTagAttrList> for a list of
348
+ // default attributes.
349
+ //
350
+ // Returns:
351
+ //
352
+ // (jQuery) A filtered jQuery collection of elements.
353
+
354
+ p_urlFilter = function( selector, attr ) {
355
+ return this.filter( ':' + selector + (attr ? '(' + attr + ')' : '') );
356
+ };
357
+
358
+ $.fn[str_urlInternal] = curry( p_urlFilter, str_urlInternal );
359
+ $.fn[str_urlExternal] = curry( p_urlFilter, str_urlExternal );
360
+
361
+
362
+ // Method: :urlInternal
363
+ //
364
+ // Filter a jQuery collection of elements, returning only elements that have
365
+ // an internal URL (as determined by <jQuery.isUrlInternal>). If URL cannot
366
+ // be determined, remove the element from the collection.
367
+ //
368
+ // Usage:
369
+ //
370
+ // jQuery('selector').filter(':urlInternal'); - -
371
+ // jQuery('selector').filter(':urlInternal(attr)'); - -
372
+ //
373
+ // Arguments:
374
+ //
375
+ // attr - (String) Optional name of an attribute that will contain a URL to
376
+ // test internal-ness against. See <jQuery.urlTagAttrList> for a list of
377
+ // default attributes.
378
+ //
379
+ // Returns:
380
+ //
381
+ // (jQuery) A filtered jQuery collection of elements.
382
+
383
+ // Method: :urlExternal
384
+ //
385
+ // Filter a jQuery collection of elements, returning only elements that have
386
+ // an external URL (as determined by <jQuery.isUrlExternal>). If URL cannot
387
+ // be determined, remove the element from the collection.
388
+ //
389
+ // Usage:
390
+ //
391
+ // jQuery('selector').filter(':urlExternal'); - -
392
+ // jQuery('selector').filter(':urlExternal(attr)'); - -
393
+ //
394
+ // Arguments:
395
+ //
396
+ // attr - (String) Optional name of an attribute that will contain a URL to
397
+ // test external-ness against. See <jQuery.urlTagAttrList> for a list of
398
+ // default attributes.
399
+ //
400
+ // Returns:
401
+ //
402
+ // (jQuery) A filtered jQuery collection of elements.
403
+
404
+ p_urlFilterSelector = function( func, elem, i, match ) {
405
+ var a = match[3] || get_attr( elem );
406
+
407
+ return a ? !!func( $(elem).attr(a) ) : FALSE;
408
+ };
409
+
410
+ $.expr[':'][str_urlInternal] = curry( p_urlFilterSelector, p_isUrlInternal );
411
+ $.expr[':'][str_urlExternal] = curry( p_urlFilterSelector, p_isUrlExternal );
412
+
413
+
414
+ // Section: URL Query String / Fragment
415
+ //
416
+ // Method: jQuery.queryString (deserialize)
417
+ //
418
+ // Deserialize any params string or the current document's query string into
419
+ // an object. Multiple sequential values will be converted into an array, ie.
420
+ // 'n=a&n=b&n=c' -> { n: ['a', 'b', 'c'] }.
421
+ //
422
+ // Usage:
423
+ //
424
+ // jQuery.queryString( [ params_str ] [ , cast_values ] ); - -
425
+ //
426
+ // Arguments:
427
+ //
428
+ // params_str - (String) A stand-alone params string or a URL containing
429
+ // params to be deserialized. If omitted, defaults to the current page
430
+ // query string (document.location.search).
431
+ // cast_values - (Boolean) If true, converts any numbers or true, false,
432
+ // null, and undefined to their appropriate literal. Defaults to false.
433
+ //
434
+ // Returns:
435
+ //
436
+ // (Object) The deserialized params string.
437
+
438
+ // Method: jQuery.queryString (serialize)
439
+ //
440
+ // Serialize an object into a params string. Arrays will be converted to
441
+ // multiple sequential values, ie. { n: ['a', 'b', 'c'] } -> 'n=a&n=b&n=c'
442
+ // (this method is just a wrapper for jQuery.param).
443
+ //
444
+ // Usage:
445
+ //
446
+ // jQuery.queryString( params_obj ); - -
447
+ //
448
+ // Arguments:
449
+ //
450
+ // params_obj - (Object) An object to be serialized. Note: A JSON string (or
451
+ // some analog) should be used for deep structures, since nested data
452
+ // structures other than shallow arrays can't be serialized into a query
453
+ // string in a meaningful way.
454
+ //
455
+ // Returns:
456
+ //
457
+ // (String) A params string with urlencoded data in the format 'a=b&c=d&e=f'.
458
+
459
+ // Method: jQuery.queryString (build url)
460
+ //
461
+ // Merge a URL (with or without a pre-existing params) plus any object or
462
+ // params string into a new URL.
463
+ //
464
+ // Usage:
465
+ //
466
+ // jQuery.queryString( url, params [ , merge_mode ] ); - -
467
+ //
468
+ // Arguments:
469
+ //
470
+ // url - (String) A valid URL, optionally containing a query string and/or
471
+ // #anchor, or fragment.
472
+ // params - (String or Object) Either a serialized params string or a data
473
+ // object to be merged into the URL.
474
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
475
+ // specified, and is as-follows:
476
+ //
477
+ // * 0: params argument will override any params in url.
478
+ // * 1: any params in url will override params argument.
479
+ // * 2: params argument will completely replace any params in url.
480
+ //
481
+ // Returns:
482
+ //
483
+ // (String) A URL with urlencoded params in the format 'url?a=b&c=d&e=f'.
484
+
485
+ // Method: jQuery.fragment (deserialize)
486
+ //
487
+ // Deserialize any params string or the current document's fragment into an
488
+ // object. Multiple sequential values will be converted into an array, ie.
489
+ // 'n=a&n=b&n=c' -> { n: ['a', 'b', 'c'] }.
490
+ //
491
+ // Usage:
492
+ //
493
+ // jQuery.fragment( [ params_str ] [ , cast_values ] ); - -
494
+ //
495
+ // Arguments:
496
+ //
497
+ // params_str - (String) A stand-alone params string or a URL containing
498
+ // params to be deserialized. If omitted, defaults to the current page
499
+ // fragment (document.location.hash).
500
+ // cast_values - (Boolean) If true, converts any numbers or true, false,
501
+ // null, and undefined to their appropriate literal. Defaults to false.
502
+ //
503
+ // Returns:
504
+ //
505
+ // (Object) The deserialized params string.
506
+
507
+ // Method: jQuery.fragment (serialize)
508
+ //
509
+ // Serialize an object into a params string. Arrays will be converted to
510
+ // multiple sequential values, ie. { n: ['a', 'b', 'c'] } -> 'n=a&n=b&n=c'
511
+ // (this method is just a wrapper for jQuery.param).
512
+ //
513
+ // Usage:
514
+ //
515
+ // jQuery.fragment( params_obj ); - -
516
+ //
517
+ // Arguments:
518
+ //
519
+ // params_obj - (Object) An object to be serialized. Note: A JSON string (or
520
+ // some analog) should be used for deep structures, since nested data
521
+ // structures other than shallow arrays can't be serialized into a query
522
+ // string in a meaningful way.
523
+ //
524
+ // Returns:
525
+ //
526
+ // (String) A params string with urlencoded data in the format 'a=b&c=d&e=f'.
527
+
528
+ // Method: jQuery.fragment (build url)
529
+ //
530
+ // Merge a URL (with or without a pre-existing params) plus any object or
531
+ // params string into a new URL.
532
+ //
533
+ // Usage:
534
+ //
535
+ // jQuery.fragment( url, params [ , merge_mode ] ); - -
536
+ //
537
+ // Arguments:
538
+ //
539
+ // url - (String) A valid URL, optionally containing a query string and/or
540
+ // #anchor, or fragment.
541
+ // params - (String or Object) Either a serialized params string or a data
542
+ // object to be merged into the URL.
543
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
544
+ // specified, and is as-follows:
545
+ //
546
+ // * 0: params argument will override any params in url.
547
+ // * 1: any params in url will override params argument.
548
+ // * 2: params argument will completely replace any params in url.
549
+ //
550
+ // Returns:
551
+ //
552
+ // (String) A URL with urlencoded params in the format 'url#a=b&c=d&e=f'.
553
+
554
+ function p_params( fragment_mode, arg0, arg1, arg2 ) {
555
+ var params;
556
+
557
+ if ( is_string(arg1) || is_object(arg1) ) {
558
+ // Build URL.
559
+ return build_url( arg0, arg1, arg2, fragment_mode );
560
+
561
+ } else if ( is_object(arg0) ) {
562
+ // Serialize.
563
+ return $.param( arg0 );
564
+
565
+ } else if ( is_string(arg0) ) {
566
+ // Deserialize.
567
+ return deserialize( arg0, arg1, fragment_mode );
568
+
569
+ } else {
570
+ // Deserialize document query string / fragment.
571
+ params = fragment_mode
572
+ ? get_fragment()
573
+ : loc.search;
574
+
575
+ return deserialize( params, arg0, fragment_mode );
576
+ }
577
+ };
578
+
579
+ $[str_queryString] = curry( p_params, 0 );
580
+ $[str_fragment] = curry( p_params, 1 );
581
+
582
+ // Method: jQuery.fn.queryString
583
+ //
584
+ // Update URL attribute in one or more elements, merging the current URL (with
585
+ // or without pre-existing params) plus any object or params string into a new
586
+ // URL, which is then set into that attribute. Like <jQuery.queryString (build
587
+ // url)>, but for all elements in a jQuery collection.
588
+ //
589
+ // Usage:
590
+ //
591
+ // jQuery('selector').queryString( [ attr, ] params [ , merge_mode ] ); - -
592
+ //
593
+ // Arguments:
594
+ //
595
+ // attr - (String) Optional name of an attribute that will contain a URL to
596
+ // merge params into. See <jQuery.urlTagAttrList> for a list of default
597
+ // attributes.
598
+ // params - (String or Object) Either a serialized params string or a data
599
+ // object to be merged into the URL.
600
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
601
+ // specified, and is as-follows:
602
+ //
603
+ // * 0: params argument will override any params in attr URL.
604
+ // * 1: any params in attr URL will override params argument.
605
+ // * 2: params argument will completely replace any params in attr URL.
606
+ //
607
+ // Returns:
608
+ //
609
+ // (jQuery) The initial jQuery collection of elements, but with modified URL
610
+ // attribute values.
611
+
612
+ // Method: jQuery.fn.fragment
613
+ //
614
+ // Update URL attribute in one or more elements, merging the current URL (with
615
+ // or without pre-existing params) plus any object or params string into a new
616
+ // URL, which is then set into that attribute. Like <jQuery.fragment (build
617
+ // url)>, but for all elements in a jQuery collection.
618
+ //
619
+ // Usage:
620
+ //
621
+ // jQuery('selector').fragment( [ attr, ] params [ , merge_mode ] ); - -
622
+ //
623
+ // Arguments:
624
+ //
625
+ // attr - (String) Optional name of an attribute that will contain a URL to
626
+ // merge params into. See <jQuery.urlTagAttrList> for a list of default
627
+ // attributes.
628
+ // params - (String or Object) Either a serialized params string or a data
629
+ // object to be merged into the URL.
630
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
631
+ // specified, and is as-follows:
632
+ //
633
+ // * 0: params argument will override any params in attr URL.
634
+ // * 1: any params in attr URL will override params argument.
635
+ // * 2: params argument will completely replace any params in attr URL.
636
+ //
637
+ // Returns:
638
+ //
639
+ // (jQuery) The initial jQuery collection of elements, but with modified URL
640
+ // attribute values.
641
+
642
+ function p_fn_params() {
643
+ var attr,
644
+ params,
645
+ merge_mode,
646
+ args = aps.call( arguments ),
647
+ fragment_mode = args.shift();
648
+
649
+ if ( is_string(args[1]) || is_object(args[1]) ) {
650
+ attr = args.shift();
651
+ }
652
+ params = args.shift();
653
+ merge_mode = args.shift();
654
+
655
+ return this.each(function(){
656
+
657
+ var that = $(this),
658
+ a = attr || get_attr( this ),
659
+ url = a && that.attr( a ) || '';
660
+
661
+ url = p_params( fragment_mode, url, params, merge_mode );
662
+ that.attr( a, url );
663
+
664
+ });
665
+ };
666
+
667
+ $.fn[str_queryString] = curry( p_fn_params, 0 );
668
+ $.fn[str_fragment] = curry( p_fn_params, 1 );
669
+
670
+ // Method: jQuery.passQueryString
671
+ //
672
+ // Merge a URL (with or without pre-existing params) plus the document query
673
+ // string into a new URL, optionally omitting specified params or parsing the
674
+ // document params with a callback function pre-merge.
675
+ //
676
+ // Usage:
677
+ //
678
+ // jQuery.passQueryString( url [ , parse ] [ , merge_mode ] ); - -
679
+ //
680
+ // Arguments:
681
+ //
682
+ // url - (String) A valid URL, optionally containing a query string and/or
683
+ // #anchor, or fragment.
684
+ // parse - (Array or Function) An optional array of key names to -not- merge
685
+ // into the URL, or a function that returns the object that will be merged
686
+ // into url (the document params are deserialized and passed to this
687
+ // function as its only argument).
688
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
689
+ // specified, and is as-follows:
690
+ //
691
+ // * 0: document params will override any params in url.
692
+ // * 1: any params in url will override document params.
693
+ // * 2: document params will completely replace any params in url.
694
+ //
695
+ // Returns:
696
+ //
697
+ // (String) A URL with urlencoded params in the format 'url?a=b&c=d&e=f'.
698
+
699
+ // Method: jQuery.passFragment
700
+ //
701
+ // Merge a URL (with or without pre-existing params) plus the document
702
+ // fragment into a new URL, optionally omitting specified params or parsing
703
+ // the document params with a callback function pre-merge.
704
+ //
705
+ // Usage:
706
+ //
707
+ // jQuery.passFragment( url [ , parse ] [ , merge_mode ] ); - -
708
+ //
709
+ // Arguments:
710
+ //
711
+ // url - (String) A valid URL, optionally containing a query string and/or
712
+ // #anchor, or fragment.
713
+ // parse - (Array or Function) An optional array of key names to -not- merge
714
+ // into the URL, or a function that returns the object that will be merged
715
+ // into url (the document params are deserialized and passed to this
716
+ // function as its only argument).
717
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
718
+ // specified, and is as-follows:
719
+ //
720
+ // * 0: document params will override any params in url.
721
+ // * 1: any params in url will override document params.
722
+ // * 2: document params will completely replace any params in url.
723
+ //
724
+ // Returns:
725
+ //
726
+ // (String) A URL with urlencoded params in the format 'url#a=b&c=d&e=f'.
727
+
728
+ function p_passParams() {
729
+ var args = aps.call( arguments ),
730
+ fragment_mode = args.shift(),
731
+ url = args.shift(),
732
+ params = p_params( fragment_mode );
733
+
734
+ if ( $.isFunction(args[0]) ) {
735
+ params = args.shift()( params );
736
+ } else if ( $.isArray(args[0]) ) {
737
+ $.each(args.shift(), function(i,v){
738
+ delete params[v];
739
+ });
740
+ }
741
+
742
+ return p_params( fragment_mode, url, params, args.shift() );
743
+ };
744
+
745
+ $[str_passQueryString] = curry( p_passParams, 0 );
746
+ $[str_passFragment] = curry( p_passParams, 1 );
747
+
748
+
749
+ // Method: jQuery.fn.passQueryString
750
+ //
751
+ // Update URL attribute in one or more elements, merging the current URL (with
752
+ // or without pre-existing params) plus the document query string into a new
753
+ // URL (optionally parsing the document params with a callback function
754
+ // pre-merge), which is then set into that attribute. Like
755
+ // <jQuery.passQueryString>, but for all elements in a jQuery collection.
756
+ //
757
+ // Usage:
758
+ //
759
+ // jQuery('selector').passQueryString( [ attr ] [ , parse ] [ , merge_mode ] ); - -
760
+ //
761
+ // Arguments:
762
+ //
763
+ // attr - (String) Optional name of an attribute that will contain a URL to
764
+ // merge params into. See <jQuery.urlTagAttrList> for a list of default
765
+ // attributes.
766
+ // parse - (Array or Function) An optional array of key names to -not- merge
767
+ // into the URL, or a function that returns the object that will be merged
768
+ // into url (the document params are deserialized and passed to this
769
+ // function as its only argument).
770
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
771
+ // specified, and is as-follows:
772
+ //
773
+ // * 0: document params will override any params in attr URL.
774
+ // * 1: any params in attr URL will override document params.
775
+ // * 2: document params will completely replace any params in attr URL.
776
+ //
777
+ // Returns:
778
+ //
779
+ // (jQuery) The initial jQuery collection of elements, but with modified URL
780
+ // attribute values.
781
+
782
+ // Method: jQuery.fn.passFragment
783
+ //
784
+ // Update URL attribute in one or more elements, merging the current URL (with
785
+ // or without pre-existing params) plus the document fragment into a new URL
786
+ // (optionally parsing the document params with a callback function
787
+ // pre-merge), which is then set into that attribute. Like
788
+ // <jQuery.passFragment>, but for all elements in a jQuery collection.
789
+ //
790
+ // Usage:
791
+ //
792
+ // jQuery('selector').passFragment( [ attr ] [ , parse ] [ , merge_mode ] ); - -
793
+ //
794
+ // Arguments:
795
+ //
796
+ // attr - (String) Optional name of an attribute that will contain a URL to
797
+ // merge params into. See <jQuery.urlTagAttrList> for a list of default
798
+ // attributes.
799
+ // parse - (Array or Function) An optional array of key names to -not- merge
800
+ // into the URL, or a function that returns the object that will be merged
801
+ // into url (the document params are deserialized and passed to this
802
+ // function as its only argument).
803
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
804
+ // specified, and is as-follows:
805
+ //
806
+ // * 0: document params will override any params in attr URL.
807
+ // * 1: any params in attr URL will override document params.
808
+ // * 2: document params will completely replace any params in attr URL.
809
+ //
810
+ // Returns:
811
+ //
812
+ // (jQuery) The initial jQuery collection of elements, but with modified URL
813
+ // attribute values.
814
+
815
+ function p_fn_passParams() {
816
+ var attr,
817
+ args = aps.call(arguments),
818
+ fragment_mode = args.shift();
819
+
820
+ if ( is_string(args[0]) ) {
821
+ attr = args.shift();
822
+ }
823
+
824
+ return this.each(function(){
825
+
826
+ var that = $(this),
827
+ a = attr || get_attr( this ),
828
+ url = a && that.attr( a ) || '';
829
+
830
+ url = p_passParams.apply( this, [fragment_mode, url].concat(args) );
831
+ that.attr( a, url );
832
+
833
+ });
834
+ };
835
+
836
+ $.fn[str_passQueryString] = curry( p_fn_passParams, 0 );
837
+ $.fn[str_passFragment] = curry( p_fn_passParams, 1 );
838
+
839
+
840
+ // Deserialize a params string, optionally preceded by a url? or ?, or
841
+ // followed by an #anchor (or if fragment_mode, optionally preceded by a url#
842
+ // or #) into an object, optionally casting numbers, null, true, false, and
843
+ // undefined values appropriately.
844
+
845
+ function deserialize( params, cast_values, fragment_mode ) {
846
+ var p,
847
+ key,
848
+ val,
849
+ obj = {},
850
+ cast_types = { 'null': null, 'true': TRUE, 'false': FALSE },
851
+ decode_uri_component = decodeURIComponent,
852
+ re = fragment_mode
853
+ ? /^.*[#]/
854
+ : /^.*[?]|#.*$/g;
855
+
856
+ params = params.replace( re, '' ).replace( /\+/g, ' ' ).split('&');
857
+
858
+ while ( params.length ) {
859
+
860
+ p = params.shift().split('=');
861
+ key = decode_uri_component( p[0] );
862
+
863
+ if ( p.length === 2 ) {
864
+ val = decode_uri_component( p[1] );
865
+
866
+ if ( cast_values ) {
867
+ if ( val && !isNaN(val) ) {
868
+ val = Number( val );
869
+ } else if ( val === 'undefined' ) {
870
+ val = undefined;
871
+ } else if ( cast_types[val] !== undefined ) {
872
+ val = cast_types[val];
873
+ }
874
+ }
875
+
876
+ if ( $.isArray(obj[key]) ) {
877
+ obj[key].push( val );
878
+ } else if ( obj[key] !== undefined ) {
879
+ obj[key] = [obj[key], val];
880
+ } else {
881
+ obj[key] = val;
882
+ }
883
+
884
+ } else if ( key ) {
885
+ obj[key] = cast_values
886
+ ? undefined
887
+ : '';
888
+ }
889
+ }
890
+
891
+ return obj;
892
+ };
893
+
894
+ // Merge a URL (with or without a pre-existing params string and/or #anchor,
895
+ // or fragment) plus any object or params string into a new URL.
896
+
897
+ function build_url( url, params, merge_mode, fragment_mode ) {
898
+ var qs,
899
+ re = fragment_mode
900
+ ? /^([^#]*)[#]?(.*)$/
901
+ : /^([^#?]*)[?]?([^#]*)(#?.*)/,
902
+ matches = url.match( re ),
903
+ url_params = deserialize( matches[2], 0, fragment_mode ),
904
+ hash = matches[3] || '';
905
+
906
+ if ( is_string(params) ) {
907
+ params = deserialize( params, 0, fragment_mode );
908
+ }
909
+
910
+ if ( merge_mode === 2 ) {
911
+ qs = params;
912
+ } else if ( merge_mode === 1 ) {
913
+ qs = $.extend( {}, params, url_params );
914
+ } else {
915
+ qs = $.extend( {}, url_params, params );
916
+ }
917
+
918
+ qs = $.param( qs );
919
+ return matches[1] + ( fragment_mode ? '#' : qs || !matches[1] ? '?' : '' ) + qs + hash;
920
+ };
921
+
922
+
923
+ // Method: jQuery.setFragment
924
+ //
925
+ // Set the document fragment. Will trigger the <fragmentChange> event if
926
+ // <jQuery.fragmentChange> has been enabled, and the new fragment is actually
927
+ // different than the previous fragment.
928
+ //
929
+ // Usage:
930
+ //
931
+ // jQuery.setFragment( [ params [ , merge_mode ] ] ); - -
932
+ //
933
+ // Arguments:
934
+ //
935
+ // params - (String or Object) Either a serialized params string or a data
936
+ // object to set as the current document's fragment. If omitted, sets the
937
+ // document fragment to # (this may cause your browser to scroll).
938
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
939
+ // specified, and is as-follows:
940
+ //
941
+ // * 0: params argument will override any params in document fragment.
942
+ // * 1: any params in document fragment will override params argument.
943
+ // * 2: params argument will completely replace any params in document
944
+ // fragment.
945
+ //
946
+ // Returns:
947
+ //
948
+ // Nothing.
949
+
950
+ $.setFragment = p_setFragment = function( params, merge_mode ) {
951
+ var frag = is_object( params )
952
+ ? p_params( TRUE, params )
953
+ : (params || '').replace( /^#/, '' );
954
+
955
+ frag = params
956
+ ? build_url( '#' + get_fragment(), '#' + frag, merge_mode, 1 )
957
+ : '#';
958
+
959
+ //loc.hash = frag; // Safari 3 & Chrome barf if frag === '#'.
960
+ loc.href = loc.href.replace( /#.*$/, '' ) + frag;
961
+ };
962
+
963
+
964
+ // Method: jQuery.fragmentChange
965
+ //
966
+ // Enable or disable the polling loop that watches the document fragment for
967
+ // changes and triggers the <fragmentChange> event. The event object passed to
968
+ // a bound event callback has the property "fragment" which contains the
969
+ // fragment params string. Disabled by default.
970
+ //
971
+ // In browsers that support it, the onhashchange event is used (IE8, FF3.6)
972
+ //
973
+ // Note: When this is enabled for the first time, a hidden IFRAME is written
974
+ // into the body for Internet Explorer 6 and 7 to enable fragment-based
975
+ // browser history.
976
+ //
977
+ // Usage:
978
+ //
979
+ // jQuery.fragmentChange( [ state ] ); - -
980
+ //
981
+ // Arguments:
982
+ //
983
+ // state - (Boolean or Number) If true, a polling loop is started with the
984
+ // default delay of 100 and the fragmentChange event is enabled. If omitted
985
+ // or false, the polling loop is stopped and the fragmentChange event is
986
+ // disabled. A zero-or-greater numeric polling loop delay in milliseconds
987
+ // may also be specified.
988
+ //
989
+ // Returns:
990
+ //
991
+ // Nothing.
992
+
993
+ // Event: fragmentChange
994
+ //
995
+ // Fired when the document fragment changes, provided <jQuery.fragmentChange>
996
+ // has been enabled.
997
+ //
998
+ // The event object that is passed as the sole argument to the callback has a
999
+ // .fragment property, which is a URI encoded string reflecting the current
1000
+ // location.hash, with any leading # removed. Using e.fragment should be more
1001
+ // reliable than accessing location.hash directly, as only Firefox URI decodes
1002
+ // the location.hash property automatically.
1003
+ //
1004
+ // Usage:
1005
+ //
1006
+ // > $(document).bind('fragmentChange', function(e) {
1007
+ // > var fragment_str = e.fragment,
1008
+ // > fragment_obj = $.fragment();
1009
+ // > ...
1010
+ // > });
1011
+
1012
+ $[str_fragmentChange] = function( delay ) {
1013
+ if ( delay === TRUE ) { delay = 100; }
1014
+
1015
+ function trigger() {
1016
+ var event = $.Event( str_fragmentChange );
1017
+ event[str_fragment] = get_fragment();
1018
+
1019
+ $(document).trigger( event );
1020
+ };
1021
+
1022
+ has_onhashchange && $(window).unbind( str_hashchange );
1023
+
1024
+ timeout_id && clearTimeout( timeout_id );
1025
+ timeout_id = null;
1026
+
1027
+ if ( typeof delay === 'number' ) {
1028
+ if ( has_onhashchange ) {
1029
+ $(window).bind( str_hashchange, trigger );
1030
+
1031
+ } else {
1032
+ last_fragment = get_fragment();
1033
+
1034
+ if ( $.isFunction(ie_history) ) {
1035
+ ie_history = ie_history();
1036
+ }
1037
+
1038
+ (function loopy(){
1039
+ var frag = get_fragment(),
1040
+ ie_frag = ie_history[str_fragment]( last_fragment );
1041
+
1042
+ if ( frag !== last_fragment ) {
1043
+ ie_history[str_update]( frag, ie_frag );
1044
+
1045
+ last_fragment = frag;
1046
+ trigger();
1047
+
1048
+ } else if ( ie_frag !== last_fragment ) {
1049
+ p_setFragment( ie_frag, 2 );
1050
+ }
1051
+
1052
+ timeout_id = setTimeout( loopy, delay < 0 ? 0 : delay );
1053
+ })();
1054
+ }
1055
+ }
1056
+ };
1057
+
1058
+ // Handle fragment-based browser history in IE 6-7.
1059
+
1060
+ function ie_history() {
1061
+ var iframe,
1062
+ browser = $.browser,
1063
+ that = {};
1064
+
1065
+ that[str_update] = that[str_fragment] = function( val ){ return val; };
1066
+
1067
+ if ( browser.msie && browser.version < 8 ) {
1068
+
1069
+ that[str_update] = function( frag, ie_frag ) {
1070
+ var doc = iframe.document;
1071
+ if ( frag !== ie_frag ) {
1072
+ doc.open();
1073
+ doc.close();
1074
+ doc.location.hash = '#' + frag;
1075
+ }
1076
+ };
1077
+
1078
+ that[str_fragment] = function() {
1079
+ return iframe.document.location.hash.replace( /^#/, '' );
1080
+ };
1081
+
1082
+ iframe = $('<iframe/>').hide().appendTo( 'body' )
1083
+ .get(0).contentWindow;
1084
+
1085
+ that[str_update]( get_fragment() );
1086
+ }
1087
+
1088
+ return that;
1089
+ };
1090
+
1091
+ })(jQuery);