decap-cms-widget-file 2.13.0-beta.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.
- package/CHANGELOG.md +463 -0
- package/LICENSE +22 -0
- package/README.md +9 -0
- package/dist/decap-cms-widget-file.js +8 -0
- package/dist/decap-cms-widget-file.js.LICENSE.txt +39 -0
- package/dist/decap-cms-widget-file.js.map +1 -0
- package/dist/esm/FilePreview.js +72 -0
- package/dist/esm/index.js +33 -0
- package/dist/esm/schema.js +14 -0
- package/dist/esm/withFileControl.js +412 -0
- package/package.json +40 -0
- package/src/FilePreview.js +46 -0
- package/src/index.js +18 -0
- package/src/schema.js +5 -0
- package/src/withFileControl.js +429 -0
- package/webpack.config.js +3 -0
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "decap-cms-widget-file",
|
|
3
|
+
"description": "Widget for uploading files in Decap CMS.",
|
|
4
|
+
"version": "2.13.0-beta.0",
|
|
5
|
+
"homepage": "https://www.decapcms.org/docs/widgets/#file",
|
|
6
|
+
"repository": "https://github.com/decaporg/decap-cms/tree/master/packages/decap-cms-widget-file",
|
|
7
|
+
"bugs": "https://github.com/decaporg/decap-cms/issues",
|
|
8
|
+
"module": "dist/esm/index.js",
|
|
9
|
+
"main": "dist/decap-cms-widget-file.js",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"decap-cms",
|
|
13
|
+
"widget",
|
|
14
|
+
"file",
|
|
15
|
+
"upload",
|
|
16
|
+
"file-upload"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"scripts": {
|
|
20
|
+
"develop": "yarn build:esm --watch",
|
|
21
|
+
"build": "cross-env NODE_ENV=production webpack",
|
|
22
|
+
"build:esm": "cross-env NODE_ENV=esm babel src --out-dir dist/esm --ignore \"**/__tests__\" --root-mode upward"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"array-move": "4.0.0",
|
|
26
|
+
"common-tags": "^1.8.0",
|
|
27
|
+
"react-sortable-hoc": "^2.0.0"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@emotion/core": "^10.0.35",
|
|
31
|
+
"@emotion/styled": "^10.0.27",
|
|
32
|
+
"decap-cms-ui-default": "^2.12.1",
|
|
33
|
+
"immutable": "^3.7.6",
|
|
34
|
+
"prop-types": "^15.7.2",
|
|
35
|
+
"react": "^16.8.4 || ^17.0.0",
|
|
36
|
+
"react-immutable-proptypes": "^2.1.0",
|
|
37
|
+
"uuid": "^3.3.2"
|
|
38
|
+
},
|
|
39
|
+
"gitHead": "1bdf716e5655bf088a343cd90210a2d361a9db52"
|
|
40
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from '@emotion/styled';
|
|
4
|
+
import { List } from 'immutable';
|
|
5
|
+
import { WidgetPreviewContainer } from 'decap-cms-ui-default';
|
|
6
|
+
|
|
7
|
+
const FileLink = styled(({ href, path }) => (
|
|
8
|
+
<a href={href} rel="noopener noreferrer" target="_blank">
|
|
9
|
+
{path}
|
|
10
|
+
</a>
|
|
11
|
+
))`
|
|
12
|
+
display: block;
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
function FileLinkList({ values, getAsset, field }) {
|
|
16
|
+
return (
|
|
17
|
+
<div>
|
|
18
|
+
{values.map(value => (
|
|
19
|
+
<FileLink key={value} path={value} href={getAsset(value, field)} />
|
|
20
|
+
))}
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function FileContent(props) {
|
|
26
|
+
const { value, getAsset, field } = props;
|
|
27
|
+
if (Array.isArray(value) || List.isList(value)) {
|
|
28
|
+
return <FileLinkList values={value} getAsset={getAsset} field={field} />;
|
|
29
|
+
}
|
|
30
|
+
return <FileLink key={value} path={value} href={getAsset(value, field)} />;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function FilePreview(props) {
|
|
34
|
+
return (
|
|
35
|
+
<WidgetPreviewContainer>
|
|
36
|
+
{props.value ? <FileContent {...props} /> : null}
|
|
37
|
+
</WidgetPreviewContainer>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
FilePreview.propTypes = {
|
|
42
|
+
getAsset: PropTypes.func.isRequired,
|
|
43
|
+
value: PropTypes.node,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default FilePreview;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import withFileControl from './withFileControl';
|
|
2
|
+
import previewComponent from './FilePreview';
|
|
3
|
+
import schema from './schema';
|
|
4
|
+
|
|
5
|
+
const controlComponent = withFileControl();
|
|
6
|
+
|
|
7
|
+
function Widget(opts = {}) {
|
|
8
|
+
return {
|
|
9
|
+
name: 'file',
|
|
10
|
+
controlComponent,
|
|
11
|
+
previewComponent,
|
|
12
|
+
schema,
|
|
13
|
+
...opts,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const DecapCmsWidgetFile = { Widget, controlComponent, previewComponent, withFileControl };
|
|
18
|
+
export default DecapCmsWidgetFile;
|
package/src/schema.js
ADDED
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
4
|
+
import styled from '@emotion/styled';
|
|
5
|
+
import { css } from '@emotion/core';
|
|
6
|
+
import { Map, List } from 'immutable';
|
|
7
|
+
import { once } from 'lodash';
|
|
8
|
+
import uuid from 'uuid/v4';
|
|
9
|
+
import { oneLine } from 'common-tags';
|
|
10
|
+
import {
|
|
11
|
+
lengths,
|
|
12
|
+
components,
|
|
13
|
+
buttons,
|
|
14
|
+
borders,
|
|
15
|
+
effects,
|
|
16
|
+
shadows,
|
|
17
|
+
IconButton,
|
|
18
|
+
} from 'decap-cms-ui-default';
|
|
19
|
+
import { basename } from 'decap-cms-lib-util';
|
|
20
|
+
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
|
|
21
|
+
import { arrayMoveImmutable as arrayMove } from 'array-move';
|
|
22
|
+
|
|
23
|
+
const MAX_DISPLAY_LENGTH = 50;
|
|
24
|
+
|
|
25
|
+
const ImageWrapper = styled.div`
|
|
26
|
+
flex-basis: 155px;
|
|
27
|
+
width: 155px;
|
|
28
|
+
height: 100px;
|
|
29
|
+
margin-right: 20px;
|
|
30
|
+
margin-bottom: 20px;
|
|
31
|
+
border: ${borders.textField};
|
|
32
|
+
border-radius: ${lengths.borderRadius};
|
|
33
|
+
overflow: hidden;
|
|
34
|
+
${effects.checkerboard};
|
|
35
|
+
${shadows.inset};
|
|
36
|
+
cursor: ${props => (props.sortable ? 'pointer' : 'auto')};
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
const SortableImageButtonsWrapper = styled.div`
|
|
40
|
+
display: flex;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
column-gap: 10px;
|
|
43
|
+
margin-right: 20px;
|
|
44
|
+
margin-top: -10px;
|
|
45
|
+
margin-bottom: 10px;
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
const StyledImage = styled.img`
|
|
49
|
+
width: 100%;
|
|
50
|
+
height: 100%;
|
|
51
|
+
object-fit: contain;
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
function Image(props) {
|
|
55
|
+
return <StyledImage role="presentation" {...props} />;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function SortableImageButtons({ onRemove, onReplace }) {
|
|
59
|
+
return (
|
|
60
|
+
<SortableImageButtonsWrapper>
|
|
61
|
+
<IconButton size="small" type="media" onClick={onReplace}></IconButton>
|
|
62
|
+
<IconButton size="small" type="close" onClick={onRemove}></IconButton>
|
|
63
|
+
</SortableImageButtonsWrapper>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const SortableImage = SortableElement(({ itemValue, getAsset, field, onRemove, onReplace }) => {
|
|
68
|
+
return (
|
|
69
|
+
<div>
|
|
70
|
+
<ImageWrapper sortable>
|
|
71
|
+
<Image src={getAsset(itemValue, field) || ''} />
|
|
72
|
+
</ImageWrapper>
|
|
73
|
+
<SortableImageButtons
|
|
74
|
+
item={itemValue}
|
|
75
|
+
onRemove={onRemove}
|
|
76
|
+
onReplace={onReplace}
|
|
77
|
+
></SortableImageButtons>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const SortableMultiImageWrapper = SortableContainer(
|
|
83
|
+
({ items, getAsset, field, onRemoveOne, onReplaceOne }) => {
|
|
84
|
+
return (
|
|
85
|
+
<div
|
|
86
|
+
css={css`
|
|
87
|
+
display: flex;
|
|
88
|
+
flex-wrap: wrap;
|
|
89
|
+
`}
|
|
90
|
+
>
|
|
91
|
+
{items.map((itemValue, index) => (
|
|
92
|
+
<SortableImage
|
|
93
|
+
key={`item-${itemValue}`}
|
|
94
|
+
index={index}
|
|
95
|
+
itemValue={itemValue}
|
|
96
|
+
getAsset={getAsset}
|
|
97
|
+
field={field}
|
|
98
|
+
onRemove={onRemoveOne(index)}
|
|
99
|
+
onReplace={onReplaceOne(index)}
|
|
100
|
+
/>
|
|
101
|
+
))}
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
},
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const FileLink = styled.a`
|
|
108
|
+
margin-bottom: 20px;
|
|
109
|
+
font-weight: normal;
|
|
110
|
+
color: inherit;
|
|
111
|
+
|
|
112
|
+
&:hover,
|
|
113
|
+
&:active,
|
|
114
|
+
&:focus {
|
|
115
|
+
text-decoration: underline;
|
|
116
|
+
}
|
|
117
|
+
`;
|
|
118
|
+
|
|
119
|
+
const FileLinks = styled.div`
|
|
120
|
+
margin-bottom: 12px;
|
|
121
|
+
`;
|
|
122
|
+
|
|
123
|
+
const FileLinkList = styled.ul`
|
|
124
|
+
list-style-type: none;
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
const FileWidgetButton = styled.button`
|
|
128
|
+
${buttons.button};
|
|
129
|
+
${components.badge};
|
|
130
|
+
margin-bottom: 12px;
|
|
131
|
+
`;
|
|
132
|
+
|
|
133
|
+
const FileWidgetButtonRemove = styled.button`
|
|
134
|
+
${buttons.button};
|
|
135
|
+
${components.badgeDanger};
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
function isMultiple(value) {
|
|
139
|
+
return Array.isArray(value) || List.isList(value);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function sizeOfValue(value) {
|
|
143
|
+
if (Array.isArray(value)) {
|
|
144
|
+
return value.length;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (List.isList(value)) {
|
|
148
|
+
return value.size;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return value ? 1 : 0;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function valueListToArray(value) {
|
|
155
|
+
return List.isList(value) ? value.toArray() : value;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const warnDeprecatedOptions = once(field =>
|
|
159
|
+
console.warn(oneLine`
|
|
160
|
+
Decap CMS config: ${field.get('name')} field: property "options" has been deprecated for the
|
|
161
|
+
${field.get('widget')} widget and will be removed in the next major release. Rather than
|
|
162
|
+
\`field.options.media_library\`, apply media library options for this widget under
|
|
163
|
+
\`field.media_library\`.
|
|
164
|
+
`),
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
export default function withFileControl({ forImage } = {}) {
|
|
168
|
+
return class FileControl extends React.Component {
|
|
169
|
+
static propTypes = {
|
|
170
|
+
field: PropTypes.object.isRequired,
|
|
171
|
+
getAsset: PropTypes.func.isRequired,
|
|
172
|
+
mediaPaths: ImmutablePropTypes.map.isRequired,
|
|
173
|
+
onAddAsset: PropTypes.func.isRequired,
|
|
174
|
+
onChange: PropTypes.func.isRequired,
|
|
175
|
+
onRemoveInsertedMedia: PropTypes.func.isRequired,
|
|
176
|
+
onOpenMediaLibrary: PropTypes.func.isRequired,
|
|
177
|
+
onClearMediaControl: PropTypes.func.isRequired,
|
|
178
|
+
onRemoveMediaControl: PropTypes.func.isRequired,
|
|
179
|
+
classNameWrapper: PropTypes.string.isRequired,
|
|
180
|
+
value: PropTypes.oneOfType([
|
|
181
|
+
PropTypes.string,
|
|
182
|
+
PropTypes.arrayOf(PropTypes.string),
|
|
183
|
+
ImmutablePropTypes.listOf(PropTypes.string),
|
|
184
|
+
]),
|
|
185
|
+
t: PropTypes.func.isRequired,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
static defaultProps = {
|
|
189
|
+
value: '',
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
constructor(props) {
|
|
193
|
+
super(props);
|
|
194
|
+
this.controlID = uuid();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
shouldComponentUpdate(nextProps) {
|
|
198
|
+
/**
|
|
199
|
+
* Always update if the value or getAsset changes.
|
|
200
|
+
*/
|
|
201
|
+
if (this.props.value !== nextProps.value || this.props.getAsset !== nextProps.getAsset) {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* If there is a media path for this control in the state object, and that
|
|
207
|
+
* path is different than the value in `nextProps`, update.
|
|
208
|
+
*/
|
|
209
|
+
const mediaPath = nextProps.mediaPaths.get(this.controlID);
|
|
210
|
+
if (mediaPath && nextProps.value !== mediaPath) {
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
componentDidUpdate() {
|
|
218
|
+
const { mediaPaths, value, onRemoveInsertedMedia, onChange } = this.props;
|
|
219
|
+
const mediaPath = mediaPaths.get(this.controlID);
|
|
220
|
+
if (mediaPath && mediaPath !== value) {
|
|
221
|
+
onChange(mediaPath);
|
|
222
|
+
} else if (mediaPath && mediaPath === value) {
|
|
223
|
+
onRemoveInsertedMedia(this.controlID);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
componentWillUnmount() {
|
|
228
|
+
this.props.onRemoveMediaControl(this.controlID);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
handleChange = e => {
|
|
232
|
+
const { field, onOpenMediaLibrary, value } = this.props;
|
|
233
|
+
e.preventDefault();
|
|
234
|
+
const mediaLibraryFieldOptions = this.getMediaLibraryFieldOptions();
|
|
235
|
+
|
|
236
|
+
return onOpenMediaLibrary({
|
|
237
|
+
controlID: this.controlID,
|
|
238
|
+
forImage,
|
|
239
|
+
privateUpload: field.get('private'),
|
|
240
|
+
value: valueListToArray(value),
|
|
241
|
+
allowMultiple: !!mediaLibraryFieldOptions.get('allow_multiple', true),
|
|
242
|
+
config: mediaLibraryFieldOptions.get('config'),
|
|
243
|
+
field,
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
handleUrl = subject => e => {
|
|
248
|
+
e.preventDefault();
|
|
249
|
+
|
|
250
|
+
const url = window.prompt(this.props.t(`editor.editorWidgets.${subject}.promptUrl`));
|
|
251
|
+
|
|
252
|
+
return this.props.onChange(url);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
handleRemove = e => {
|
|
256
|
+
e.preventDefault();
|
|
257
|
+
this.props.onClearMediaControl(this.controlID);
|
|
258
|
+
return this.props.onChange('');
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
onRemoveOne = index => () => {
|
|
262
|
+
const { value } = this.props;
|
|
263
|
+
value.splice(index, 1);
|
|
264
|
+
return this.props.onChange(sizeOfValue(value) > 0 ? [...value] : null);
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
onReplaceOne = index => () => {
|
|
268
|
+
const { field, onOpenMediaLibrary, value } = this.props;
|
|
269
|
+
const mediaLibraryFieldOptions = this.getMediaLibraryFieldOptions();
|
|
270
|
+
|
|
271
|
+
return onOpenMediaLibrary({
|
|
272
|
+
controlID: this.controlID,
|
|
273
|
+
forImage,
|
|
274
|
+
privateUpload: field.get('private'),
|
|
275
|
+
value: valueListToArray(value),
|
|
276
|
+
replaceIndex: index,
|
|
277
|
+
allowMultiple: false,
|
|
278
|
+
config: mediaLibraryFieldOptions.get('config'),
|
|
279
|
+
field,
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
getMediaLibraryFieldOptions = () => {
|
|
284
|
+
const { field } = this.props;
|
|
285
|
+
|
|
286
|
+
if (field.hasIn(['options', 'media_library'])) {
|
|
287
|
+
warnDeprecatedOptions(field);
|
|
288
|
+
return field.getIn(['options', 'media_library'], Map());
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return field.get('media_library', Map());
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
allowsMultiple = () => {
|
|
295
|
+
const mediaLibraryFieldOptions = this.getMediaLibraryFieldOptions();
|
|
296
|
+
return (
|
|
297
|
+
mediaLibraryFieldOptions.get('config', false) &&
|
|
298
|
+
mediaLibraryFieldOptions.get('config').get('multiple', false)
|
|
299
|
+
);
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
onSortEnd = ({ oldIndex, newIndex }) => {
|
|
303
|
+
const { value } = this.props;
|
|
304
|
+
const newValue = arrayMove(value, oldIndex, newIndex);
|
|
305
|
+
return this.props.onChange(newValue);
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
getValidateValue = () => {
|
|
309
|
+
const { value } = this.props;
|
|
310
|
+
if (value) {
|
|
311
|
+
return isMultiple(value) ? value.map(v => basename(v)) : basename(value);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return value;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
renderFileLink = value => {
|
|
318
|
+
const size = MAX_DISPLAY_LENGTH;
|
|
319
|
+
if (!value || value.length <= size) {
|
|
320
|
+
return value;
|
|
321
|
+
}
|
|
322
|
+
const text = `${value.slice(0, size / 2)}\u2026${value.slice(-(size / 2) + 1)}`;
|
|
323
|
+
return (
|
|
324
|
+
<FileLink href={value} rel="noopener" target="_blank">
|
|
325
|
+
{text}
|
|
326
|
+
</FileLink>
|
|
327
|
+
);
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
renderFileLinks = () => {
|
|
331
|
+
const { value } = this.props;
|
|
332
|
+
|
|
333
|
+
if (isMultiple(value)) {
|
|
334
|
+
return (
|
|
335
|
+
<FileLinks>
|
|
336
|
+
<FileLinkList>
|
|
337
|
+
{value.map(val => (
|
|
338
|
+
<li key={val}>{this.renderFileLink(val)}</li>
|
|
339
|
+
))}
|
|
340
|
+
</FileLinkList>
|
|
341
|
+
</FileLinks>
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
return <FileLinks>{this.renderFileLink(value)}</FileLinks>;
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
renderImages = () => {
|
|
348
|
+
const { getAsset, value, field } = this.props;
|
|
349
|
+
|
|
350
|
+
if (isMultiple(value)) {
|
|
351
|
+
return (
|
|
352
|
+
<SortableMultiImageWrapper
|
|
353
|
+
items={value}
|
|
354
|
+
onSortEnd={this.onSortEnd}
|
|
355
|
+
onRemoveOne={this.onRemoveOne}
|
|
356
|
+
onReplaceOne={this.onReplaceOne}
|
|
357
|
+
distance={4}
|
|
358
|
+
getAsset={getAsset}
|
|
359
|
+
field={field}
|
|
360
|
+
axis="xy"
|
|
361
|
+
lockToContainerEdges={true}
|
|
362
|
+
></SortableMultiImageWrapper>
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const src = getAsset(value, field);
|
|
367
|
+
return (
|
|
368
|
+
<ImageWrapper>
|
|
369
|
+
<Image src={src || ''} />
|
|
370
|
+
</ImageWrapper>
|
|
371
|
+
);
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
renderSelection = subject => {
|
|
375
|
+
const { t, field } = this.props;
|
|
376
|
+
const allowsMultiple = this.allowsMultiple();
|
|
377
|
+
return (
|
|
378
|
+
<div>
|
|
379
|
+
{forImage ? this.renderImages() : null}
|
|
380
|
+
<div>
|
|
381
|
+
{forImage ? null : this.renderFileLinks()}
|
|
382
|
+
<FileWidgetButton onClick={this.handleChange}>
|
|
383
|
+
{t(
|
|
384
|
+
`editor.editorWidgets.${subject}.${
|
|
385
|
+
this.allowsMultiple() ? 'addMore' : 'chooseDifferent'
|
|
386
|
+
}`,
|
|
387
|
+
)}
|
|
388
|
+
</FileWidgetButton>
|
|
389
|
+
{field.get('choose_url', true) && !this.allowsMultiple() ? (
|
|
390
|
+
<FileWidgetButton onClick={this.handleUrl(subject)}>
|
|
391
|
+
{t(`editor.editorWidgets.${subject}.replaceUrl`)}
|
|
392
|
+
</FileWidgetButton>
|
|
393
|
+
) : null}
|
|
394
|
+
<FileWidgetButtonRemove onClick={this.handleRemove}>
|
|
395
|
+
{t(`editor.editorWidgets.${subject}.remove${allowsMultiple ? 'All' : ''}`)}
|
|
396
|
+
</FileWidgetButtonRemove>
|
|
397
|
+
</div>
|
|
398
|
+
</div>
|
|
399
|
+
);
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
renderNoSelection = subject => {
|
|
403
|
+
const { t, field } = this.props;
|
|
404
|
+
return (
|
|
405
|
+
<>
|
|
406
|
+
<FileWidgetButton onClick={this.handleChange}>
|
|
407
|
+
{t(`editor.editorWidgets.${subject}.choose${this.allowsMultiple() ? 'Multiple' : ''}`)}
|
|
408
|
+
</FileWidgetButton>
|
|
409
|
+
{field.get('choose_url', true) ? (
|
|
410
|
+
<FileWidgetButton onClick={this.handleUrl(subject)}>
|
|
411
|
+
{t(`editor.editorWidgets.${subject}.chooseUrl`)}
|
|
412
|
+
</FileWidgetButton>
|
|
413
|
+
) : null}
|
|
414
|
+
</>
|
|
415
|
+
);
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
render() {
|
|
419
|
+
const { value, classNameWrapper } = this.props;
|
|
420
|
+
const subject = forImage ? 'image' : 'file';
|
|
421
|
+
|
|
422
|
+
return (
|
|
423
|
+
<div className={classNameWrapper}>
|
|
424
|
+
<span>{value ? this.renderSelection(subject) : this.renderNoSelection(subject)}</span>
|
|
425
|
+
</div>
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
}
|