sidebar.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /* sidebar.js - Handle the table of content iframed page
  2. Copyright © 2017 Free Software Foundation, Inc.
  3. This file is part of GNU Texinfo.
  4. GNU Texinfo is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. GNU Texinfo is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Texinfo. If not, see <http://www.gnu.org/licenses/>. */
  14. import * as actions from "./actions";
  15. import {
  16. clear_toc_styles,
  17. create_link_dict,
  18. fix_links,
  19. scan_toc
  20. } from "./toc";
  21. import config from "./config";
  22. import { iframe_dispatch } from "./store";
  23. /** Sidebar component encapsulating the iframe and its state. */
  24. export class
  25. Sidebar
  26. {
  27. constructor ()
  28. {
  29. /* Actual state of the sidebar. */
  30. this.state = null;
  31. /* Reference to the DOM element. */
  32. this.element = document.createElement ("div");
  33. this.element.setAttribute ("id", "sidebar");
  34. }
  35. /* Render 'sidebar' according to STATE which is a new state. */
  36. render (state)
  37. {
  38. if (this.state && this.state !== state)
  39. this.update (state);
  40. else /* Initial render */
  41. {
  42. let iframe = document.createElement ("iframe");
  43. iframe.setAttribute ("name", "slider");
  44. iframe.setAttribute ("src", (config.TOC_FILENAME
  45. + "#main=" + config.INDEX_NAME));
  46. this.element.appendChild (iframe);
  47. }
  48. this.state = state;
  49. }
  50. /* Updating render. */
  51. update (state)
  52. {
  53. if (state.current !== this.state.current)
  54. {
  55. /* Update sidebar to highlight the title corresponding to
  56. 'state.current'. */
  57. let iframe = this.element.querySelector ("iframe");
  58. let msg = { message_kind: "update-sidebar", selected: state.current };
  59. iframe.contentWindow.postMessage (msg, "*");
  60. }
  61. }
  62. }
  63. /*----------------------------------------------
  64. | Auxilary functions for the sidebar context. |
  65. `---------------------------------------------*/
  66. /* Add a link from TOC_FILENAME to the main index file. */
  67. function
  68. add_header ()
  69. {
  70. let li = document.querySelector ("li");
  71. if (li && li.firstElementChild && li.firstElementChild.matches ("a")
  72. && li.firstElementChild.getAttribute ("href") === config.INDEX_NAME)
  73. li.parentNode.removeChild (li);
  74. let header = document.querySelector ("header");
  75. let h1 = document.querySelector ("h1");
  76. if (header && h1)
  77. {
  78. let a = document.createElement ("a");
  79. a.setAttribute ("href", "index.html");
  80. header.appendChild (a);
  81. let div = document.createElement ("div");
  82. a.appendChild (div);
  83. let img = document.createElement ("img");
  84. img.setAttribute ("src", config.PACKAGE_LOGO);
  85. div.appendChild (img);
  86. let span = document.createElement ("span");
  87. span.appendChild (h1.firstChild);
  88. div.appendChild (span);
  89. h1.parentNode.removeChild (h1);
  90. }
  91. }
  92. /*------------------------------------------
  93. | Event handlers for the sidebar context. |
  94. `-----------------------------------------*/
  95. /** Initialize TOC_FILENAME which must be loaded in the context of an
  96. iframe. */
  97. export function
  98. on_load ()
  99. {
  100. add_header ();
  101. document.body.setAttribute ("class", "toc-sidebar");
  102. /* Specify the base URL to use for all relative URLs. */
  103. /* FIXME: Add base also for sub-pages. */
  104. let base = document.createElement ("base");
  105. base.setAttribute ("href",
  106. window.location.href.replace (/[/][^/]*$/, "/"));
  107. document.head.appendChild (base);
  108. let links = Array.from (document.links);
  109. fix_links (links);
  110. /* Create a link referencing the Table of content. */
  111. let toc_a = document.createElementNS (config.XHTML_NAMESPACE, "a");
  112. toc_a.setAttribute ("href", config.TOC_FILENAME);
  113. toc_a.appendChild (document.createTextNode ("Table of Contents"));
  114. let toc_li = document.createElementNS (config.XHTML_NAMESPACE, "li");
  115. toc_li.appendChild (toc_a);
  116. let index_li = links[links.length - 1].parentNode;
  117. let index_grand = index_li.parentNode.parentNode;
  118. /* XXX: hack */
  119. if (index_grand.matches ("li"))
  120. index_li = index_grand;
  121. index_li.parentNode.insertBefore (toc_li, index_li.nextSibling);
  122. scan_toc (document.body, config.INDEX_NAME);
  123. let divs = Array.from (document.querySelectorAll ("div"));
  124. divs.reverse ()
  125. .forEach (div => {
  126. if (div.getAttribute ("class") === "toc-title")
  127. div.parentNode.removeChild (div);
  128. });
  129. /* Get 'backward' and 'forward' link attributes. */
  130. let dict = create_link_dict (document.querySelector ("ul"));
  131. iframe_dispatch (actions.cache_links (dict));
  132. /* Create iframe divs in 'config.MAIN_NAME'. */
  133. top.postMessage ({ message_kind: "node-list" }, "*");
  134. }
  135. /** Handle messages received via the Message API. */
  136. export function
  137. on_message (event)
  138. {
  139. let data = event.data;
  140. switch (data.message_kind)
  141. {
  142. case "update-sidebar":
  143. {
  144. let selected = data.selected;
  145. clear_toc_styles (document.body);
  146. let filename = (selected === config.INDEX_ID) ?
  147. config.INDEX_NAME : (selected + ".xhtml");
  148. scan_toc (document.body, filename);
  149. break;
  150. }
  151. default:
  152. break;
  153. }
  154. }