@@ -39,3 +39,205 @@ function addTOCInteractivity() {
39
39
$ ( document ) . ready ( ( ) => {
40
40
addTOCInteractivity ( ) ;
41
41
} ) ;
42
+
43
+
44
+ function setupVersionSwitcher ( ) {
45
+ // Setup Version Switcher
46
+
47
+ // Only enable version switcher when window.versionSwitcher is filled by sphinx
48
+ if ( ! window . versionSwitcher ) {
49
+ return ;
50
+ }
51
+ let pageName = window . versionSwitcher . pageName ;
52
+ let versionJsonUrl = window . versionSwitcher . versionJsonUrl ;
53
+ let enableLocaleSupport = window . versionSwitcher . enableLocaleSupport ;
54
+ let allLocales = window . versionSwitcher . allLocales ;
55
+
56
+ // Remote version should like this.
57
+ // .name and .alias must be unique in each locale.
58
+ // It's not necessary to have same versions in all locales.
59
+ // When locale is enabled, there must be only one .default=true item in each locale to indicate which one should be redirect if target version doesn't exist in target locale.
60
+
61
+ /*
62
+ let allVersions = {
63
+ "en": [
64
+ {
65
+ "name": "v1.2.0",
66
+ "url": "v1.2.0",
67
+ "alias": ["latest"],
68
+ "default": true
69
+ },
70
+ {
71
+ "name": "v1.1.0",
72
+ "url": "v1.1.0",
73
+ "alias": []
74
+ },
75
+ ],
76
+ "zh":[
77
+ {
78
+ "name": "v1.0.0",
79
+ "url": "v1.0.0",
80
+ "alias": []
81
+ "default": true
82
+ },
83
+ ],
84
+ };
85
+ */
86
+ function parseCurrentURL ( ) {
87
+ // parseCurrentURL look up current pathname, generate all information about current version and locale.
88
+
89
+ let pathname = window . location . pathname ;
90
+
91
+ // add "index.html" back when browser omit it.
92
+ if ( pageName . endsWith ( "index.html" ) && pathname . endsWith ( "/" ) ) {
93
+ pathname += "index.html" ;
94
+ }
95
+ if ( pathname . slice ( - pageName . length ) !== pageName ) {
96
+ // Sphinx generated pages should have exactly same suffix
97
+ throw 'page suffix do not match requirements' ;
98
+ }
99
+
100
+ // Get base URL by Removing '/' and pageName
101
+ let baseURL = pathname . slice ( 0 , - ( pageName . length + 1 ) ) ;
102
+ let parts = baseURL . split ( '/' ) ;
103
+
104
+ let currentVersion = '' ;
105
+ let currentLocale = '' ;
106
+
107
+ if ( enableLocaleSupport ) {
108
+ if ( parts . length < 1 ) {
109
+ throw 'page base URL do not have any locale information' ;
110
+ }
111
+ currentLocale = parts . pop ( ) ;
112
+ }
113
+ if ( parts . length < 1 ) {
114
+ throw 'page base URL do not have any locale information' ;
115
+ }
116
+ currentVersion = parts . pop ( ) ;
117
+ // This is base URL without any version or locate.
118
+ let globalBaseURL = parts . join ( '/' )
119
+
120
+ return { pageName, baseURL, currentVersion, currentLocale, globalBaseURL} ;
121
+ }
122
+
123
+ // validate Check currentLocale and currentVersion is valid.
124
+ // Return canonicalVersion: indicate current version's real name
125
+ function validate ( allVersions , info ) {
126
+ let locale = "default" ; // Use default as key when locale feature is disabled
127
+ if ( enableLocaleSupport ) {
128
+ locale = info . currentLocale ;
129
+ }
130
+ let version_list = allVersions [ locale ] ;
131
+
132
+ if ( version_list === undefined ) {
133
+ throw `locale '${ locale } 'doesn't exist in remote version mapping` ;
134
+ }
135
+
136
+ let canonicalVersion = function ( ) { // Match currentVersion in version_list, try to find canonical version name by matching name and alias
137
+ for ( const v of version_list ) {
138
+ if ( info . currentVersion === v . name ) {
139
+ return v . name ;
140
+ }
141
+ for ( const alias_name of v . alias ) {
142
+ if ( info . currentVersion === alias_name ) {
143
+ return v . name ;
144
+ }
145
+ }
146
+ }
147
+ throw `version '${ info . currentVersion } ' doesn't exist in remove version maaping`
148
+ } ( )
149
+
150
+ return canonicalVersion ;
151
+ }
152
+
153
+ // Set locale or version to null to indicate unchanged property.
154
+ function constructUrl ( info , targetLocale , targetVersion ) {
155
+ let segments = [ info . globalBaseURL ] ;
156
+
157
+ if ( targetLocale == null ) {
158
+ targetLocale = info . currentLocale ;
159
+ }
160
+ if ( targetVersion == null ) {
161
+ targetVersion = info . currentVersion ;
162
+ }
163
+ segments . push ( targetVersion ) ;
164
+ if ( enableLocaleSupport ) {
165
+ segments . push ( targetLocale ) ;
166
+ }
167
+ segments . push ( info . pageName ) ;
168
+ return segments . join ( '/' ) + window . location . hash ;
169
+ }
170
+
171
+ function render ( allVersions , info ) {
172
+ function onSwitchVersion ( evt ) {
173
+ evt . preventDefault ( )
174
+ let selected = evt . currentTarget . getAttribute ( 'key' ) ;
175
+
176
+ // process with alias problem, e.g. do not jump if target is just an alias of current one.
177
+ if ( selected == info . canonicalVersion ) {
178
+ // Current page is already the target version, ignore
179
+ return ;
180
+ }
181
+
182
+ let new_url = constructUrl ( info , null , selected ) ;
183
+ window . location . assign ( new_url ) ;
184
+ }
185
+
186
+ function onSwitchLocale ( evt ) {
187
+ evt . preventDefault ( )
188
+ let selected = evt . currentTarget . getAttribute ( 'key' ) ;
189
+
190
+ let new_url = constructUrl ( info , selected , null ) ;
191
+ window . location . assign ( new_url ) ;
192
+ }
193
+
194
+ // Fill the current version in the dropdown, always show real name instead of alias
195
+ document . getElementById ( "version-dropdown" ) . innerText = info . canonicalVersion ;
196
+
197
+ const menuHTML = ( function ( ) {
198
+ return allVersions [ info . currentLocale ] . map ( ( version ) => {
199
+ let text = version . name ;
200
+ if ( version . alias . length > 0 ) {
201
+ text = `${ version . name } (${ version . alias . join ( ' ' ) } )`
202
+ }
203
+
204
+ return `<button class="dropdown-item" key="${ version . name } ">${ text } </button>`
205
+ } )
206
+ } ) ( ) . join ( '' )
207
+ // fill the version menu
208
+ document . getElementById ( "version-menu" ) . innerHTML = menuHTML ;
209
+
210
+ // bind the changes to this menu to trigger the switching function
211
+ $ ( '#version-menu button' ) . on ( 'click' , onSwitchVersion )
212
+
213
+ // Adding locale switcher
214
+ const localeHTML = ( function ( ) {
215
+ return allLocales . map ( ( l ) => {
216
+ if ( l . locale === info . currentLocale ) {
217
+ return `<a class="locale-btn locale-current" key="${ l . locale } ">${ l . display } </a>`
218
+ } else {
219
+ return `<a class="locale-btn locale-option "key="${ l . locale } ">${ l . display } </a>`
220
+ }
221
+ } )
222
+ } ) ( ) . join ( '/' )
223
+ document . getElementById ( "locale-switcher" ) . innerHTML = localeHTML ;
224
+
225
+ $ ( '#locale-switcher .locale-option' ) . on ( 'click' , onSwitchLocale )
226
+ }
227
+
228
+ // Trigger fetch as earlier as possible to speedup page loading.
229
+ let p = fetch ( versionJsonUrl ) . then ( ( resp ) => {
230
+ return resp . json ( )
231
+ } ) ;
232
+
233
+ let info = parseCurrentURL ( ) ;
234
+
235
+ p . then ( ( allVersions ) => {
236
+ let canonicalVersion = validate ( allVersions , info ) ;
237
+ info . canonicalVersion = canonicalVersion ;
238
+
239
+ render ( allVersions , info ) ;
240
+ } )
241
+ }
242
+
243
+ $ ( document ) . ready ( setupVersionSwitcher ) ;
0 commit comments