forked from cowboy/jquery-urlinternal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjquery.ba-urlinternal.js
494 lines (442 loc) · 15.8 KB
/
jquery.ba-urlinternal.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
/*!
* urlInternal - v1.0 - 10/7/2009
* http://benalman.com/projects/jquery-urlinternal-plugin/
*
* Copyright (c) 2009 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
// Script: jQuery urlInternal: Easily test URL internal-, external or fragment-ness
//
// *Version: 1.0, Last updated: 10/7/2009*
//
// Project Home - http://benalman.com/projects/jquery-urlinternal-plugin/
// GitHub - http://github.com/cowboy/jquery-urlinternal/
// Source - http://github.com/cowboy/jquery-urlinternal/raw/master/jquery.ba-urlinternal.js
// (Minified) - http://github.com/cowboy/jquery-urlinternal/raw/master/jquery.ba-urlinternal.min.js (1.7kb)
//
// About: License
//
// Copyright (c) 2009 "Cowboy" Ben Alman,
// Dual licensed under the MIT and GPL licenses.
// http://benalman.com/about/license/
//
// About: Examples
//
// This working example, complete with fully commented code, illustrates a few
// ways in which this plugin can be used.
//
// http://benalman.com/code/projects/jquery-urlinternal/examples/urlinternal/
//
// About: Support and Testing
//
// Information about what version or versions of jQuery this plugin has been
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - 1.3.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, Chrome, Opera 9.6-10.
// Unit Tests - http://benalman.com/code/projects/jquery-urlinternal/unit/
//
// About: Release History
//
// 1.0 - (10/7/2009) Initial release
(function($){
'$:nomunge'; // Used by YUI compressor.
// Some convenient shortcuts.
var undefined,
TRUE = !0,
FALSE = !1,
loc = window.location,
aps = Array.prototype.slice,
matches = loc.href.match( /^((https?:\/\/.*?\/)?[^#]*)#?.*$/ ),
loc_fragbase = matches[1] + '#',
loc_hostbase = matches[2],
loc_fragbasenoprotocol = loc_fragbase.replace( /^https?:(.*)/g, '$1' ),
// Method references.
jq_elemUrlAttr,
jq_urlInternalHost,
jq_urlInternalRegExp,
jq_isUrlInternal,
jq_isUrlExternal,
jq_isUrlFragment,
// Reused strings.
str_elemUrlAttr = 'elemUrlAttr',
str_href = 'href',
str_src = 'src',
str_urlInternal = 'urlInternal',
str_urlExternal = 'urlExternal',
str_urlFragment = 'urlFragment',
url_regexp,
// Used by jQuery.elemUrlAttr.
elemUrlAttr_cache = {};
// Why write the same function twice? Let's curry! Mmmm, curry..
function curry( func ) {
var args = aps.call( arguments, 1 );
return function() {
return func.apply( this, args.concat( aps.call( arguments ) ) );
};
};
// Section: Methods
//
// Method: jQuery.isUrlInternal
//
// Test whether or not a URL is internal. Non-navigating URLs (ie. #anchor,
// javascript:, mailto:, news:, tel:, im: or non-http/https protocol://
// links) are not considered internal.
//
// Usage:
//
// > jQuery.isUrlInternal( url );
//
// Arguments:
//
// url - (String) a URL to test the internal-ness of.
//
// Returns:
//
// (Boolean) true if the URL is internal, false if external, or undefined if
// the URL is non-navigating.
$.isUrlInternal = jq_isUrlInternal = function( url ) {
// non-navigating: url is nonexistent or a fragment
if ( !url || jq_isUrlFragment( url ) ) { return undefined; }
// internal: url is absolute-but-internal (see $.urlInternalRegExp)
if ( url_regexp.test(url) ) { return TRUE; }
// external: url is absolute (begins with http:// or https:// or //)
if ( /^(?:https?:)?\/\//i.test(url) ) { return FALSE; }
// non-navigating: url begins with scheme:
if ( /^[a-z\d.-]+:/i.test(url) ) { return undefined; }
return TRUE;
};
// Method: jQuery.isUrlExternal
//
// Test whether or not a URL is external. Non-navigating URLs (ie. #anchor,
// mailto:, javascript:, or non-http/https protocol:// links) are not
// considered external.
//
// Usage:
//
// > jQuery.isUrlExternal( url );
//
// Arguments:
//
// url - (String) a URL to test the external-ness of.
//
// Returns:
//
// (Boolean) true if the URL is external, false if internal, or undefined if
// the URL is non-navigating.
$.isUrlExternal = jq_isUrlExternal = function( url ) {
var result = jq_isUrlInternal( url );
return typeof result === 'boolean'
? !result
: result;
};
// Method: jQuery.isUrlFragment
//
// Test whether or not a URL is a fragment in the context of the current page,
// meaning the URL can either begin with # or be a partial URL or full URI,
// but when it is navigated to, only the document.location.hash will change,
// and the page will not reload.
//
// Usage:
//
// > jQuery.isUrlFragment( url );
//
// Arguments:
//
// url - (String) a URL to test the fragment-ness of.
//
// Returns:
//
// (Boolean) true if the URL is a fragment, false otherwise.
$.isUrlFragment = jq_isUrlFragment = function( url ) {
var matches = ( url || '' ).match( /^([^#]?)([^#]*#).*$/ );
// url *might* be a fragment, since there were matches.
return !!matches && (
// url is just a fragment.
matches[2] === '#'
// url is absolute and contains a fragment, but is otherwise the same URI.
|| url.indexOf( loc_fragbase ) === 0
// url is "protocol relative" absolute and contains a fragment, but is otherwise the same URI.
|| ( matches[0].slice(0, 2) === '//' && url.indexOf( loc_fragbasenoprotocol ) === 0 )
// url is relative, begins with '/', contains a fragment, and is otherwise
// the same URI.
|| ( matches[1] === '/' ? loc_hostbase + matches[2] === loc_fragbase
// url is relative, but doesn't begin with '/', contains a fragment, and
// is otherwise the same URI. This isn't even remotely efficient, but it's
// significantly less code than parsing everything. Besides, it will only
// even be tested on url values that contain '#', aren't absolute, and
// don't begin with '/', which is not going to be many of them.
: !/^https?:\/\//i.test( url ) && $('<a href="' + url + '"/>')[0].href.indexOf( loc_fragbase ) === 0 )
);
};
// Method: jQuery.fn.urlInternal
//
// Filter a jQuery collection of elements, returning only elements that have
// an internal URL (as determined by <jQuery.isUrlInternal>). If URL cannot
// be determined, remove the element from the collection.
//
// Usage:
//
// > jQuery('selector').urlInternal( [ attr ] );
//
// Arguments:
//
// attr - (String) Optional name of an attribute that will contain a URL to
// test internal-ness against. See <jQuery.elemUrlAttr> for a list of
// default attributes.
//
// Returns:
//
// (jQuery) A filtered jQuery collection of elements.
// Method: jQuery.fn.urlExternal
//
// Filter a jQuery collection of elements, returning only elements that have
// an external URL (as determined by <jQuery.isUrlExternal>). If URL cannot
// be determined, remove the element from the collection.
//
// Usage:
//
// > jQuery('selector').urlExternal( [ attr ] );
//
// Arguments:
//
// attr - (String) Optional name of an attribute that will contain a URL to
// test external-ness against. See <jQuery.elemUrlAttr> for a list of
// default attributes.
//
// Returns:
//
// (jQuery) A filtered jQuery collection of elements.
// Method: jQuery.fn.urlFragment
//
// Filter a jQuery collection of elements, returning only elements that have
// an fragment URL (as determined by <jQuery.isUrlFragment>). If URL cannot
// be determined, remove the element from the collection.
//
// Note that in most browsers, selecting $("a[href^=#]") is reliable, but this
// doesn't always work in IE6/7! In order to properly test whether a URL
// attribute's value is a fragment in the context of the current page, you can
// either make your selector a bit more complicated.. or use .urlFragment!
//
// Usage:
//
// > jQuery('selector').urlFragment( [ attr ] );
//
// Arguments:
//
// attr - (String) Optional name of an attribute that will contain a URL to
// test external-ness against. See <jQuery.elemUrlAttr> for a list of
// default attributes.
//
// Returns:
//
// (jQuery) A filtered jQuery collection of elements.
function fn_filter( str, attr ) {
return this.filter( ':' + str + (attr ? '(' + attr + ')' : '') );
};
$.fn[ str_urlInternal ] = curry( fn_filter, str_urlInternal );
$.fn[ str_urlExternal ] = curry( fn_filter, str_urlExternal );
$.fn[ str_urlFragment ] = curry( fn_filter, str_urlFragment );
// Section: Selectors
//
// Selector: :urlInternal
//
// Filter a jQuery collection of elements, returning only elements that have
// an internal URL (as determined by <jQuery.isUrlInternal>). If URL cannot
// be determined, remove the element from the collection.
//
// Usage:
//
// > jQuery('selector').filter(':urlInternal');
// > jQuery('selector').filter(':urlInternal(attr)');
//
// Arguments:
//
// attr - (String) Optional name of an attribute that will contain a URL to
// test internal-ness against. See <jQuery.elemUrlAttr> for a list of
// default attributes.
//
// Returns:
//
// (jQuery) A filtered jQuery collection of elements.
// Selector: :urlExternal
//
// Filter a jQuery collection of elements, returning only elements that have
// an external URL (as determined by <jQuery.isUrlExternal>). If URL cannot
// be determined, remove the element from the collection.
//
// Usage:
//
// > jQuery('selector').filter(':urlExternal');
// > jQuery('selector').filter(':urlExternal(attr)');
//
// Arguments:
//
// attr - (String) Optional name of an attribute that will contain a URL to
// test external-ness against. See <jQuery.elemUrlAttr> for a list of
// default attributes.
//
// Returns:
//
// (jQuery) A filtered jQuery collection of elements.
// Selector: :urlFragment
//
// Filter a jQuery collection of elements, returning only elements that have
// an fragment URL (as determined by <jQuery.isUrlFragment>). If URL cannot
// be determined, remove the element from the collection.
//
// Note that in most browsers, selecting $("a[href^=#]") is reliable, but this
// doesn't always work in IE6/7! In order to properly test whether a URL
// attribute's value is a fragment in the context of the current page, you can
// either make your selector a bit more complicated.. or use :urlFragment!
//
// Usage:
//
// > jQuery('selector').filter(':urlFragment');
// > jQuery('selector').filter(':urlFragment(attr)');
//
// Arguments:
//
// attr - (String) Optional name of an attribute that will contain a URL to
// test fragment-ness against. See <jQuery.elemUrlAttr> for a list of
// default attributes.
//
// Returns:
//
// (jQuery) A filtered jQuery collection of elements.
function fn_selector( func, elem, i, match ) {
var a = match[3] || jq_elemUrlAttr()[ ( elem.nodeName || '' ).toLowerCase() ] || '';
return a ? !!func( elem.getAttribute( a ) ) : FALSE;
};
$.expr[':'][ str_urlInternal ] = curry( fn_selector, jq_isUrlInternal );
$.expr[':'][ str_urlExternal ] = curry( fn_selector, jq_isUrlExternal );
$.expr[':'][ str_urlFragment ] = curry( fn_selector, jq_isUrlFragment );
// Section: Support methods
//
// Method: jQuery.elemUrlAttr
//
// Get the internal "Default URL attribute per tag" list, or augment the list
// with additional tag-attribute pairs, in case the defaults are insufficient.
//
// In the <jQuery.fn.urlInternal> and <jQuery.fn.urlExternal> methods, as well
// as the <:urlInternal> and <:urlExternal> selectors, this list is used to
// determine which attribute contains the URL to be modified, if an "attr"
// param is not specified.
//
// Default Tag-Attribute List:
//
// a - href
// base - href
// iframe - src
// img - src
// input - src
// form - action
// link - href
// script - src
//
// Usage:
//
// > jQuery.elemUrlAttr( [ tag_attr ] );
//
// Arguments:
//
// tag_attr - (Object) An object containing a list of tag names and their
// associated default attribute names in the format { tag: 'attr', ... } to
// be merged into the internal tag-attribute list.
//
// Returns:
//
// (Object) An object containing all stored tag-attribute values.
// Only define function and set defaults if function doesn't already exist, as
// the jQuery BBQ plugin will provide this method as well.
$[ str_elemUrlAttr ] || ($[ str_elemUrlAttr ] = function( obj ) {
return $.extend( elemUrlAttr_cache, obj );
})({
a: str_href,
base: str_href,
iframe: str_src,
img: str_src,
input: str_src,
form: 'action',
link: str_href,
script: str_src
});
jq_elemUrlAttr = $[ str_elemUrlAttr ];
// Method: jQuery.urlInternalHost
//
// Constructs the regular expression that matches an absolute-but-internal
// URL from the current page's protocol, hostname and port, allowing for any
// number of optional hostnames. For example, if the current page is
// http://benalman.com/test or http://www.benalman.com/test, specifying an
// argument of "www" would yield this pattern:
//
// > /^(?:http:)?\/\/(?:(?:www)\.)?benalman.com\//i
//
// This pattern will match URLs beginning with both http://benalman.com/ and
// http://www.benalman.com/. If the current page is http://benalman.com/test,
// http://www.benalman.com/test or http://foo.benalman.com/test, specifying
// arguments "www", "foo" would yield this pattern:
//
// > /^(?:http:)?\/\/(?:(?:www|foo)\.)?benalman.com\//i
//
// This pattern will match URLs beginning with http://benalman.com/,
// http://www.benalman.com/ and http://foo.benalman.com/.
//
// Not specifying any alt_hostname will disable any alt-hostname matching.
//
// Note that the plugin is initialized by default to an alt_hostname of "www".
// Should you need more control, <jQuery.urlInternalRegExp> may be used to
// completely customize the absolute-but-internal matching pattern.
//
// Usage:
//
// > jQuery.urlInternalHost( [ alt_hostname [, alt_hostname ] ... ] );
//
// Arguments:
//
// alt_hostname - (String) An optional alternate hostname to use when testing
// URL absolute-but-internal-ness.
//
// Returns:
//
// (RegExp) The absolute-but-internal pattern, as a RegExp.
$.urlInternalHost = jq_urlInternalHost = function( alt_hostname ) {
alt_hostname = alt_hostname
? '(?:(?:' + Array.prototype.join.call( arguments, '|' ) + ')\\.)?'
: '';
var re = new RegExp( '^' + alt_hostname + '(.*)', 'i' ),
pattern = '^(?:' + loc.protocol + ')?//'
+ loc.hostname.replace(re, alt_hostname + '$1').replace( /\\?\./g, '\\.' )
+ (loc.port ? ':' + loc.port : '') + '/';
return jq_urlInternalRegExp( pattern );
};
// Method: jQuery.urlInternalRegExp
//
// Set or get the regular expression that matches an absolute-but-internal
// URL.
//
// Usage:
//
// > jQuery.urlInternalRegExp( [ re ] );
//
// Arguments:
//
// re - (String or RegExp) The regular expression pattern. If not passed,
// nothing is changed.
//
// Returns:
//
// (RegExp) The absolute-but-internal pattern, as a RegExp.
$.urlInternalRegExp = jq_urlInternalRegExp = function( re ) {
if ( re ) {
url_regexp = typeof re === 'string'
? new RegExp( re, 'i' )
: re;
}
return url_regexp;
};
// Initialize url_regexp with a reasonable default.
jq_urlInternalHost( 'www' );
})(jQuery);