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