web-mojo 2.2.57 → 2.2.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/admin.cjs.js +1 -1
  2. package/dist/admin.cjs.js.map +1 -1
  3. package/dist/admin.es.js +1 -10105
  4. package/dist/admin.es.js.map +1 -1
  5. package/dist/auth.cjs.js +1 -1
  6. package/dist/auth.es.js +1 -588
  7. package/dist/auth.es.js.map +1 -1
  8. package/dist/charts.cjs.js +1 -1
  9. package/dist/charts.es.js +1 -571
  10. package/dist/charts.es.js.map +1 -1
  11. package/dist/chunks/ChatView-D4A9rIX3.js +2 -0
  12. package/dist/chunks/ChatView-D4A9rIX3.js.map +1 -0
  13. package/dist/chunks/ChatView-nxaq8aIo.js +2 -0
  14. package/dist/chunks/ChatView-nxaq8aIo.js.map +1 -0
  15. package/dist/chunks/Collection-1sPoIFvQ.js +2 -0
  16. package/dist/chunks/{Collection-DaiL0uGl.js.map → Collection-1sPoIFvQ.js.map} +1 -1
  17. package/dist/chunks/{Collection-CxbNKOas.js → Collection-DSBRXpwK.js} +2 -2
  18. package/dist/chunks/{Collection-CxbNKOas.js.map → Collection-DSBRXpwK.js.map} +1 -1
  19. package/dist/chunks/{ContextMenu-ClwHEbbD.js → ContextMenu-BWy7WqF4.js} +2 -2
  20. package/dist/chunks/{ContextMenu-ClwHEbbD.js.map → ContextMenu-BWy7WqF4.js.map} +1 -1
  21. package/dist/chunks/ContextMenu-BvniQz-N.js +3 -0
  22. package/dist/chunks/{ContextMenu-sgvgSACY.js.map → ContextMenu-BvniQz-N.js.map} +1 -1
  23. package/dist/chunks/DataView--nUWtq6r.js +2 -0
  24. package/dist/chunks/{DataView-Dzo0jbs2.js.map → DataView--nUWtq6r.js.map} +1 -1
  25. package/dist/chunks/{DataView-1xh3GFeC.js → DataView-CK3Z0TJH.js} +2 -2
  26. package/dist/chunks/{DataView-1xh3GFeC.js.map → DataView-CK3Z0TJH.js.map} +1 -1
  27. package/dist/chunks/Dialog-BcgSR01Z.js +2 -0
  28. package/dist/chunks/{Dialog-DOGDalUq.js.map → Dialog-BcgSR01Z.js.map} +1 -1
  29. package/dist/chunks/{Dialog-CQlTDhZS.js → Dialog-DwCTFV6O.js} +2 -2
  30. package/dist/chunks/{Dialog-CQlTDhZS.js.map → Dialog-DwCTFV6O.js.map} +1 -1
  31. package/dist/chunks/FormPlugins-DvQ-G5J5.js +2 -0
  32. package/dist/chunks/{FormPlugins-DY6e88YT.js.map → FormPlugins-DvQ-G5J5.js.map} +1 -1
  33. package/dist/chunks/{FormView-DaKA4Sys.js → FormView-CRmEReTC.js} +3 -3
  34. package/dist/chunks/{FormView-DaKA4Sys.js.map → FormView-CRmEReTC.js.map} +1 -1
  35. package/dist/chunks/FormView-OLA7t-yv.js +3 -0
  36. package/dist/chunks/{FormView-Dz3mYasQ.js.map → FormView-OLA7t-yv.js.map} +1 -1
  37. package/dist/chunks/ListView-6JQ6tRXs.js +2 -0
  38. package/dist/chunks/{ListView-X5w5jf51.js.map → ListView-6JQ6tRXs.js.map} +1 -1
  39. package/dist/chunks/{ListView-CDzKIpd8.js → ListView-DVStKiMi.js} +2 -2
  40. package/dist/chunks/{ListView-CDzKIpd8.js.map → ListView-DVStKiMi.js.map} +1 -1
  41. package/dist/chunks/{MetricsCountryMapView-Dx2cw7ya.js → MetricsCountryMapView-CnAEbUw_.js} +2 -2
  42. package/dist/chunks/{MetricsCountryMapView-Dx2cw7ya.js.map → MetricsCountryMapView-CnAEbUw_.js.map} +1 -1
  43. package/dist/chunks/MetricsCountryMapView-J067qrrt.js +2 -0
  44. package/dist/chunks/{MetricsCountryMapView-B2xz6zUw.js.map → MetricsCountryMapView-J067qrrt.js.map} +1 -1
  45. package/dist/chunks/{MetricsMiniChartWidget-CBuso0OE.js → MetricsMiniChartWidget-BeD1slGs.js} +2 -2
  46. package/dist/chunks/{MetricsMiniChartWidget-CBuso0OE.js.map → MetricsMiniChartWidget-BeD1slGs.js.map} +1 -1
  47. package/dist/chunks/MetricsMiniChartWidget-x2gFjHOU.js +2 -0
  48. package/dist/chunks/{MetricsMiniChartWidget-DvKd7Qrk.js.map → MetricsMiniChartWidget-x2gFjHOU.js.map} +1 -1
  49. package/dist/chunks/PDFViewer-CsyKn-gh.js +2 -0
  50. package/dist/chunks/{PDFViewer-EJ9cOfPF.js.map → PDFViewer-CsyKn-gh.js.map} +1 -1
  51. package/dist/chunks/{PDFViewer-ofMGdSaj.js → PDFViewer-DSa4BZCm.js} +2 -2
  52. package/dist/chunks/{PDFViewer-ofMGdSaj.js.map → PDFViewer-DSa4BZCm.js.map} +1 -1
  53. package/dist/chunks/Rest-DHbszkuP.js +2 -0
  54. package/dist/chunks/Rest-DHbszkuP.js.map +1 -0
  55. package/dist/chunks/Rest-Ds9e8tN8.js +2 -0
  56. package/dist/chunks/Rest-Ds9e8tN8.js.map +1 -0
  57. package/dist/chunks/TokenManager-D6SjKgPZ.js +2 -0
  58. package/dist/chunks/{TokenManager-DoN9e6q6.js.map → TokenManager-D6SjKgPZ.js.map} +1 -1
  59. package/dist/chunks/{TokenManager-Gqvj7SDX.js → TokenManager-REbha1Le.js} +2 -2
  60. package/dist/chunks/{TokenManager-Gqvj7SDX.js.map → TokenManager-REbha1Le.js.map} +1 -1
  61. package/dist/chunks/WebApp-CULZpO_0.js +2 -0
  62. package/dist/chunks/{WebApp-6qvqmOts.js.map → WebApp-CULZpO_0.js.map} +1 -1
  63. package/dist/chunks/{WebApp-_dgpwtFw.js → WebApp-DovLtA60.js} +2 -2
  64. package/dist/chunks/{WebApp-_dgpwtFw.js.map → WebApp-DovLtA60.js.map} +1 -1
  65. package/dist/chunks/WebSocketClient-B-wc3mez.js +2 -0
  66. package/dist/chunks/{WebSocketClient-DG2olXpH.js.map → WebSocketClient-B-wc3mez.js.map} +1 -1
  67. package/dist/chunks/{WebSocketClient-MFkFlSue.js → WebSocketClient-BdZ9QYll.js} +2 -2
  68. package/dist/chunks/{WebSocketClient-MFkFlSue.js.map → WebSocketClient-BdZ9QYll.js.map} +1 -1
  69. package/dist/chunks/version-C3dnl1bg.js +2 -0
  70. package/dist/chunks/version-C3dnl1bg.js.map +1 -0
  71. package/dist/chunks/{version-BVADfTA5.js → version-ioN546cp.js} +2 -2
  72. package/dist/chunks/{version-BVADfTA5.js.map → version-ioN546cp.js.map} +1 -1
  73. package/dist/css/web-mojo.css +1 -1
  74. package/dist/docit.cjs.js +1 -1
  75. package/dist/docit.es.js +1 -957
  76. package/dist/docit.es.js.map +1 -1
  77. package/dist/index.cjs.js +1 -1
  78. package/dist/index.es.js +1 -3252
  79. package/dist/index.es.js.map +1 -1
  80. package/dist/lightbox.cjs.js +1 -1
  81. package/dist/lightbox.es.js +1 -3737
  82. package/dist/lightbox.es.js.map +1 -1
  83. package/dist/loader.umd.js +2 -2
  84. package/dist/map.cjs.js +1 -1
  85. package/dist/map.es.js +1 -1032
  86. package/dist/map.es.js.map +1 -1
  87. package/dist/mojo-auth.es.js +338 -0
  88. package/dist/mojo-auth.umd.js +1 -0
  89. package/dist/timeline.cjs.js +1 -1
  90. package/dist/timeline.es.js +1 -224
  91. package/dist/timeline.es.js.map +1 -1
  92. package/dist/web-mojo.lite.iife.js +14 -3
  93. package/dist/web-mojo.lite.iife.js.map +1 -1
  94. package/dist/web-mojo.lite.iife.min.js +6 -6
  95. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  96. package/package.json +2 -2
  97. package/dist/chunks/ChatView-9k6xBWXk.js +0 -7632
  98. package/dist/chunks/ChatView-9k6xBWXk.js.map +0 -1
  99. package/dist/chunks/ChatView-CdtuCDYm.js +0 -2
  100. package/dist/chunks/ChatView-CdtuCDYm.js.map +0 -1
  101. package/dist/chunks/Collection-DaiL0uGl.js +0 -1014
  102. package/dist/chunks/ContextMenu-sgvgSACY.js +0 -1535
  103. package/dist/chunks/DataView-Dzo0jbs2.js +0 -862
  104. package/dist/chunks/Dialog-DOGDalUq.js +0 -1579
  105. package/dist/chunks/FormPlugins-DY6e88YT.js +0 -124
  106. package/dist/chunks/FormView-Dz3mYasQ.js +0 -8636
  107. package/dist/chunks/ListView-X5w5jf51.js +0 -495
  108. package/dist/chunks/MetricsCountryMapView-B2xz6zUw.js +0 -1054
  109. package/dist/chunks/MetricsMiniChartWidget-DvKd7Qrk.js +0 -3283
  110. package/dist/chunks/PDFViewer-EJ9cOfPF.js +0 -946
  111. package/dist/chunks/Rest-CgSjfMaU.js +0 -2
  112. package/dist/chunks/Rest-CgSjfMaU.js.map +0 -1
  113. package/dist/chunks/Rest-W-sPfGh9.js +0 -4375
  114. package/dist/chunks/Rest-W-sPfGh9.js.map +0 -1
  115. package/dist/chunks/TokenManager-DoN9e6q6.js +0 -1423
  116. package/dist/chunks/WebApp-6qvqmOts.js +0 -1386
  117. package/dist/chunks/WebSocketClient-DG2olXpH.js +0 -209
  118. package/dist/chunks/version-OyPGnx30.js +0 -38
  119. package/dist/chunks/version-OyPGnx30.js.map +0 -1
package/dist/docit.es.js CHANGED
@@ -1,958 +1,2 @@
1
- import { W as WebApp } from "./chunks/WebApp-6qvqmOts.js";
2
- import { T as TokenManager, a as TopNav } from "./chunks/TokenManager-DoN9e6q6.js";
3
- import { V as View } from "./chunks/Rest-W-sPfGh9.js";
4
- import { P as Page, C as ContextMenu, T as ToastService, U as User } from "./chunks/ContextMenu-sgvgSACY.js";
5
- import { M as Model, C as Collection } from "./chunks/Collection-DaiL0uGl.js";
6
- import { B, a, V, b, c, d } from "./chunks/version-OyPGnx30.js";
7
- class DocNavSidebar extends View {
8
- constructor(options = {}) {
9
- super({
10
- className: "docit-sidebar-nav",
11
- tagName: "nav",
12
- ...options
13
- });
14
- this.singleBookMode = options.singleBookMode || false;
15
- this.books = options.books;
16
- this.docPages = options.docPages;
17
- this.activeUser = options.activeUser;
18
- this.currentBook = null;
19
- this.currentDocPage = null;
20
- }
21
- async onInit() {
22
- await super.onInit();
23
- this.getApp().events.on("page:show", this._onPageShow.bind(this));
24
- }
25
- async _onPageShow({ query }) {
26
- const bookSlug = query.doc_book;
27
- const pageSlug = query.doc_page;
28
- const app = this.getApp();
29
- if (bookSlug) {
30
- const book = this.books.findWhere({ slug: bookSlug });
31
- if (book && (!this.currentBook || this.currentBook.id !== book.id)) {
32
- await app.setActiveBook(book);
33
- this.currentBook = app.currentBook;
34
- }
35
- } else {
36
- if (this.currentBook) {
37
- await app.setActiveBook(null);
38
- this.currentBook = null;
39
- }
40
- }
41
- this.currentDocPage = pageSlug ? this.docPages.findWhere({ slug: pageSlug }) : null;
42
- this.render();
43
- }
44
- getTemplate() {
45
- return `
46
- <div class="docit-nav-body pt-3">
47
- {{#currentBook}}
48
- {{#docPages.models}}
49
- <a href="#" class="docit-page-link {{#isActive}}active{{/isActive}}"
50
- data-action="select-page" data-page-slug="{{slug}}">
51
- <i class="{{#metadata.icon}}{{metadata.icon}}{{/metadata.icon}}{{^metadata.icon}}bi bi-file-earmark-text{{/metadata.icon}} me-2"></i>
52
- <span>{{title|capitalize}}</span>
53
- </a>
54
- {{/docPages.models}}
55
- {{^docPages.models}}
56
- <div class="docit-nav-empty"><p>No pages in this book.</p></div>
57
- {{/docPages.models}}
58
- {{/currentBook}}
59
- {{^currentBook}}
60
- {{#books.models}}
61
- <a href="#" class="docit-book-item" data-action="select-book" data-book-slug="{{slug}}">
62
- <i class="bi bi-book me-2"></i>
63
- <span class="book-title">{{title}}</span>
64
- <span class="badge bg-secondary ms-auto">{{page_count}}</span>
65
- </a>
66
- {{/books.models}}
67
- {{/currentBook}}
68
- </div>
69
- {{#currentBook}}
70
- <div class="docit-nav-footer">
71
- {{#canEdit}}
72
- <button class="btn btn-link w-100 mb-2" data-action="create-page">
73
- <i class="bi bi-plus-circle me-2"></i>
74
- Create New Page
75
- </button>
76
- {{/canEdit}}
77
- <button class="btn btn-link w-100" data-action="back-to-books">
78
- <i class="bi bi-arrow-left me-2"></i>
79
- Back to Books
80
- </button>
81
- </div>
82
- {{/currentBook}}
83
- {{^currentBook}}
84
- {{#canEdit}}
85
- <div class="docit-nav-footer">
86
- <button class="btn btn-link w-100" data-action="create-book">
87
- <i class="bi bi-plus-circle me-2"></i>
88
- Create New Book
89
- </button>
90
- </div>
91
- {{/canEdit}}
92
- {{/currentBook}}
93
- `;
94
- }
95
- async onBeforeRender() {
96
- await super.onBeforeRender();
97
- this.canEdit = this.getApp().canEdit();
98
- if (this.docPages && this.currentDocPage) {
99
- this.docPages.forEach((page) => {
100
- page.isActive = page.id === this.currentDocPage.id;
101
- });
102
- }
103
- }
104
- async onActionSelectBook(event, element) {
105
- event.preventDefault();
106
- const bookSlug = element.dataset.bookSlug;
107
- const book = this.books.findWhere({ slug: bookSlug });
108
- if (book) {
109
- await this.getApp().setActiveBook(book);
110
- const firstPage = this.docPages.at(0);
111
- const query = { doc_book: book.get("slug") };
112
- if (firstPage) {
113
- query.doc_page = firstPage.get("slug");
114
- }
115
- this.getApp().showPage("docs", query, {});
116
- }
117
- }
118
- onActionSelectPage(event, element) {
119
- event.preventDefault();
120
- const pageSlug = element.dataset.pageSlug;
121
- if (this.currentBook && pageSlug) {
122
- this.getApp().showPage("docs", {
123
- doc_book: this.currentBook.get("slug"),
124
- doc_page: pageSlug
125
- }, {});
126
- }
127
- }
128
- async onActionBackToBooks(event, element) {
129
- event.preventDefault();
130
- await this.getApp().setActiveBook(null);
131
- this.getApp().showPage("home");
132
- }
133
- async onActionCreateBook() {
134
- await this.getApp().createNewBook();
135
- }
136
- async onActionCreatePage() {
137
- if (this.currentBook) {
138
- await this.getApp().createNewPage(this.currentBook);
139
- }
140
- }
141
- setBooks(books) {
142
- this.books = books;
143
- this.render();
144
- }
145
- setDocPages(docPages) {
146
- this.docPages = docPages;
147
- this.render();
148
- }
149
- setCurrentBook(book) {
150
- this.currentBook = book;
151
- this.render();
152
- if (this.getApp().topnav) {
153
- if (book) {
154
- this.getApp().topnav.setBrand(book.get("title"));
155
- } else {
156
- this.getApp().topnav.setBrand("Documentation");
157
- }
158
- }
159
- }
160
- setUser(user) {
161
- this.activeUser = user;
162
- this.render();
163
- }
164
- }
165
- class DocHomePage extends Page {
166
- constructor(options = {}) {
167
- super({
168
- pageName: "home",
169
- title: "Documentation",
170
- className: "docit-home-page",
171
- ...options
172
- });
173
- }
174
- async getTemplate() {
175
- return `
176
- <div class="docit-empty-state vh-100 d-flex flex-column align-items-center justify-content-center">
177
- <i class="bi bi-collection" style="font-size: 4rem;"></i>
178
- <h3 class="mt-4">Welcome to the Documentation Portal</h3>
179
- <p class="text-muted">Please select a book from the sidebar to get started.</p>
180
- </div>
181
- `;
182
- }
183
- }
184
- class DocitBook extends Model {
185
- static endpoint = "/api/docit/book";
186
- buildUrl(id = null) {
187
- if (this.get("slug") && !this.id) {
188
- return `/api/docit/book/slug/${this.get("slug")}`;
189
- } else if (this.id) {
190
- return `/api/docit/book/${this.id}`;
191
- }
192
- return this.endpoint;
193
- }
194
- }
195
- class DocitBookList extends Collection {
196
- constructor(options = {}) {
197
- super({
198
- ModelClass: DocitBook,
199
- endpoint: "/api/docit/book",
200
- ...options
201
- });
202
- }
203
- /**
204
- * Custom parsing to handle the specific API response structure for book lists.
205
- */
206
- parse(response) {
207
- if (response.data && response.data.status) {
208
- this.meta = {
209
- ...this.meta,
210
- total: response.data.count || 0,
211
- graph: response.data.graph
212
- };
213
- return response.data.data || [];
214
- }
215
- return super.parse(response);
216
- }
217
- }
218
- class DocitPage extends Model {
219
- static endpoint = "/api/docit/page";
220
- buildUrl(id = null) {
221
- if (this.get("slug") && !this.id) {
222
- return `/api/docit/page/slug/${this.get("slug")}`;
223
- } else if (this.id) {
224
- return `/api/docit/page/${this.id}`;
225
- }
226
- return this.endpoint;
227
- }
228
- }
229
- class DocitPageList extends Collection {
230
- constructor(options = {}) {
231
- super({
232
- ModelClass: DocitPage,
233
- endpoint: "/api/docit/page",
234
- ...options
235
- });
236
- }
237
- /**
238
- * Custom parsing to handle the specific API response structure for page lists.
239
- */
240
- parse(response) {
241
- if (response.data && response.data.status) {
242
- this.meta = {
243
- ...this.meta,
244
- total: response.data.count || 0,
245
- graph: response.data.graph,
246
- book: response.data.book
247
- };
248
- return response.data.data || [];
249
- }
250
- return super.parse(response);
251
- }
252
- }
253
- class DocPage extends Page {
254
- constructor(options = {}) {
255
- super({
256
- pageName: "docs",
257
- title: "Documentation",
258
- className: "docit-page",
259
- ...options
260
- });
261
- this.bookModel = null;
262
- this.model = null;
263
- }
264
- async onInit() {
265
- await super.onInit();
266
- this.pageContextMenu = new ContextMenu({
267
- config: this.getPageContextMenuConfig(),
268
- containerId: "page-context-menu"
269
- });
270
- this.addChild(this.pageContextMenu);
271
- }
272
- getPageContextMenuConfig() {
273
- return {
274
- icon: "bi-three-dots",
275
- buttonClass: "btn btn-outline-secondary btn-sm",
276
- items: [
277
- { label: "View History", action: "view-history", icon: "bi-clock-history" },
278
- { type: "divider" },
279
- { label: "Edit Page Content", action: "edit-page", icon: "bi-pencil" },
280
- { label: "Edit Page Info", action: "edit-page-info", icon: "bi-list-ol" },
281
- { type: "divider" },
282
- { label: "Edit Book Info", action: "edit-book", icon: "bi-book" },
283
- { type: "divider" },
284
- { label: "Delete Page", action: "delete-page", icon: "bi-trash", danger: true }
285
- ]
286
- };
287
- }
288
- async getTemplate() {
289
- return `
290
- <div class="docit-page-container position-relative">
291
- {{#loading}}
292
- <div class="docit-loading">
293
- <div class="spinner-border" role="status">
294
- <span class="visually-hidden">Loading...</span>
295
- </div>
296
- </div>
297
- {{/loading}}
298
-
299
- {{^loading}}
300
- {{#model|bool}}
301
- <div class="docit-page-toolbar">
302
- <div class="row">
303
- <div class="col d-flex justify-content-end">
304
- <div data-container="page-context-menu"></div>
305
- </div>
306
- </div>
307
- </div>
308
- <article class="docit-page-content">
309
- {{{model.html}}}
310
- </article>
311
-
312
- <nav class="docit-page-nav">
313
- {{#prevPage}}
314
- <a href="#" class="docit-nav-prev" data-action="navigate-to-page" data-page-slug="{{slug}}">
315
- <i class="bi bi-arrow-left"></i>
316
- <div>
317
- <small>Previous</small>
318
- <span>{{title}}</span>
319
- </div>
320
- </a>
321
- {{/prevPage}}
322
- {{^prevPage}}
323
- <div></div>
324
- {{/prevPage}}
325
-
326
- {{#nextPage}}
327
- <a href="#" class="docit-nav-next" data-action="navigate-to-page" data-page-slug="{{slug}}">
328
- <div>
329
- <small>Next</small>
330
- <span>{{title}}</span>
331
- </div>
332
- <i class="bi bi-arrow-right"></i>
333
- </a>
334
- {{/nextPage}}
335
-
336
- <div class="my-3">
337
- <span class="text-muted">Last updated: {{model.modified|datetime}}</span>
338
- </div>
339
- </nav>
340
- {{/model|bool}}
341
-
342
- {{^model|bool}}
343
- <div class="docit-empty-state">
344
- <i class="bi bi-file-earmark-text"></i>
345
- <h3>Select a page</h3>
346
- <p>Choose a page from the sidebar to view its content.</p>
347
- </div>
348
- {{/model|bool}}
349
- {{/loading}}
350
- </div>
351
- `;
352
- }
353
- async onParams(params = {}, query = {}) {
354
- await super.onParams(params, query);
355
- this.loading = true;
356
- await this.render();
357
- const app = this.getApp();
358
- const bookSlug = app.bookSlug || query.doc_book;
359
- const pageSlug = query.doc_page;
360
- if (!bookSlug) {
361
- setTimeout(() => {
362
- app.showPage("home");
363
- }, 100);
364
- return;
365
- }
366
- try {
367
- if (bookSlug) {
368
- if (!app.currentBook || app.currentBook.get("slug") !== bookSlug) {
369
- const book = new DocitBook({ slug: bookSlug });
370
- await book.fetch();
371
- await app.setActiveBook(book);
372
- }
373
- this.bookModel = app.currentBook;
374
- if (pageSlug) {
375
- this.model = new DocitPage({ slug: pageSlug });
376
- await this.model.fetch({ graph: "html" });
377
- } else {
378
- const firstPage = app.docPages.at(0);
379
- if (firstPage) {
380
- this.model = new DocitPage({ id: firstPage.id });
381
- await this.model.fetch({ graph: "html" });
382
- } else {
383
- this.model = null;
384
- }
385
- }
386
- } else {
387
- this.bookModel = null;
388
- this.model = null;
389
- }
390
- this.canEdit = app.canEdit();
391
- this.setupNavigation();
392
- } catch (error) {
393
- console.error("Failed to load page:", error);
394
- this.showError("Failed to load documentation page");
395
- this.model = null;
396
- } finally {
397
- this.loading = false;
398
- await this.render();
399
- app.events.emit("docit:page-rendered", {
400
- book: this.bookModel,
401
- page: this.model
402
- });
403
- }
404
- }
405
- setupNavigation() {
406
- if (!this.model) {
407
- this.prevPage = null;
408
- this.nextPage = null;
409
- return;
410
- }
411
- const app = this.getApp();
412
- const pages = app.docPages.models;
413
- const currentIndex = pages.findIndex((p) => p.id === this.model.id);
414
- this.prevPage = currentIndex > 0 ? { slug: pages[currentIndex - 1].get("slug"), title: pages[currentIndex - 1].get("title") } : null;
415
- this.nextPage = currentIndex < pages.length - 1 ? { slug: pages[currentIndex + 1].get("slug"), title: pages[currentIndex + 1].get("title") } : null;
416
- }
417
- async onActionNavigateToPage(event, element) {
418
- event.preventDefault();
419
- const pageSlug = element.dataset.pageSlug;
420
- if (pageSlug) {
421
- this.getApp().showPage("docs", {}, {
422
- doc_book: this.bookModel.get("slug"),
423
- doc_page: pageSlug
424
- });
425
- }
426
- }
427
- async onActionEditPage(event, element) {
428
- event.preventDefault();
429
- if (this.model) {
430
- this.getApp().showPage("edit", {
431
- id: this.model.id,
432
- doc_book: this.bookModel.get("slug"),
433
- doc_page: this.model.get("slug")
434
- }, {});
435
- }
436
- }
437
- async onActionViewHistory(event, element) {
438
- this.showInfo("Revision history coming soon.");
439
- }
440
- async onActionEditPageInfo(event, element) {
441
- if (this.model) {
442
- this.getApp().showModelForm({
443
- model: this.model,
444
- fields: [
445
- { label: "Title", name: "title", type: "text" },
446
- { label: "Order Priority", name: "order_priority" },
447
- { label: "Slug", name: "slug" }
448
- ]
449
- });
450
- }
451
- }
452
- async onActionEditBook(event, element) {
453
- if (this.model) {
454
- const book = this.getApp().sidebar.currentBook;
455
- if (!book) return;
456
- this.getApp().showModelForm({
457
- model: book,
458
- fields: [
459
- { label: "Title", name: "title", type: "text" },
460
- { label: "Order Priority", name: "order_priority" },
461
- { label: "Slug", name: "slug" },
462
- { label: "Is Active", name: "is_active", type: "switch" }
463
- ]
464
- });
465
- }
466
- }
467
- async onActionDeletePage(event, element) {
468
- if (!this.model) return;
469
- const confirmed = await this.getApp().showConfirm({
470
- title: "Delete Page",
471
- body: `Are you sure you want to delete "${this.model.get("title")}"?`,
472
- confirmText: "Delete",
473
- confirmClass: "btn-danger"
474
- });
475
- if (confirmed) {
476
- await this.model.destroy();
477
- this.showSuccess("Page deleted.");
478
- await this.getApp().setActiveBook(this.bookModel);
479
- const firstPage = this.getApp().docPages.at(0);
480
- if (firstPage) {
481
- this.getApp().showPage("docs", {}, { doc_book: this.bookModel.get("slug"), doc_page: firstPage.get("slug") });
482
- } else {
483
- this.getApp().showPage("docs", {}, { doc_book: this.bookModel.get("slug") });
484
- }
485
- }
486
- }
487
- async onAfterRender() {
488
- await super.onAfterRender();
489
- if (typeof Prism !== "undefined" && this.model) {
490
- Prism.highlightAll();
491
- }
492
- }
493
- }
494
- class DocEditPage extends Page {
495
- constructor(options = {}) {
496
- super({
497
- pageName: "edit",
498
- title: "Edit Page",
499
- className: "docit-edit-page",
500
- ...options
501
- });
502
- this.model = null;
503
- this.editor = null;
504
- this.isDirty = false;
505
- }
506
- async getTemplate() {
507
- return `
508
- <div class="docit-edit-container vh-100">
509
- {{#loading}}
510
- <div class="docit-loading"><div class="spinner-border"></div></div>
511
- {{/loading}}
512
-
513
- {{^loading}}{{#model}}
514
- <header class="docit-edit-header">
515
- <div class="docit-edit-title-row">
516
- <h2>Editing: {{model.title}}</h2>
517
- <div class="docit-edit-actions">
518
- <button class="btn btn-outline-secondary" data-action="cancel-edit">Cancel</button>
519
- <button class="btn btn-success" data-action="save-page">
520
- <i class="bi bi-check-lg"></i> Save Changes
521
- </button>
522
- </div>
523
- </div>
524
- </header>
525
- <div class="docit-edit-body flex-grow-1">
526
- <div id="editor"></div>
527
- </div>
528
- {{/model}}
529
- {{^model}}
530
- <div class="docit-error-state">
531
- <h3>Page Not Found</h3>
532
- <p>The page you're trying to edit could not be found.</p>
533
- <button class="btn btn-primary" data-action="go-back">Go Back</button>
534
- </div>
535
- {{/model}}{{/loading}}
536
- </div>
537
- `;
538
- }
539
- async onParams(params = {}, query = {}) {
540
- await super.onParams(params, query);
541
- let model = null;
542
- if (query.id) {
543
- model = new DocitPage({ id: query.id });
544
- } else if (query.doc_page) {
545
- model = new DocitPage({ slug: query.doc_page });
546
- }
547
- this.model = model;
548
- if (this.model) {
549
- await this.model.fetch({ graph: "detail" });
550
- }
551
- }
552
- initEditor() {
553
- if (this.editor || !this.element.querySelector("#editor")) return;
554
- this.editor = new toastui.Editor({
555
- el: this.element.querySelector("#editor"),
556
- height: "100%",
557
- initialEditType: "markdown",
558
- previewStyle: "tab",
559
- initialValue: this.model.get("content") || ""
560
- });
561
- this.editor.on("change", () => {
562
- this.isDirty = true;
563
- });
564
- }
565
- async onActionSavePage() {
566
- if (!this.model || !this.editor) return;
567
- this.saving = true;
568
- this.getApp().showLoading("saving...");
569
- try {
570
- const content = this.editor.getMarkdown();
571
- await this.model.save({ content });
572
- this.isDirty = false;
573
- this.getApp().toast.success("Page saved successfully.");
574
- this.getApp().showPage("docs", this.query);
575
- } catch (error) {
576
- console.error("Failed to save page:", error);
577
- this.getApp().toast.error("Failed to save page.");
578
- } finally {
579
- this.saving = false;
580
- this.getApp().hideLoading();
581
- }
582
- }
583
- async onActionCancelEdit() {
584
- this.getApp().showPage("docs", this.query);
585
- }
586
- onActionGoBack() {
587
- this.getApp().showPage("docs");
588
- }
589
- async onBeforeRender() {
590
- await super.onBeforeRender();
591
- if (this.editor) {
592
- this.editor.destroy();
593
- this.editor = null;
594
- }
595
- }
596
- async onAfterRender() {
597
- await super.onAfterRender();
598
- if (this.model) {
599
- this.initEditor();
600
- }
601
- }
602
- async onBeforeDestroy() {
603
- this.editor?.destroy();
604
- await super.onBeforeDestroy();
605
- }
606
- }
607
- class DocItApp extends WebApp {
608
- constructor(config = {}) {
609
- const defaults = {
610
- name: config.title || "DocIt Portal",
611
- version: config.version || "1.0.0",
612
- debug: config.debug || false,
613
- container: config.container || "#app",
614
- defaultRoute: "home",
615
- basePath: config.basePath || "",
616
- ...config
617
- };
618
- super(defaults);
619
- this.bookSlug = config.bookSlug || null;
620
- this.showBookNav = config.showBookNav !== void 0 ? config.showBookNav : !this.bookSlug;
621
- this.theme = config.theme || "light";
622
- this.editPermissions = config.permissions?.edit || ["manage_docit"];
623
- this.sidebarConfig = {
624
- showSearch: true,
625
- defaultCollapsed: false,
626
- ...config.sidebar
627
- };
628
- this.books = new DocitBookList();
629
- this.books.params.sort = "-order_priority";
630
- this.docPages = new DocitPageList();
631
- this.docPages.params.sort = "-order_priority";
632
- this.toast = new ToastService();
633
- this.currentBook = null;
634
- this.sidebar = null;
635
- this.isDocItReady = false;
636
- this.tokenManager = new TokenManager();
637
- this.activeUser = null;
638
- }
639
- /**
640
- * Start the DocIt application
641
- */
642
- async start() {
643
- try {
644
- console.log("Starting DocIt Portal...");
645
- this.setupDocItLayout();
646
- await this.setupTopNav();
647
- await this.setupSidebar();
648
- await this.checkAuthStatus();
649
- this.registerDocItPages();
650
- await super.start();
651
- await this.loadInitialData();
652
- this.isDocItReady = true;
653
- this.events.emit("docit:ready", { app: this });
654
- console.log("✅ DocIt Portal ready");
655
- } catch (error) {
656
- console.error("Failed to start DocIt:", error);
657
- this.showError("Failed to initialize documentation portal");
658
- throw error;
659
- }
660
- }
661
- /**
662
- * Setup DocIt specific layout
663
- */
664
- setupDocItLayout() {
665
- const container = typeof this.container === "string" ? document.querySelector(this.container) : this.container;
666
- if (!container) {
667
- throw new Error(`Container not found: ${this.container}`);
668
- }
669
- container.classList.add("docit-app", `docit-theme-${this.theme}`);
670
- container.innerHTML = `
671
- <div class="docit-app-layout">
672
- <div id="topnav-container"></div>
673
- <div class="docit-body-layout">
674
- <div class="docit-sidebar" id="docit-sidebar"></div>
675
- <div class="docit-main">
676
- <div class="docit-content" id="page-container"></div>
677
- </div>
678
- </div>
679
- </div>
680
- `;
681
- this.pageContainer = "#page-container";
682
- }
683
- async setupTopNav() {
684
- this.topnav = new TopNav({
685
- containerId: "topnav-container",
686
- brand: this.name,
687
- theme: "navbar navbar-expand-lg bg-dark navbar-dark",
688
- showSidebarToggle: false,
689
- displayMode: "brand",
690
- rightItems: [
691
- {
692
- id: "login",
693
- icon: "bi-box-arrow-in-right",
694
- href: "/examples/auth/",
695
- label: "Login"
696
- }
697
- ],
698
- userMenu: {
699
- label: "User",
700
- icon: "bi-person-circle",
701
- items: [
702
- {
703
- label: "Profile",
704
- icon: "bi-person",
705
- action: "profile"
706
- },
707
- {
708
- divider: true
709
- },
710
- {
711
- label: "Logout",
712
- icon: "bi-box-arrow-right",
713
- action: "logout"
714
- }
715
- ]
716
- }
717
- });
718
- await this.topnav.render();
719
- }
720
- onActionToggleSidebar() {
721
- const layout = document.querySelector(".docit-layout");
722
- layout.classList.toggle("sidebar-collapsed");
723
- }
724
- /**
725
- * Setup sidebar navigation
726
- */
727
- async setupSidebar() {
728
- this.sidebar = new DocNavSidebar({
729
- containerId: "docit-sidebar",
730
- app: this,
731
- singleBookMode: !!this.bookSlug,
732
- showBookNav: this.showBookNav,
733
- books: this.books,
734
- docPages: this.docPages,
735
- activeUser: this.activeUser,
736
- ...this.sidebarConfig
737
- });
738
- await this.sidebar.render();
739
- }
740
- /**
741
- * Register DocIt pages
742
- */
743
- registerDocItPages() {
744
- this.registerPage("home", DocHomePage, {
745
- route: "/",
746
- permissions: null
747
- });
748
- this.registerPage("docs", DocPage, {
749
- route: "/docs",
750
- permissions: null
751
- // Public access
752
- });
753
- this.registerPage("edit", DocEditPage, {
754
- route: "/edit",
755
- permissions: this.editPermissions
756
- });
757
- }
758
- /**
759
- * Load initial data based on mode
760
- */
761
- async loadInitialData() {
762
- try {
763
- if (this.bookSlug) {
764
- const book = new DocitBook({ slug: this.bookSlug });
765
- await book.fetch();
766
- if (book.id) {
767
- this.books.add(book);
768
- await this.setActiveBook(book);
769
- } else {
770
- throw new Error(`Book with slug '${this.bookSlug}' not found.`);
771
- }
772
- } else {
773
- await this.books.fetch({ graph: "list" });
774
- this.sidebar.render();
775
- }
776
- } catch (error) {
777
- console.error("Failed to load initial data:", error);
778
- this.showError("Failed to load documentation");
779
- }
780
- }
781
- /**
782
- * Set the active book and load its pages
783
- * @param {DocitBook} book - The book to set as active
784
- */
785
- async setActiveBook(book) {
786
- if (this.currentBook && book && this.currentBook.id === book.id) {
787
- return;
788
- }
789
- this.currentBook = book;
790
- this.docPages.reset();
791
- if (book) {
792
- await this.docPages.fetch({
793
- book: book.get("id"),
794
- graph: "list"
795
- });
796
- }
797
- this.sidebar.setCurrentBook(book);
798
- this.sidebar.setDocPages(this.docPages);
799
- this.events.emit("docit:book-changed", { book });
800
- }
801
- /**
802
- * Save doc page content using Model
803
- */
804
- async saveDocPageContent(docPageId, content) {
805
- const docPage = this.docPages.get(docPageId) || new DocitPage({ id: docPageId });
806
- docPage.set("content", content);
807
- const response = await docPage.save();
808
- if (!response.success || !response.data.status) {
809
- throw new Error("Failed to save doc page");
810
- }
811
- return docPage;
812
- }
813
- /**
814
- * Check if user can edit
815
- */
816
- canEdit() {
817
- const user = this.activeUser;
818
- if (!user) return false;
819
- return this.editPermissions.some((perm) => user.hasPermission ? user.hasPermission(perm) : false);
820
- }
821
- /**
822
- * Check authentication status and load user
823
- */
824
- async checkAuthStatus() {
825
- try {
826
- const token = this.tokenManager.getTokenInstance();
827
- if (!token || !token.isValid()) {
828
- this.events.emit("auth:unauthorized", { app: this });
829
- return;
830
- }
831
- if (token.isExpired()) {
832
- this.events.emit("auth:expired", { app: this });
833
- return;
834
- }
835
- this.tokenManager.startAutoRefresh(this);
836
- this.rest.setAuthToken(token.token);
837
- const user = new User({ id: token.getUserId() });
838
- await user.fetch();
839
- this.setActiveUser(user);
840
- } catch (error) {
841
- console.error("Failed to check auth status:", error);
842
- this.events.emit("auth:error", { error, app: this });
843
- }
844
- }
845
- /**
846
- * Set the active authenticated user
847
- */
848
- setActiveUser(user) {
849
- this.activeUser = user;
850
- if (this.sidebar) {
851
- this.sidebar.setUser(user);
852
- }
853
- if (this.topnav) {
854
- this.topnav.setUser(user);
855
- this.tonnav.render();
856
- }
857
- this.events.emit("user:changed", { user, app: this });
858
- return this;
859
- }
860
- /**
861
- * Clear the active user (logout)
862
- */
863
- clearActiveUser() {
864
- this.activeUser = null;
865
- this.tokenManager.clearTokens();
866
- this.rest.clearAuth();
867
- if (this.sidebar) {
868
- this.sidebar.setUser(null);
869
- }
870
- this.events.emit("user:cleared", { app: this });
871
- return this;
872
- }
873
- /**
874
- * Handle logout
875
- */
876
- async logout() {
877
- this.clearActiveUser();
878
- this.books.reset();
879
- this.docPages.reset();
880
- this.currentBook = null;
881
- this.events.emit("auth:logout", { app: this });
882
- window.location.reload();
883
- }
884
- async createNewBook() {
885
- const result = await this.showModelForm({
886
- title: "Create New Book",
887
- model: new DocitBook(),
888
- fields: [
889
- { name: "title", label: "Title", required: true },
890
- { name: "slug", label: "Slug", required: true, helpText: "A URL-friendly identifier." }
891
- ]
892
- });
893
- if (result && result.success) {
894
- this.books.add(result.data);
895
- this.sidebar.render();
896
- this.showSuccess("Book created successfully.");
897
- }
898
- }
899
- async createNewPage(book) {
900
- if (!book) return;
901
- const data = await this.showForm({
902
- title: "Create New Page",
903
- fields: [
904
- { name: "title", label: "Title", required: true },
905
- { name: "slug", label: "Slug", required: true, helpText: "A URL-friendly identifier." }
906
- ]
907
- });
908
- if (data && data.slug) {
909
- data.book = book.id;
910
- }
911
- const newPage = new DocitPage();
912
- const result = await newPage.save(data);
913
- if (result && result.success) {
914
- this.docPages.add(newPage);
915
- this.sidebar.render();
916
- this.showPage("edit", {
917
- id: newPage.id,
918
- doc_book: book.get("slug"),
919
- doc_page: newPage.get("slug")
920
- }, {});
921
- }
922
- }
923
- /**
924
- * Static factory method for quick setup
925
- */
926
- static create(config = {}) {
927
- return new DocItApp(config);
928
- }
929
- /**
930
- * Quick setup for single-book mode
931
- */
932
- static createForBook(bookSlug, config = {}) {
933
- return new DocItApp({
934
- ...config,
935
- bookSlug,
936
- showBookNav: false
937
- });
938
- }
939
- }
940
- export {
941
- B as BUILD_TIME,
942
- DocEditPage,
943
- DocHomePage,
944
- DocItApp,
945
- DocNavSidebar,
946
- DocPage,
947
- DocitBook,
948
- DocitBookList,
949
- DocitPage,
950
- DocitPageList,
951
- a as VERSION,
952
- V as VERSION_INFO,
953
- b as VERSION_MAJOR,
954
- c as VERSION_MINOR,
955
- d as VERSION_REVISION,
956
- WebApp
957
- };
1
+ import{W as t}from"./chunks/WebApp-CULZpO_0.js";import{T as e,a as i}from"./chunks/TokenManager-D6SjKgPZ.js";import{V as o}from"./chunks/Rest-DHbszkuP.js";import{P as s,C as a,T as n,U as r}from"./chunks/ContextMenu-BvniQz-N.js";import{M as d,C as c}from"./chunks/Collection-1sPoIFvQ.js";import{B as l,V as h,a as g,b as u,c as p,d as b}from"./chunks/version-C3dnl1bg.js";class DocNavSidebar extends o{constructor(t={}){super({className:"docit-sidebar-nav",tagName:"nav",...t}),this.singleBookMode=t.singleBookMode||!1,this.books=t.books,this.docPages=t.docPages,this.activeUser=t.activeUser,this.currentBook=null,this.currentDocPage=null}async onInit(){await super.onInit(),this.getApp().events.on("page:show",this._onPageShow.bind(this))}async _onPageShow({query:t}){const e=t.doc_book,i=t.doc_page,o=this.getApp();if(e){const t=this.books.findWhere({slug:e});!t||this.currentBook&&this.currentBook.id===t.id||(await o.setActiveBook(t),this.currentBook=o.currentBook)}else this.currentBook&&(await o.setActiveBook(null),this.currentBook=null);this.currentDocPage=i?this.docPages.findWhere({slug:i}):null,this.render()}getTemplate(){return'\n <div class="docit-nav-body pt-3">\n {{#currentBook}}\n {{#docPages.models}}\n <a href="#" class="docit-page-link {{#isActive}}active{{/isActive}}"\n data-action="select-page" data-page-slug="{{slug}}">\n <i class="{{#metadata.icon}}{{metadata.icon}}{{/metadata.icon}}{{^metadata.icon}}bi bi-file-earmark-text{{/metadata.icon}} me-2"></i>\n <span>{{title|capitalize}}</span>\n </a>\n {{/docPages.models}}\n {{^docPages.models}}\n <div class="docit-nav-empty"><p>No pages in this book.</p></div>\n {{/docPages.models}}\n {{/currentBook}}\n {{^currentBook}}\n {{#books.models}}\n <a href="#" class="docit-book-item" data-action="select-book" data-book-slug="{{slug}}">\n <i class="bi bi-book me-2"></i>\n <span class="book-title">{{title}}</span>\n <span class="badge bg-secondary ms-auto">{{page_count}}</span>\n </a>\n {{/books.models}}\n {{/currentBook}}\n </div>\n {{#currentBook}}\n <div class="docit-nav-footer">\n {{#canEdit}}\n <button class="btn btn-link w-100 mb-2" data-action="create-page">\n <i class="bi bi-plus-circle me-2"></i>\n Create New Page\n </button>\n {{/canEdit}}\n <button class="btn btn-link w-100" data-action="back-to-books">\n <i class="bi bi-arrow-left me-2"></i>\n Back to Books\n </button>\n </div>\n {{/currentBook}}\n {{^currentBook}}\n {{#canEdit}}\n <div class="docit-nav-footer">\n <button class="btn btn-link w-100" data-action="create-book">\n <i class="bi bi-plus-circle me-2"></i>\n Create New Book\n </button>\n </div>\n {{/canEdit}}\n {{/currentBook}}\n '}async onBeforeRender(){await super.onBeforeRender(),this.canEdit=this.getApp().canEdit(),this.docPages&&this.currentDocPage&&this.docPages.forEach(t=>{t.isActive=t.id===this.currentDocPage.id})}async onActionSelectBook(t,e){t.preventDefault();const i=e.dataset.bookSlug,o=this.books.findWhere({slug:i});if(o){await this.getApp().setActiveBook(o);const t=this.docPages.at(0),e={doc_book:o.get("slug")};t&&(e.doc_page=t.get("slug")),this.getApp().showPage("docs",e,{})}}onActionSelectPage(t,e){t.preventDefault();const i=e.dataset.pageSlug;this.currentBook&&i&&this.getApp().showPage("docs",{doc_book:this.currentBook.get("slug"),doc_page:i},{})}async onActionBackToBooks(t,e){t.preventDefault(),await this.getApp().setActiveBook(null),this.getApp().showPage("home")}async onActionCreateBook(){await this.getApp().createNewBook()}async onActionCreatePage(){this.currentBook&&await this.getApp().createNewPage(this.currentBook)}setBooks(t){this.books=t,this.render()}setDocPages(t){this.docPages=t,this.render()}setCurrentBook(t){this.currentBook=t,this.render(),this.getApp().topnav&&(t?this.getApp().topnav.setBrand(t.get("title")):this.getApp().topnav.setBrand("Documentation"))}setUser(t){this.activeUser=t,this.render()}}class DocHomePage extends s{constructor(t={}){super({pageName:"home",title:"Documentation",className:"docit-home-page",...t})}async getTemplate(){return'\n <div class="docit-empty-state vh-100 d-flex flex-column align-items-center justify-content-center">\n <i class="bi bi-collection" style="font-size: 4rem;"></i>\n <h3 class="mt-4">Welcome to the Documentation Portal</h3>\n <p class="text-muted">Please select a book from the sidebar to get started.</p>\n </div>\n '}}class DocitBook extends d{static endpoint="/api/docit/book";buildUrl(t=null){return this.get("slug")&&!this.id?`/api/docit/book/slug/${this.get("slug")}`:this.id?`/api/docit/book/${this.id}`:this.endpoint}}class DocitBookList extends c{constructor(t={}){super({ModelClass:DocitBook,endpoint:"/api/docit/book",...t})}parse(t){return t.data&&t.data.status?(this.meta={...this.meta,total:t.data.count||0,graph:t.data.graph},t.data.data||[]):super.parse(t)}}class DocitPage extends d{static endpoint="/api/docit/page";buildUrl(t=null){return this.get("slug")&&!this.id?`/api/docit/page/slug/${this.get("slug")}`:this.id?`/api/docit/page/${this.id}`:this.endpoint}}class DocitPageList extends c{constructor(t={}){super({ModelClass:DocitPage,endpoint:"/api/docit/page",...t})}parse(t){return t.data&&t.data.status?(this.meta={...this.meta,total:t.data.count||0,graph:t.data.graph,book:t.data.book},t.data.data||[]):super.parse(t)}}class DocPage extends s{constructor(t={}){super({pageName:"docs",title:"Documentation",className:"docit-page",...t}),this.bookModel=null,this.model=null}async onInit(){await super.onInit(),this.pageContextMenu=new a({config:this.getPageContextMenuConfig(),containerId:"page-context-menu"}),this.addChild(this.pageContextMenu)}getPageContextMenuConfig(){return{icon:"bi-three-dots",buttonClass:"btn btn-outline-secondary btn-sm",items:[{label:"View History",action:"view-history",icon:"bi-clock-history"},{type:"divider"},{label:"Edit Page Content",action:"edit-page",icon:"bi-pencil"},{label:"Edit Page Info",action:"edit-page-info",icon:"bi-list-ol"},{type:"divider"},{label:"Edit Book Info",action:"edit-book",icon:"bi-book"},{type:"divider"},{label:"Delete Page",action:"delete-page",icon:"bi-trash",danger:!0}]}}async getTemplate(){return'\n <div class="docit-page-container position-relative">\n {{#loading}}\n <div class="docit-loading">\n <div class="spinner-border" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n </div>\n {{/loading}}\n\n {{^loading}}\n {{#model|bool}}\n <div class="docit-page-toolbar">\n <div class="row">\n <div class="col d-flex justify-content-end">\n <div data-container="page-context-menu"></div>\n </div>\n </div>\n </div>\n <article class="docit-page-content">\n {{{model.html}}}\n </article>\n\n <nav class="docit-page-nav">\n {{#prevPage}}\n <a href="#" class="docit-nav-prev" data-action="navigate-to-page" data-page-slug="{{slug}}">\n <i class="bi bi-arrow-left"></i>\n <div>\n <small>Previous</small>\n <span>{{title}}</span>\n </div>\n </a>\n {{/prevPage}}\n {{^prevPage}}\n <div></div>\n {{/prevPage}}\n\n {{#nextPage}}\n <a href="#" class="docit-nav-next" data-action="navigate-to-page" data-page-slug="{{slug}}">\n <div>\n <small>Next</small>\n <span>{{title}}</span>\n </div>\n <i class="bi bi-arrow-right"></i>\n </a>\n {{/nextPage}}\n\n <div class="my-3">\n <span class="text-muted">Last updated: {{model.modified|datetime}}</span>\n </div>\n </nav>\n {{/model|bool}}\n\n {{^model|bool}}\n <div class="docit-empty-state">\n <i class="bi bi-file-earmark-text"></i>\n <h3>Select a page</h3>\n <p>Choose a page from the sidebar to view its content.</p>\n </div>\n {{/model|bool}}\n {{/loading}}\n </div>\n '}async onParams(t={},e={}){await super.onParams(t,e),this.loading=!0,await this.render();const i=this.getApp(),o=i.bookSlug||e.doc_book,s=e.doc_page;if(o)try{if(o){if(!i.currentBook||i.currentBook.get("slug")!==o){const t=new DocitBook({slug:o});await t.fetch(),await i.setActiveBook(t)}if(this.bookModel=i.currentBook,s)this.model=new DocitPage({slug:s}),await this.model.fetch({graph:"html"});else{const t=i.docPages.at(0);t?(this.model=new DocitPage({id:t.id}),await this.model.fetch({graph:"html"})):this.model=null}}else this.bookModel=null,this.model=null;this.canEdit=i.canEdit(),this.setupNavigation()}catch(a){console.error("Failed to load page:",a),this.showError("Failed to load documentation page"),this.model=null}finally{this.loading=!1,await this.render(),i.events.emit("docit:page-rendered",{book:this.bookModel,page:this.model})}else setTimeout(()=>{i.showPage("home")},100)}setupNavigation(){if(!this.model)return this.prevPage=null,void(this.nextPage=null);const t=this.getApp().docPages.models,e=t.findIndex(t=>t.id===this.model.id);this.prevPage=e>0?{slug:t[e-1].get("slug"),title:t[e-1].get("title")}:null,this.nextPage=e<t.length-1?{slug:t[e+1].get("slug"),title:t[e+1].get("title")}:null}async onActionNavigateToPage(t,e){t.preventDefault();const i=e.dataset.pageSlug;i&&this.getApp().showPage("docs",{},{doc_book:this.bookModel.get("slug"),doc_page:i})}async onActionEditPage(t,e){t.preventDefault(),this.model&&this.getApp().showPage("edit",{id:this.model.id,doc_book:this.bookModel.get("slug"),doc_page:this.model.get("slug")},{})}async onActionViewHistory(t,e){this.showInfo("Revision history coming soon.")}async onActionEditPageInfo(t,e){this.model&&this.getApp().showModelForm({model:this.model,fields:[{label:"Title",name:"title",type:"text"},{label:"Order Priority",name:"order_priority"},{label:"Slug",name:"slug"}]})}async onActionEditBook(t,e){if(this.model){const t=this.getApp().sidebar.currentBook;if(!t)return;this.getApp().showModelForm({model:t,fields:[{label:"Title",name:"title",type:"text"},{label:"Order Priority",name:"order_priority"},{label:"Slug",name:"slug"},{label:"Is Active",name:"is_active",type:"switch"}]})}}async onActionDeletePage(t,e){if(this.model&&await this.getApp().showConfirm({title:"Delete Page",body:`Are you sure you want to delete "${this.model.get("title")}"?`,confirmText:"Delete",confirmClass:"btn-danger"})){await this.model.destroy(),this.showSuccess("Page deleted."),await this.getApp().setActiveBook(this.bookModel);const t=this.getApp().docPages.at(0);t?this.getApp().showPage("docs",{},{doc_book:this.bookModel.get("slug"),doc_page:t.get("slug")}):this.getApp().showPage("docs",{},{doc_book:this.bookModel.get("slug")})}}async onAfterRender(){await super.onAfterRender(),"undefined"!=typeof Prism&&this.model&&Prism.highlightAll()}}class DocEditPage extends s{constructor(t={}){super({pageName:"edit",title:"Edit Page",className:"docit-edit-page",...t}),this.model=null,this.editor=null,this.isDirty=!1}async getTemplate(){return'\n <div class="docit-edit-container vh-100">\n {{#loading}}\n <div class="docit-loading"><div class="spinner-border"></div></div>\n {{/loading}}\n\n {{^loading}}{{#model}}\n <header class="docit-edit-header">\n <div class="docit-edit-title-row">\n <h2>Editing: {{model.title}}</h2>\n <div class="docit-edit-actions">\n <button class="btn btn-outline-secondary" data-action="cancel-edit">Cancel</button>\n <button class="btn btn-success" data-action="save-page">\n <i class="bi bi-check-lg"></i> Save Changes\n </button>\n </div>\n </div>\n </header>\n <div class="docit-edit-body flex-grow-1">\n <div id="editor"></div>\n </div>\n {{/model}}\n {{^model}}\n <div class="docit-error-state">\n <h3>Page Not Found</h3>\n <p>The page you\'re trying to edit could not be found.</p>\n <button class="btn btn-primary" data-action="go-back">Go Back</button>\n </div>\n {{/model}}{{/loading}}\n </div>\n '}async onParams(t={},e={}){await super.onParams(t,e);let i=null;e.id?i=new DocitPage({id:e.id}):e.doc_page&&(i=new DocitPage({slug:e.doc_page})),this.model=i,this.model&&await this.model.fetch({graph:"detail"})}initEditor(){!this.editor&&this.element.querySelector("#editor")&&(this.editor=new toastui.Editor({el:this.element.querySelector("#editor"),height:"100%",initialEditType:"markdown",previewStyle:"tab",initialValue:this.model.get("content")||""}),this.editor.on("change",()=>{this.isDirty=!0}))}async onActionSavePage(){if(this.model&&this.editor){this.saving=!0,this.getApp().showLoading("saving...");try{const t=this.editor.getMarkdown();await this.model.save({content:t}),this.isDirty=!1,this.getApp().toast.success("Page saved successfully."),this.getApp().showPage("docs",this.query)}catch(t){console.error("Failed to save page:",t),this.getApp().toast.error("Failed to save page.")}finally{this.saving=!1,this.getApp().hideLoading()}}}async onActionCancelEdit(){this.getApp().showPage("docs",this.query)}onActionGoBack(){this.getApp().showPage("docs")}async onBeforeRender(){await super.onBeforeRender(),this.editor&&(this.editor.destroy(),this.editor=null)}async onAfterRender(){await super.onAfterRender(),this.model&&this.initEditor()}async onBeforeDestroy(){this.editor?.destroy(),await super.onBeforeDestroy()}}class DocItApp extends t{constructor(t={}){super({name:t.title||"DocIt Portal",version:t.version||"1.0.0",debug:t.debug||!1,container:t.container||"#app",defaultRoute:"home",basePath:t.basePath||"",...t}),this.bookSlug=t.bookSlug||null,this.showBookNav=void 0!==t.showBookNav?t.showBookNav:!this.bookSlug,this.theme=t.theme||"light",this.editPermissions=t.permissions?.edit||["manage_docit"],this.sidebarConfig={showSearch:!0,defaultCollapsed:!1,...t.sidebar},this.books=new DocitBookList,this.books.params.sort="-order_priority",this.docPages=new DocitPageList,this.docPages.params.sort="-order_priority",this.toast=new n,this.currentBook=null,this.sidebar=null,this.isDocItReady=!1,this.tokenManager=new e,this.activeUser=null}async start(){try{this.setupDocItLayout(),await this.setupTopNav(),await this.setupSidebar(),await this.checkAuthStatus(),this.registerDocItPages(),await super.start(),await this.loadInitialData(),this.isDocItReady=!0,this.events.emit("docit:ready",{app:this})}catch(t){throw console.error("Failed to start DocIt:",t),this.showError("Failed to initialize documentation portal"),t}}setupDocItLayout(){const t="string"==typeof this.container?document.querySelector(this.container):this.container;if(!t)throw new Error(`Container not found: ${this.container}`);t.classList.add("docit-app",`docit-theme-${this.theme}`),t.innerHTML='\n <div class="docit-app-layout">\n <div id="topnav-container"></div>\n <div class="docit-body-layout">\n <div class="docit-sidebar" id="docit-sidebar"></div>\n <div class="docit-main">\n <div class="docit-content" id="page-container"></div>\n </div>\n </div>\n </div>\n ',this.pageContainer="#page-container"}async setupTopNav(){this.topnav=new i({containerId:"topnav-container",brand:this.name,theme:"navbar navbar-expand-lg bg-dark navbar-dark",showSidebarToggle:!1,displayMode:"brand",rightItems:[{id:"login",icon:"bi-box-arrow-in-right",href:"/examples/auth/",label:"Login"}],userMenu:{label:"User",icon:"bi-person-circle",items:[{label:"Profile",icon:"bi-person",action:"profile"},{divider:!0},{label:"Logout",icon:"bi-box-arrow-right",action:"logout"}]}}),await this.topnav.render()}onActionToggleSidebar(){document.querySelector(".docit-layout").classList.toggle("sidebar-collapsed")}async setupSidebar(){this.sidebar=new DocNavSidebar({containerId:"docit-sidebar",app:this,singleBookMode:!!this.bookSlug,showBookNav:this.showBookNav,books:this.books,docPages:this.docPages,activeUser:this.activeUser,...this.sidebarConfig}),await this.sidebar.render()}registerDocItPages(){this.registerPage("home",DocHomePage,{route:"/",permissions:null}),this.registerPage("docs",DocPage,{route:"/docs",permissions:null}),this.registerPage("edit",DocEditPage,{route:"/edit",permissions:this.editPermissions})}async loadInitialData(){try{if(this.bookSlug){const t=new DocitBook({slug:this.bookSlug});if(await t.fetch(),!t.id)throw new Error(`Book with slug '${this.bookSlug}' not found.`);this.books.add(t),await this.setActiveBook(t)}else await this.books.fetch({graph:"list"}),this.sidebar.render()}catch(t){console.error("Failed to load initial data:",t),this.showError("Failed to load documentation")}}async setActiveBook(t){this.currentBook&&t&&this.currentBook.id===t.id||(this.currentBook=t,this.docPages.reset(),t&&await this.docPages.fetch({book:t.get("id"),graph:"list"}),this.sidebar.setCurrentBook(t),this.sidebar.setDocPages(this.docPages),this.events.emit("docit:book-changed",{book:t}))}async saveDocPageContent(t,e){const i=this.docPages.get(t)||new DocitPage({id:t});i.set("content",e);const o=await i.save();if(!o.success||!o.data.status)throw new Error("Failed to save doc page");return i}canEdit(){const t=this.activeUser;return!!t&&this.editPermissions.some(e=>!!t.hasPermission&&t.hasPermission(e))}async checkAuthStatus(){try{const t=this.tokenManager.getTokenInstance();if(!t||!t.isValid())return void this.events.emit("auth:unauthorized",{app:this});if(t.isExpired())return void this.events.emit("auth:expired",{app:this});this.tokenManager.startAutoRefresh(this),this.rest.setAuthToken(t.token);const e=new r({id:t.getUserId()});await e.fetch(),this.setActiveUser(e)}catch(t){console.error("Failed to check auth status:",t),this.events.emit("auth:error",{error:t,app:this})}}setActiveUser(t){return this.activeUser=t,this.sidebar&&this.sidebar.setUser(t),this.topnav&&(this.topnav.setUser(t),this.tonnav.render()),this.events.emit("user:changed",{user:t,app:this}),this}clearActiveUser(){return this.activeUser=null,this.tokenManager.clearTokens(),this.rest.clearAuth(),this.sidebar&&this.sidebar.setUser(null),this.events.emit("user:cleared",{app:this}),this}async logout(){this.clearActiveUser(),this.books.reset(),this.docPages.reset(),this.currentBook=null,this.events.emit("auth:logout",{app:this}),window.location.reload()}async createNewBook(){const t=await this.showModelForm({title:"Create New Book",model:new DocitBook,fields:[{name:"title",label:"Title",required:!0},{name:"slug",label:"Slug",required:!0,helpText:"A URL-friendly identifier."}]});t&&t.success&&(this.books.add(t.data),this.sidebar.render(),this.showSuccess("Book created successfully."))}async createNewPage(t){if(!t)return;const e=await this.showForm({title:"Create New Page",fields:[{name:"title",label:"Title",required:!0},{name:"slug",label:"Slug",required:!0,helpText:"A URL-friendly identifier."}]});e&&e.slug&&(e.book=t.id);const i=new DocitPage,o=await i.save(e);o&&o.success&&(this.docPages.add(i),this.sidebar.render(),this.showPage("edit",{id:i.id,doc_book:t.get("slug"),doc_page:i.get("slug")},{}))}static create(t={}){return new DocItApp(t)}static createForBook(t,e={}){return new DocItApp({...e,bookSlug:t,showBookNav:!1})}}export{l as BUILD_TIME,DocEditPage,DocHomePage,DocItApp,DocNavSidebar,DocPage,DocitBook,DocitBookList,DocitPage,DocitPageList,h as VERSION,g as VERSION_INFO,u as VERSION_MAJOR,p as VERSION_MINOR,b as VERSION_REVISION,t as WebApp};
958
2
  //# sourceMappingURL=docit.es.js.map