doc_list.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. app.views.DocList = class DocList extends app.View {
  2. static className = "_list";
  3. static attributes = { role: "navigation" };
  4. static events = {
  5. open: "onOpen",
  6. close: "onClose",
  7. click: "onClick",
  8. };
  9. static routes = { after: "afterRoute" };
  10. static elements = {
  11. disabledTitle: "._list-title",
  12. disabledList: "._disabled-list",
  13. };
  14. init() {
  15. this.lists = {};
  16. this.addSubview((this.listFocus = new app.views.ListFocus(this.el)));
  17. this.addSubview((this.listFold = new app.views.ListFold(this.el)));
  18. this.addSubview((this.listSelect = new app.views.ListSelect(this.el)));
  19. app.on("ready", () => this.render());
  20. }
  21. activate() {
  22. if (super.activate(...arguments)) {
  23. for (var slug in this.lists) {
  24. var list = this.lists[slug];
  25. list.activate();
  26. }
  27. this.listSelect.selectCurrent();
  28. }
  29. }
  30. deactivate() {
  31. if (super.deactivate(...arguments)) {
  32. for (var slug in this.lists) {
  33. var list = this.lists[slug];
  34. list.deactivate();
  35. }
  36. }
  37. }
  38. render() {
  39. let html = "";
  40. for (var doc of app.docs.all()) {
  41. html += this.tmpl("sidebarDoc", doc, {
  42. fullName: app.docs.countAllBy("name", doc.name) > 1,
  43. });
  44. }
  45. this.html(html);
  46. if (!app.isSingleDoc() && app.disabledDocs.size() !== 0) {
  47. this.renderDisabled();
  48. }
  49. }
  50. renderDisabled() {
  51. this.append(
  52. this.tmpl("sidebarDisabled", { count: app.disabledDocs.size() }),
  53. );
  54. this.refreshElements();
  55. this.renderDisabledList();
  56. }
  57. renderDisabledList() {
  58. if (app.settings.get("hideDisabled")) {
  59. this.removeDisabledList();
  60. } else {
  61. this.appendDisabledList();
  62. }
  63. }
  64. appendDisabledList() {
  65. let doc;
  66. let html = "";
  67. const docs = [].concat(...(app.disabledDocs.all() || []));
  68. while ((doc = docs.shift())) {
  69. if (doc.version != null) {
  70. var versions = "";
  71. while (true) {
  72. versions += this.tmpl("sidebarDoc", doc, { disabled: true });
  73. if (docs[0]?.name !== doc.name) {
  74. break;
  75. }
  76. doc = docs.shift();
  77. }
  78. html += this.tmpl("sidebarDisabledVersionedDoc", doc, versions);
  79. } else {
  80. html += this.tmpl("sidebarDoc", doc, { disabled: true });
  81. }
  82. }
  83. this.append(this.tmpl("sidebarDisabledList", html));
  84. this.disabledTitle.classList.add("open-title");
  85. this.refreshElements();
  86. }
  87. removeDisabledList() {
  88. if (this.disabledList) {
  89. $.remove(this.disabledList);
  90. }
  91. this.disabledTitle.classList.remove("open-title");
  92. this.refreshElements();
  93. }
  94. reset(options) {
  95. if (options == null) {
  96. options = {};
  97. }
  98. this.listSelect.deselect();
  99. if (this.listFocus != null) {
  100. this.listFocus.blur();
  101. }
  102. this.listFold.reset();
  103. if (options.revealCurrent || app.isSingleDoc()) {
  104. this.revealCurrent();
  105. }
  106. }
  107. onOpen(event) {
  108. $.stopEvent(event);
  109. const doc = app.docs.findBy("slug", event.target.getAttribute("data-slug"));
  110. if (doc && !this.lists[doc.slug]) {
  111. this.lists[doc.slug] = doc.types.isEmpty()
  112. ? new app.views.EntryList(doc.entries.all())
  113. : new app.views.TypeList(doc);
  114. $.after(event.target, this.lists[doc.slug].el);
  115. }
  116. }
  117. onClose(event) {
  118. $.stopEvent(event);
  119. const doc = app.docs.findBy("slug", event.target.getAttribute("data-slug"));
  120. if (doc && this.lists[doc.slug]) {
  121. this.lists[doc.slug].detach();
  122. delete this.lists[doc.slug];
  123. }
  124. }
  125. select(model) {
  126. this.listSelect.selectByHref(model?.fullPath());
  127. }
  128. reveal(model) {
  129. this.openDoc(model.doc);
  130. if (model.type) {
  131. this.openType(model.getType());
  132. }
  133. this.focus(model);
  134. this.paginateTo(model);
  135. this.scrollTo(model);
  136. }
  137. focus(model) {
  138. if (this.listFocus != null) {
  139. this.listFocus.focus(this.find(`a[href='${model.fullPath()}']`));
  140. }
  141. }
  142. revealCurrent() {
  143. let model;
  144. if ((model = app.router.context.type || app.router.context.entry)) {
  145. this.reveal(model);
  146. this.select(model);
  147. }
  148. }
  149. openDoc(doc) {
  150. if (app.disabledDocs.contains(doc) && doc.version) {
  151. this.listFold.open(
  152. this.find(`[data-slug='${doc.slug_without_version}']`),
  153. );
  154. }
  155. this.listFold.open(this.find(`[data-slug='${doc.slug}']`));
  156. }
  157. closeDoc(doc) {
  158. this.listFold.close(this.find(`[data-slug='${doc.slug}']`));
  159. }
  160. openType(type) {
  161. this.listFold.open(
  162. this.lists[type.doc.slug].find(`[data-slug='${type.slug}']`),
  163. );
  164. }
  165. paginateTo(model) {
  166. if (this.lists[model.doc.slug] != null) {
  167. this.lists[model.doc.slug].paginateTo(model);
  168. }
  169. }
  170. scrollTo(model) {
  171. $.scrollTo(this.find(`a[href='${model.fullPath()}']`), null, "top", {
  172. margin: app.isMobile() ? 48 : 0,
  173. });
  174. }
  175. toggleDisabled() {
  176. if (this.disabledTitle.classList.contains("open-title")) {
  177. this.removeDisabledList();
  178. app.settings.set("hideDisabled", true);
  179. } else {
  180. this.appendDisabledList();
  181. app.settings.set("hideDisabled", false);
  182. }
  183. }
  184. onClick(event) {
  185. let slug;
  186. const target = $.eventTarget(event);
  187. if (
  188. this.disabledTitle &&
  189. $.hasChild(this.disabledTitle, target) &&
  190. target.tagName !== "A"
  191. ) {
  192. $.stopEvent(event);
  193. this.toggleDisabled();
  194. } else if ((slug = target.getAttribute("data-enable"))) {
  195. $.stopEvent(event);
  196. const doc = app.disabledDocs.findBy("slug", slug);
  197. if (doc) {
  198. this.onEnabled = this.onEnabled.bind(this);
  199. app.enableDoc(doc, this.onEnabled, this.onEnabled);
  200. }
  201. }
  202. }
  203. onEnabled() {
  204. this.reset();
  205. this.render();
  206. }
  207. afterRoute(route, context) {
  208. if (context.init) {
  209. if (this.activated) {
  210. this.reset({ revealCurrent: true });
  211. }
  212. } else {
  213. this.select(context.type || context.entry);
  214. }
  215. }
  216. };