@fiduswriter/editor 0.1.78 → 0.1.79

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 (60) hide show
  1. package/dist/citations/index.js +3 -3
  2. package/dist/citations/index.js.map +1 -1
  3. package/dist/collab/chat.js +1 -1
  4. package/dist/collab/chat.js.map +1 -1
  5. package/dist/collab/colors.js +1 -1
  6. package/dist/collab/colors.js.map +1 -1
  7. package/dist/comments/interactions.js +1 -1
  8. package/dist/comments/interactions.js.map +1 -1
  9. package/dist/exporter/native/file.d.ts +1 -1
  10. package/dist/exporter/native/file.d.ts.map +1 -1
  11. package/dist/exporter/native/file.js +2 -2
  12. package/dist/exporter/native/file.js.map +1 -1
  13. package/dist/footnotes/layout.js +1 -1
  14. package/dist/footnotes/layout.js.map +1 -1
  15. package/dist/index.d.ts +3 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +15 -4
  18. package/dist/index.js.map +1 -1
  19. package/dist/marginboxes/index.js +8 -8
  20. package/dist/marginboxes/index.js.map +1 -1
  21. package/dist/menus/headerbar/view.js +12 -12
  22. package/dist/menus/headerbar/view.js.map +1 -1
  23. package/dist/menus/selection/view.js +2 -2
  24. package/dist/menus/selection/view.js.map +1 -1
  25. package/dist/menus/toolbar/view.js +4 -4
  26. package/dist/menus/toolbar/view.js.map +1 -1
  27. package/dist/navigator/index.js +9 -9
  28. package/dist/navigator/index.js.map +1 -1
  29. package/dist/state_plugins/settings.js +2 -2
  30. package/dist/state_plugins/settings.js.map +1 -1
  31. package/dist/static_app.d.ts +26 -1
  32. package/dist/static_app.d.ts.map +1 -1
  33. package/dist/static_app.js +3 -2
  34. package/dist/static_app.js.map +1 -1
  35. package/dist/static_editor.d.ts +5 -0
  36. package/dist/static_editor.d.ts.map +1 -1
  37. package/dist/static_editor.js +11 -1
  38. package/dist/static_editor.js.map +1 -1
  39. package/dist/track/mod.js +1 -1
  40. package/dist/track/mod.js.map +1 -1
  41. package/dist/types.d.ts +6 -0
  42. package/dist/types.d.ts.map +1 -1
  43. package/package.json +4 -4
  44. package/src/citations/index.ts +3 -3
  45. package/src/collab/chat.ts +1 -1
  46. package/src/collab/colors.ts +1 -1
  47. package/src/comments/interactions.ts +1 -1
  48. package/src/exporter/native/file.ts +4 -2
  49. package/src/footnotes/layout.ts +1 -1
  50. package/src/index.ts +18 -4
  51. package/src/marginboxes/index.ts +8 -8
  52. package/src/menus/headerbar/view.ts +12 -12
  53. package/src/menus/selection/view.ts +2 -2
  54. package/src/menus/toolbar/view.ts +4 -4
  55. package/src/navigator/index.ts +9 -9
  56. package/src/state_plugins/settings.ts +2 -2
  57. package/src/static_app.ts +26 -2
  58. package/src/static_editor.ts +19 -1
  59. package/src/track/mod.ts +1 -1
  60. package/src/types.ts +6 -0
@@ -132,23 +132,23 @@ export class HeaderbarView {
132
132
 
133
133
  bindEvents(): void {
134
134
  this.listeners.onclick = event => this.onclick(event)
135
- document.body.addEventListener("click", this.listeners.onclick)
135
+ this.editor.dom.addEventListener("click", this.listeners.onclick)
136
136
  this.listeners.onKeydown = event => this.onKeydown(event)
137
- document.body.addEventListener("keydown", this.listeners.onKeydown)
137
+ this.editor.dom.addEventListener("keydown", this.listeners.onKeydown)
138
138
  this.listeners.onKeyup = event => this.onKeyup(event)
139
- document.body.addEventListener("keyup", this.listeners.onKeyup)
139
+ this.editor.dom.addEventListener("keyup", this.listeners.onKeyup)
140
140
  this.listeners.onFocusout = event => this.onFocusout(event)
141
- document.body.addEventListener("focusout", this.listeners.onFocusout)
141
+ this.editor.dom.addEventListener("focusout", this.listeners.onFocusout)
142
142
  }
143
143
 
144
144
  destroy(): void {
145
145
  if (document.activeElement?.id === "document-title") {
146
146
  this.saveFileName()
147
147
  }
148
- document.body.removeEventListener("click", this.listeners.onclick!)
149
- document.body.removeEventListener("keydown", this.listeners.onKeydown!)
150
- document.body.removeEventListener("keyup", this.listeners.onKeyup!)
151
- document.body.removeEventListener("focusout", this.listeners.onFocusout!)
148
+ this.editor.dom.removeEventListener("click", this.listeners.onclick!)
149
+ this.editor.dom.removeEventListener("keydown", this.listeners.onKeydown!)
150
+ this.editor.dom.removeEventListener("keyup", this.listeners.onKeyup!)
151
+ this.editor.dom.removeEventListener("focusout", this.listeners.onFocusout!)
152
152
  }
153
153
 
154
154
  onclick(event: MouseEvent): void {
@@ -425,7 +425,7 @@ export class HeaderbarView {
425
425
  if (!findTarget(event, "h1#document-title")) {
426
426
  return
427
427
  }
428
- const docTitleEl = document.body.querySelector("h1#document-title")
428
+ const docTitleEl = this.editor.dom.querySelector("h1#document-title")
429
429
  if (
430
430
  !docTitleEl?.childNodes.length ||
431
431
  (docTitleEl.childNodes.length === 1 &&
@@ -537,7 +537,7 @@ export class HeaderbarView {
537
537
  // We are offline. Just reset.
538
538
  return this.update()
539
539
  }
540
- const docTitleEl = document.body.querySelector("h1#document-title") as HTMLElement | null
540
+ const docTitleEl = this.editor.dom.querySelector("h1#document-title") as HTMLElement | null
541
541
  if (!docTitleEl) {
542
542
  return
543
543
  }
@@ -589,9 +589,9 @@ export class HeaderbarView {
589
589
  this.dd.apply(this.headerEl, diff)
590
590
  const model = this.editor.menu.headerbarModel as HeaderbarModel
591
591
  if (model.open) {
592
- document.body.classList.remove("header-closed")
592
+ this.editor.dom.classList.remove("header-closed")
593
593
  } else {
594
- document.body.classList.add("header-closed")
594
+ this.editor.dom.classList.add("header-closed")
595
595
  }
596
596
  }
597
597
 
@@ -78,11 +78,11 @@ export class SelectionMenuView {
78
78
 
79
79
  bindEvents(): void {
80
80
  this.listeners.onclick = event => this.onclick(event)
81
- document.body.addEventListener("click", this.listeners.onclick as EventListener)
81
+ this.editor.dom.addEventListener("click", this.listeners.onclick as EventListener)
82
82
  }
83
83
 
84
84
  destroy(): void {
85
- document.body.removeEventListener(
85
+ this.editor.dom.removeEventListener(
86
86
  "click",
87
87
  this.listeners.onclick as EventListener
88
88
  )
@@ -95,14 +95,14 @@ export class ToolbarView {
95
95
 
96
96
  bindEvents(): void {
97
97
  this.listeners.onclick = event => this.onclick(event)
98
- document.body.addEventListener("click", this.listeners.onclick)
98
+ this.editor.dom.addEventListener("click", this.listeners.onclick)
99
99
  this.listeners.onmousedown = event => this.onmousedown(event)
100
- document.body.addEventListener("mousedown", this.listeners.onmousedown)
100
+ this.editor.dom.addEventListener("mousedown", this.listeners.onmousedown)
101
101
  }
102
102
 
103
103
  destroy(): void {
104
- document.body.removeEventListener("click", this.listeners.onclick!)
105
- document.body.removeEventListener(
104
+ this.editor.dom.removeEventListener("click", this.listeners.onclick!)
105
+ this.editor.dom.removeEventListener(
106
106
  "mousedown",
107
107
  this.listeners.onmousedown!
108
108
  )
@@ -46,7 +46,7 @@ export class ModNavigator {
46
46
  }
47
47
 
48
48
  bindEvents(): void {
49
- document.body.addEventListener("click", event => {
49
+ this.editor.dom.addEventListener("click", event => {
50
50
  const el: {target?: HTMLElement} = {}
51
51
  switch (true) {
52
52
  case findTarget(event, "#navigator-button", el):
@@ -139,17 +139,17 @@ export class ModNavigator {
139
139
  }
140
140
  })
141
141
 
142
- document.body
142
+ this.editor.dom
143
143
  .querySelector("#navigator-list")
144
144
  ?.addEventListener("mouseover", () => {
145
- document.body.classList.add("no-scroll")
145
+ this.editor.dom.classList.add("no-scroll")
146
146
  })
147
- document.body
147
+ this.editor.dom
148
148
  .querySelector("#navigator-list")
149
149
  ?.addEventListener("mouseout", () => {
150
- document.body.classList.remove("no-scroll")
150
+ this.editor.dom.classList.remove("no-scroll")
151
151
  })
152
- document.body.addEventListener("keydown", event => {
152
+ this.editor.dom.addEventListener("keydown", event => {
153
153
  // Alt+n shortcut to toggle navigator
154
154
  if (event.altKey && event.key.toLowerCase() === "n") {
155
155
  event.preventDefault()
@@ -368,8 +368,8 @@ export class ModNavigator {
368
368
  if (this.lastSelectedTarget) {
369
369
  const target =
370
370
  this.lastSelectedTarget == "title"
371
- ? document.body.querySelector(`div.doc-title`)
372
- : document.body.querySelector(`#${this.lastSelectedTarget}`)
371
+ ? this.editor.dom.querySelector(`div.doc-title`)
372
+ : this.editor.dom.querySelector(`#${this.lastSelectedTarget}`)
373
373
  if (target) {
374
374
  // Set selection at end of target.
375
375
  const range = document.createRange()
@@ -437,7 +437,7 @@ export class ModNavigator {
437
437
  populateNavigator(): string | false {
438
438
  const currentPos = this.editor.view.state.selection.$head.pos
439
439
  const title =
440
- document.body.querySelector("div.doc-title")?.textContent ||
440
+ this.editor.dom.querySelector("div.doc-title")?.textContent ||
441
441
  gettext("Untitled Document")
442
442
  const items: NavigatorItem[] = [
443
443
  {
@@ -131,7 +131,7 @@ export const settingsPlugin = (options: SettingsOptions) => {
131
131
  if (!docStyleEl) {
132
132
  docStyleEl = document.createElement("style")
133
133
  docStyleEl.id = "document-style"
134
- document.body.appendChild(docStyleEl)
134
+ options.editor.dom.appendChild(docStyleEl)
135
135
  }
136
136
 
137
137
  docStyleEl.innerHTML = docStyleCSS
@@ -149,7 +149,7 @@ export const settingsPlugin = (options: SettingsOptions) => {
149
149
  if (!langStyleEl) {
150
150
  langStyleEl = document.createElement("style")
151
151
  langStyleEl.id = "language-style"
152
- document.body.appendChild(langStyleEl)
152
+ options.editor.dom.appendChild(langStyleEl)
153
153
  }
154
154
 
155
155
  langStyleEl.innerHTML = `
package/src/static_app.ts CHANGED
@@ -77,6 +77,29 @@ export interface StaticAppConfig {
77
77
  json: Record<string, unknown>
78
78
  status: number
79
79
  }>
80
+ /**
81
+ * Editor save mode:
82
+ * - "external" (default): the host drives saving through
83
+ * `onSaveDocument`; no autosave runs inside the editor.
84
+ * - "direct": the editor autosaves (every 10 s and on page hide) via the
85
+ * `saveDocument` connector. `onSaveDocument` is used as the save
86
+ * connector and should return `{json: {version}, status}` (or
87
+ * `{json, status: 409}` on version conflict, which triggers the
88
+ * built-in merge).
89
+ */
90
+ saveMode?: "external" | "direct"
91
+ /**
92
+ * Optional API connector overrides. When provided, these replace the
93
+ * corresponding in-memory connectors, letting the editor talk to a real
94
+ * backend (e.g. Django) instead of the static in-memory stores.
95
+ */
96
+ apiConnectors?: Partial<{
97
+ document: EditorDocumentApi
98
+ documentImport: EditorDocumentImportApi
99
+ image: ImageApi
100
+ bibliography: BibliographyApi
101
+ contacts: EditorContactsApi
102
+ }>
80
103
  /**
81
104
  * Optional user preferences that control inline editing helpers.
82
105
  * Recognized keys include `inline_references` and `inline_math`.
@@ -341,7 +364,7 @@ export async function createStaticApp(
341
364
  isOffline: () => false,
342
365
  settings: {
343
366
  APPS: [appName],
344
- EDITOR_SAVE_MODE: "external",
367
+ EDITOR_SAVE_MODE: config.saveMode ?? "external",
345
368
  EDITOR_ONLY_MODE: true,
346
369
  E2EE_MODE: "disabled",
347
370
  LANGUAGE: config.locale
@@ -357,7 +380,8 @@ export async function createStaticApp(
357
380
  documentImport: documentImportApi,
358
381
  image: imageApi,
359
382
  bibliography: bibliographyApi,
360
- contacts: contactsApi
383
+ contacts: contactsApi,
384
+ ...config.apiConnectors
361
385
  }
362
386
  } as unknown as EditorApp
363
387
 
@@ -71,6 +71,11 @@ export interface StaticEditorConfig
71
71
  }>
72
72
  /** Optional extra editor plugins. */
73
73
  plugins?: Array<[string, Record<string, unknown>]>
74
+ /**
75
+ * Optional container element (or selector) to mount the editor into.
76
+ * When omitted, the editor replaces `document.body` (full-page mode).
77
+ */
78
+ mount?: HTMLElement | string
74
79
  /**
75
80
  * Optional user preferences that control inline editing helpers.
76
81
  * Recognized keys include `inline_references` and `inline_math`.
@@ -242,8 +247,21 @@ export async function createStaticEditor(
242
247
  // exports and printing use the latest edits.
243
248
  plugins.push([app.name, {ConfirmedDocEditorPlugin}])
244
249
 
250
+ let mount: HTMLElement | undefined
251
+ if (config.mount) {
252
+ mount =
253
+ typeof config.mount === "string"
254
+ ? (document.querySelector(config.mount) as HTMLElement)
255
+ : config.mount
256
+ if (!mount) {
257
+ throw new Error(
258
+ `createStaticEditor: mount element not found (${String(config.mount)})`
259
+ )
260
+ }
261
+ }
262
+
245
263
  const editor = new Editor(
246
- {app, user},
264
+ {app, user, mount},
247
265
  docPath,
248
266
  String(docId),
249
267
  plugins
package/src/track/mod.ts CHANGED
@@ -30,7 +30,7 @@ export class ModTrack {
30
30
 
31
31
  bindEvents(): void {
32
32
  // Bind all the click events related to track changes
33
- document.body.addEventListener("click", event => {
33
+ this.editor.dom.addEventListener("click", event => {
34
34
  const el: {target?: HTMLElement} = {}
35
35
  switch (true) {
36
36
  case findTarget(event, ".track-accept", el): {
package/src/types.ts CHANGED
@@ -337,6 +337,11 @@ export interface EditorUser {
337
337
  export interface EditorOptions {
338
338
  app: EditorApp
339
339
  user: EditorUser
340
+ /**
341
+ * Optional container element to mount the editor into. When omitted, the
342
+ * editor replaces `document.body` (full-page mode).
343
+ */
344
+ mount?: HTMLElement
340
345
  }
341
346
 
342
347
  /** Editor plugin tuple used to build the ProseMirror state. */
@@ -366,6 +371,7 @@ export interface Editor {
366
371
  view: EditorView
367
372
  currentView: EditorView
368
373
  dom: HTMLElement
374
+ mount?: HTMLElement
369
375
  ws?: {
370
376
  connectionCount?: number
371
377
  online?: boolean