Skip to content

Commit

Permalink
feat: enable version switcher
Browse files Browse the repository at this point in the history
  • Loading branch information
xxr3376 authored and cheekyshibe committed Mar 15, 2021
1 parent 894d0df commit a35d8f5
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 51 deletions.
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

180 changes: 129 additions & 51 deletions pydata_sphinx_theme/version-switcher.html
Original file line number Diff line number Diff line change
@@ -1,67 +1,145 @@
{% if theme_use_version_switch == true %}
<script type="text/javascript">
(function () {
(function () {
const version_json_url = "{{theme_version_switch_json_url}}";
const enable_locale = "{{theme_version_switch_enable_locale}}" === 'True';

// TODO: Handle with api.json file to get the meta-data.
// TODO check how to pass an array instead of raw string
const all_locales = "{{theme_version_switch_locales}}";

// Select versions that could be switched by user
var all_versions = {
'latest': 'v1.2.0',
'v1.1': 'v1.1.0',
'v1.0': 'v1.0.0',
};
// 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.

function change_version(url, new_version) {
var version_regex = /\/(latest|(v\d+\.\d+.\d+))\//;
return url.replace(version_regex, '/' + new_version + '/');
}
/*
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 (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 = location.pathname.slice(0, -(page_name.length + 1));
let parts = base_url.split('/');

let current_version = parts.pop();
let current_locale = '';

function on_switch() {
var selected = $(this).children('option:selected').attr('value');

// original url
var url = window.location.href;
// changed url
var new_url = change_version(url, selected);

if (new_url != url) {
// check beforehand if url exists, otherwise redirect to the version's start page
$.ajax({
url: new_url,
success: function () {
window.location.href = new_url;
},
error: function () {
window.location.href = "https://pydata-sphinx-theme.readthedocs.io/en/" + selected;
}
});
}
if (enable_locale) {
if (parts.length < 1) {
throw 'page base URL do not have any locale information';
}
current_locale = 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};
}

function validate(all_versions, info) {
// TODO check all_versions is valid

// TODO check current_locale and current_version is valid
return;
}

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

$(document).ready(function () {
// var version = DOCUMENTATION_OPTIONS.VERSION;
// Take the first 2 parts of the release (e.g. "3.4.5" -> "3.4")
// version = version.split('.').slice(0, 2).join('.');
if (target_locale == null) {
target_locale = info.current_locale;
}
if (target_version == null) {
target_version = info.current_version;
}
if (enable_locale) {
segments.push(target_locale);
}
segments.push(target_version);
segments.push(info.page_name);
return segments.join('/') + location.hash;
}

// fill the current version in the dropdown
document.getElementById("version-dropdown").innerText = 'latest';
function render(all_versions, info) {
function on_switch(evt) {
evt.preventDefault()
let selected = evt.currentTarget.getAttribute('key');

const getVersionLink = () => {
return Object.keys(all_versions).map(key => `<button class="dropdown-item">${key}</button>`)
}
// fill the version menu
document.getElementById("version-menu").innerHTML = getVersionLink().join('');
// TODO process with alias problem, e.g. do not jump if target is just an alias of current one.
let new_url = construct_url(info, null, selected);
window.location.assign(new_url);
}
// fill the current version in the dropdown
document.getElementById("version-dropdown").innerText = 'latest';

// bind the changes to this menu to trigger the switching function
// TODO: Change this to use the dropdown button's on_select() callback function
$('.version-dropdown select').bind('change', on_switch);
});
})();
// TODO show alias as well
const getVersionLink = () => {
return all_versions[info.current_locale].map((item) => {
return item.name;
}).map(key => `<button class="dropdown-item" key="${key}">${key}<\/button>`)
}
// fill the version menu
document.getElementById("version-menu").innerHTML = getVersionLink().join('');

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

// TODO add locale button
}


// 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) => {
validate(all_versions, info);
render(all_versions, info);
})
});
})();

</script>

<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 -->
<!-- placeholder for javascript filling above -->
</button>
<div id="version-menu" class="dropdown-menu" style="min-width: 6rem;">
<!-- placeholder for javascript filling above -->
</div>
<!-- placeholder for javascript filling above -->
</div>

{% endif %}

0 comments on commit a35d8f5

Please sign in to comment.