Initial commit
This commit is contained in:
295
BlenderDocumentation/_static/js/version_switch.js
Normal file
295
BlenderDocumentation/_static/js/version_switch.js
Normal file
@@ -0,0 +1,295 @@
|
||||
(function() {//switch: v1.5
|
||||
"use strict";
|
||||
|
||||
var versionsFileUrl = "https://docs.blender.org/PROD/versions.json"
|
||||
|
||||
var all_versions;
|
||||
var all_langs = {
|
||||
"en": "English",
|
||||
"ar": "اَلْعَرَبِيَّةُ",
|
||||
"ca": "Català",
|
||||
"de": "Deutsch",
|
||||
"es": "Español",
|
||||
"fi": "Suomi",
|
||||
"fr": "Français",
|
||||
"id": "Bahasa Indonesia",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"ka": "ქართული",
|
||||
"ko": "한국어",
|
||||
"nb": "Norsk Bokmål",
|
||||
"nl": "Nederlands",
|
||||
"pt": "Português",
|
||||
"ru": "Ρусский",
|
||||
"sk": "Slovenčina",
|
||||
"sl": "Slovenščina",
|
||||
"sr": "српски",
|
||||
"th": "ภาษาไทย",
|
||||
"uk": "Українська",
|
||||
"vi": "Tiếng Việt",
|
||||
"zh-hans": "中文(简体)",
|
||||
"zh-hant": "中文(繁體)",
|
||||
};
|
||||
|
||||
class Popover {
|
||||
constructor(id) {
|
||||
this.isOpen=false;
|
||||
this.type = (id === "version-popover");
|
||||
this.btn = document.querySelector('#' + id);
|
||||
this.dialog = this.btn.nextElementSibling;
|
||||
this.list = this.dialog.querySelector("ul");
|
||||
this.sel = null;
|
||||
const that = this;
|
||||
this.btnClickHandler = function(e) {that.init();e.preventDefault();e.stopPropagation();};
|
||||
this.btnKeyHandler = function(e) {if(that.btnKeyFilter(e)){that.init();e.preventDefault();e.stopPropagation();} };
|
||||
this.btn.addEventListener("click", this.btnClickHandler);
|
||||
this.btn.addEventListener("keydown", this.btnKeyHandler);
|
||||
}
|
||||
|
||||
init() {
|
||||
this.btn.removeEventListener("click", this.btnClickHandler);
|
||||
this.btn.removeEventListener("keydown", this.btnKeyHandler);
|
||||
|
||||
new Promise((resolve, reject) => {
|
||||
if(all_versions === undefined) {
|
||||
this.btn.classList.add("wait");
|
||||
fetch(versionsFileUrl)
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
all_versions = data;
|
||||
resolve();
|
||||
})
|
||||
.catch(() => {
|
||||
console.error("Version Switch Error: versions.json could not be loaded.");
|
||||
this.btn.classList.remove("disabled");
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
let release = DOCUMENTATION_OPTIONS.VERSION;
|
||||
const m = release.match(/\d\.\d+/g);
|
||||
if (m) {release = m[0];}
|
||||
let lang = DOCUMENTATION_OPTIONS.LANGUAGE;
|
||||
if(!lang || lang === "None" || lang === "") {lang = "en";}
|
||||
|
||||
this.warnOld(release, all_versions);
|
||||
|
||||
const version = this.getNamed(release);
|
||||
this.buildList(version, lang);
|
||||
|
||||
this.list.firstElementChild.remove();
|
||||
const that = this;
|
||||
this.list.addEventListener("keydown", function(e) {that.keyMove(e);});
|
||||
|
||||
this.btn.classList.remove("wait");
|
||||
this.btnOpenHandler();
|
||||
this.btn.addEventListener("mousedown", function(e){that.btnOpenHandler(); e.preventDefault()});
|
||||
this.btn.addEventListener("keydown", function(e){ if(that.btnKeyFilter(e)){that.btnOpenHandler();} });
|
||||
});
|
||||
}
|
||||
warnOld(release, all_versions) {
|
||||
// Note this is effectively disabled now, two issues must fixed:
|
||||
// * versions.js does not contain a current entry, because that leads to
|
||||
// duplicate version numbers in the menu. These need to be deduplicated.
|
||||
// * It only shows the warning after opening the menu to switch version
|
||||
// or language, when versions.js is loaded. This is too late to be useful.
|
||||
let current = all_versions.current
|
||||
if (!current) {
|
||||
//console.log("Version Switch Error: no 'current' in version.json.");
|
||||
return;
|
||||
}
|
||||
const m = current.match(/\d\.\d+/g);
|
||||
if (m) {current = parseFloat(m[0]);}
|
||||
if (release < current) {
|
||||
const currentURL = window.location.pathname.replace(release, current);
|
||||
const warning = document.querySelector("template#version-warning").firstElementChild.cloneNode(true);
|
||||
const link = warning.querySelector('a');
|
||||
link.setAttribute('href', currentURL);
|
||||
link.textContent = current;
|
||||
|
||||
let body = document.querySelector("div.body");
|
||||
if (!body.length) {body = document.querySelector("div.document");}
|
||||
body.prepend(warning);
|
||||
}
|
||||
}
|
||||
buildList(v, l) {
|
||||
const url = new URL(window.location.href);
|
||||
let pathSplit = ["", "manual", l, v];
|
||||
if (url.pathname.startsWith("/manual/")) {
|
||||
pathSplit.push(url.pathname.split('/').slice(4).join('/'));
|
||||
} else {
|
||||
pathSplit.push(url.pathname.substring(1));
|
||||
}
|
||||
let dyn, cur;
|
||||
if(this.type) {
|
||||
dyn = all_versions;
|
||||
cur = v;
|
||||
} else {
|
||||
dyn = all_langs;
|
||||
cur = l;
|
||||
}
|
||||
const that = this;
|
||||
const template = document.querySelector("template#version-entry").content;
|
||||
for (let [ix, title] of Object.entries(dyn)) {
|
||||
let clone;
|
||||
if (ix === cur) {
|
||||
clone = template.querySelector("li.selected").cloneNode(true);
|
||||
clone.querySelector("span").innerHTML = title;
|
||||
} else {
|
||||
pathSplit[2 + that.type] = ix;
|
||||
let href = new URL(url);
|
||||
href.pathname = pathSplit.join('/');
|
||||
clone = template.firstElementChild.cloneNode(true);
|
||||
const link = clone.querySelector("a");
|
||||
link.href = href;
|
||||
if (that.type) {
|
||||
link.innerHTML = title;
|
||||
} else {
|
||||
const hint = document.createElement("bdi");
|
||||
hint.innerHTML = title;
|
||||
link.appendChild(hint);
|
||||
}
|
||||
link.setAttribute("lang", !that.type ? ix : "en");
|
||||
}
|
||||
that.list.append(clone);
|
||||
};
|
||||
return this.list;
|
||||
}
|
||||
getNamed(v) {
|
||||
for (let [ix, title] of Object.entries(all_versions)) {
|
||||
if (ix === "dev" || ix === "latest") {
|
||||
const m = title.match(/\d\.\d[\w\d\.]*/)[0];
|
||||
if (parseFloat(m) == v) {
|
||||
v = ix;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
return v;
|
||||
}
|
||||
dialogToggle(speed) {
|
||||
speed = window.matchMedia("(prefers-reduced-motion: reduce)").matches ? 0 : speed;
|
||||
const wasClose = !this.isOpen;
|
||||
const that = this;
|
||||
if(!this.isOpen) {
|
||||
this.btn.classList.add("version-btn-open");
|
||||
this.btn.setAttribute("aria-pressed", true);
|
||||
this.dialog.setAttribute("aria-hidden", false);
|
||||
this.dialog.style.display = "block";
|
||||
this.dialog.animate({opacity: [0, 1], easing: ['ease-in', 'ease-out']}, speed).finished
|
||||
.then(() => {
|
||||
this.focusoutHandlerPrime = function(e) {that.focusoutHandler(); e.stopImmediatePropagation();};
|
||||
this.mouseoutHandlerPrime = function(e){that.mouseoutHandler(); e.stopImmediatePropagation();};
|
||||
this.btn.parentNode.addEventListener("focusout", this.focusoutHandlerPrime);
|
||||
this.btn.parentNode.addEventListener("mouseleave", this.mouseoutHandlerPrime);
|
||||
});
|
||||
this.isOpen = true;
|
||||
} else {
|
||||
this.btn.classList.remove("version-btn-open");
|
||||
this.btn.setAttribute("aria-pressed", false);
|
||||
this.dialog.setAttribute("aria-hidden", true);
|
||||
this.btn.parentNode.removeEventListener("focusout", this.focusoutHandlerPrime);
|
||||
this.btn.parentNode.removeEventListener("mouseleave", this.mouseoutHandlerPrime);
|
||||
this.dialog.animate({opacity: [1, 0], easing: ['ease-in', 'ease-out']}, speed).finished
|
||||
.then(() => {
|
||||
this.dialog.style.display = "none";
|
||||
if (this.sel) {this.sel.setAttribute("tabindex", -1);}
|
||||
this.btn.setAttribute("tabindex", 0);
|
||||
if(document.activeElement !== null && document.activeElement !== document && document.activeElement !== document.body) {
|
||||
this.btn.focus();
|
||||
}
|
||||
});
|
||||
this.isOpen = false;
|
||||
}
|
||||
|
||||
if(wasClose) {
|
||||
if (this.sel) {this.sel.setAttribute("tabindex", -1);}
|
||||
if(document.activeElement !== null && document.activeElement !== document && document.activeElement !== document.body) {
|
||||
const nw = this.listEnter();
|
||||
nw.setAttribute("tabindex", 0);
|
||||
nw.focus();
|
||||
this.sel = nw;
|
||||
}
|
||||
}
|
||||
}
|
||||
btnOpenHandler() {
|
||||
this.dialogToggle(300);
|
||||
}
|
||||
focusoutHandler() {
|
||||
const list = this.list;
|
||||
const that = this;
|
||||
setTimeout(function() {
|
||||
if (!list.querySelector(":focus")) {
|
||||
that.dialogToggle(200);
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
mouseoutHandler() {
|
||||
this.dialogToggle(200);
|
||||
}
|
||||
btnKeyFilter(e) {
|
||||
if (e.ctrlKey || e.shiftKey) {return false;}
|
||||
if(e.key === " " || e.key === "Enter" || (e.key === "ArrowDown" && e.altKey) || e.key === "ArrowDown" || e.key === "ArrowUp") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
keyMove(e) {
|
||||
if (e.ctrlKey || e.shiftKey) {return true;}
|
||||
let nw = e.target;
|
||||
switch(e.key) {
|
||||
case "ArrowUp": nw = this.listPrev(nw); break;
|
||||
case "ArrowDown": nw = this.listNext(nw); break;
|
||||
case "Home": nw = this.listFirst(); break;
|
||||
case "End": nw = this.listLast(); break;
|
||||
case "Escape": nw = this.listExit(); break;
|
||||
case "ArrowLeft": nw = this.listExit(); break;
|
||||
case "ArrowRight": nw = this.listExit(); break;
|
||||
default: return false;
|
||||
}
|
||||
nw.setAttribute("tabindex", 0);
|
||||
nw.focus();
|
||||
if (this.sel) {this.sel.setAttribute("tabindex", -1);}
|
||||
this.sel = nw;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
listPrev(nw) {
|
||||
if (nw.parentNode.previousElementSibling.length !== 0) {
|
||||
return nw.parentNode.previousElementSibling.firstElementChild;
|
||||
} else {
|
||||
return this.listLast();
|
||||
}
|
||||
}
|
||||
listNext(nw) {
|
||||
if (nw.parentNode.nextElementSibling.length !== 0) {
|
||||
return nw.parentNode.nextElementSibling.firstElementChild;
|
||||
} else {
|
||||
return this.listFirst();
|
||||
}
|
||||
}
|
||||
listFirst() {
|
||||
return this.list.firstElementChild.firstElementChild;
|
||||
}
|
||||
listLast() {
|
||||
return this.list.lastElementChild.firstElementChild;
|
||||
}
|
||||
listExit() {
|
||||
this.mouseoutHandler();
|
||||
return this.btn;
|
||||
}
|
||||
listEnter() {
|
||||
return this.list.firstElementChild.firstElementChild;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
let lang = DOCUMENTATION_OPTIONS.LANGUAGE;
|
||||
if(!lang || lang === "None") {lang = "en";}
|
||||
if(all_langs.hasOwnProperty(lang)) {document.querySelector("#lang-popover").innerHTML = all_langs[lang];}
|
||||
new Popover("version-popover");
|
||||
new Popover("lang-popover");
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user