@fiduswriter/books-document 0.1.27 → 0.1.29
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/README.md +1 -1
- package/dist/ui/book_dialog/dialog.d.ts +98 -0
- package/dist/ui/book_dialog/dialog.d.ts.map +1 -0
- package/dist/ui/book_dialog/dialog.js +590 -0
- package/dist/ui/book_dialog/dialog.js.map +1 -0
- package/dist/ui/book_dialog/export.d.ts +81 -0
- package/dist/ui/book_dialog/export.d.ts.map +1 -0
- package/dist/ui/book_dialog/export.js +184 -0
- package/dist/ui/book_dialog/export.js.map +1 -0
- package/dist/ui/book_dialog/index.d.ts +38 -0
- package/dist/ui/book_dialog/index.d.ts.map +1 -0
- package/dist/ui/book_dialog/index.js +36 -0
- package/dist/ui/book_dialog/index.js.map +1 -0
- package/dist/ui/book_dialog/sanity_check.d.ts +22 -0
- package/dist/ui/book_dialog/sanity_check.d.ts.map +1 -0
- package/dist/ui/book_dialog/sanity_check.js +109 -0
- package/dist/ui/book_dialog/sanity_check.js.map +1 -0
- package/dist/ui/book_dialog/templates.d.ts +74 -0
- package/dist/ui/book_dialog/templates.d.ts.map +1 -0
- package/dist/ui/book_dialog/templates.js +526 -0
- package/dist/ui/book_dialog/templates.js.map +1 -0
- package/dist/ui/book_dialog/types.d.ts +165 -0
- package/dist/ui/book_dialog/types.d.ts.map +1 -0
- package/dist/ui/book_dialog/types.js +15 -0
- package/dist/ui/book_dialog/types.js.map +1 -0
- package/package.json +20 -16
- package/src/ui/book_dialog/dialog.ts +765 -0
- package/src/ui/book_dialog/export.ts +398 -0
- package/src/ui/book_dialog/index.ts +81 -0
- package/src/ui/book_dialog/sanity_check.ts +208 -0
- package/src/ui/book_dialog/templates.ts +705 -0
- package/src/ui/book_dialog/types.ts +180 -0
|
@@ -0,0 +1,705 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML templates of the book dialog.
|
|
3
|
+
*
|
|
4
|
+
* One function per dialog pane plus the tab strip that holds them. Field ids
|
|
5
|
+
* are fixed: the dialog reads them back in `./dialog.js` when saving.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {LANGUAGES} from "@fiduswriter/document/schema/const"
|
|
9
|
+
import {escapeText, gettext, longFilePath} from "fwtoolkit"
|
|
10
|
+
import type {Book, BookStyle, Chapter, DocumentListEntry} from "../../types.js"
|
|
11
|
+
import type {BookDialogInfo, BookDialogPart} from "./types.js"
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* The `rights` field is a Django-backend notion. A book that has no access
|
|
15
|
+
* rights at all -- a local `.fidusbook` file, say -- is editable, so the
|
|
16
|
+
* templates only disable fields for an explicitly read-only book.
|
|
17
|
+
*/
|
|
18
|
+
const isReadOnly = (book: Book): boolean => book.rights === "read"
|
|
19
|
+
|
|
20
|
+
/** A template for the basic info book template pane */
|
|
21
|
+
export const bookBasicInfoTemplate = ({book}: {book: Book}) =>
|
|
22
|
+
`<table class="fw-dialog-table">
|
|
23
|
+
<tbody>
|
|
24
|
+
<tr>
|
|
25
|
+
<th>
|
|
26
|
+
<h4 class="fw-tablerow-title">${gettext("Title")}</h4>
|
|
27
|
+
</th>
|
|
28
|
+
<td>
|
|
29
|
+
<input class="entry-form" type="text" id="book-title"
|
|
30
|
+
value="${escapeText(book.title)}"
|
|
31
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
32
|
+
>
|
|
33
|
+
</td>
|
|
34
|
+
</tr>
|
|
35
|
+
<tr>
|
|
36
|
+
<th>
|
|
37
|
+
<h4 class="fw-tablerow-title">${gettext("Author")}</h4>
|
|
38
|
+
</th>
|
|
39
|
+
<td>
|
|
40
|
+
<input class="entry-form" type="text" id="book-metadata-author"
|
|
41
|
+
value="${escapeText(book.metadata.author ?? "")}"
|
|
42
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
43
|
+
>
|
|
44
|
+
</td>
|
|
45
|
+
</tr>
|
|
46
|
+
<tr>
|
|
47
|
+
<th>
|
|
48
|
+
<h4 class="fw-tablerow-title">${gettext("Subtitle")}</h4>
|
|
49
|
+
</th>
|
|
50
|
+
<td>
|
|
51
|
+
<input class="entry-form" type="text" id="book-metadata-subtitle"
|
|
52
|
+
value="${escapeText(book.metadata.subtitle ?? "")}"
|
|
53
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
54
|
+
>
|
|
55
|
+
</td>
|
|
56
|
+
</tr>
|
|
57
|
+
<tr>
|
|
58
|
+
<th>
|
|
59
|
+
<h4 class="fw-tablerow-title">${gettext("Version")}</h4>
|
|
60
|
+
</th>
|
|
61
|
+
<td>
|
|
62
|
+
<input class="entry-form" type="text" id="book-metadata-version"
|
|
63
|
+
value="${escapeText(book.metadata.version ?? "")}"
|
|
64
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
65
|
+
>
|
|
66
|
+
</td>
|
|
67
|
+
</tr>
|
|
68
|
+
<tr>
|
|
69
|
+
<th>
|
|
70
|
+
<h4 class="fw-tablerow-title">${gettext("Language")}</h4>
|
|
71
|
+
</th>
|
|
72
|
+
<td>
|
|
73
|
+
<div class="fw-select-container">
|
|
74
|
+
<select class="entry-form dk fw-button fw-light fw-large" name="book-settings-language"
|
|
75
|
+
title="${gettext("Select language")}"
|
|
76
|
+
id="book-settings-language"
|
|
77
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
78
|
+
>
|
|
79
|
+
${LANGUAGES.map(
|
|
80
|
+
language =>
|
|
81
|
+
`<option value="${language[0]}"
|
|
82
|
+
${
|
|
83
|
+
language[0] ===
|
|
84
|
+
book.settings.language
|
|
85
|
+
? "selected"
|
|
86
|
+
: ""
|
|
87
|
+
}
|
|
88
|
+
>
|
|
89
|
+
${escapeText(language[1])}
|
|
90
|
+
</option>`
|
|
91
|
+
).join("")}
|
|
92
|
+
</select>
|
|
93
|
+
<div class="fw-select-arrow fa fa-caret-down"></div>
|
|
94
|
+
</div>
|
|
95
|
+
</td>
|
|
96
|
+
</tr>
|
|
97
|
+
<tr>
|
|
98
|
+
<th>
|
|
99
|
+
<h4 class="fw-tablerow-title">${gettext("Publisher")}</h4>
|
|
100
|
+
</th>
|
|
101
|
+
<td>
|
|
102
|
+
<input class="entry-form" type="text" id="book-metadata-publisher"
|
|
103
|
+
value="${escapeText(book.metadata.publisher ?? "")}"
|
|
104
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
105
|
+
>
|
|
106
|
+
</td>
|
|
107
|
+
</tr>
|
|
108
|
+
<tr>
|
|
109
|
+
<th>
|
|
110
|
+
<h4 class="fw-tablerow-title">${gettext(
|
|
111
|
+
"Copyright notice"
|
|
112
|
+
)}</h4>
|
|
113
|
+
</th>
|
|
114
|
+
<td>
|
|
115
|
+
<input class="entry-form" type="text" id="book-metadata-copyright"
|
|
116
|
+
value="${escapeText(book.metadata.copyright ?? "")}"
|
|
117
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
118
|
+
>
|
|
119
|
+
</td>
|
|
120
|
+
</tr>
|
|
121
|
+
<tr>
|
|
122
|
+
<th>
|
|
123
|
+
<h4 class="fw-tablerow-title" title="${gettext(
|
|
124
|
+
"Comma separated keywords"
|
|
125
|
+
)}">
|
|
126
|
+
${gettext("Keywords")}
|
|
127
|
+
</h4>
|
|
128
|
+
</th>
|
|
129
|
+
<td>
|
|
130
|
+
<input class="entry-form" type="text" id="book-metadata-keywords"
|
|
131
|
+
value="${book.metadata.keywords}"
|
|
132
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
133
|
+
>
|
|
134
|
+
</td>
|
|
135
|
+
</tr>
|
|
136
|
+
<tr>
|
|
137
|
+
<th>
|
|
138
|
+
<h4 class="fw-tablerow-title">${gettext("Description")}</h4>
|
|
139
|
+
</th>
|
|
140
|
+
<td>
|
|
141
|
+
<textarea class="entry-form" id="book-metadata-description" rows="4"
|
|
142
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
143
|
+
>${escapeText(book.metadata.description ?? "")}</textarea>
|
|
144
|
+
</td>
|
|
145
|
+
</tr>
|
|
146
|
+
<tr>
|
|
147
|
+
<th>
|
|
148
|
+
<h4 class="fw-tablerow-title">${gettext("ISBN")}</h4>
|
|
149
|
+
</th>
|
|
150
|
+
<td>
|
|
151
|
+
<input class="entry-form" type="text" id="book-metadata-isbn"
|
|
152
|
+
value="${escapeText(book.metadata.isbn ?? "")}"
|
|
153
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
154
|
+
>
|
|
155
|
+
</td>
|
|
156
|
+
</tr>
|
|
157
|
+
<tr>
|
|
158
|
+
<th>
|
|
159
|
+
<h4 class="fw-tablerow-title" title="${gettext("E.g.: 2024 or January 2024")}">
|
|
160
|
+
${gettext("Publication date")}
|
|
161
|
+
</h4>
|
|
162
|
+
</th>
|
|
163
|
+
<td>
|
|
164
|
+
<input class="entry-form" type="text" id="book-metadata-publication-date"
|
|
165
|
+
value="${escapeText(book.metadata.publication_date ?? "")}"
|
|
166
|
+
placeholder="${gettext("E.g.: 2024")}"
|
|
167
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
168
|
+
>
|
|
169
|
+
</td>
|
|
170
|
+
</tr>
|
|
171
|
+
<tr>
|
|
172
|
+
<th>
|
|
173
|
+
<h4 class="fw-tablerow-title">${gettext("Series title")}</h4>
|
|
174
|
+
</th>
|
|
175
|
+
<td>
|
|
176
|
+
<input class="entry-form" type="text" id="book-metadata-series-title"
|
|
177
|
+
value="${escapeText(book.metadata.series_title ?? "")}"
|
|
178
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
179
|
+
>
|
|
180
|
+
</td>
|
|
181
|
+
</tr>
|
|
182
|
+
<tr>
|
|
183
|
+
<th>
|
|
184
|
+
<h4 class="fw-tablerow-title">${gettext("Series position")}</h4>
|
|
185
|
+
</th>
|
|
186
|
+
<td>
|
|
187
|
+
<input class="entry-form" type="text" id="book-metadata-series-position"
|
|
188
|
+
value="${escapeText(book.metadata.series_position ?? "")}"
|
|
189
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
190
|
+
>
|
|
191
|
+
</td>
|
|
192
|
+
</tr>
|
|
193
|
+
</tbody>
|
|
194
|
+
</table>`
|
|
195
|
+
|
|
196
|
+
/** A template for the citation style pane of the book dialog */
|
|
197
|
+
export const bookBibliographyDataTemplate = ({
|
|
198
|
+
book,
|
|
199
|
+
citationStyles
|
|
200
|
+
}: {
|
|
201
|
+
book: Book
|
|
202
|
+
citationStyles: Array<{id: string; title?: string}>
|
|
203
|
+
}) =>
|
|
204
|
+
`<table class="fw-dialog-table">
|
|
205
|
+
<tbody>
|
|
206
|
+
<tr>
|
|
207
|
+
<th>
|
|
208
|
+
<h4 class="fw-tablerow-title">${gettext("Citation style")}</h4>
|
|
209
|
+
</th>
|
|
210
|
+
<td>
|
|
211
|
+
<div class="fw-select-container">
|
|
212
|
+
<select class="entry-form dk fw-button fw-light fw-large" name="book-settings-citationstyle"
|
|
213
|
+
title="${gettext(
|
|
214
|
+
"Select citation style for the book"
|
|
215
|
+
)}"
|
|
216
|
+
id="book-settings-citationstyle"
|
|
217
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
218
|
+
>
|
|
219
|
+
${Object.entries(citationStyles)
|
|
220
|
+
.map(
|
|
221
|
+
([key, value]) =>
|
|
222
|
+
`<option value="${key}" ${
|
|
223
|
+
key === book.settings.citationstyle
|
|
224
|
+
? "selected"
|
|
225
|
+
: ""
|
|
226
|
+
}>
|
|
227
|
+
${value}
|
|
228
|
+
</option>`
|
|
229
|
+
)
|
|
230
|
+
.join("")}
|
|
231
|
+
</select>
|
|
232
|
+
<div class="fw-select-arrow fa fa-caret-down"></div>
|
|
233
|
+
</div>
|
|
234
|
+
</td>
|
|
235
|
+
</tr>
|
|
236
|
+
</tbody>
|
|
237
|
+
</table>`
|
|
238
|
+
|
|
239
|
+
const paperSizes = [
|
|
240
|
+
["folio", gettext("Folio (15 x 12 inch)")],
|
|
241
|
+
["quarto", gettext("Quarto (12 × 9 inch)")],
|
|
242
|
+
["octavo", gettext("Octavo (9 x 6 inch)")],
|
|
243
|
+
["a5", gettext("A5")],
|
|
244
|
+
["a4", gettext("A4")]
|
|
245
|
+
]
|
|
246
|
+
|
|
247
|
+
/** A template for the print related data pane of the book dialog */
|
|
248
|
+
export const bookPrintDataTemplate = ({
|
|
249
|
+
book,
|
|
250
|
+
bookStyleList
|
|
251
|
+
}: {
|
|
252
|
+
book: Book
|
|
253
|
+
bookStyleList: BookStyle[]
|
|
254
|
+
}) =>
|
|
255
|
+
`<table class="fw-dialog-table">
|
|
256
|
+
<tbody>
|
|
257
|
+
<tr>
|
|
258
|
+
<th>
|
|
259
|
+
<h4 class="fw-tablerow-title">${gettext("Book style")}</h4>
|
|
260
|
+
</th>
|
|
261
|
+
<td>
|
|
262
|
+
<div class="fw-select-container">
|
|
263
|
+
<select class="entry-form dk fw-button fw-light fw-large" name="book-settings-bookstyle"
|
|
264
|
+
title="${gettext(
|
|
265
|
+
"Select stylesheet for the book"
|
|
266
|
+
)}"
|
|
267
|
+
id="book-settings-bookstyle"
|
|
268
|
+
${
|
|
269
|
+
isReadOnly(book) || !bookStyleList.length
|
|
270
|
+
? 'disabled="disabled"'
|
|
271
|
+
: ""
|
|
272
|
+
}
|
|
273
|
+
>
|
|
274
|
+
${bookStyleList
|
|
275
|
+
.map(
|
|
276
|
+
(bookStyle: BookStyle) =>
|
|
277
|
+
`<option value="${bookStyle.slug}"
|
|
278
|
+
${
|
|
279
|
+
bookStyle.slug ===
|
|
280
|
+
book.settings.book_style
|
|
281
|
+
? "selected"
|
|
282
|
+
: ""
|
|
283
|
+
}
|
|
284
|
+
>
|
|
285
|
+
${escapeText((bookStyle.title as string) ?? "")}
|
|
286
|
+
</option>`
|
|
287
|
+
)
|
|
288
|
+
.join("")}
|
|
289
|
+
</select>
|
|
290
|
+
<div class="fw-select-arrow fa fa-caret-down"></div>
|
|
291
|
+
</div>
|
|
292
|
+
</td>
|
|
293
|
+
</tr>
|
|
294
|
+
<tr>
|
|
295
|
+
<th>
|
|
296
|
+
<h4 class="fw-tablerow-title">${gettext("Paper size")}</h4>
|
|
297
|
+
</th>
|
|
298
|
+
<td>
|
|
299
|
+
<div class="fw-select-container">
|
|
300
|
+
<select class="entry-form dk fw-button fw-light fw-large" name="book-settings-papersize"
|
|
301
|
+
title="${gettext(
|
|
302
|
+
"Select paper size for the book"
|
|
303
|
+
)}"
|
|
304
|
+
id="book-settings-papersize"
|
|
305
|
+
${isReadOnly(book) ? 'disabled="disabled"' : ""}
|
|
306
|
+
>
|
|
307
|
+
${paperSizes
|
|
308
|
+
.map(
|
|
309
|
+
size =>
|
|
310
|
+
`<option value="${size[0]}" ${
|
|
311
|
+
size[0] ===
|
|
312
|
+
book.settings.papersize
|
|
313
|
+
? "selected"
|
|
314
|
+
: ""
|
|
315
|
+
}>
|
|
316
|
+
${size[1]}
|
|
317
|
+
</option>`
|
|
318
|
+
)
|
|
319
|
+
.join("")}
|
|
320
|
+
</select>
|
|
321
|
+
<div class="fw-select-arrow fa fa-caret-down"></div>
|
|
322
|
+
</div>
|
|
323
|
+
</td>
|
|
324
|
+
</tr>
|
|
325
|
+
</tbody>
|
|
326
|
+
</table>`
|
|
327
|
+
|
|
328
|
+
/** A template for the cover image input on the epub pane of the book dialog. */
|
|
329
|
+
export const bookEpubDataCoverTemplate = ({
|
|
330
|
+
book,
|
|
331
|
+
imageDB
|
|
332
|
+
}: {
|
|
333
|
+
book: Book
|
|
334
|
+
imageDB: BookDialogInfo["imageDB"]
|
|
335
|
+
}) =>
|
|
336
|
+
`<th class="figure-preview-row">
|
|
337
|
+
<h4 class="fw-tablerow-title">${gettext("Cover image")}</h4>
|
|
338
|
+
</th>
|
|
339
|
+
<td>
|
|
340
|
+
${
|
|
341
|
+
book.cover_image
|
|
342
|
+
? `<div class="img" style="background-image: url(${
|
|
343
|
+
imageDB.db[book.cover_image].image
|
|
344
|
+
});" title="${gettext("Cover image")}"></div>`
|
|
345
|
+
: ""
|
|
346
|
+
}
|
|
347
|
+
</td>
|
|
348
|
+
${
|
|
349
|
+
isReadOnly(book)
|
|
350
|
+
? ""
|
|
351
|
+
: `<td class="figure-preview-row">
|
|
352
|
+
<button type="button" class="fw-dialog-titlebar-button ui-widget ui-state-default
|
|
353
|
+
ui-corner-all ui-button-text-only fw-button fw-dark"
|
|
354
|
+
id="select-cover-image-button" role="button" aria-disabled="false" title="${gettext(
|
|
355
|
+
"Select a cover image"
|
|
356
|
+
)}">
|
|
357
|
+
<span class="ui-button-text">${gettext("Select Image")}</span>
|
|
358
|
+
</button>
|
|
359
|
+
${
|
|
360
|
+
book.cover_image
|
|
361
|
+
? `<button type="button" class="fw-dialog-titlebar-button ui-widget ui-state-default
|
|
362
|
+
ui-corner-all ui-button-text-only fw-button fw-orange"
|
|
363
|
+
id="remove-cover-image-button" role="button" aria-disabled="false" title="${gettext(
|
|
364
|
+
"Remove cover image"
|
|
365
|
+
)}">
|
|
366
|
+
<span class="ui-button-text">${gettext("Remove Image")}</span>
|
|
367
|
+
</button>`
|
|
368
|
+
: ""
|
|
369
|
+
}
|
|
370
|
+
</td>`
|
|
371
|
+
}`
|
|
372
|
+
|
|
373
|
+
/** A template for the epub related data pane of the book dialog */
|
|
374
|
+
export const bookEpubDataTemplate = ({
|
|
375
|
+
book,
|
|
376
|
+
imageDB
|
|
377
|
+
}: {
|
|
378
|
+
book: Book
|
|
379
|
+
imageDB: BookDialogInfo["imageDB"]
|
|
380
|
+
}) =>
|
|
381
|
+
`<table class="fw-dialog-table fw-media-uploader">
|
|
382
|
+
<tbody>
|
|
383
|
+
<tr id="cover-preview-row">
|
|
384
|
+
${bookEpubDataCoverTemplate({
|
|
385
|
+
book,
|
|
386
|
+
imageDB
|
|
387
|
+
})}
|
|
388
|
+
</tr>
|
|
389
|
+
</tbody>
|
|
390
|
+
</table>`
|
|
391
|
+
|
|
392
|
+
/** A template for the ODT template row of the book dialog. */
|
|
393
|
+
export const bookODTDataRowTemplate = ({book}: {book: Book}) =>
|
|
394
|
+
`<th class="odt-file-row">
|
|
395
|
+
<h4 class="fw-tablerow-title">${gettext("ODT Template")}</h4>
|
|
396
|
+
</th>
|
|
397
|
+
<td>
|
|
398
|
+
${
|
|
399
|
+
book.odt_template
|
|
400
|
+
? `<a href="${book.odt_template}" id="odt-template-file-url" download>${escapeText(
|
|
401
|
+
book.odt_template
|
|
402
|
+
)}</a>`
|
|
403
|
+
: ""
|
|
404
|
+
}
|
|
405
|
+
</td>
|
|
406
|
+
${
|
|
407
|
+
isReadOnly(book)
|
|
408
|
+
? ""
|
|
409
|
+
: `<td class="odt-template-row">
|
|
410
|
+
<button type="button" class="fw-dialog-titlebar-button ui-widget ui-state-default
|
|
411
|
+
ui-corner-all ui-button-text-only fw-button fw-dark"
|
|
412
|
+
id="select-odt-template" role="button" aria-disabled="false"
|
|
413
|
+
title="${gettext("Select an ODT template file")}">
|
|
414
|
+
<span class="ui-button-text">${gettext(
|
|
415
|
+
"Select ODT template file"
|
|
416
|
+
)}</span>
|
|
417
|
+
</button>
|
|
418
|
+
<input type="file" id="input-odt-template" accept=".odt" class="fw-media-file-input">
|
|
419
|
+
${
|
|
420
|
+
book.odt_template
|
|
421
|
+
? `<button type="button" class="fw-dialog-titlebar-button ui-widget ui-state-default
|
|
422
|
+
ui-corner-all ui-button-text-only fw-button fw-orange"
|
|
423
|
+
id="remove-odt-template-button" role="button" aria-disabled="false"
|
|
424
|
+
title="${gettext("Remove ODT template file")}">
|
|
425
|
+
<span class="ui-button-text">
|
|
426
|
+
${gettext("Remove ODT template file")}
|
|
427
|
+
</span>
|
|
428
|
+
</button>`
|
|
429
|
+
: ""
|
|
430
|
+
}
|
|
431
|
+
</td>`
|
|
432
|
+
}`
|
|
433
|
+
|
|
434
|
+
/** A template for the ODT related data pane of the book dialog */
|
|
435
|
+
export const bookODTDataTemplate = ({book}: {book: Book}) =>
|
|
436
|
+
`<table class="fw-dialog-table">
|
|
437
|
+
<tbody>
|
|
438
|
+
<tr id="odt-template-row">
|
|
439
|
+
${bookODTDataRowTemplate({book})}
|
|
440
|
+
</tr>
|
|
441
|
+
</tbody>
|
|
442
|
+
</table>`
|
|
443
|
+
|
|
444
|
+
/** A template for the DOCX template row of the book dialog. */
|
|
445
|
+
export const bookDOCXDataRowTemplate = ({book}: {book: Book}) =>
|
|
446
|
+
`<th class="docx-file-row">
|
|
447
|
+
<h4 class="fw-tablerow-title">${gettext("DOCX Template")}</h4>
|
|
448
|
+
</th>
|
|
449
|
+
<td>
|
|
450
|
+
${
|
|
451
|
+
book.docx_template
|
|
452
|
+
? `<a href="${book.docx_template}" id="docx-template-file-url" download>${escapeText(
|
|
453
|
+
book.docx_template
|
|
454
|
+
)}</a>`
|
|
455
|
+
: ""
|
|
456
|
+
}
|
|
457
|
+
</td>
|
|
458
|
+
${
|
|
459
|
+
isReadOnly(book)
|
|
460
|
+
? ""
|
|
461
|
+
: `<td class="docx-template-row">
|
|
462
|
+
<button type="button" class="fw-dialog-titlebar-button ui-widget ui-state-default
|
|
463
|
+
ui-corner-all ui-button-text-only fw-button fw-dark"
|
|
464
|
+
id="select-docx-template" role="button" aria-disabled="false"
|
|
465
|
+
title="${gettext("Select an DOCX template file")}">
|
|
466
|
+
<span class="ui-button-text">${gettext(
|
|
467
|
+
"Select DOCX template file"
|
|
468
|
+
)}</span>
|
|
469
|
+
</button>
|
|
470
|
+
<input type="file" id="input-docx-template" accept=".docx" class="fw-media-file-input">
|
|
471
|
+
${
|
|
472
|
+
book.docx_template
|
|
473
|
+
? `<button type="button" class="fw-dialog-titlebar-button ui-widget ui-state-default
|
|
474
|
+
ui-corner-all ui-button-text-only fw-button fw-orange"
|
|
475
|
+
id="remove-docx-template-button" role="button" aria-disabled="false"
|
|
476
|
+
title="${gettext("Remove DOCX template file")}">
|
|
477
|
+
<span class="ui-button-text">
|
|
478
|
+
${gettext("Remove DOCX template file")}
|
|
479
|
+
</span>
|
|
480
|
+
</button>`
|
|
481
|
+
: ""
|
|
482
|
+
}
|
|
483
|
+
</td>`
|
|
484
|
+
}`
|
|
485
|
+
|
|
486
|
+
/** A template for the DOCX related data pane of the book dialog */
|
|
487
|
+
export const bookDOCXDataTemplate = ({book}: {book: Book}) =>
|
|
488
|
+
`<table class="fw-dialog-table">
|
|
489
|
+
<tbody>
|
|
490
|
+
<tr id="docx-template-row">
|
|
491
|
+
${bookDOCXDataRowTemplate({book})}
|
|
492
|
+
</tr>
|
|
493
|
+
</tbody>
|
|
494
|
+
</table>`
|
|
495
|
+
|
|
496
|
+
/** A template for the sanity check pane of the book dialog */
|
|
497
|
+
export const bookSanityCheckTemplate = () =>
|
|
498
|
+
`<table class="fw-dialog-table">
|
|
499
|
+
<tbody>
|
|
500
|
+
<tr>
|
|
501
|
+
<th>
|
|
502
|
+
<button type="button" id="perform-sanity-check-button" class="fw-dialog-titlebar-button fw-button fw-dark">${gettext(
|
|
503
|
+
"Perform sanity check"
|
|
504
|
+
)}</button>
|
|
505
|
+
</th>
|
|
506
|
+
<td id="sanity-check-output"></td>
|
|
507
|
+
</tr>
|
|
508
|
+
</tbody>
|
|
509
|
+
</table>`
|
|
510
|
+
|
|
511
|
+
/** A template for the book dialog. */
|
|
512
|
+
export const bookDialogTemplate = ({
|
|
513
|
+
title,
|
|
514
|
+
bookInfo,
|
|
515
|
+
dialogParts
|
|
516
|
+
}: {
|
|
517
|
+
title: string
|
|
518
|
+
bookInfo: BookDialogInfo
|
|
519
|
+
dialogParts: BookDialogPart[]
|
|
520
|
+
}) =>
|
|
521
|
+
`<div id="book-dialog" title="${title}">
|
|
522
|
+
<div id="bookoptions-tab">
|
|
523
|
+
<ul class="fw-tabs-nav">
|
|
524
|
+
${dialogParts
|
|
525
|
+
.map(
|
|
526
|
+
(part, index) =>
|
|
527
|
+
`<li class="fw-tab-link ${index === 0 ? "fw-current-tab" : ""}">
|
|
528
|
+
<a href="#optionTab${index}" class="fw-tab-link-inner" title="${escapeText(
|
|
529
|
+
part.description
|
|
530
|
+
)}">
|
|
531
|
+
${escapeText(part.title)}
|
|
532
|
+
</a>
|
|
533
|
+
</li>`
|
|
534
|
+
)
|
|
535
|
+
.join("")}
|
|
536
|
+
</ul>
|
|
537
|
+
${dialogParts
|
|
538
|
+
.map(
|
|
539
|
+
(part, index) =>
|
|
540
|
+
`<div class="tab-content fw-tabs-panel" id="optionTab${index}" title="${escapeText(
|
|
541
|
+
part.description
|
|
542
|
+
)}">
|
|
543
|
+
${part.template(bookInfo)}
|
|
544
|
+
</div>`
|
|
545
|
+
)
|
|
546
|
+
.join("")}
|
|
547
|
+
</div>
|
|
548
|
+
</div>`
|
|
549
|
+
|
|
550
|
+
/** A template for the chapter pane of the book dialog. */
|
|
551
|
+
export const bookDialogChaptersTemplate = ({
|
|
552
|
+
book,
|
|
553
|
+
documentList
|
|
554
|
+
}: {
|
|
555
|
+
book: Book
|
|
556
|
+
documentList: DocumentListEntry[]
|
|
557
|
+
}) => {
|
|
558
|
+
const hasEncryptedChapters = book.chapters.some(
|
|
559
|
+
chapter => documentList.find(doc => doc.id === chapter.text)?.e2ee
|
|
560
|
+
)
|
|
561
|
+
return `${
|
|
562
|
+
isReadOnly(book)
|
|
563
|
+
? ""
|
|
564
|
+
: `<div class="fw-ar-container">
|
|
565
|
+
<h3 class="fw-green-title">${gettext("My documents")}</h3>
|
|
566
|
+
<div id="book-document-list"></div>
|
|
567
|
+
</div>
|
|
568
|
+
<span id="add-chapter" class="fw-button fw-large fw-square fw-light fw-ar-button">
|
|
569
|
+
<i class="fas fa-caret-right"></i>
|
|
570
|
+
</span>`
|
|
571
|
+
}
|
|
572
|
+
<div class="fw-ar-container">
|
|
573
|
+
<h3 class="fw-green-title">${gettext("Book chapters")}</h3>
|
|
574
|
+
<table class="fw-data-table">
|
|
575
|
+
<thead class="fw-data-table-header">
|
|
576
|
+
<tr>
|
|
577
|
+
<th colspan="2">${gettext("Title")}</th>
|
|
578
|
+
<th colspan="2">${gettext("Sort")}</th>
|
|
579
|
+
${isReadOnly(book) ? "" : "<th> </th>"}
|
|
580
|
+
</tr>
|
|
581
|
+
</thead>
|
|
582
|
+
<tbody class="fw-data-table-body fw-small" id="book-chapter-list">
|
|
583
|
+
${bookChapterListTemplate({
|
|
584
|
+
book,
|
|
585
|
+
documentList
|
|
586
|
+
})}
|
|
587
|
+
</tbody>
|
|
588
|
+
</table>
|
|
589
|
+
${
|
|
590
|
+
hasEncryptedChapters
|
|
591
|
+
? `<p class="fw-note e2ee-chapter-notice">
|
|
592
|
+
<i class="fas fa-lock"></i>
|
|
593
|
+
${gettext("This book contains encrypted chapters. A personal passphrase is required to export or run a sanity check on this book.")}
|
|
594
|
+
</p>`
|
|
595
|
+
: ""
|
|
596
|
+
}
|
|
597
|
+
</div>`
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/** A template for the chapter list on the chapter pane the book dialog. */
|
|
601
|
+
export const bookChapterListTemplate = ({
|
|
602
|
+
book,
|
|
603
|
+
documentList
|
|
604
|
+
}: {
|
|
605
|
+
book: Book
|
|
606
|
+
documentList: DocumentListEntry[]
|
|
607
|
+
}) => {
|
|
608
|
+
let partCounter = 1
|
|
609
|
+
return book.chapters
|
|
610
|
+
.slice()
|
|
611
|
+
.sort((a: Chapter, b: Chapter) => a.number - b.number)
|
|
612
|
+
.map((chapter: Chapter, index: number, array: Chapter[]) => {
|
|
613
|
+
const doc = documentList.find(doc => doc.id === chapter.text)
|
|
614
|
+
return `<tr
|
|
615
|
+
${doc ? "" : 'class="noaccess"'}
|
|
616
|
+
>
|
|
617
|
+
<td width="222" data-id="${
|
|
618
|
+
chapter.text
|
|
619
|
+
}" class="fw-checkable-td" ${
|
|
620
|
+
doc
|
|
621
|
+
? `title="${longFilePath(
|
|
622
|
+
doc.title ?? "",
|
|
623
|
+
doc.path ?? ""
|
|
624
|
+
)}"`
|
|
625
|
+
: ""
|
|
626
|
+
}>
|
|
627
|
+
<span class="fw-inline">
|
|
628
|
+
${doc ? "" : '<i class="fas fa-minus-circle"></i>'}
|
|
629
|
+
${doc && doc.e2ee ? `<i class="fas fa-lock e2ee-chapter-icon" title="${gettext("Encrypted document")}"></i>` : ""}
|
|
630
|
+
${
|
|
631
|
+
(chapter.part ?? "").length
|
|
632
|
+
? `<b class="part">
|
|
633
|
+
${partCounter++}. ${gettext("Book part")}:
|
|
634
|
+
${escapeText(chapter.part ?? "")}
|
|
635
|
+
</b>
|
|
636
|
+
<br>`
|
|
637
|
+
: ""
|
|
638
|
+
}
|
|
639
|
+
${chapter.number}
|
|
640
|
+
${
|
|
641
|
+
doc
|
|
642
|
+
? doc.title
|
|
643
|
+
? doc.title
|
|
644
|
+
: gettext("Untitled")
|
|
645
|
+
: gettext("No access")
|
|
646
|
+
}
|
|
647
|
+
</span>
|
|
648
|
+
</td>
|
|
649
|
+
${
|
|
650
|
+
isReadOnly(book)
|
|
651
|
+
? ""
|
|
652
|
+
: `<td width="30" data-id="${chapter.text}" class="edit-chapter">
|
|
653
|
+
<i class="fas fa-pencil-alt fw-link-text"></i>
|
|
654
|
+
</td>
|
|
655
|
+
${
|
|
656
|
+
index === 0
|
|
657
|
+
? '<td width="10"></td>'
|
|
658
|
+
: `<td width="10" class="book-sort-up" data-id="${chapter.text}">
|
|
659
|
+
<i class="fas fa-sort-up"></i>
|
|
660
|
+
</td>`
|
|
661
|
+
}
|
|
662
|
+
${
|
|
663
|
+
index + 1 === array.length
|
|
664
|
+
? '<td width="10"></td>'
|
|
665
|
+
: `<td width="10" class="book-sort-down" data-id="${chapter.text}">
|
|
666
|
+
<i class="fas fa-sort-down"></i>
|
|
667
|
+
</td>`
|
|
668
|
+
}
|
|
669
|
+
<td width="50" align="center">
|
|
670
|
+
<span class="delete-chapter fw-inline" data-id="${
|
|
671
|
+
chapter.text
|
|
672
|
+
}">
|
|
673
|
+
<i class="fas fa-trash-alt fw-link-text"></i>
|
|
674
|
+
</span>
|
|
675
|
+
</td>`
|
|
676
|
+
}${
|
|
677
|
+
isReadOnly(book)
|
|
678
|
+
? `<td width="30"></td>
|
|
679
|
+
<td width="10"></td>
|
|
680
|
+
<td width="10"></td>
|
|
681
|
+
<td width="50"></td>`
|
|
682
|
+
: ""
|
|
683
|
+
}
|
|
684
|
+
</tr>`
|
|
685
|
+
})
|
|
686
|
+
.join("")
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/** A template for the chapter dialog for books */
|
|
690
|
+
export const bookChapterDialogTemplate = ({chapter}: {chapter: Chapter}) =>
|
|
691
|
+
`<table class="fw-dialog-table">
|
|
692
|
+
<tr>
|
|
693
|
+
<th>
|
|
694
|
+
<h4 title="${gettext(
|
|
695
|
+
"If this chapter starts a part of the book, specify the title of that part here"
|
|
696
|
+
)}">
|
|
697
|
+
${gettext("Book part title")}
|
|
698
|
+
</h4>
|
|
699
|
+
</th>
|
|
700
|
+
<td>
|
|
701
|
+
<input type="text" id="book-chapter-part"
|
|
702
|
+
value="${escapeText(chapter.part ?? "")}">
|
|
703
|
+
</td>
|
|
704
|
+
</tr>
|
|
705
|
+
</table>`
|