@fiduswriter/bibliography-manager 0.1.0

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 (105) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +20 -0
  3. package/dist/database/index.js +172 -0
  4. package/dist/database/index.js.map +1 -0
  5. package/dist/database/server_connector.js +47 -0
  6. package/dist/database/server_connector.js.map +1 -0
  7. package/dist/export/index.js +23 -0
  8. package/dist/export/index.js.map +1 -0
  9. package/dist/form/cats.js +22 -0
  10. package/dist/form/cats.js.map +1 -0
  11. package/dist/form/fields/date.js +28 -0
  12. package/dist/form/fields/date.js.map +1 -0
  13. package/dist/form/fields/key.js +100 -0
  14. package/dist/form/fields/key.js.map +1 -0
  15. package/dist/form/fields/key_list.js +37 -0
  16. package/dist/form/fields/key_list.js.map +1 -0
  17. package/dist/form/fields/literal.js +43 -0
  18. package/dist/form/fields/literal.js.map +1 -0
  19. package/dist/form/fields/literal_list.js +36 -0
  20. package/dist/form/fields/literal_list.js.map +1 -0
  21. package/dist/form/fields/literal_long.js +42 -0
  22. package/dist/form/fields/literal_long.js.map +1 -0
  23. package/dist/form/fields/name.js +121 -0
  24. package/dist/form/fields/name.js.map +1 -0
  25. package/dist/form/fields/name_list.js +36 -0
  26. package/dist/form/fields/name_list.js.map +1 -0
  27. package/dist/form/fields/range.js +89 -0
  28. package/dist/form/fields/range.js.map +1 -0
  29. package/dist/form/fields/range_list.js +36 -0
  30. package/dist/form/fields/range_list.js.map +1 -0
  31. package/dist/form/fields/tag_list.js +30 -0
  32. package/dist/form/fields/tag_list.js.map +1 -0
  33. package/dist/form/fields/title.js +46 -0
  34. package/dist/form/fields/title.js.map +1 -0
  35. package/dist/form/fields/uri.js +40 -0
  36. package/dist/form/fields/uri.js.map +1 -0
  37. package/dist/form/fields/verbatim.js +19 -0
  38. package/dist/form/fields/verbatim.js.map +1 -0
  39. package/dist/form/index.js +344 -0
  40. package/dist/form/index.js.map +1 -0
  41. package/dist/form/strings.js +89 -0
  42. package/dist/form/strings.js.map +1 -0
  43. package/dist/form/templates.js +59 -0
  44. package/dist/form/templates.js.map +1 -0
  45. package/dist/import/bibliography_import.js +83 -0
  46. package/dist/import/bibliography_import.js.map +1 -0
  47. package/dist/import/dialog.js +71 -0
  48. package/dist/import/dialog.js.map +1 -0
  49. package/dist/import/index.js +3 -0
  50. package/dist/import/index.js.map +1 -0
  51. package/dist/import/templates.js +12 -0
  52. package/dist/import/templates.js.map +1 -0
  53. package/dist/index.js +6 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/overview/index.js +453 -0
  56. package/dist/overview/index.js.map +1 -0
  57. package/dist/overview/menu.js +91 -0
  58. package/dist/overview/menu.js.map +1 -0
  59. package/dist/overview/templates.js +24 -0
  60. package/dist/overview/templates.js.map +1 -0
  61. package/dist/plugins/bibliography_overview/index.js +2 -0
  62. package/dist/plugins/bibliography_overview/index.js.map +1 -0
  63. package/dist/schema/literal.js +24 -0
  64. package/dist/schema/literal.js.map +1 -0
  65. package/dist/schema/literal_long.js +40 -0
  66. package/dist/schema/literal_long.js.map +1 -0
  67. package/dist/schema/title.js +31 -0
  68. package/dist/schema/title.js.map +1 -0
  69. package/dist/tools.js +53 -0
  70. package/dist/tools.js.map +1 -0
  71. package/package.json +55 -0
  72. package/src/database/index.js +234 -0
  73. package/src/database/server_connector.js +57 -0
  74. package/src/export/index.js +27 -0
  75. package/src/form/cats.js +24 -0
  76. package/src/form/fields/date.js +31 -0
  77. package/src/form/fields/key.js +113 -0
  78. package/src/form/fields/key_list.js +45 -0
  79. package/src/form/fields/literal.js +48 -0
  80. package/src/form/fields/literal_list.js +42 -0
  81. package/src/form/fields/literal_long.js +47 -0
  82. package/src/form/fields/name.js +152 -0
  83. package/src/form/fields/name_list.js +42 -0
  84. package/src/form/fields/range.js +104 -0
  85. package/src/form/fields/range_list.js +42 -0
  86. package/src/form/fields/tag_list.js +33 -0
  87. package/src/form/fields/title.js +51 -0
  88. package/src/form/fields/uri.js +43 -0
  89. package/src/form/fields/verbatim.js +21 -0
  90. package/src/form/index.js +424 -0
  91. package/src/form/strings.js +122 -0
  92. package/src/form/templates.js +70 -0
  93. package/src/import/bibliography_import.js +104 -0
  94. package/src/import/dialog.js +95 -0
  95. package/src/import/index.js +2 -0
  96. package/src/import/templates.js +12 -0
  97. package/src/index.js +5 -0
  98. package/src/overview/index.js +548 -0
  99. package/src/overview/menu.js +106 -0
  100. package/src/overview/templates.js +30 -0
  101. package/src/plugins/bibliography_overview/index.js +1 -0
  102. package/src/schema/literal.js +34 -0
  103. package/src/schema/literal_long.js +50 -0
  104. package/src/schema/title.js +42 -0
  105. package/src/tools.js +58 -0
@@ -0,0 +1,122 @@
1
+ import {
2
+ BibFieldTypes,
3
+ BibTypes,
4
+ getFieldHelp,
5
+ getFieldTitle,
6
+ getLangidTitle,
7
+ getLocale,
8
+ getOtherOptionTitle,
9
+ getTypeTitle
10
+ } from "bibliojson"
11
+
12
+ // Cache for the current locale to avoid repeated lookups
13
+ let cachedLocale = null
14
+ let cachedLang = null
15
+
16
+ function getCachedLocale() {
17
+ const lang = document.documentElement.lang || "en"
18
+ if (lang !== cachedLang) {
19
+ cachedLocale = getLocale(lang)
20
+ cachedLang = lang
21
+ }
22
+ return cachedLocale
23
+ }
24
+
25
+ // Dynamic field title getter that uses bibliojson's i18n
26
+ export function getBibFieldTitle(fieldKey, bibType = null) {
27
+ const locale = getCachedLocale()
28
+ if (bibType && BibTypes[bibType]) {
29
+ return getFieldTitle(locale, bibType, fieldKey)
30
+ }
31
+ // Fallback to generic field title
32
+ const fieldType = BibFieldTypes[fieldKey]
33
+ if (fieldType && fieldType.title) {
34
+ return fieldType.title
35
+ }
36
+ return fieldKey
37
+ }
38
+
39
+ // Dynamic type title getter
40
+ export function getBibTypeTitle(typeKey) {
41
+ const locale = getCachedLocale()
42
+ return getTypeTitle(locale, typeKey)
43
+ }
44
+
45
+ // Dynamic field help getter
46
+ export function getBibFieldHelp(fieldKey) {
47
+ const locale = getCachedLocale()
48
+ return getFieldHelp(locale, fieldKey)
49
+ }
50
+
51
+ // Dynamic option title getter (for editortype, pagination, pubstate, etc.)
52
+ export function getBibOptionTitle(optionKey) {
53
+ const locale = getCachedLocale()
54
+ return getOtherOptionTitle(locale, optionKey)
55
+ }
56
+
57
+ // Dynamic langid title getter
58
+ export function getBibLangidTitle(langidKey) {
59
+ const locale = getCachedLocale()
60
+ return getLangidTitle(locale, langidKey)
61
+ }
62
+
63
+ // For backward compatibility, create proxy objects that dynamically return translations
64
+ // These should be used sparingly - prefer using the function versions above
65
+ export const BibFieldTitles = new Proxy(
66
+ {},
67
+ {
68
+ get(_target, prop) {
69
+ return getBibFieldTitle(prop)
70
+ }
71
+ }
72
+ )
73
+
74
+ export const BibTypeTitles = new Proxy(
75
+ {},
76
+ {
77
+ get(_target, prop) {
78
+ return getBibTypeTitle(prop)
79
+ }
80
+ }
81
+ )
82
+
83
+ export const BibFieldHelp = new Proxy(
84
+ {},
85
+ {
86
+ get(_target, prop) {
87
+ return getBibFieldHelp(prop)
88
+ }
89
+ }
90
+ )
91
+
92
+ export const BibOptionTitles = new Proxy(
93
+ {},
94
+ {
95
+ get(_target, prop) {
96
+ return getBibOptionTitle(prop)
97
+ }
98
+ }
99
+ )
100
+
101
+ // Export a function to get all type titles as an object (for templates that need to map all types)
102
+ export function getAllTypeTitles() {
103
+ const locale = getCachedLocale()
104
+ const titles = {}
105
+ Object.keys(BibTypes).forEach(typeKey => {
106
+ titles[typeKey] = getTypeTitle(locale, typeKey)
107
+ })
108
+ return titles
109
+ }
110
+
111
+ // Export a function to get all field help texts
112
+ export function getAllFieldHelp() {
113
+ const locale = getCachedLocale()
114
+ const help = {}
115
+ Object.keys(BibFieldTypes).forEach(fieldKey => {
116
+ const helpText = getFieldHelp(locale, fieldKey)
117
+ if (helpText) {
118
+ help[fieldKey] = helpText
119
+ }
120
+ })
121
+ return help
122
+ }
@@ -0,0 +1,70 @@
1
+ /** A template for the bibliography item edit dialog. */
2
+ import {DialogTabs} from "fwtoolkit"
3
+ import {getAllTypeTitles} from "./strings"
4
+
5
+ const requiredFieldsTemplate = () =>
6
+ `<table class="fw-dialog-table"><tbody id="eo-fields"></tbody></table>
7
+ <table class="fw-dialog-table"><tbody id="req-fields"></tbody></table>`
8
+
9
+ const optionalFieldsTemplate = () =>
10
+ `<table class="fw-dialog-table"><tbody id="opt-fields"></tbody></table>`
11
+
12
+ const categoriesTemplate = () =>
13
+ `<table class="fw-dialog-table">
14
+ <tbody>
15
+ <tr>
16
+ <th><h4 class="fw-tablerow-title">${gettext("Categories")}</h4></th>
17
+ <td id="categories-field"></td>
18
+ </tr>
19
+ </tbody>
20
+ </table>`
21
+
22
+ export const bibDialog = ({bib_type, BibTypes, hasCats}) => {
23
+ const typeTitles = getAllTypeTitles()
24
+ const tabs = [
25
+ {
26
+ id: "req-fields-tab",
27
+ title: gettext("Required Fields"),
28
+ template: requiredFieldsTemplate
29
+ },
30
+ {
31
+ id: "opt-fields-tab",
32
+ title: gettext("Optional Fields"),
33
+ template: optionalFieldsTemplate
34
+ }
35
+ ]
36
+ if (hasCats) {
37
+ tabs.push({
38
+ id: "categories-tab",
39
+ title: gettext("Categories"),
40
+ template: categoriesTemplate
41
+ })
42
+ }
43
+ const dialogTabs = new DialogTabs(tabs, {containerId: "bib-dialog-tabs"})
44
+ return `<div class="bib-dialog-header">
45
+ <div class="fw-select-container">
46
+ <select id="select-bibtype" class="fw-button fw-light fw-large" required>
47
+ ${
48
+ bib_type === false
49
+ ? `<option class="fw-placeholder" selected disabled value="">${gettext("Select source type")}</option>`
50
+ : ""
51
+ }
52
+ ${Object.keys(BibTypes)
53
+ .map(
54
+ key =>
55
+ `<option value="${key}"
56
+ ${key === bib_type ? "selected" : ""}>
57
+ ${typeTitles[key]}
58
+ </option>`
59
+ )
60
+ .join("")}
61
+ </select>
62
+ <div class="fw-select-arrow fa fa-caret-down"></div>
63
+ </div>
64
+ <div class="entry-key-input-container">
65
+ <input type="text" id="entry-key" class="fw-button fw-light" value="" placeholder="${gettext("Citation key")}" />
66
+ <div id="entry-key-warning" class="entry-key-warning"></div>
67
+ </div>
68
+ </div>
69
+ ${dialogTabs.render()}`
70
+ }
@@ -0,0 +1,104 @@
1
+ import {sniffFormat} from "bibliojson"
2
+ import {addAlert, makeWorker} from "fwtoolkit"
3
+
4
+ const ERROR_MSG = {
5
+ no_entries: gettext(
6
+ "No bibliography entries could be found in import file."
7
+ ),
8
+ entry_error: gettext("An error occured while reading a bibliography entry"),
9
+ unknown_field: gettext(
10
+ "Field cannot not be saved. Fidus Writer does not support the field."
11
+ ),
12
+ unknown_type: gettext(
13
+ 'Entry has been saved as "misc". Fidus Writer does not support the entry type.'
14
+ ),
15
+ unknown_date: gettext("Field does not contain a valid EDTF string."),
16
+ server_save: gettext("The bibliography could not be updated"),
17
+ unsupported_format: gettext("The file format could not be recognized.")
18
+ }
19
+
20
+ export class BibliographyImporter {
21
+ constructor(
22
+ fileContents,
23
+ bibDB,
24
+ addToListCall,
25
+ callback,
26
+ showAlerts = true
27
+ ) {
28
+ this.fileContents = fileContents
29
+ this.bibDB = bibDB
30
+ this.addToListCall = addToListCall
31
+ this.callback = callback
32
+ this.showAlerts = showAlerts
33
+ }
34
+
35
+ init() {
36
+ // Detect the format of the input file
37
+ const format = sniffFormat(this.fileContents)
38
+
39
+ if (!format) {
40
+ if (this.showAlerts) {
41
+ addAlert("error", ERROR_MSG.unsupported_format)
42
+ }
43
+ if (this.callback) {
44
+ this.callback()
45
+ }
46
+ return
47
+ }
48
+
49
+ // Use the worker for the detected format
50
+ const importWorker = makeWorker(
51
+ staticUrl("js/bibliography_import_worker.js")
52
+ )
53
+ importWorker.onmessage = message => this.onMessage(message.data)
54
+ importWorker.postMessage({
55
+ fileContents: this.fileContents,
56
+ format: format
57
+ })
58
+ }
59
+
60
+ onMessage(message) {
61
+ let errorMsg, data
62
+ switch (message.type) {
63
+ case "error":
64
+ case "warning":
65
+ errorMsg = ERROR_MSG[message.errorCode]
66
+ if (!errorMsg) {
67
+ errorMsg = gettext(
68
+ "There was an issue with the bibliography import"
69
+ )
70
+ }
71
+ if (message.errorType) {
72
+ errorMsg += `, error_type: ${message.errorType}`
73
+ }
74
+ if (message.key) {
75
+ errorMsg += `, key: ${message.key}`
76
+ }
77
+ if (message.type_name) {
78
+ errorMsg += `, entry: ${message.type_name}`
79
+ }
80
+ if (message.field_name) {
81
+ errorMsg += `, field_name: ${message.field_name}`
82
+ }
83
+ if (message.entry) {
84
+ errorMsg += `, entry: ${message.entry}`
85
+ }
86
+ if (this.showAlerts) {
87
+ addAlert(message.type, errorMsg)
88
+ }
89
+ break
90
+ case "data":
91
+ data = message.data
92
+ this.bibDB.saveBibEntries(data, true).then(idTranslations => {
93
+ const newIds = idTranslations.map(idTrans => idTrans[1])
94
+ this.addToListCall(newIds)
95
+ })
96
+ break
97
+ default:
98
+ break
99
+ }
100
+ if (message.done && this.callback) {
101
+ this.callback()
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,95 @@
1
+ import {Dialog, activateWait, addAlert, deactivateWait} from "fwtoolkit"
2
+ import {importBibFileTemplate} from "./templates"
3
+ /** First step of the bibliography file import. Creates a dialog box to specify upload file.
4
+ * Supports multiple formats: BibTeX/BibLaTeX, CSL-JSON, RIS, EndNote, Citavi, NBIB, ODT/DOCX citations.
5
+ */
6
+
7
+ export class BibliographyFileImportDialog {
8
+ constructor(bibDB, addToListCall, app) {
9
+ this.bibDB = bibDB
10
+ this.addToListCall = addToListCall
11
+ this.tmpDB = false
12
+ this.app = app
13
+ }
14
+
15
+ init() {
16
+ if (this.app.isOffline()) {
17
+ addAlert(
18
+ "info",
19
+ gettext(
20
+ "You are currently offline. Please try again when you are back online."
21
+ )
22
+ )
23
+ return
24
+ }
25
+ const buttons = [
26
+ {
27
+ text: gettext("Import"),
28
+ classes: "fw-dark submit-import",
29
+ click: () => {
30
+ let bibFile = document.getElementById("bib-uploader").files
31
+ if (0 === bibFile.length) {
32
+ return false
33
+ }
34
+ bibFile = bibFile[0]
35
+ if (10485760 < bibFile.size) {
36
+ return false
37
+ }
38
+ if (this.app.isOffline()) {
39
+ addAlert(
40
+ "info",
41
+ gettext(
42
+ "You are currently offline. Please try again when you are back online."
43
+ )
44
+ )
45
+ dialog.close()
46
+ return false
47
+ }
48
+ activateWait()
49
+ const reader = new window.FileReader()
50
+ reader.onload = event => {
51
+ import("./bibliography_import").then(
52
+ ({BibliographyImporter}) => {
53
+ const importer = new BibliographyImporter(
54
+ event.target.result,
55
+ this.bibDB,
56
+ this.addToListCall,
57
+ () => deactivateWait()
58
+ )
59
+ importer.init()
60
+ }
61
+ )
62
+ }
63
+ reader.readAsText(bibFile)
64
+ dialog.close()
65
+ }
66
+ },
67
+ {
68
+ type: "cancel"
69
+ }
70
+ ]
71
+ const dialog = new Dialog({
72
+ id: "importbibtex",
73
+ title: gettext("Import a bibliography"),
74
+ body: importBibFileTemplate(),
75
+ height: 200,
76
+ buttons
77
+ })
78
+ dialog.open()
79
+ document
80
+ .getElementById("bib-uploader")
81
+ .addEventListener(
82
+ "change",
83
+ () =>
84
+ (document.getElementById("import-bib-name").innerHTML =
85
+ document
86
+ .getElementById("bib-uploader")
87
+ .value.replace(/C:\\fakepath\\/i, ""))
88
+ )
89
+ document
90
+ .getElementById("import-bib-btn")
91
+ .addEventListener("click", () =>
92
+ document.getElementById("bib-uploader").click()
93
+ )
94
+ }
95
+ }
@@ -0,0 +1,2 @@
1
+ export {BibliographyFileImportDialog} from "./dialog"
2
+ export {BibliographyImporter} from "./bibliography_import"
@@ -0,0 +1,12 @@
1
+ /** a template for the bibliography file import dialog */
2
+ export const importBibFileTemplate = () =>
3
+ `<form id="import-bib-form" method="post" enctype="multipart/form-data" class="ajax-upload">
4
+ <input type="file" id="bib-uploader" name="bib" required />
5
+ <span id="import-bib-btn" class="fw-button fw-light fw-large">
6
+ ${gettext("Select a file")}
7
+ </span>
8
+ <label id="import-bib-name" class="ajax-upload-label"></label>
9
+ <div class="import-format-info" style="margin-top: 10px; font-size: 0.9em; color: #666;">
10
+ ${gettext("Supported formats: BibTeX/BibLaTeX, CSL-JSON, RIS, EndNote XML, EndNote Tagged, Citavi XML, Citavi JSON, NBIB/PubMed, ODT citations, DOCX citations")}
11
+ </div>
12
+ </form>`
package/src/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export {BibliographyOverview} from "./overview/index.js"
2
+ export {BibEntryForm} from "./form/index.js"
3
+ export {BibliographyDB} from "./database/index.js"
4
+ export {importBibFile} from "./import/index.js"
5
+ export {exportBibFile} from "./export/index.js"