@pie-lib/editable-html 10.0.0-beta.4 → 10.0.0-beta.6
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 +255 -152
- package/lib/components.js +15 -39
- package/lib/components.js.map +1 -1
- package/lib/editor.js +200 -356
- package/lib/editor.js.map +1 -1
- package/lib/index.js +25 -49
- package/lib/index.js.map +1 -1
- package/lib/new-serialization.js +31 -71
- package/lib/new-serialization.js.map +1 -1
- package/lib/parse-html.js +7 -6
- package/lib/parse-html.js.map +1 -1
- package/lib/plugins/characters/custom-popper.js +3 -13
- package/lib/plugins/characters/custom-popper.js.map +1 -1
- package/lib/plugins/characters/index.js +20 -59
- package/lib/plugins/characters/index.js.map +1 -1
- package/lib/plugins/characters/utils.js +1 -1
- package/lib/plugins/characters/utils.js.map +1 -1
- package/lib/plugins/hotKeys/index.js +9 -16
- package/lib/plugins/hotKeys/index.js.map +1 -1
- package/lib/plugins/image/alt-dialog.js +6 -27
- package/lib/plugins/image/alt-dialog.js.map +1 -1
- package/lib/plugins/image/component.js +42 -99
- package/lib/plugins/image/component.js.map +1 -1
- package/lib/plugins/image/image-toolbar.js +14 -50
- package/lib/plugins/image/image-toolbar.js.map +1 -1
- package/lib/plugins/image/index.js +16 -59
- package/lib/plugins/image/index.js.map +1 -1
- package/lib/plugins/image/insert-image-handler.js +13 -25
- package/lib/plugins/image/insert-image-handler.js.map +1 -1
- package/lib/plugins/index.js +6 -36
- package/lib/plugins/index.js.map +1 -1
- package/lib/plugins/list/index.js +11 -46
- package/lib/plugins/list/index.js.map +1 -1
- package/lib/plugins/math/index.js +89 -93
- package/lib/plugins/math/index.js.map +1 -1
- package/lib/plugins/media/index.js +32 -109
- package/lib/plugins/media/index.js.map +1 -1
- package/lib/plugins/media/media-dialog.js +107 -195
- package/lib/plugins/media/media-dialog.js.map +1 -1
- package/lib/plugins/media/media-toolbar.js +7 -27
- package/lib/plugins/media/media-toolbar.js.map +1 -1
- package/lib/plugins/media/media-wrapper.js +9 -14
- package/lib/plugins/media/media-wrapper.js.map +1 -1
- package/lib/plugins/respArea/drag-in-the-blank/choice.js +13 -53
- package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +1 -1
- package/lib/plugins/respArea/drag-in-the-blank/index.js +6 -20
- package/lib/plugins/respArea/drag-in-the-blank/index.js.map +1 -1
- package/lib/plugins/respArea/explicit-constructed-response/index.js +5 -10
- package/lib/plugins/respArea/explicit-constructed-response/index.js.map +1 -1
- package/lib/plugins/respArea/icons/index.js +16 -31
- package/lib/plugins/respArea/icons/index.js.map +1 -1
- package/lib/plugins/respArea/index.js +7 -54
- package/lib/plugins/respArea/index.js.map +1 -1
- package/lib/plugins/respArea/inline-dropdown/index.js +3 -10
- package/lib/plugins/respArea/inline-dropdown/index.js.map +1 -1
- package/lib/plugins/respArea/utils.js +6 -21
- package/lib/plugins/respArea/utils.js.map +1 -1
- package/lib/plugins/table/icons/index.js +1 -8
- package/lib/plugins/table/icons/index.js.map +1 -1
- package/lib/plugins/table/index.js +54 -187
- package/lib/plugins/table/index.js.map +1 -1
- package/lib/plugins/table/table-toolbar.js +12 -44
- package/lib/plugins/table/table-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/default-toolbar.js +17 -46
- package/lib/plugins/toolbar/default-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/done-button.js +2 -10
- package/lib/plugins/toolbar/done-button.js.map +1 -1
- package/lib/plugins/toolbar/editor-and-toolbar.js +134 -144
- package/lib/plugins/toolbar/editor-and-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/index.js +2 -6
- package/lib/plugins/toolbar/index.js.map +1 -1
- package/lib/plugins/toolbar/toolbar-buttons.js +9 -40
- package/lib/plugins/toolbar/toolbar-buttons.js.map +1 -1
- package/lib/plugins/toolbar/toolbar.js +29 -83
- package/lib/plugins/toolbar/toolbar.js.map +1 -1
- package/lib/plugins/utils.js +8 -30
- package/lib/plugins/utils.js.map +1 -1
- package/lib/serialization.js +11 -69
- package/lib/serialization.js.map +1 -1
- package/lib/test-serializer.js +5 -56
- package/lib/test-serializer.js.map +1 -1
- package/lib/theme.js +1 -1
- package/lib/theme.js.map +1 -1
- package/package.json +7 -7
- package/playground/image/data.js +20 -20
- package/playground/image/index.html +20 -22
- package/playground/image/index.jsx +10 -12
- package/playground/index.html +23 -25
- package/playground/mathquill/index.html +20 -23
- package/playground/mathquill/index.jsx +22 -18
- package/playground/prod-test/index.html +20 -24
- package/playground/prod-test/index.jsx +3 -5
- package/playground/schema-override/data.js +10 -10
- package/playground/schema-override/image-plugin.jsx +4 -3
- package/playground/schema-override/index.html +19 -21
- package/playground/schema-override/index.jsx +14 -13
- package/playground/serialization/data.js +10 -10
- package/playground/serialization/image-plugin.jsx +4 -3
- package/playground/serialization/index.html +20 -22
- package/playground/table-examples.html +8 -5
- package/playground/webpack.config.js +10 -10
- package/src/editor.jsx +108 -104
- package/src/index.jsx +20 -13
- package/src/new-serialization.jsx +30 -11
- package/src/parse-html.js +1 -1
- package/src/plugins/characters/custom-popper.js +7 -7
- package/src/plugins/characters/index.jsx +34 -23
- package/src/plugins/characters/utils.js +81 -81
- package/src/plugins/image/alt-dialog.jsx +5 -4
- package/src/plugins/image/component.jsx +47 -44
- package/src/plugins/image/image-toolbar.jsx +19 -27
- package/src/plugins/image/index.jsx +24 -18
- package/src/plugins/image/insert-image-handler.js +9 -0
- package/src/plugins/index.jsx +7 -9
- package/src/plugins/list/index.jsx +7 -7
- package/src/plugins/math/index.jsx +71 -28
- package/src/plugins/media/index.jsx +7 -7
- package/src/plugins/media/media-dialog.js +63 -89
- package/src/plugins/media/media-toolbar.jsx +8 -8
- package/src/plugins/media/media-wrapper.jsx +8 -5
- package/src/plugins/respArea/drag-in-the-blank/choice.jsx +19 -21
- package/src/plugins/respArea/drag-in-the-blank/index.jsx +4 -4
- package/src/plugins/respArea/explicit-constructed-response/index.jsx +5 -4
- package/src/plugins/respArea/icons/index.jsx +14 -11
- package/src/plugins/respArea/index.jsx +9 -15
- package/src/plugins/respArea/inline-dropdown/index.jsx +6 -6
- package/src/plugins/respArea/utils.jsx +7 -3
- package/src/plugins/table/icons/index.jsx +11 -17
- package/src/plugins/table/index.jsx +14 -10
- package/src/plugins/table/table-toolbar.jsx +6 -6
- package/src/plugins/toolbar/default-toolbar.jsx +9 -9
- package/src/plugins/toolbar/done-button.jsx +4 -4
- package/src/plugins/toolbar/editor-and-toolbar.jsx +36 -33
- package/src/plugins/toolbar/index.jsx +3 -2
- package/src/plugins/toolbar/toolbar-buttons.jsx +11 -11
- package/src/plugins/toolbar/toolbar.jsx +6 -1
- package/src/plugins/utils.js +2 -2
- package/src/serialization.jsx +34 -32
- package/src/test-serializer.js +2 -9
- package/lib/old-serialization.js +0 -330
- package/lib/slate-editor.js +0 -302
- package/src/test-serializer.js.rej +0 -20
- package/yarn-error.log +0 -18318
|
@@ -4,7 +4,7 @@ import { ReactEditor } from 'slate-react';
|
|
|
4
4
|
import { jsx } from 'slate-hyperscript';
|
|
5
5
|
import Functions from '@material-ui/icons/Functions';
|
|
6
6
|
import { MathPreview, MathToolbar } from '@pie-lib/math-toolbar';
|
|
7
|
-
import { wrapMath, unWrapMath } from '@pie-lib/math-rendering';
|
|
7
|
+
import { wrapMath, unWrapMath, mmlToLatex, renderMath } from '@pie-lib/math-rendering';
|
|
8
8
|
import debug from 'debug';
|
|
9
9
|
import PropTypes from 'prop-types';
|
|
10
10
|
import isEqual from 'lodash/isEqual';
|
|
@@ -15,22 +15,23 @@ const log = debug('@pie-lib:editable-html:plugins:math');
|
|
|
15
15
|
const TEXT_NODE = 3;
|
|
16
16
|
|
|
17
17
|
function generateAdditionalKeys(keyData = []) {
|
|
18
|
-
return keyData.map(key => ({
|
|
18
|
+
return keyData.map((key) => ({
|
|
19
19
|
name: key,
|
|
20
20
|
latex: key,
|
|
21
21
|
write: key,
|
|
22
|
-
label: key
|
|
22
|
+
label: key,
|
|
23
23
|
}));
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
// eslint-disable-next-line react/display-name
|
|
26
27
|
export const CustomToolbarComp = React.memo(
|
|
27
|
-
props => {
|
|
28
|
+
(props) => {
|
|
28
29
|
const { node, nodePath, onFocus, onBlur, onClick, editor } = props;
|
|
29
30
|
const { pluginProps } = props || {};
|
|
30
31
|
const { math } = pluginProps || {};
|
|
31
32
|
const { keypadMode, customKeys, controlledKeypadMode = true } = math || {};
|
|
32
33
|
|
|
33
|
-
const onDone = latex => {
|
|
34
|
+
const onDone = (latex) => {
|
|
34
35
|
const update = {
|
|
35
36
|
...node.data,
|
|
36
37
|
latex
|
|
@@ -67,16 +68,14 @@ export const CustomToolbarComp = React.memo(
|
|
|
67
68
|
const { node, pluginProps: { math: { keypadMode, controlledKeypadMode } = {} } = {} } = prev;
|
|
68
69
|
const {
|
|
69
70
|
node: nodeNext,
|
|
70
|
-
pluginProps: {
|
|
71
|
-
math: { keypadMode: keypadModeNext, controlledKeypadMode: controlledKeypadModeNext } = {}
|
|
72
|
-
} = {}
|
|
71
|
+
pluginProps: { math: { keypadMode: keypadModeNext, controlledKeypadMode: controlledKeypadModeNext } = {} } = {},
|
|
73
72
|
} = next;
|
|
74
73
|
const keypadModeChanged = keypadMode !== keypadModeNext;
|
|
75
74
|
const controlledKeypadModeChanged = controlledKeypadMode !== controlledKeypadModeNext;
|
|
76
75
|
|
|
77
76
|
const equal = isEqual(node, nodeNext);
|
|
78
77
|
return equal && !keypadModeChanged && !controlledKeypadModeChanged;
|
|
79
|
-
}
|
|
78
|
+
},
|
|
80
79
|
);
|
|
81
80
|
|
|
82
81
|
CustomToolbarComp.propTypes = {
|
|
@@ -96,12 +95,17 @@ CustomToolbarComp.propTypes = {
|
|
|
96
95
|
onToolbarDone: PropTypes.func,
|
|
97
96
|
onFocus: PropTypes.func,
|
|
98
97
|
onClick: PropTypes.func,
|
|
99
|
-
onBlur: PropTypes.func
|
|
98
|
+
onBlur: PropTypes.func,
|
|
100
99
|
};
|
|
101
100
|
|
|
102
101
|
const mathTypes = ['math', 'mathml'];
|
|
103
102
|
|
|
104
|
-
export default function MathPlugin() {
|
|
103
|
+
export default function MathPlugin(opts) {
|
|
104
|
+
MathPlugin.mathMlOptions = {
|
|
105
|
+
mmlOutput: opts.mmlOutput,
|
|
106
|
+
mmlEditing: opts.mmlEditing,
|
|
107
|
+
};
|
|
108
|
+
|
|
105
109
|
return {
|
|
106
110
|
name: 'math',
|
|
107
111
|
toolbar: {
|
|
@@ -119,7 +123,7 @@ export default function MathPlugin() {
|
|
|
119
123
|
* @param onDone {(change?: Slate.Change, finishEditing :boolea) => void} - a function to call once the toolbar
|
|
120
124
|
* has made any changes, call with the node.key and a data object.
|
|
121
125
|
*/
|
|
122
|
-
CustomToolbarComp
|
|
126
|
+
CustomToolbarComp,
|
|
123
127
|
},
|
|
124
128
|
rules: editor => {
|
|
125
129
|
const { isVoid, isInline } = editor;
|
|
@@ -136,19 +140,19 @@ export default function MathPlugin() {
|
|
|
136
140
|
},
|
|
137
141
|
supports: node => mathTypes.includes(node.type),
|
|
138
142
|
schema: {
|
|
139
|
-
document: { match: [{ type: 'math' }] }
|
|
143
|
+
document: { match: [{ type: 'math' }] },
|
|
140
144
|
},
|
|
141
145
|
|
|
142
146
|
pluginStyles: (node, parentNode, p) => {
|
|
143
147
|
if (p) {
|
|
144
148
|
return {
|
|
145
149
|
position: 'absolute',
|
|
146
|
-
top: 'initial'
|
|
150
|
+
top: 'initial',
|
|
147
151
|
};
|
|
148
152
|
}
|
|
149
153
|
},
|
|
150
154
|
|
|
151
|
-
renderNode: props => {
|
|
155
|
+
renderNode: (props) => {
|
|
152
156
|
if (props.node.type === 'math') {
|
|
153
157
|
log('[renderNode]: data:', props.node.data);
|
|
154
158
|
return <MathPreview {...props} />;
|
|
@@ -167,7 +171,7 @@ export default function MathPlugin() {
|
|
|
167
171
|
</span>
|
|
168
172
|
);
|
|
169
173
|
}
|
|
170
|
-
}
|
|
174
|
+
},
|
|
171
175
|
};
|
|
172
176
|
}
|
|
173
177
|
|
|
@@ -175,22 +179,28 @@ MathPlugin.ROUND_BRACKETS = 'round_brackets';
|
|
|
175
179
|
MathPlugin.SQUARE_BRACKETS = 'square_brackets';
|
|
176
180
|
MathPlugin.DOLLAR = 'dollar';
|
|
177
181
|
MathPlugin.DOUBLE_DOLLAR = 'double_dollar';
|
|
182
|
+
MathPlugin.mathMlOptions = {};
|
|
183
|
+
|
|
184
|
+
MathPlugin.propTypes = {
|
|
185
|
+
attributes: PropTypes.object,
|
|
186
|
+
node: PropTypes.node,
|
|
187
|
+
};
|
|
178
188
|
|
|
179
189
|
export const inlineMath = () => ({
|
|
180
190
|
type: 'math',
|
|
181
191
|
data: {
|
|
182
|
-
latex: ''
|
|
192
|
+
latex: '',
|
|
183
193
|
},
|
|
184
|
-
children: [{ text: '' }]
|
|
194
|
+
children: [{ text: '' }],
|
|
185
195
|
});
|
|
186
196
|
|
|
187
|
-
const htmlDecode = input => {
|
|
197
|
+
const htmlDecode = (input) => {
|
|
188
198
|
const doc = new DOMParser().parseFromString(input, 'text/html');
|
|
189
199
|
|
|
190
200
|
return doc.documentElement.textContent;
|
|
191
201
|
};
|
|
192
202
|
|
|
193
|
-
const getTagName = el => {
|
|
203
|
+
const getTagName = (el) => {
|
|
194
204
|
return ((el && el.tagName) || '').toLowerCase();
|
|
195
205
|
};
|
|
196
206
|
|
|
@@ -201,7 +211,7 @@ const getTagName = el => {
|
|
|
201
211
|
* @param input
|
|
202
212
|
* @returns {*}
|
|
203
213
|
*/
|
|
204
|
-
const lessThanHandling = input => {
|
|
214
|
+
const lessThanHandling = (input) => {
|
|
205
215
|
const arrowSplit = input.split('<');
|
|
206
216
|
|
|
207
217
|
// if we don't have at least 2 characters there's no point in checking
|
|
@@ -234,8 +244,7 @@ export const serialization = {
|
|
|
234
244
|
* an inline child and the block is of type block
|
|
235
245
|
* This is for legacy content only since our math rendering is valid for the core slate rules
|
|
236
246
|
*/
|
|
237
|
-
const hasMathChild =
|
|
238
|
-
BLOCK_TAGS[tagName] && el.childNodes.length === 1 && getTagName(el.firstChild) === 'math';
|
|
247
|
+
const hasMathChild = BLOCK_TAGS[tagName] && el.childNodes.length === 1 && getTagName(el.firstChild) === 'math';
|
|
239
248
|
log('[deserialize] name: ', tagName);
|
|
240
249
|
|
|
241
250
|
/**
|
|
@@ -244,11 +253,25 @@ export const serialization = {
|
|
|
244
253
|
if (tagName === 'math' || (el.dataset && el.dataset.type === 'mathml') || hasMathChild) {
|
|
245
254
|
const newHtml = hasMathChild ? el.innerHTML : el.outerHTML;
|
|
246
255
|
|
|
256
|
+
if (MathPlugin.mathMlOptions.mmlEditing) {
|
|
257
|
+
const htmlToUse = mmlToLatex(newHtml);
|
|
258
|
+
const latex = htmlDecode(htmlToUse);
|
|
259
|
+
const { unwrapped, wrapType } = unWrapMath(latex);
|
|
260
|
+
|
|
261
|
+
return jsx('element', {
|
|
262
|
+
type: 'math',
|
|
263
|
+
data: {
|
|
264
|
+
latex: unwrapped,
|
|
265
|
+
wrapper: wrapType,
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
247
270
|
return jsx('element', {
|
|
248
271
|
type: 'mathml',
|
|
249
272
|
data: {
|
|
250
|
-
html: newHtml
|
|
251
|
-
}
|
|
273
|
+
html: newHtml,
|
|
274
|
+
},
|
|
252
275
|
});
|
|
253
276
|
}
|
|
254
277
|
|
|
@@ -271,8 +294,8 @@ export const serialization = {
|
|
|
271
294
|
type: 'math',
|
|
272
295
|
data: {
|
|
273
296
|
latex: unwrapped,
|
|
274
|
-
wrapper: wrapType
|
|
275
|
-
}
|
|
297
|
+
wrapper: wrapType,
|
|
298
|
+
},
|
|
276
299
|
});
|
|
277
300
|
}
|
|
278
301
|
},
|
|
@@ -281,6 +304,26 @@ export const serialization = {
|
|
|
281
304
|
const { latex, wrapper } = object.data || {};
|
|
282
305
|
log('[serialize] latex: ', latex);
|
|
283
306
|
const decoded = htmlDecode(lessThanHandling(latex));
|
|
307
|
+
|
|
308
|
+
if (MathPlugin.mathMlOptions.mmlOutput) {
|
|
309
|
+
const res = renderMath(`<span data-latex="" data-raw="${decoded}">${wrapMath(decoded, wrapper)}</span>`);
|
|
310
|
+
const newLatex = mmlToLatex(res);
|
|
311
|
+
|
|
312
|
+
// we need to remove all the spaces from the latex to be able to compare it
|
|
313
|
+
const strippedL = latex.replace(/\s/g, '');
|
|
314
|
+
const strippedNewL = newLatex.replace(/\s/g, '');
|
|
315
|
+
|
|
316
|
+
// we check if the latex keeps his form after being converted to mathml and back to latex
|
|
317
|
+
// if it does we can safely convert it to mathml
|
|
318
|
+
if (isEqual(strippedL, strippedNewL)) {
|
|
319
|
+
return <span data-type="mathml" dangerouslySetInnerHTML={{ __html: res }} />;
|
|
320
|
+
} else {
|
|
321
|
+
// if it doesn't we keep the latex version
|
|
322
|
+
console.log('This latex can not be safely converted to mathml:', latex, 'so we will keep the latex version!!!');
|
|
323
|
+
console.warn('This latex can not be safely converted to mathml:', latex, 'so we will keep the latex version!!!');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
284
327
|
return (
|
|
285
328
|
<span data-latex="" data-raw={decoded}>
|
|
286
329
|
{wrapMath(decoded, wrapper)}
|
|
@@ -296,5 +339,5 @@ export const serialization = {
|
|
|
296
339
|
|
|
297
340
|
return <span data-type="mathml" dangerouslySetInnerHTML={{ __html: html }} />;
|
|
298
341
|
}
|
|
299
|
-
}
|
|
342
|
+
},
|
|
300
343
|
};
|
|
@@ -18,10 +18,10 @@ const log = debug('@pie-lib:editable-html:plugins:image');
|
|
|
18
18
|
const removeDialogs = () => {
|
|
19
19
|
const prevDialogs = document.querySelectorAll('.insert-media-dialog');
|
|
20
20
|
|
|
21
|
-
prevDialogs.forEach(s => s.remove());
|
|
21
|
+
prevDialogs.forEach((s) => s.remove());
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
export const insertDialog = props => {
|
|
24
|
+
export const insertDialog = (props) => {
|
|
25
25
|
const newEl = document.createElement('div');
|
|
26
26
|
const { type, callback, opts, ...rest } = props;
|
|
27
27
|
const initialBodyOverflow = document.body.style.overflow;
|
|
@@ -95,9 +95,9 @@ export default function MediaPlugin(type, opts) {
|
|
|
95
95
|
starts: undefined,
|
|
96
96
|
src: undefined,
|
|
97
97
|
url: undefined,
|
|
98
|
-
width: undefined
|
|
98
|
+
width: undefined,
|
|
99
99
|
},
|
|
100
|
-
children: [{ text: '' }]
|
|
100
|
+
children: [{ text: '' }],
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
editor.insertNode(inline);
|
|
@@ -323,11 +323,11 @@ export const serialization = {
|
|
|
323
323
|
'data-ends': ends,
|
|
324
324
|
'data-starts': starts,
|
|
325
325
|
'data-title': title,
|
|
326
|
-
'data-url': url
|
|
326
|
+
'data-url': url,
|
|
327
327
|
};
|
|
328
328
|
const props = {
|
|
329
329
|
...style,
|
|
330
|
-
src
|
|
330
|
+
src,
|
|
331
331
|
};
|
|
332
332
|
|
|
333
333
|
if (tag === 'audio') {
|
|
@@ -349,5 +349,5 @@ export const serialization = {
|
|
|
349
349
|
{...props}
|
|
350
350
|
/>
|
|
351
351
|
);
|
|
352
|
-
}
|
|
352
|
+
},
|
|
353
353
|
};
|
|
@@ -18,7 +18,7 @@ import ActionDelete from '@material-ui/icons/Delete';
|
|
|
18
18
|
|
|
19
19
|
const log = debug('@pie-lib:editable-html:plugins:media:dialog');
|
|
20
20
|
|
|
21
|
-
const matchYoutubeUrl = url => {
|
|
21
|
+
const matchYoutubeUrl = (url) => {
|
|
22
22
|
if (!url) {
|
|
23
23
|
return false;
|
|
24
24
|
}
|
|
@@ -30,13 +30,13 @@ const matchYoutubeUrl = url => {
|
|
|
30
30
|
return false;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
const matchVimeoUrl = url =>
|
|
33
|
+
const matchVimeoUrl = (url) =>
|
|
34
34
|
url &&
|
|
35
35
|
/(http|https)?:\/\/(www\.)?(player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^/]*)\/videos\/|)(video\/)?(\d+)(?:|\/\?)/.test(
|
|
36
|
-
url
|
|
36
|
+
url,
|
|
37
37
|
);
|
|
38
38
|
|
|
39
|
-
const matchSoundCloudUrl = url => {
|
|
39
|
+
const matchSoundCloudUrl = (url) => {
|
|
40
40
|
if (!url) {
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
@@ -45,12 +45,12 @@ const matchSoundCloudUrl = url => {
|
|
|
45
45
|
return url.match(regexp) && url.match(regexp)[2];
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
const makeApiRequest = url => {
|
|
49
|
-
return new Promise(resolve => {
|
|
48
|
+
const makeApiRequest = (url) => {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
50
|
try {
|
|
51
51
|
fetch(`https://soundcloud.com/oembed?format=json&url=${url}`)
|
|
52
|
-
.then(response => response.json())
|
|
53
|
-
.then(json => {
|
|
52
|
+
.then((response) => response.json())
|
|
53
|
+
.then((json) => {
|
|
54
54
|
const d = document.createElement('div');
|
|
55
55
|
|
|
56
56
|
d.innerHTML = json.html;
|
|
@@ -59,7 +59,7 @@ const makeApiRequest = url => {
|
|
|
59
59
|
|
|
60
60
|
resolve(iframe.src);
|
|
61
61
|
})
|
|
62
|
-
.catch(err => {
|
|
62
|
+
.catch((err) => {
|
|
63
63
|
resolve('');
|
|
64
64
|
log(err);
|
|
65
65
|
});
|
|
@@ -71,7 +71,7 @@ const makeApiRequest = url => {
|
|
|
71
71
|
|
|
72
72
|
const typeMap = {
|
|
73
73
|
video: 'Video',
|
|
74
|
-
audio: 'Audio'
|
|
74
|
+
audio: 'Audio',
|
|
75
75
|
};
|
|
76
76
|
|
|
77
77
|
export class MediaDialog extends React.Component {
|
|
@@ -83,7 +83,7 @@ export class MediaDialog extends React.Component {
|
|
|
83
83
|
handleClose: PropTypes.func,
|
|
84
84
|
uploadSoundSupport: PropTypes.shape({
|
|
85
85
|
add: PropTypes.func,
|
|
86
|
-
delete: PropTypes.func
|
|
86
|
+
delete: PropTypes.func,
|
|
87
87
|
}),
|
|
88
88
|
type: PropTypes.string,
|
|
89
89
|
src: PropTypes.string,
|
|
@@ -92,7 +92,7 @@ export class MediaDialog extends React.Component {
|
|
|
92
92
|
starts: PropTypes.number,
|
|
93
93
|
ends: PropTypes.number,
|
|
94
94
|
height: PropTypes.number,
|
|
95
|
-
width: PropTypes.number
|
|
95
|
+
width: PropTypes.number,
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
constructor(props) {
|
|
@@ -114,8 +114,8 @@ export class MediaDialog extends React.Component {
|
|
|
114
114
|
fileUpload: {
|
|
115
115
|
loading: false,
|
|
116
116
|
url: '',
|
|
117
|
-
error: null
|
|
118
|
-
}
|
|
117
|
+
error: null,
|
|
118
|
+
},
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -123,8 +123,8 @@ export class MediaDialog extends React.Component {
|
|
|
123
123
|
if (this.props.url) {
|
|
124
124
|
this.urlChange({
|
|
125
125
|
target: {
|
|
126
|
-
value: this.props.url
|
|
127
|
-
}
|
|
126
|
+
value: this.props.url,
|
|
127
|
+
},
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -171,20 +171,20 @@ export class MediaDialog extends React.Component {
|
|
|
171
171
|
this.setState({ formattedUrl: null, updating: true }, callback);
|
|
172
172
|
};
|
|
173
173
|
|
|
174
|
-
handleStateChange = newState => this.setState(newState, this.formatUrl);
|
|
174
|
+
handleStateChange = (newState) => this.setState(newState, this.formatUrl);
|
|
175
175
|
|
|
176
|
-
urlChange = e => {
|
|
176
|
+
urlChange = (e) => {
|
|
177
177
|
const { value } = e.target || {};
|
|
178
178
|
const { type } = this.props;
|
|
179
179
|
|
|
180
180
|
if (type && type === 'audio') {
|
|
181
181
|
if (matchSoundCloudUrl(value)) {
|
|
182
182
|
makeApiRequest(value)
|
|
183
|
-
.then(urlToUse => {
|
|
183
|
+
.then((urlToUse) => {
|
|
184
184
|
this.handleStateChange({
|
|
185
185
|
urlToUse,
|
|
186
186
|
invalid: !urlToUse,
|
|
187
|
-
url: value || ''
|
|
187
|
+
url: value || '',
|
|
188
188
|
});
|
|
189
189
|
})
|
|
190
190
|
.catch(log);
|
|
@@ -203,7 +203,7 @@ export class MediaDialog extends React.Component {
|
|
|
203
203
|
this.handleStateChange({
|
|
204
204
|
urlToUse,
|
|
205
205
|
url: value || '',
|
|
206
|
-
invalid: false
|
|
206
|
+
invalid: false,
|
|
207
207
|
});
|
|
208
208
|
|
|
209
209
|
return;
|
|
@@ -219,7 +219,7 @@ export class MediaDialog extends React.Component {
|
|
|
219
219
|
urlToUse,
|
|
220
220
|
url: value || '',
|
|
221
221
|
ends: null,
|
|
222
|
-
invalid: false
|
|
222
|
+
invalid: false,
|
|
223
223
|
});
|
|
224
224
|
|
|
225
225
|
return;
|
|
@@ -229,13 +229,13 @@ export class MediaDialog extends React.Component {
|
|
|
229
229
|
this.handleStateChange({
|
|
230
230
|
urlToUse: '',
|
|
231
231
|
url: '',
|
|
232
|
-
invalid: true
|
|
232
|
+
invalid: true,
|
|
233
233
|
});
|
|
234
234
|
};
|
|
235
235
|
|
|
236
|
-
changeHandler = type => e => this.handleStateChange({ [type]: e.target.value });
|
|
236
|
+
changeHandler = (type) => (e) => this.handleStateChange({ [type]: e.target.value });
|
|
237
237
|
|
|
238
|
-
handleDone = val => {
|
|
238
|
+
handleDone = (val) => {
|
|
239
239
|
const { handleClose } = this.props;
|
|
240
240
|
const { tabValue, fileUpload } = this.state;
|
|
241
241
|
const isInsertURL = tabValue === 0;
|
|
@@ -257,25 +257,25 @@ export class MediaDialog extends React.Component {
|
|
|
257
257
|
width,
|
|
258
258
|
url,
|
|
259
259
|
urlToUse,
|
|
260
|
-
src: formattedUrl
|
|
260
|
+
src: formattedUrl,
|
|
261
261
|
});
|
|
262
262
|
} else {
|
|
263
263
|
handleClose(val, {
|
|
264
264
|
tag: 'audio',
|
|
265
|
-
src: fileUpload.url
|
|
265
|
+
src: fileUpload.url,
|
|
266
266
|
});
|
|
267
267
|
}
|
|
268
268
|
};
|
|
269
269
|
|
|
270
|
-
handleUploadFile = async e => {
|
|
270
|
+
handleUploadFile = async (e) => {
|
|
271
271
|
e.preventDefault();
|
|
272
272
|
|
|
273
273
|
this.setState({
|
|
274
274
|
fileUpload: {
|
|
275
275
|
...this.state.fileUpload,
|
|
276
276
|
error: null,
|
|
277
|
-
loading: true
|
|
278
|
-
}
|
|
277
|
+
loading: true,
|
|
278
|
+
},
|
|
279
279
|
});
|
|
280
280
|
|
|
281
281
|
const fileChosen = e.target.files[0];
|
|
@@ -288,8 +288,8 @@ export class MediaDialog extends React.Component {
|
|
|
288
288
|
this.setState({
|
|
289
289
|
fileUpload: {
|
|
290
290
|
...this.state.fileUpload,
|
|
291
|
-
url: dataURL
|
|
292
|
-
}
|
|
291
|
+
url: dataURL,
|
|
292
|
+
},
|
|
293
293
|
});
|
|
294
294
|
};
|
|
295
295
|
reader.readAsDataURL(fileChosen);
|
|
@@ -305,32 +305,32 @@ export class MediaDialog extends React.Component {
|
|
|
305
305
|
fileUpload: {
|
|
306
306
|
...this.state.fileUpload,
|
|
307
307
|
loading: false,
|
|
308
|
-
error: err
|
|
309
|
-
}
|
|
308
|
+
error: err,
|
|
309
|
+
},
|
|
310
310
|
});
|
|
311
311
|
} else {
|
|
312
312
|
this.setState({
|
|
313
313
|
fileUpload: {
|
|
314
314
|
...this.state.fileUpload,
|
|
315
315
|
loading: false,
|
|
316
|
-
url: src
|
|
317
|
-
}
|
|
316
|
+
url: src,
|
|
317
|
+
},
|
|
318
318
|
});
|
|
319
319
|
}
|
|
320
|
-
}
|
|
320
|
+
},
|
|
321
321
|
});
|
|
322
322
|
};
|
|
323
323
|
|
|
324
324
|
handleRemoveFile = async () => {
|
|
325
|
-
this.props.uploadSoundSupport.delete(this.state.fileUpload.url, err => {
|
|
325
|
+
this.props.uploadSoundSupport.delete(this.state.fileUpload.url, (err) => {
|
|
326
326
|
if (err) {
|
|
327
327
|
//eslint-disable-next-line
|
|
328
328
|
console.log(err);
|
|
329
329
|
this.setState({
|
|
330
330
|
fileUpload: {
|
|
331
331
|
...this.state.fileUpload,
|
|
332
|
-
error: err
|
|
333
|
-
}
|
|
332
|
+
error: err,
|
|
333
|
+
},
|
|
334
334
|
});
|
|
335
335
|
}
|
|
336
336
|
});
|
|
@@ -340,36 +340,23 @@ export class MediaDialog extends React.Component {
|
|
|
340
340
|
fileUpload: {
|
|
341
341
|
...this.state.fileUpload,
|
|
342
342
|
loading: false,
|
|
343
|
-
url: ''
|
|
344
|
-
}
|
|
343
|
+
url: '',
|
|
344
|
+
},
|
|
345
345
|
});
|
|
346
346
|
};
|
|
347
347
|
|
|
348
348
|
render() {
|
|
349
349
|
const { classes, open, disablePortal, type, edit, uploadSoundSupport } = this.props;
|
|
350
|
-
const {
|
|
351
|
-
ends,
|
|
352
|
-
height,
|
|
353
|
-
invalid,
|
|
354
|
-
starts,
|
|
355
|
-
width,
|
|
356
|
-
url,
|
|
357
|
-
formattedUrl,
|
|
358
|
-
updating,
|
|
359
|
-
tabValue,
|
|
360
|
-
fileUpload
|
|
361
|
-
} = this.state;
|
|
350
|
+
const { ends, height, invalid, starts, width, url, formattedUrl, updating, tabValue, fileUpload } = this.state;
|
|
362
351
|
const isYoutube = matchYoutubeUrl(url);
|
|
363
352
|
const isInsertURL = tabValue === 0;
|
|
364
353
|
const isUploadMedia = tabValue === 1;
|
|
365
|
-
const submitIsDisabled = isInsertURL
|
|
366
|
-
? invalid || url === null || url === undefined
|
|
367
|
-
: !fileUpload.url;
|
|
354
|
+
const submitIsDisabled = isInsertURL ? invalid || url === null || url === undefined : !fileUpload.url;
|
|
368
355
|
|
|
369
356
|
return (
|
|
370
357
|
<Dialog
|
|
371
358
|
classes={{
|
|
372
|
-
paper: classes.paper
|
|
359
|
+
paper: classes.paper,
|
|
373
360
|
}}
|
|
374
361
|
disablePortal={disablePortal}
|
|
375
362
|
open={open}
|
|
@@ -387,9 +374,7 @@ export class MediaDialog extends React.Component {
|
|
|
387
374
|
this.setState({ tabValue: value });
|
|
388
375
|
}}
|
|
389
376
|
>
|
|
390
|
-
<MuiTab
|
|
391
|
-
label={type === 'video' ? 'Insert YouTube or Vimeo URL' : 'Insert SoundCloud URL'}
|
|
392
|
-
/>
|
|
377
|
+
<MuiTab label={type === 'video' ? 'Insert YouTube or Vimeo URL' : 'Insert SoundCloud URL'} />
|
|
393
378
|
{uploadSoundSupport?.add && uploadSoundSupport?.delete && type !== 'video' ? (
|
|
394
379
|
<MuiTab label="Upload file" />
|
|
395
380
|
) : null}
|
|
@@ -413,7 +398,7 @@ export class MediaDialog extends React.Component {
|
|
|
413
398
|
{type === 'video' && (
|
|
414
399
|
<DialogContent
|
|
415
400
|
classes={{
|
|
416
|
-
root: classes.properties
|
|
401
|
+
root: classes.properties,
|
|
417
402
|
}}
|
|
418
403
|
>
|
|
419
404
|
<DialogContentText>Video Properties</DialogContentText>
|
|
@@ -453,7 +438,7 @@ export class MediaDialog extends React.Component {
|
|
|
453
438
|
<React.Fragment>
|
|
454
439
|
<DialogContent
|
|
455
440
|
classes={{
|
|
456
|
-
root: classes.properties
|
|
441
|
+
root: classes.properties,
|
|
457
442
|
}}
|
|
458
443
|
>
|
|
459
444
|
<TextField
|
|
@@ -492,25 +477,14 @@ export class MediaDialog extends React.Component {
|
|
|
492
477
|
<audio controls="controls">
|
|
493
478
|
<source type="audio/mp3" src={fileUpload.url} />
|
|
494
479
|
</audio>
|
|
495
|
-
<IconButton
|
|
496
|
-
aria-label="delete"
|
|
497
|
-
className={classes.deleteIcon}
|
|
498
|
-
onClick={this.handleRemoveFile}
|
|
499
|
-
>
|
|
480
|
+
<IconButton aria-label="delete" className={classes.deleteIcon} onClick={this.handleRemoveFile}>
|
|
500
481
|
<ActionDelete />
|
|
501
482
|
</IconButton>
|
|
502
483
|
</div>
|
|
503
|
-
{fileUpload.loading ?
|
|
504
|
-
<Typography variant="subheading">Loading...</Typography>
|
|
505
|
-
) : null}
|
|
484
|
+
{fileUpload.loading ? <Typography variant="subheading">Loading...</Typography> : null}
|
|
506
485
|
</>
|
|
507
486
|
) : !fileUpload.loading ? (
|
|
508
|
-
<input
|
|
509
|
-
accept="audio/*"
|
|
510
|
-
className={classes.input}
|
|
511
|
-
onChange={this.handleUploadFile}
|
|
512
|
-
type="file"
|
|
513
|
-
/>
|
|
487
|
+
<input accept="audio/*" className={classes.input} onChange={this.handleUploadFile} type="file" />
|
|
514
488
|
) : null}
|
|
515
489
|
{!!fileUpload.error && (
|
|
516
490
|
<Typography className={classes.error} variant="caption">
|
|
@@ -535,35 +509,35 @@ export class MediaDialog extends React.Component {
|
|
|
535
509
|
}
|
|
536
510
|
}
|
|
537
511
|
|
|
538
|
-
const styles = () => ({
|
|
512
|
+
const styles = (theme) => ({
|
|
539
513
|
paper: {
|
|
540
|
-
minWidth: '500px'
|
|
514
|
+
minWidth: '500px',
|
|
541
515
|
},
|
|
542
516
|
properties: {
|
|
543
|
-
padding: 0
|
|
517
|
+
padding: 0,
|
|
544
518
|
},
|
|
545
519
|
row: {
|
|
546
520
|
display: 'flex',
|
|
547
|
-
flexDirection: 'space-between'
|
|
521
|
+
flexDirection: 'space-between',
|
|
548
522
|
},
|
|
549
523
|
rowItem: {
|
|
550
|
-
marginRight:
|
|
551
|
-
cursor: 'pointer'
|
|
524
|
+
marginRight: theme.spacing.unit * 1.5,
|
|
525
|
+
cursor: 'pointer',
|
|
552
526
|
},
|
|
553
527
|
active: {
|
|
554
528
|
color: color.primary(),
|
|
555
|
-
borderBottom: `2px solid ${color.primary()}
|
|
529
|
+
borderBottom: `2px solid ${color.primary()}`,
|
|
556
530
|
},
|
|
557
531
|
uploadInput: {
|
|
558
|
-
marginTop:
|
|
532
|
+
marginTop: theme.spacing.unit * 1.5,
|
|
559
533
|
},
|
|
560
534
|
error: {
|
|
561
|
-
marginTop:
|
|
562
|
-
color:
|
|
535
|
+
marginTop: theme.spacing.unit * 1.5,
|
|
536
|
+
color: theme.palette.error.main,
|
|
563
537
|
},
|
|
564
538
|
deleteIcon: {
|
|
565
|
-
marginLeft:
|
|
566
|
-
}
|
|
539
|
+
marginLeft: theme.spacing.unit * 1.5,
|
|
540
|
+
},
|
|
567
541
|
});
|
|
568
542
|
|
|
569
543
|
export default withStyles(styles)(MediaDialog);
|