Skip to content

Commit

Permalink
feature: add version switcher
Browse files Browse the repository at this point in the history
  • Loading branch information
cheekyshibe authored and xxr3376 committed Mar 17, 2021
1 parent b5351c5 commit acd3084
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 1 deletion.
8 changes: 7 additions & 1 deletion pydata_sphinx_theme/docs-navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@
{% endif %}

{%- block icon_links -%}
{%- include "icon-links.html" with context -%}
{%- include "icon-links.html" with context -%}
{%- endblock %}

{% if theme_use_version_switch == true %}
{%- include "version-switcher.html" %}
{% endif %}
</li>
</ul>
</div>
</div>
5 changes: 5 additions & 0 deletions pydata_sphinx_theme/theme.conf
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ search_bar_position = sidebar
navigation_with_keys = True
show_toc_level = 1
navbar_align = content
use_version_switch = True
version_switch_json_url = /versions.json
version_switch_enable_locale = True
version_switch_locales = zh, en

206 changes: 206 additions & 0 deletions pydata_sphinx_theme/version-switcher.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
<script type="text/javascript">
(function () {
const version_json_url = "{{theme_version_switch_json_url}}";
const enable_locale = "{{theme_version_switch_enable_locale}}" === 'True';

// TODO check how to pass an array instead of raw string
// const all_locales = "{{theme_version_switch_locales}}";
all_locales = [
{
"locale": "zh",
"display": "中文"
},
{
"locale": "en",
"display": "EN"
}
]


// Remote version should like this.
// .name and .alias must be unique in each locale.
// It's not necessary to have same versions in all locales.
// 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.

/*
let all_versions = {
"en": [
{
"name": "v1.2.0",
"url": "v1.2.0",
"alias": ["latest"],
"default": true
},
{
"name": "v1.1.0",
"url": "v1.1.0",
"alias": []
},
],
"zh":[
{
"name": "v1.0.0",
"url": "v1.0.0",
"alias": []
"default": true
},
],
};
*/

function parse_current_url() {
// sphinx will fill here.
let page_name = "{{pagename}}.html";

if (window.location.pathname.slice(-page_name.length) !== page_name) {
// Sphinx generated pages should have exactly same suffix
throw 'page suffix do not match requirements';
}
// Get base URL by Removing '/' and page_name
let base_url = window.location.pathname.slice(0, -(page_name.length + 1));
let parts = base_url.split('/');

let current_version = '';
let current_locale = '';

if (enable_locale) {
if (parts.length < 1) {
throw 'page base URL do not have any locale information';
}
current_locale = parts.pop();
}
if (parts.length < 1) {
throw 'page base URL do not have any locale information';
}
current_version = parts.pop();
// This is base URL without any version or locate.
let global_base_url = parts.join('/')

return {page_name, base_url, current_version, current_locale, global_base_url};
}

// validate Check current_locale and current_version is valid.
// Return canonical_version: indicate current version's real name
function validate(all_versions, info) {
let locale = "default"; // Use default as key when locale feature is disabled
if (enable_locale) {
locale = info.current_locale;
}
let version_list = all_versions[locale];

if (version_list === undefined) {
throw `locale '${locale}'doesn't exist in remote version mapping`;
}

let canonical_version = function() { // Match current_version in version_list, try to find canonical version name by matching name and alias
for (const v of version_list) {
if (info.current_version === v.name) {
return v.name;
}
for (const alias_name of v.alias) {
if (info.current_version === alias_name) {
return v.name;
}
}
}
throw `version '${info.current_version}' doesn't exist in remove version maaping`
}()

return canonical_version;
}

// Set locale or version to null to indicate unchanged property.
function construct_url(info, target_locale, target_version) {
let segments = [info.global_base_url];

if (target_locale == null) {
target_locale = info.current_locale;
}
if (target_version == null) {
target_version = info.current_version;
}
segments.push(target_version);
if (enable_locale) {
segments.push(target_locale);
}
segments.push(info.page_name);
return segments.join('/') + window.location.hash;
}

function render(all_versions, info) {
function on_switch(evt) {
evt.preventDefault()
let selected = evt.currentTarget.getAttribute('key');

// process with alias problem, e.g. do not jump if target is just an alias of current one.
if (selected == info.canonical_version) {
// Current page is already the target version, ignore
return;
}

let new_url = construct_url(info, null, selected);
window.location.assign(new_url);
}
// Fill the current version in the dropdown, always show real name instead of alias
document.getElementById("version-dropdown").innerText = info.canonical_version;

const menu_html = (function() {
return all_versions[info.current_locale].map((version) => {
let text = version.name;
if (version.alias.length > 0) {
text = `${version.name} (${version.alias.join(' ')})`
}

return `<button class="dropdown-item" key="${version.name}">${text}</button>`
})
})().join('')
// fill the version menu
document.getElementById("version-menu").innerHTML = menu_html;

// bind the changes to this menu to trigger the switching function
$('#version-menu button').on('click', on_switch)

// Adding locale switcher
const locale_html = (function() {
return all_locales.map((l) => {
return `<span><a key="${l.locale}">${l.display}</a></span>`
})
})().join('/')
document.getElementById("locale-switcher").innerHTML = locale_html;
}


// Trigger fetch as earlier as possible to speedup page loading.
let p = fetch(version_json_url).then((resp) => {
return resp.json()
});

$(document).ready(function () {
let info = parse_current_url();

p.then((all_versions) => {
let canonical_version = validate(all_versions, info);
info.canonical_version = canonical_version;

render(all_versions, info);
})
});
})();

</script>

<ul class="navbar-nav">
<li class="nav-item dropdown">
<button id="version-dropdown" class="btn btn-secondary btn-sm dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<!-- placeholder for javascript filling above -->
</button>
<div id="version-menu" class="dropdown-menu" style="min-width: 6rem;">
<!-- placeholder for javascript filling above -->
</div>
</li>
<li class="nav-item">
<span id="locale-switcher">
<!-- placeholder for locale switcher -->
</span>
</li>
</ul>

0 comments on commit acd3084

Please sign in to comment.