diff --git a/doc/python_api/static/css/version_switch.css b/doc/python_api/static/css/version_switch.css
index adb80b01c0a..28a73440c31 100644
--- a/doc/python_api/static/css/version_switch.css
+++ b/doc/python_api/static/css/version_switch.css
@@ -1,9 +1,9 @@
/* Override RTD theme */
.rst-versions {
- display: none;
border-top: 0px;
overflow: visible;
}
+
.version-btn.vdeact {
cursor: default;
color: dimgray;
@@ -12,6 +12,7 @@
.version-btn.vdeact::after {
content: "";
}
+
#versionwrap {
display: flex;
padding-top: 2px;
@@ -19,6 +20,7 @@
justify-content: center;
flex-wrap: wrap;
}
+
.version-btn {
display: inline-block;
background-color: #272525;
@@ -34,31 +36,39 @@
z-index: 400;
transition: border-color 0.4s;
}
+
.version-btn::after {
- content:"\f0d8";
+ content: "\f0d8";
display: inline;
font: normal normal normal 16px/1 FontAwesome;
color: #8d8c8c;
vertical-align: top;
padding-left: 0.5em;
}
+
.version-btn-open::after {
color: gray;
}
-.version-btn:hover, .version-btn:focus {
+
+.version-btn:hover,
+.version-btn:focus {
border-color: #525252;
}
+
.version-btn-open {
color: gray;
border: solid 1px gray;
}
+
.version-btn.wait {
cursor: wait;
}
+
.version-btn.disabled {
cursor: not-allowed;
color: dimgray;
}
+
.version-dialog {
display: none;
position: absolute;
@@ -74,6 +84,7 @@
overflow-y: auto;
cursor: default;
}
+
.version-title {
padding: 5px;
color: black;
@@ -82,6 +93,7 @@
background-color: #27ae60;
border-bottom: solid 1.5px #444;
}
+
.version-list {
margin-bottom: 4px;
text-align: center;
@@ -89,7 +101,10 @@
border: solid 1px gray;
border-radius: 0px 0px 3px 3px;
}
-.version-list a, .version-list span, .version-list li {
+
+.version-list a,
+.version-list span,
+.version-list li {
position: relative;
display: block;
font-size: 98%;
@@ -99,21 +114,28 @@
padding: 4px 0px;
color: #404040;
}
+
.version-list li {
background-color: #ede9e9;
color: #404040;
padding: 1px;
}
-.version-list li:hover, .version-list li a:focus {
+
+.version-list li:hover,
+.version-list li a:focus {
background-color: #b9cfda;
}
-.version-list li.selected, .version-list li.selected:hover {
+
+.version-list li.selected,
+.version-list li.selected:hover {
background-color: #8d8c8c;
}
+
.version-list li.selected span {
cursor: default;
outline-color: red;
}
+
.version-arrow {
position: absolute;
width: 8px;
diff --git a/doc/python_api/static/js/version_switch.js b/doc/python_api/static/js/version_switch.js
index b2d25069fbe..c00253bfe73 100644
--- a/doc/python_api/static/js/version_switch.js
+++ b/doc/python_api/static/js/version_switch.js
@@ -1,63 +1,60 @@
-(function() { // switch: v1.2
+(function() { // switch: v1.4
"use strict";
var versionsFileUrl = "https://docs.blender.org/PROD/versions.json"
var all_versions;
-var Popover = function() {
- function Popover(id)
+class Popover {
+ constructor(id)
{
this.isOpen = false;
this.type = (id === "version-popover");
- this.$btn = $('#' + id);
- this.$dialog = this.$btn.next();
- this.$list = this.$dialog.children("ul");
+ this.btn = document.querySelector('#' + id);
+ this.dialog = this.btn.nextElementSibling;
+ this.list = this.dialog.querySelector("ul");
this.sel = null;
- this.beforeInit();
- }
-
- Popover.prototype = {
- beforeInit : function() {
- var that = this;
- this.$btn.on("click", function(e) {
+ 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.on("keydown", function(e) {
- if (that.btnKeyFilter(e)) {
- that.init();
- e.preventDefault();
- e.stopPropagation();
- }
- });
- },
- init : function() {
- this.$btn.off("click");
- this.$btn.off("keydown");
+ }
+ };
+ 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.addClass("wait");
- this.loadVL(this);
+ 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 {
- this.afterLoad();
+ resolve();
}
- },
- loadVL : function(that) {
- $.getJSON(versionsFileUrl, function(data) {
- all_versions = data;
- that.afterLoad();
- return true;
- }).fail(function() {
- console.log("Version Switch Error: versions.json could not be loaded.");
- that.$btn.addClass("disabled");
- return false;
- });
- },
- afterLoad : function() {
- var release = DOCUMENTATION_OPTIONS.VERSION;
+ }).then(() => {
+ let release = DOCUMENTATION_OPTIONS.VERSION;
const m = release.match(/\d\.\d+/g);
if (m) {
release = m[0];
@@ -65,259 +62,274 @@ var Popover = function() {
this.warnOld(release, all_versions);
- var version = this.getNamed(release);
- var list = this.buildList(version);
+ const version = this.getNamed(release);
+ this.buildList(version);
- this.$list.children(":first-child").remove();
- this.$list.append(list);
- var that = this;
- this.$list.on("keydown", function(e) {
+ this.list.firstElementChild.remove();
+ const that = this;
+ this.list.addEventListener("keydown", function(e) {
that.keyMove(e);
});
- this.$btn.removeClass("wait");
+ this.btn.classList.remove("wait");
this.btnOpenHandler();
- this.$btn.on("mousedown", function(e) {
+ this.btn.addEventListener("mousedown", function(e) {
that.btnOpenHandler();
e.preventDefault()
});
- this.$btn.on("keydown", function(e) {
+ this.btn.addEventListener("keydown", function(e) {
if (that.btnKeyFilter(e)) {
that.btnOpenHandler();
}
});
- },
- warnOld : function(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
- // when versions.js is loaded. This is too late to be useful.
- var 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) {
- var currentURL = window.location.pathname.replace(release, current);
- var warning = $('
' +
- '
Note
' +
- '
' +
- 'You are not using the most up to date version of the documentation. ' +
- ' is the newest version.' +
- '
' +
- '
');
-
- warning.find('a').attr('href', currentURL).text(current);
-
- var body = $("div.body");
- if (!body.length) {
- body = $("div.document");
- }
- body.prepend(warning);
- }
- },
- buildList : function(v) {
- var url = new URL(window.location.href);
- let pathSplit = [ "", "api", v ];
- if (url.pathname.startsWith("/api/")) {
- pathSplit.push(url.pathname.split('/').slice(3).join('/'));
- }
- else {
- pathSplit.push(url.pathname.substring(1));
- }
- if (this.type) {
- var dyn = all_versions;
- var cur = v;
- }
- var buf = [];
- var that = this;
- $.each(dyn, function(ix, title) {
- buf.push("' +
- title + '');
- }
- else {
- pathSplit[2 + that.type] = ix;
- var href = new URL(url);
- href.pathname = pathSplit.join('/');
- buf.push(' tabindex="-1" role="presentation">' +
- title + '');
- }
- });
- return buf.join('');
- },
- getNamed : function(v) {
- $.each(all_versions, function(ix, title) {
- if (ix === "master" || ix === "main" || ix === "latest") {
- var m = title.match(/\d\.\d[\w\d\.]*/)[0];
- if (parseFloat(m) == v) {
- v = ix;
- return false;
- }
- }
- });
- return v;
- },
- dialogToggle : function(speed) {
- var wasClose = !this.isOpen;
- var that = this;
- if (!this.isOpen) {
- this.$btn.addClass("version-btn-open");
- this.$btn.attr("aria-pressed", true);
- this.$dialog.attr("aria-hidden", false);
- this.$dialog.fadeIn(speed, function() {
- that.$btn.parent().on("focusout", function(e) {
- that.focusoutHandler();
- e.stopImmediatePropagation();
- })
- that.$btn.parent().on("mouseleave", function(e) {
- that.mouseoutHandler();
- e.stopImmediatePropagation();
- });
- });
- this.isOpen = true;
- }
- else {
- this.$btn.removeClass("version-btn-open");
- this.$btn.attr("aria-pressed", false);
- this.$dialog.attr("aria-hidden", true);
- this.$btn.parent().off("focusout");
- this.$btn.parent().off("mouseleave");
- this.$dialog.fadeOut(speed, function() {
- if (this.$sel) {
- this.$sel.attr("tabindex", -1);
- }
- that.$btn.attr("tabindex", 0);
- if (document.activeElement !== null && document.activeElement !== document &&
- document.activeElement !== document.body) {
- that.$btn.focus();
- }
- });
- this.isOpen = false;
- }
-
- if (wasClose) {
- if (this.$sel) {
- this.$sel.attr("tabindex", -1);
- }
- if (document.activeElement !== null && document.activeElement !== document &&
- document.activeElement !== document.body) {
- var $nw = this.listEnter();
- $nw.attr("tabindex", 0);
- $nw.focus();
- this.$sel = $nw;
- }
- }
- },
- btnOpenHandler : function() {
- this.dialogToggle(300);
- },
- focusoutHandler : function() {
- var list = this.$list;
- var that = this;
- setTimeout(function() {
- if (list.find(":focus").length === 0) {
- that.dialogToggle(200);
- }
- }, 200);
- },
- mouseoutHandler : function() {
- this.dialogToggle(200);
- },
- btnKeyFilter : function(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 : function(e) {
- if (e.ctrlKey || e.shiftKey) {
- return true;
- }
- var p = true;
- var $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:
- p = false;
- }
- if (p) {
- $nw.attr("tabindex", 0);
- $nw.focus();
- if (this.$sel) {
- this.$sel.attr("tabindex", -1);
- }
- this.$sel = $nw;
- e.preventDefault();
- e.stopPropagation();
- }
- },
- listPrev : function($nw) {
- if ($nw.parent().prev().length !== 0) {
- return $nw.parent().prev().children(":first-child");
- }
- else {
- return this.listLast();
- }
- },
- listNext : function($nw) {
- if ($nw.parent().next().length !== 0) {
- return $nw.parent().next().children(":first-child");
- }
- else {
- return this.listFirst();
- }
- },
- listFirst : function() {
- return this.$list.children(":first-child").children(":first-child");
- },
- listLast : function() {
- return this.$list.children(":last-child").children(":first-child");
- },
- listExit : function() {
- this.mouseoutHandler();
- return this.$btn;
- },
- listEnter : function() {
- return this.$list.children(":first-child").children(":first-child");
+ });
+ }
+ 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
+ // 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;
}
- };
- return Popover
-}();
+ 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;
-$(document).ready(function() {
- var lng_popover = new Popover("version-popover");
-});
+ let body = document.querySelector("div.body");
+ if (!body.length) {
+ body = document.querySelector("div.document");
+ }
+ body.prepend(warning);
+ }
+ }
+ buildList(v)
+ {
+ const url = new URL(window.location.href);
+ let pathSplit = [ "", "api", v ];
+ if (url.pathname.startsWith("/api/")) {
+ 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;
+ }
+ 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[1 + 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;
+ link.innerHTML = title;
+ }
+ that.list.append(clone);
+ };
+ return this.list;
+ }
+ getNamed(v)
+ {
+ for (let [ix, title] of Object.entries(all_versions)) {
+ if (ix === "master" || ix === "main" || ix === "latest") {
+ const m = title.match(/\d\.\d[\w\d\.]*/)[0];
+ if (parseFloat(m) == v) {
+ v = ix;
+ return false;
+ }
+ }
+ };
+ return v;
+ }
+ dialogToggle(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', () => { new Popover("version-popover"); });
})();
diff --git a/doc/python_api/templates/versions.html b/doc/python_api/templates/versions.html
index 482d4361207..ec3788f8bc5 100644
--- a/doc/python_api/templates/versions.html
+++ b/doc/python_api/templates/versions.html
@@ -1,19 +1,30 @@
-
-
+
{{ release }}
+
+
+
+
-
+
+
+
Note
+
+ You are not using the most up to date version of the documentation.
+ is the newest version.
+
+
+
+
\ No newline at end of file