versions.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. const themeFlyoutDisplay = "hidden";
  2. const themeVersionSelector = "True";
  3. const themeLanguageSelector = "True";
  4. if (themeFlyoutDisplay === "attached") {
  5. function renderLanguages(config) {
  6. if (!config.projects.translations.length) {
  7. return "";
  8. }
  9. const languagesHTML = `
  10. <dl>
  11. <dt>Languages</dt>
  12. ${config.projects.translations
  13. .map(
  14. (translation) => `
  15. <dd ${translation.slug == config.projects.current.slug ? 'class="rtd-current-item"' : ""}>
  16. <a href="${translation.urls.documentation}">${translation.language.code}</a>
  17. </dd>
  18. `,
  19. )
  20. .join("\n")}
  21. </dl>
  22. `;
  23. return languagesHTML;
  24. }
  25. function renderVersions(config) {
  26. if (!config.versions.active.length) {
  27. return "";
  28. }
  29. const versionsHTML = `
  30. <dl>
  31. <dt>Versions</dt>
  32. ${config.versions.active
  33. .map(
  34. (version) => `
  35. <dd ${version.slug === config.versions.current.slug ? 'class="rtd-current-item"' : ""}>
  36. <a href="${version.urls.documentation}">${version.slug}</a>
  37. </dd>
  38. `,
  39. )
  40. .join("\n")}
  41. </dl>
  42. `;
  43. return versionsHTML;
  44. }
  45. function renderDownloads(config) {
  46. if (!Object.keys(config.versions.current.downloads).length) {
  47. return "";
  48. }
  49. const downloadsNameDisplay = {
  50. pdf: "PDF",
  51. epub: "Epub",
  52. htmlzip: "HTML",
  53. };
  54. const downloadsHTML = `
  55. <dl>
  56. <dt>Downloads</dt>
  57. ${Object.entries(config.versions.current.downloads)
  58. .map(
  59. ([name, url]) => `
  60. <dd>
  61. <a href="${url}">${downloadsNameDisplay[name]}</a>
  62. </dd>
  63. `,
  64. )
  65. .join("\n")}
  66. </dl>
  67. `;
  68. return downloadsHTML;
  69. }
  70. document.addEventListener("readthedocs-addons-data-ready", function (event) {
  71. const config = event.detail.data();
  72. const flyout = `
  73. <div class="rst-versions" data-toggle="rst-versions" role="note">
  74. <span class="rst-current-version" data-toggle="rst-current-version">
  75. <span class="fa fa-book"> Read the Docs</span>
  76. v: ${config.versions.current.slug}
  77. <span class="fa fa-caret-down"></span>
  78. </span>
  79. <div class="rst-other-versions">
  80. <div class="injected">
  81. ${renderLanguages(config)}
  82. ${renderVersions(config)}
  83. ${renderDownloads(config)}
  84. <dl>
  85. <dt>On Read the Docs</dt>
  86. <dd>
  87. <a href="${config.projects.current.urls.home}">Project Home</a>
  88. </dd>
  89. <dd>
  90. <a href="${config.projects.current.urls.builds}">Builds</a>
  91. </dd>
  92. <dd>
  93. <a href="${config.projects.current.urls.downloads}">Downloads</a>
  94. </dd>
  95. </dl>
  96. <dl>
  97. <dt>Search</dt>
  98. <dd>
  99. <form id="flyout-search-form">
  100. <input
  101. class="wy-form"
  102. type="text"
  103. name="q"
  104. aria-label="Search docs"
  105. placeholder="Search docs"
  106. />
  107. </form>
  108. </dd>
  109. </dl>
  110. <hr />
  111. <small>
  112. <span>Hosted by <a href="https://about.readthedocs.org/?utm_source=&utm_content=flyout">Read the Docs</a></span>
  113. </small>
  114. </div>
  115. </div>
  116. `;
  117. // Inject the generated flyout into the body HTML element.
  118. document.body.insertAdjacentHTML("beforeend", flyout);
  119. // Trigger the Read the Docs Addons Search modal when clicking on the "Search docs" input from inside the flyout.
  120. document
  121. .querySelector("#flyout-search-form")
  122. .addEventListener("focusin", () => {
  123. const event = new CustomEvent("readthedocs-search-show");
  124. document.dispatchEvent(event);
  125. });
  126. })
  127. }
  128. if (themeLanguageSelector || themeVersionSelector) {
  129. function onSelectorSwitch(event) {
  130. const option = event.target.selectedIndex;
  131. const item = event.target.options[option];
  132. window.location.href = item.dataset.url;
  133. }
  134. document.addEventListener("readthedocs-addons-data-ready", function (event) {
  135. const config = event.detail.data();
  136. const versionSwitch = document.querySelector(
  137. "div.switch-menus > div.version-switch",
  138. );
  139. if (themeVersionSelector) {
  140. let versions = config.versions.active;
  141. if (config.versions.current.hidden || config.versions.current.type === "external") {
  142. versions.unshift(config.versions.current);
  143. }
  144. const versionSelect = `
  145. <select>
  146. ${versions
  147. .map(
  148. (version) => `
  149. <option
  150. value="${version.slug}"
  151. ${config.versions.current.slug === version.slug ? 'selected="selected"' : ""}
  152. data-url="${version.urls.documentation}">
  153. ${version.slug}
  154. </option>`,
  155. )
  156. .join("\n")}
  157. </select>
  158. `;
  159. versionSwitch.innerHTML = versionSelect;
  160. versionSwitch.firstElementChild.addEventListener("change", onSelectorSwitch);
  161. }
  162. const languageSwitch = document.querySelector(
  163. "div.switch-menus > div.language-switch",
  164. );
  165. if (themeLanguageSelector) {
  166. if (config.projects.translations.length) {
  167. // Add the current language to the options on the selector
  168. let languages = config.projects.translations.concat(
  169. config.projects.current,
  170. );
  171. languages = languages.sort((a, b) =>
  172. a.language.name.localeCompare(b.language.name),
  173. );
  174. const languageSelect = `
  175. <select>
  176. ${languages
  177. .map(
  178. (language) => `
  179. <option
  180. value="${language.language.code}"
  181. ${config.projects.current.slug === language.slug ? 'selected="selected"' : ""}
  182. data-url="${language.urls.documentation}">
  183. ${language.language.name}
  184. </option>`,
  185. )
  186. .join("\n")}
  187. </select>
  188. `;
  189. languageSwitch.innerHTML = languageSelect;
  190. languageSwitch.firstElementChild.addEventListener("change", onSelectorSwitch);
  191. }
  192. else {
  193. languageSwitch.remove();
  194. }
  195. }
  196. });
  197. }
  198. document.addEventListener("readthedocs-addons-data-ready", function (event) {
  199. // Trigger the Read the Docs Addons Search modal when clicking on "Search docs" input from the topnav.
  200. document
  201. .querySelector("[role='search'] input")
  202. .addEventListener("focusin", () => {
  203. const event = new CustomEvent("readthedocs-search-show");
  204. document.dispatchEvent(event);
  205. });
  206. });