@performant-software/semantic-components 1.0.1 → 1.0.2-beta.1

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 (36) hide show
  1. package/build/index.js +1 -1
  2. package/build/index.js.map +1 -1
  3. package/build/main.css +26 -0
  4. package/package.json +6 -3
  5. package/src/components/BibliographyList.css +3 -0
  6. package/src/components/BibliographyList.js +286 -0
  7. package/src/components/BibliographyModal.js +125 -0
  8. package/src/components/BibliographySearchInput.css +13 -0
  9. package/src/components/BibliographySearchInput.js +86 -0
  10. package/src/components/Citation.js +78 -0
  11. package/src/components/CreatorField.css +11 -0
  12. package/src/components/CreatorField.js +137 -0
  13. package/src/components/Creators.js +97 -0
  14. package/src/components/List.js +7 -2
  15. package/src/components/SortSelector.js +91 -0
  16. package/src/components/StyleSelector.js +75 -0
  17. package/src/constants/Sort.js +2 -0
  18. package/src/context/ZoteroTranslateContext.js +7 -0
  19. package/src/i18n/en.json +29 -0
  20. package/src/index.js +1 -0
  21. package/src/resources/BibliographyTypes.json +117 -0
  22. package/src/resources/CitationStyles.json +25 -0
  23. package/src/utils/Bibliography.js +191 -0
  24. package/types/components/BibliographyList.js.flow +286 -0
  25. package/types/components/BibliographyModal.js.flow +125 -0
  26. package/types/components/BibliographySearchInput.js.flow +86 -0
  27. package/types/components/Citation.js.flow +78 -0
  28. package/types/components/CreatorField.js.flow +137 -0
  29. package/types/components/Creators.js.flow +97 -0
  30. package/types/components/List.js.flow +7 -2
  31. package/types/components/SortSelector.js.flow +91 -0
  32. package/types/components/StyleSelector.js.flow +75 -0
  33. package/types/constants/Sort.js.flow +2 -0
  34. package/types/context/ZoteroTranslateContext.js.flow +7 -0
  35. package/types/index.js.flow +1 -0
  36. package/types/utils/Bibliography.js.flow +191 -0
@@ -0,0 +1,191 @@
1
+ // @flow
2
+
3
+ import _ from 'underscore';
4
+ import api from 'zotero-api-client';
5
+ import BibliographyTypes from '../resources/BibliographyTypes.json';
6
+
7
+ const hiddenFields = [
8
+ 'mimeType',
9
+ 'linkMode',
10
+ 'charset',
11
+ 'md5',
12
+ 'mtime',
13
+ 'version',
14
+ 'key',
15
+ 'collections',
16
+ 'relations',
17
+ 'parentItem',
18
+ 'contentType',
19
+ 'filename',
20
+ 'tags',
21
+ 'creator',
22
+ 'abstractNote',
23
+ 'notes',
24
+ 'rights',
25
+ 'extra'
26
+ ];
27
+
28
+ const noEditFields = [
29
+ 'modified',
30
+ 'filename',
31
+ 'dateAdded',
32
+ 'dateModified'
33
+ ];
34
+
35
+ /**
36
+ * Checks the API cache for the passed key.
37
+ *
38
+ * @param key
39
+ *
40
+ * @returns {boolean}
41
+ */
42
+ const apiCheckCache = (key) => {
43
+ let cacheTimes = {};
44
+ let okToUseCache = false;
45
+
46
+ try {
47
+ cacheTimes = JSON.parse(localStorage.getItem('zotero-bib-api-cache')) || {};
48
+ } catch (e) {
49
+ // ignore
50
+ }
51
+
52
+ if (key in cacheTimes) {
53
+ okToUseCache = (Date.now() - cacheTimes[key]) < 24 * 60 * 60 * 1000;
54
+ }
55
+
56
+ if (!okToUseCache) {
57
+ cacheTimes[key] = Date.now();
58
+ localStorage.setItem('zotero-bib-api-cache', JSON.stringify(cacheTimes));
59
+ }
60
+
61
+ return okToUseCache;
62
+ };
63
+
64
+ /**
65
+ * Returns the fields for the passed item. This function was largely copied directly from zotero/bib-web.
66
+ *
67
+ * @param item
68
+ * @param itemTypeFields
69
+ * @param itemTypes
70
+ *
71
+ * @returns {{item, fields: Array<T|unknown>}|{item, fields: *[]}}
72
+ */
73
+ const getFieldsAndItem = (item, itemTypeFields, itemTypes) => {
74
+ if (!item || !itemTypeFields || !itemTypes) {
75
+ return { item, fields: [] };
76
+ }
77
+
78
+ const titleField = (item.itemType in BibliographyTypes && BibliographyTypes[item.itemType]?.title) || 'title';
79
+ let fields = [
80
+ { field: 'itemType', localized: 'Item Type' },
81
+ itemTypeFields.find((itf) => itf.field === titleField),
82
+ { field: 'creators', localized: 'Creators' },
83
+ ...itemTypeFields.filter((itf) => itf.field !== titleField)
84
+ ]
85
+ .filter((f) => f && !hiddenFields.includes(f.field))
86
+ .concat([
87
+ itemTypeFields.find((itf) => itf.field === 'abstractNote'),
88
+ itemTypeFields.find((itf) => itf.field === 'extra'),
89
+ ]);
90
+
91
+ // Add Original Date field to book and bookSection #188
92
+ if (['book', 'bookSection'].includes(item.itemType)) {
93
+ const dateIndex = fields.findIndex((f) => f.field === 'date');
94
+ fields.splice(dateIndex + 1, 0, { field: 'original-date', localized: 'Original Date' });
95
+ const matches = 'extra' in item && item.extra.match(/^original-date:\s*(.*?)$/);
96
+ if (matches) {
97
+ _.extend(item, {
98
+ 'original-date': matches[1],
99
+ extra: item.extra.replace(/^original-date:\s*.*?$/, '')
100
+ });
101
+ }
102
+ }
103
+
104
+ // Add Publisher to webpage
105
+ if (['webpage'].includes(item.itemType)) {
106
+ const beforeIndex = fields.findIndex((f) => f.field === 'websiteType');
107
+ fields.splice(beforeIndex + 1, 0, { field: 'publisher', localized: 'Publisher' });
108
+ const matches = 'extra' in item && item.extra.match(/^publisher:\s*(.*?)$/i);
109
+ if (matches) {
110
+ _.extend(item, {
111
+ publisher: matches[1],
112
+ extra: item.extra.replace(/^publisher:\s*.*?$/, '')
113
+ });
114
+ }
115
+ }
116
+
117
+ fields = fields.map((f) => ({
118
+ options: f.field === 'itemType' ? itemTypes : null,
119
+ key: f.field,
120
+ label: f.localized,
121
+ readonly: noEditFields.includes(f.field),
122
+ processing: false,
123
+ value: f.field in item ? item[f.field] : null
124
+ }));
125
+
126
+ return { item, fields };
127
+ };
128
+
129
+ /**
130
+ * Calls the Zotero API to get the fields for the passed item type.
131
+ *
132
+ * @param itemType
133
+ * @param retryOnFailure
134
+ *
135
+ * @returns {Promise<{itemTypes, itemTypeFields, itemTypeCreatorTypes}|*>}
136
+ */
137
+ const getItemTypeMeta = async (itemType: string, retryOnFailure: boolean = true): any => {
138
+ let itemTypes;
139
+ let itemTypeFields;
140
+ let itemTypeCreatorTypes;
141
+
142
+ try {
143
+ const [itemTypeR, itemTypeFieldsR, creatorTypesR] = await Promise.all([
144
+ api()
145
+ .itemTypes()
146
+ .get({ cache: apiCheckCache('itemTypes') ? 'force-cache' : 'default' }),
147
+ api()
148
+ .itemTypeFields(itemType)
149
+ .get({ cache: apiCheckCache(`itemTypeFields-${itemType}`) ? 'force-cache' : 'default' }),
150
+ api()
151
+ .itemTypeCreatorTypes(itemType)
152
+ .get({ cache: apiCheckCache(`itemTypeCreatorTypes-${itemType}`) ? 'force-cache' : 'default' })
153
+ ]);
154
+
155
+ itemTypes = itemTypeR.getData();
156
+ itemTypeFields = itemTypeFieldsR.getData();
157
+ itemTypeCreatorTypes = creatorTypesR.getData();
158
+ } catch (e) {
159
+ // Clear the api cache
160
+ localStorage.removeItem('zotero-bib-api-cache');
161
+
162
+ // Call again if we're re-trying on failure
163
+ if (retryOnFailure) {
164
+ return getItemTypeMeta(itemType, false);
165
+ }
166
+
167
+ // If all else fails, throw an exception
168
+ throw e;
169
+ }
170
+
171
+ return {
172
+ itemTypes,
173
+ itemTypeFields,
174
+ itemTypeCreatorTypes
175
+ };
176
+ };
177
+
178
+ /**
179
+ * Returns true if the passed identifier matches a URL pattern.
180
+ *
181
+ * @param id
182
+ *
183
+ * @returns {boolean}
184
+ */
185
+ const isUrl = (id) => !!id.match(/^(https?:\/\/)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b(\S*)$/i);
186
+
187
+ export default {
188
+ getFieldsAndItem,
189
+ getItemTypeMeta,
190
+ isUrl
191
+ };