@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.
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/main.css +26 -0
- package/package.json +6 -3
- package/src/components/BibliographyList.css +3 -0
- package/src/components/BibliographyList.js +286 -0
- package/src/components/BibliographyModal.js +125 -0
- package/src/components/BibliographySearchInput.css +13 -0
- package/src/components/BibliographySearchInput.js +86 -0
- package/src/components/Citation.js +78 -0
- package/src/components/CreatorField.css +11 -0
- package/src/components/CreatorField.js +137 -0
- package/src/components/Creators.js +97 -0
- package/src/components/List.js +7 -2
- package/src/components/SortSelector.js +91 -0
- package/src/components/StyleSelector.js +75 -0
- package/src/constants/Sort.js +2 -0
- package/src/context/ZoteroTranslateContext.js +7 -0
- package/src/i18n/en.json +29 -0
- package/src/index.js +1 -0
- package/src/resources/BibliographyTypes.json +117 -0
- package/src/resources/CitationStyles.json +25 -0
- package/src/utils/Bibliography.js +191 -0
- package/types/components/BibliographyList.js.flow +286 -0
- package/types/components/BibliographyModal.js.flow +125 -0
- package/types/components/BibliographySearchInput.js.flow +86 -0
- package/types/components/Citation.js.flow +78 -0
- package/types/components/CreatorField.js.flow +137 -0
- package/types/components/Creators.js.flow +97 -0
- package/types/components/List.js.flow +7 -2
- package/types/components/SortSelector.js.flow +91 -0
- package/types/components/StyleSelector.js.flow +75 -0
- package/types/constants/Sort.js.flow +2 -0
- package/types/context/ZoteroTranslateContext.js.flow +7 -0
- package/types/index.js.flow +1 -0
- 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
|
+
};
|