4
4
//= require jquery-ui/widget
5
5
6
6
/*!
7
- * jQuery UI Tabs 1.14.1
7
+ * jQuery UI Tabs @VERSION
8
8
* https://jqueryui.com
9
9
*
10
10
* Copyright OpenJS Foundation and other contributors
43
43
"use strict" ;
44
44
45
45
$ . widget ( "ui.tabs" , {
46
- version : "1.14.1 " ,
46
+ version : "@VERSION " ,
47
47
delay : 300 ,
48
48
options : {
49
49
active : null ,
@@ -66,26 +66,19 @@ $.widget( "ui.tabs", {
66
66
load : null
67
67
} ,
68
68
69
- _isLocal : ( function ( ) {
70
- var rhash = / # .* $ / ;
69
+ _isLocal : function ( anchor ) {
70
+ var anchorUrl = new URL ( anchor . href ) ,
71
+ locationUrl = new URL ( location . href ) ;
71
72
72
- return function ( anchor ) {
73
- var anchorUrl , locationUrl ;
73
+ return anchor . hash . length > 1 &&
74
74
75
- anchorUrl = anchor . href . replace ( rhash , "" ) ;
76
- locationUrl = location . href . replace ( rhash , "" ) ;
77
-
78
- // Decoding may throw an error if the URL isn't UTF-8 (#9518)
79
- try {
80
- anchorUrl = decodeURIComponent ( anchorUrl ) ;
81
- } catch ( error ) { }
82
- try {
83
- locationUrl = decodeURIComponent ( locationUrl ) ;
84
- } catch ( error ) { }
85
-
86
- return anchor . hash . length > 1 && anchorUrl === locationUrl ;
87
- } ;
88
- } ) ( ) ,
75
+ // `href` may contain a hash but also username & password;
76
+ // we want to ignore them, so we check the three fields
77
+ // below instead.
78
+ anchorUrl . origin === locationUrl . origin &&
79
+ anchorUrl . pathname === locationUrl . pathname &&
80
+ anchorUrl . search === locationUrl . search ;
81
+ } ,
89
82
90
83
_create : function ( ) {
91
84
var that = this ,
@@ -126,18 +119,31 @@ $.widget( "ui.tabs", {
126
119
_initialActive : function ( ) {
127
120
var active = this . options . active ,
128
121
collapsible = this . options . collapsible ,
129
- locationHashDecoded = decodeURIComponent ( location . hash . substring ( 1 ) ) ;
122
+ locationHash = location . hash . substring ( 1 ) ,
123
+ locationHashDecoded = decodeURIComponent ( locationHash ) ;
130
124
131
125
if ( active === null ) {
132
126
133
127
// check the fragment identifier in the URL
134
- if ( locationHashDecoded ) {
128
+ if ( locationHash ) {
135
129
this . tabs . each ( function ( i , tab ) {
136
- if ( $ ( tab ) . attr ( "aria-controls" ) === locationHashDecoded ) {
130
+ if ( $ ( tab ) . attr ( "aria-controls" ) === locationHash ) {
137
131
active = i ;
138
132
return false ;
139
133
}
140
134
} ) ;
135
+
136
+ // If not found, decode the hash & try again.
137
+ // See the comment in `_processTabs` under the `_isLocal` check
138
+ // for more information.
139
+ if ( active === null ) {
140
+ this . tabs . each ( function ( i , tab ) {
141
+ if ( $ ( tab ) . attr ( "aria-controls" ) === locationHashDecoded ) {
142
+ active = i ;
143
+ return false ;
144
+ }
145
+ } ) ;
146
+ }
141
147
}
142
148
143
149
// Check for a tab marked active via a class
@@ -435,9 +441,24 @@ $.widget( "ui.tabs", {
435
441
436
442
// Inline tab
437
443
if ( that . _isLocal ( anchor ) ) {
438
- selector = decodeURIComponent ( anchor . hash ) ;
444
+
445
+ // The "scrolling to a fragment" section of the HTML spec:
446
+ // https://html.spec.whatwg.org/#scrolling-to-a-fragment
447
+ // uses a concept of document's indicated part:
448
+ // https://html.spec.whatwg.org/#the-indicated-part-of-the-document
449
+ // Slightly below there's an algorithm to compute the indicated
450
+ // part:
451
+ // https://html.spec.whatwg.org/#the-indicated-part-of-the-document
452
+ // First, the algorithm tries the hash as-is, without decoding.
453
+ // Then, if one is not found, the same is attempted with a decoded
454
+ // hash. Replicate this logic.
455
+ selector = anchor . hash ;
439
456
panelId = selector . substring ( 1 ) ;
440
457
panel = that . element . find ( "#" + CSS . escape ( panelId ) ) ;
458
+ if ( ! panel . length ) {
459
+ panelId = decodeURIComponent ( panelId ) ;
460
+ panel = that . element . find ( "#" + CSS . escape ( panelId ) ) ;
461
+ }
441
462
442
463
// remote tab
443
464
} else {
0 commit comments