versions.js 6.8 KB

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