@pie-lib/editable-html-tip-tap 1.0.2 → 1.0.4
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/lib/components/CharacterPicker.js +221 -0
- package/lib/components/CharacterPicker.js.map +1 -0
- package/lib/components/EditableHtml.js +323 -0
- package/lib/components/EditableHtml.js.map +1 -0
- package/lib/components/MenuBar.js +694 -0
- package/lib/components/MenuBar.js.map +1 -0
- package/lib/components/TiptapContainer.js +90 -0
- package/lib/components/TiptapContainer.js.map +1 -0
- package/lib/components/buttons/done-button.js +53 -0
- package/lib/components/characters/characterUtils.js +112 -0
- package/lib/components/characters/characterUtils.js.map +1 -0
- package/lib/components/characters/custom-popper.js +73 -0
- package/lib/components/characters/custom-popper.js.map +1 -0
- package/lib/components/common/done-button.js +53 -0
- package/lib/components/common/done-button.js.map +1 -0
- package/lib/components/common/toolbar-buttons.js +194 -0
- package/lib/components/icons/CssIcon.js +37 -0
- package/lib/components/icons/CssIcon.js.map +1 -0
- package/lib/components/icons/RespArea.js +95 -0
- package/lib/components/icons/RespArea.js.map +1 -0
- package/lib/components/icons/TableIcons.js +69 -0
- package/lib/components/icons/TableIcons.js.map +1 -0
- package/lib/components/icons/TextAlign.js +194 -0
- package/lib/components/icons/TextAlign.js.map +1 -0
- package/lib/components/icons/index.js +194 -0
- package/lib/components/image/AltDialog.js +129 -0
- package/lib/components/image/ImageToolbar.js +177 -0
- package/lib/components/image/ImageToolbar.js.map +1 -0
- package/lib/components/image/InsertImageHandler.js +115 -0
- package/lib/components/image/InsertImageHandler.js.map +1 -0
- package/lib/components/image/alt-dialog.js +2 -0
- package/lib/components/media/MediaDialog.js +709 -0
- package/lib/components/media/MediaDialog.js.map +1 -0
- package/lib/components/media/MediaToolbar.js +101 -0
- package/lib/components/media/MediaToolbar.js.map +1 -0
- package/lib/components/media/MediaWrapper.js +93 -0
- package/lib/components/respArea/DragInTheBlank/DragInTheBlank.js +94 -0
- package/lib/components/respArea/DragInTheBlank/DragInTheBlank.js.map +1 -0
- package/lib/components/respArea/DragInTheBlank/choice.js +289 -0
- package/lib/components/respArea/DragInTheBlank/choice.js.map +1 -0
- package/lib/components/respArea/DragInTheBlank.js +94 -0
- package/lib/components/respArea/ExplicitConstructedResponse.js +120 -0
- package/lib/components/respArea/ExplicitConstructedResponse.js.map +1 -0
- package/lib/components/respArea/InlineDropdown.js +126 -0
- package/lib/components/respArea/InlineDropdown.js.map +1 -0
- package/lib/components/respArea/ToolbarIcon.js +105 -0
- package/lib/components/respArea/ToolbarIcon.js.map +1 -0
- package/lib/components/respArea/choice.js +2 -0
- package/lib/constants.js.map +1 -0
- package/lib/extensions/component.js +5 -5
- package/lib/extensions/component.js.map +1 -0
- package/lib/extensions/css.js.map +1 -0
- package/lib/extensions/custom-toolbar-wrapper.js +2 -4
- package/lib/extensions/custom-toolbar-wrapper.js.map +1 -0
- package/lib/extensions/extended-table.js +30 -0
- package/lib/extensions/extended-table.js.map +1 -0
- package/lib/extensions/image.js +2 -8
- package/lib/extensions/image.js.map +1 -0
- package/lib/extensions/index.js +52 -0
- package/lib/extensions/index.js.map +1 -0
- package/lib/extensions/math.js.map +1 -0
- package/lib/extensions/media.js +7 -7
- package/lib/extensions/media.js.map +1 -0
- package/lib/extensions/responseArea.js +7 -7
- package/lib/extensions/responseArea.js.map +1 -0
- package/lib/index.js +16 -1481
- package/lib/index.js.map +1 -0
- package/lib/plugins/index.js +8 -80
- package/lib/styles/editorContainerStyles.js +200 -0
- package/lib/styles/editorContainerStyles.js.map +1 -0
- package/lib/theme.js.map +1 -0
- package/lib/utils/size.js +34 -0
- package/lib/utils/size.js.map +1 -0
- package/package.json +1 -1
- package/src/components/CharacterPicker.jsx +185 -0
- package/src/components/EditableHtml.jsx +306 -0
- package/src/components/MenuBar.jsx +630 -0
- package/src/components/TiptapContainer.jsx +96 -0
- package/src/components/characters/characterUtils.js +127 -0
- package/src/{plugins/image/image-toolbar.jsx → components/image/ImageToolbar.jsx} +2 -2
- package/src/{plugins/image/insert-image-handler.js → components/image/InsertImageHandler.js} +0 -1
- package/src/{plugins/media/media-dialog.js → components/media/MediaDialog.js} +2 -2
- package/src/{plugins/respArea/drag-in-the-blank → components/respArea/DragInTheBlank}/choice.jsx +1 -1
- package/src/{plugins/respArea/inline-dropdown/index.jsx → components/respArea/InlineDropdown.jsx} +1 -1
- package/src/components/respArea/ToolbarIcon.jsx +68 -0
- package/src/extensions/component.jsx +2 -2
- package/src/extensions/custom-toolbar-wrapper.jsx +6 -7
- package/src/extensions/extended-table.js +27 -0
- package/src/extensions/image.js +2 -2
- package/src/extensions/index.js +76 -0
- package/src/extensions/media.js +12 -7
- package/src/extensions/responseArea.js +7 -7
- package/src/index.jsx +3 -1440
- package/src/styles/editorContainerStyles.js +203 -0
- package/src/utils/size.js +32 -0
- package/src/__tests__/editor.test.jsx +0 -363
- package/src/__tests__/serialization.test.js +0 -291
- package/src/block-tags.js +0 -17
- package/src/editor.jsx +0 -1197
- package/src/extensions/characters.js +0 -46
- package/src/old-index.jsx +0 -162
- package/src/parse-html.js +0 -8
- package/src/plugins/README.md +0 -27
- package/src/plugins/characters/index.jsx +0 -284
- package/src/plugins/characters/utils.js +0 -447
- package/src/plugins/css/index.jsx +0 -340
- package/src/plugins/customPlugin/index.jsx +0 -85
- package/src/plugins/html/icons/index.jsx +0 -19
- package/src/plugins/html/index.jsx +0 -72
- package/src/plugins/image/__tests__/__snapshots__/component.test.jsx.snap +0 -51
- package/src/plugins/image/__tests__/__snapshots__/image-toolbar-logic.test.jsx.snap +0 -27
- package/src/plugins/image/__tests__/__snapshots__/image-toolbar.test.jsx.snap +0 -44
- package/src/plugins/image/__tests__/component.test.jsx +0 -41
- package/src/plugins/image/__tests__/image-toolbar-logic.test.jsx +0 -42
- package/src/plugins/image/__tests__/image-toolbar.test.jsx +0 -11
- package/src/plugins/image/__tests__/index.test.js +0 -95
- package/src/plugins/image/__tests__/insert-image-handler.test.js +0 -113
- package/src/plugins/image/__tests__/mock-change.js +0 -15
- package/src/plugins/image/component.jsx +0 -343
- package/src/plugins/image/index.jsx +0 -227
- package/src/plugins/index.jsx +0 -377
- package/src/plugins/list/__tests__/index.test.js +0 -54
- package/src/plugins/list/index.jsx +0 -305
- package/src/plugins/math/__tests__/__snapshots__/index.test.jsx.snap +0 -48
- package/src/plugins/math/__tests__/index.test.jsx +0 -245
- package/src/plugins/math/index.jsx +0 -379
- package/src/plugins/media/__tests__/index.test.js +0 -75
- package/src/plugins/media/index.jsx +0 -325
- package/src/plugins/rendering/index.js +0 -31
- package/src/plugins/respArea/index.jsx +0 -299
- package/src/plugins/respArea/math-templated/index.jsx +0 -104
- package/src/plugins/respArea/utils.jsx +0 -90
- package/src/plugins/table/CustomTablePlugin.js +0 -113
- package/src/plugins/table/__tests__/__snapshots__/table-toolbar.test.jsx.snap +0 -44
- package/src/plugins/table/__tests__/index.test.jsx +0 -401
- package/src/plugins/table/__tests__/table-toolbar.test.jsx +0 -42
- package/src/plugins/table/index.jsx +0 -427
- package/src/plugins/table/table-toolbar.jsx +0 -136
- package/src/plugins/textAlign/index.jsx +0 -23
- package/src/plugins/toolbar/__tests__/__snapshots__/default-toolbar.test.jsx.snap +0 -923
- package/src/plugins/toolbar/__tests__/__snapshots__/editor-and-toolbar.test.jsx.snap +0 -20
- package/src/plugins/toolbar/__tests__/__snapshots__/toolbar-buttons.test.jsx.snap +0 -36
- package/src/plugins/toolbar/__tests__/__snapshots__/toolbar.test.jsx.snap +0 -46
- package/src/plugins/toolbar/__tests__/default-toolbar.test.jsx +0 -94
- package/src/plugins/toolbar/__tests__/editor-and-toolbar.test.jsx +0 -37
- package/src/plugins/toolbar/__tests__/toolbar-buttons.test.jsx +0 -51
- package/src/plugins/toolbar/__tests__/toolbar.test.jsx +0 -106
- package/src/plugins/toolbar/default-toolbar.jsx +0 -206
- package/src/plugins/toolbar/editor-and-toolbar.jsx +0 -257
- package/src/plugins/toolbar/index.jsx +0 -23
- package/src/plugins/toolbar/toolbar.jsx +0 -338
- package/src/plugins/utils.js +0 -31
- package/src/serialization.jsx +0 -621
- /package/src/{plugins → components}/characters/custom-popper.js +0 -0
- /package/src/{plugins/toolbar → components/common}/done-button.jsx +0 -0
- /package/src/{plugins/toolbar → components/common}/toolbar-buttons.jsx +0 -0
- /package/src/{plugins/css/icons/index.jsx → components/icons/CssIcon.jsx} +0 -0
- /package/src/{plugins/respArea/icons/index.jsx → components/icons/RespArea.jsx} +0 -0
- /package/src/{plugins/table/icons/index.jsx → components/icons/TableIcons.jsx} +0 -0
- /package/src/{plugins/textAlign/icons/index.jsx → components/icons/TextAlign.jsx} +0 -0
- /package/src/{plugins/image/alt-dialog.jsx → components/image/AltDialog.jsx} +0 -0
- /package/src/{plugins/media/media-toolbar.jsx → components/media/MediaToolbar.jsx} +0 -0
- /package/src/{plugins/media/media-wrapper.jsx → components/media/MediaWrapper.jsx} +0 -0
- /package/src/{plugins/respArea/drag-in-the-blank/index.jsx → components/respArea/DragInTheBlank/DragInTheBlank.jsx} +0 -0
- /package/src/{plugins/respArea/explicit-constructed-response/index.jsx → components/respArea/ExplicitConstructedResponse.jsx} +0 -0
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom';
|
|
3
|
-
import List from '@material-ui/core/List';
|
|
4
|
-
import { Leaf, Mark } from 'slate';
|
|
5
|
-
import Immutable from 'immutable';
|
|
6
|
-
import ListItem from '@material-ui/core/ListItem';
|
|
7
|
-
import isEmpty from 'lodash/isEmpty';
|
|
8
|
-
import debug from 'debug';
|
|
9
|
-
import CssIcon from './icons';
|
|
10
|
-
|
|
11
|
-
const log = debug('@pie-lib:editable-html:plugins:characters');
|
|
12
|
-
|
|
13
|
-
export const removeDialogs = () => {
|
|
14
|
-
const prevDialogs = document.querySelectorAll('.insert-css-dialog');
|
|
15
|
-
|
|
16
|
-
log('[characters:removeDialogs]');
|
|
17
|
-
prevDialogs.forEach((s) => s.remove());
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const insertDialog = ({ editorDOM, value, callback, opts, textNode, parentNode }) => {
|
|
21
|
-
const newEl = document.createElement('div');
|
|
22
|
-
|
|
23
|
-
log('[characters:insertDialog]');
|
|
24
|
-
|
|
25
|
-
removeDialogs();
|
|
26
|
-
|
|
27
|
-
newEl.className = 'insert-css-dialog';
|
|
28
|
-
|
|
29
|
-
let popoverEl;
|
|
30
|
-
|
|
31
|
-
const closePopOver = () => {
|
|
32
|
-
if (popoverEl) {
|
|
33
|
-
popoverEl.remove();
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
let firstCallMade = false;
|
|
38
|
-
|
|
39
|
-
const listener = (e) => {
|
|
40
|
-
// this will be triggered right after setting it because
|
|
41
|
-
// this toolbar is added on the mousedown event
|
|
42
|
-
// so right after mouseup, the click will be triggered
|
|
43
|
-
if (firstCallMade) {
|
|
44
|
-
const focusIsInModals = newEl.contains(e.target) || (popoverEl && popoverEl.contains(e.target));
|
|
45
|
-
const focusIsInEditor = editorDOM.contains(e.target);
|
|
46
|
-
|
|
47
|
-
if (!(focusIsInModals || focusIsInEditor)) {
|
|
48
|
-
handleClose();
|
|
49
|
-
}
|
|
50
|
-
} else {
|
|
51
|
-
firstCallMade = true;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const handleClose = () => {
|
|
56
|
-
callback(undefined, true);
|
|
57
|
-
newEl.remove();
|
|
58
|
-
closePopOver();
|
|
59
|
-
document.body.removeEventListener('click', listener);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const handleChange = (name) => {
|
|
63
|
-
callback(name, true);
|
|
64
|
-
newEl.remove();
|
|
65
|
-
closePopOver();
|
|
66
|
-
document.body.removeEventListener('click', listener);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const selectedText = textNode.text.slice(value.selection.anchorOffset, value.selection.focusOffset);
|
|
70
|
-
const parentNodeClass = parentNode?.data?.get('attributes')?.class;
|
|
71
|
-
const createHTML = (name) => {
|
|
72
|
-
let html = `<span class="${name}">${selectedText}</span>`;
|
|
73
|
-
|
|
74
|
-
if (parentNode) {
|
|
75
|
-
let tag;
|
|
76
|
-
|
|
77
|
-
if (parentNode?.object === 'inline') {
|
|
78
|
-
tag = 'span';
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (parentNode?.object === 'block') {
|
|
82
|
-
tag = 'div';
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
html = `<${tag} class="${parentNodeClass}">${parentNode.text.slice(
|
|
86
|
-
0,
|
|
87
|
-
value.selection.anchorOffset,
|
|
88
|
-
)}${html}${parentNode.text.slice(value.selection.focusOffset)}</${tag}>`;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return html;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const el = (
|
|
95
|
-
<div
|
|
96
|
-
style={{ background: 'white', height: 500, padding: 20, overflow: 'hidden', display: 'flex', flexFlow: 'column' }}
|
|
97
|
-
>
|
|
98
|
-
<h2>Please choose a css class</h2>
|
|
99
|
-
{parentNodeClass && <div>The current parent has this class {parentNodeClass}</div>}
|
|
100
|
-
<List component="nav" style={{ overflow: 'scroll' }}>
|
|
101
|
-
{opts.names.map((name, i) => (
|
|
102
|
-
<ListItem key={`rule-${i}`} button onClick={() => handleChange(name)}>
|
|
103
|
-
<div style={{ marginRight: 20 }}>{name}</div>
|
|
104
|
-
<div
|
|
105
|
-
dangerouslySetInnerHTML={{
|
|
106
|
-
__html: createHTML(name),
|
|
107
|
-
}}
|
|
108
|
-
/>
|
|
109
|
-
</ListItem>
|
|
110
|
-
))}
|
|
111
|
-
</List>
|
|
112
|
-
</div>
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
ReactDOM.render(el, newEl, () => {
|
|
116
|
-
const cursorItem = document.querySelector(`[data-key="${value.anchorKey}"]`);
|
|
117
|
-
|
|
118
|
-
if (cursorItem) {
|
|
119
|
-
const bodyRect = editorDOM.parentElement.parentElement.parentElement.getBoundingClientRect();
|
|
120
|
-
const boundRect = cursorItem.getBoundingClientRect();
|
|
121
|
-
|
|
122
|
-
editorDOM.parentElement.parentElement.parentElement.appendChild(newEl);
|
|
123
|
-
|
|
124
|
-
newEl.style.maxWidth = '500px';
|
|
125
|
-
newEl.style.position = 'absolute';
|
|
126
|
-
newEl.style.top = 0;
|
|
127
|
-
newEl.style.zIndex = 99999;
|
|
128
|
-
|
|
129
|
-
const leftValue = `${boundRect.left + Math.abs(bodyRect.left) + cursorItem.offsetWidth + 10}px`;
|
|
130
|
-
|
|
131
|
-
const rightValue = `${boundRect.x}px`;
|
|
132
|
-
|
|
133
|
-
newEl.style.left = leftValue;
|
|
134
|
-
|
|
135
|
-
const leftAlignedWidth = newEl.offsetWidth;
|
|
136
|
-
|
|
137
|
-
newEl.style.left = 'unset';
|
|
138
|
-
newEl.style.right = rightValue;
|
|
139
|
-
|
|
140
|
-
const rightAlignedWidth = newEl.offsetWidth;
|
|
141
|
-
|
|
142
|
-
newEl.style.left = 'unset';
|
|
143
|
-
newEl.style.right = 'unset';
|
|
144
|
-
|
|
145
|
-
if (leftAlignedWidth >= rightAlignedWidth) {
|
|
146
|
-
newEl.style.left = leftValue;
|
|
147
|
-
} else {
|
|
148
|
-
newEl.style.right = rightValue;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
document.body.addEventListener('click', listener);
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const findParentNodeInfo = (value, textNode) => {
|
|
157
|
-
const closestInline = value.document.getClosestInline(value.selection.endKey);
|
|
158
|
-
const closestBlock = value.document.getClosestBlock(value.selection.endKey);
|
|
159
|
-
let nodeToUse = null;
|
|
160
|
-
|
|
161
|
-
if (closestInline?.nodes?.find((n) => n.key === textNode.key)) {
|
|
162
|
-
nodeToUse = closestInline;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (closestBlock?.nodes?.find((n) => n.key === textNode.key)) {
|
|
166
|
-
nodeToUse = closestBlock;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return nodeToUse;
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Find the node that has a class attribute and return it.
|
|
174
|
-
* Keeping this in case the implementation of classes needs to be changed
|
|
175
|
-
* @param value
|
|
176
|
-
* @param opts
|
|
177
|
-
* @returns {*}
|
|
178
|
-
*/
|
|
179
|
-
const getNodeWithClass = (value, opts) => {
|
|
180
|
-
const blocksAtRange = value.document.getBlocksAtRangeAsArray(value.selection);
|
|
181
|
-
const inlinesAtRange = value.document.getInlinesAtRangeAsArray(value.selection);
|
|
182
|
-
const blockData = blocksAtRange[0]?.data.toJSON() || {};
|
|
183
|
-
const inlineData = inlinesAtRange[0]?.data.toJSON() || {};
|
|
184
|
-
|
|
185
|
-
if (!blockData.attributes?.class && !inlineData.attributes?.class) {
|
|
186
|
-
return null;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const { class: blockClass } = blockData.attributes || {};
|
|
190
|
-
const { class: inlineClass } = inlineData.attributes || {};
|
|
191
|
-
const inlineHasClass = opts.names.find((name) => inlineClass.includes(name));
|
|
192
|
-
|
|
193
|
-
if (inlineHasClass) {
|
|
194
|
-
return inlinesAtRange[0];
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const blockHasClass = opts.names.find((name) => blockClass.includes(name));
|
|
198
|
-
|
|
199
|
-
if (blockHasClass) {
|
|
200
|
-
return blocksAtRange[0];
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return null;
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Plugin in order to be able to add a css clas that is provided through the model
|
|
208
|
-
* on a text element. Works like a mark (bold, italic etc.).
|
|
209
|
-
* @param opts
|
|
210
|
-
* @constructor
|
|
211
|
-
*/
|
|
212
|
-
export default function CSSPlugin(opts) {
|
|
213
|
-
const plugin = {
|
|
214
|
-
name: 'extraCSSRules',
|
|
215
|
-
toolbar: {
|
|
216
|
-
isMark: true,
|
|
217
|
-
icon: <CssIcon />,
|
|
218
|
-
ariaLabel: 'CSS editor',
|
|
219
|
-
type: 'css',
|
|
220
|
-
onToggle: (change) => {
|
|
221
|
-
const type = 'css';
|
|
222
|
-
const hasMark = change.value.activeMarks.find((entry) => {
|
|
223
|
-
return entry.type === type;
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
if (hasMark) {
|
|
227
|
-
change.removeMark(hasMark);
|
|
228
|
-
} else {
|
|
229
|
-
const newMark = Mark.create(type);
|
|
230
|
-
|
|
231
|
-
change.addMark(newMark);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return change;
|
|
235
|
-
},
|
|
236
|
-
onClick: (value, onChange, getFocusedValue) => {
|
|
237
|
-
const type = 'css';
|
|
238
|
-
const hasMark = value.activeMarks.find((entry) => {
|
|
239
|
-
return entry.type === type;
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
let change = value.change();
|
|
243
|
-
|
|
244
|
-
if (hasMark) {
|
|
245
|
-
change.removeMark(hasMark);
|
|
246
|
-
onChange(change);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// keeping this if implementation needs to be changed to regular blocks instead of marks
|
|
251
|
-
// let nodeWithClass = getNodeWithClass(value, opts);
|
|
252
|
-
//
|
|
253
|
-
// if (nodeWithClass) {
|
|
254
|
-
// const nodeAttributes = nodeWithClass.data.get('attributes');
|
|
255
|
-
//
|
|
256
|
-
// opts.names.forEach((name) => {
|
|
257
|
-
// if (nodeAttributes.class.includes(name)) {
|
|
258
|
-
// nodeAttributes.class = nodeAttributes.class.replace(name, '');
|
|
259
|
-
// }
|
|
260
|
-
// });
|
|
261
|
-
//
|
|
262
|
-
// // keeping only one space between classes
|
|
263
|
-
// nodeAttributes.class = nodeAttributes.class.replace(/ +/g, ' ');
|
|
264
|
-
//
|
|
265
|
-
// nodeWithClass.data.set('attributes', nodeAttributes);
|
|
266
|
-
//
|
|
267
|
-
// let change = value.change();
|
|
268
|
-
// change.replaceNodeByKey(nodeWithClass.key, nodeWithClass);
|
|
269
|
-
//
|
|
270
|
-
// onChange(change);
|
|
271
|
-
// return;
|
|
272
|
-
// }
|
|
273
|
-
|
|
274
|
-
const editorDOM = document.querySelector(`[data-key="${value.document.key}"]`);
|
|
275
|
-
let valueToUse = value;
|
|
276
|
-
|
|
277
|
-
const callback = (className, focus) => {
|
|
278
|
-
if (getFocusedValue) {
|
|
279
|
-
valueToUse = getFocusedValue() || valueToUse;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
if (className) {
|
|
283
|
-
let change = valueToUse.change();
|
|
284
|
-
|
|
285
|
-
const newMark = Mark.create({
|
|
286
|
-
object: 'mark',
|
|
287
|
-
type: 'css',
|
|
288
|
-
data: {
|
|
289
|
-
attributes: {
|
|
290
|
-
class: className,
|
|
291
|
-
},
|
|
292
|
-
},
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
change.addMark(newMark);
|
|
296
|
-
// keeping this if implementation needs to be changed to regular blocks instead of marks
|
|
297
|
-
// change = change.wrapInline({ type: 'span', data: { attributes: { class: className } } });
|
|
298
|
-
//
|
|
299
|
-
// // change = change.splitBlockAtRange(adaptedRange);
|
|
300
|
-
// //
|
|
301
|
-
// // const newBlock = change.value.document.getFurthestBlock(change.value.selection.endKey);
|
|
302
|
-
// //
|
|
303
|
-
// // change = change.setNodeByKey(newBlock.key, { data: { attributes: { class: className } } });
|
|
304
|
-
//
|
|
305
|
-
// valueToUse = change.value;
|
|
306
|
-
// log('[characters:insert]: ', value);
|
|
307
|
-
onChange(change);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
log('[characters:click]');
|
|
311
|
-
|
|
312
|
-
if (focus) {
|
|
313
|
-
setTimeout(() => {
|
|
314
|
-
if (editorDOM) {
|
|
315
|
-
editorDOM.focus();
|
|
316
|
-
}
|
|
317
|
-
}, 0);
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
const textNode = value.document.getTextsAtRangeAsArray(value.selection)[0];
|
|
321
|
-
|
|
322
|
-
if (textNode) {
|
|
323
|
-
const parentNode = findParentNodeInfo(value, textNode, opts);
|
|
324
|
-
|
|
325
|
-
insertDialog({ editorDOM, value: valueToUse, callback, opts, textNode, parentNode });
|
|
326
|
-
}
|
|
327
|
-
},
|
|
328
|
-
},
|
|
329
|
-
renderMark(props) {
|
|
330
|
-
if (props.mark.type === 'css') {
|
|
331
|
-
const { data } = props.mark || {};
|
|
332
|
-
const jsonData = data?.toJSON() || {};
|
|
333
|
-
|
|
334
|
-
return <span {...jsonData.attributes}>{props.children}</span>;
|
|
335
|
-
}
|
|
336
|
-
},
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
return plugin;
|
|
340
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { htmlToValue } from '../../serialization';
|
|
3
|
-
|
|
4
|
-
// We're possibly going to have to support content types, so starting it as an enum
|
|
5
|
-
export const CONTENT_TYPE = {
|
|
6
|
-
FRAGMENT: 'FRAGMENT',
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
// We're possibly going to have to support multiple icon types, so starting it as an enum
|
|
10
|
-
export const ICON_TYPE = {
|
|
11
|
-
SVG: 'SVG',
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const getIcon = (customPluginProps) => {
|
|
15
|
-
const svg = customPluginProps.icon;
|
|
16
|
-
|
|
17
|
-
switch (customPluginProps.iconType) {
|
|
18
|
-
case ICON_TYPE.SVG:
|
|
19
|
-
return <span style={{ width: 28, height: 28 }} dangerouslySetInnerHTML={{ __html: svg }} />;
|
|
20
|
-
default:
|
|
21
|
-
return <span>{customPluginProps.iconAlt}</span>;
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export default function CustomPlugin(type, customPluginProps) {
|
|
26
|
-
const toolbar = {
|
|
27
|
-
icon: getIcon(customPluginProps),
|
|
28
|
-
onClick: (value, onChange, getFocusedValue) => {
|
|
29
|
-
const editorDOM = document.querySelector(`[data-key="${value.document.key}"]`);
|
|
30
|
-
let valueToUse = value;
|
|
31
|
-
const callback = ({ customContent, contentType }, focus) => {
|
|
32
|
-
valueToUse = getFocusedValue();
|
|
33
|
-
|
|
34
|
-
switch (contentType) {
|
|
35
|
-
case CONTENT_TYPE.FRAGMENT:
|
|
36
|
-
default: {
|
|
37
|
-
const contentValue = htmlToValue(customContent);
|
|
38
|
-
const change = valueToUse.change().insertFragment(contentValue.document);
|
|
39
|
-
|
|
40
|
-
valueToUse = change.value;
|
|
41
|
-
onChange(change);
|
|
42
|
-
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (focus) {
|
|
48
|
-
if (editorDOM) {
|
|
49
|
-
editorDOM.focus();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// NOTE: the emitted event (custom event named by client) will be suffixed with "PIE-"
|
|
55
|
-
window.dispatchEvent(
|
|
56
|
-
new CustomEvent(`PIE-${customPluginProps.event}`, {
|
|
57
|
-
detail: {
|
|
58
|
-
...customPluginProps,
|
|
59
|
-
callback,
|
|
60
|
-
},
|
|
61
|
-
}),
|
|
62
|
-
);
|
|
63
|
-
},
|
|
64
|
-
supports: (node) => node.object === 'inline' && node.type === type,
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
name: type,
|
|
69
|
-
toolbar,
|
|
70
|
-
renderNode(props) {
|
|
71
|
-
if (props.node.type === type) {
|
|
72
|
-
const { node } = props;
|
|
73
|
-
const { data } = node;
|
|
74
|
-
const jsonData = data.toJSON();
|
|
75
|
-
const { customContent, contentType } = jsonData;
|
|
76
|
-
|
|
77
|
-
switch (contentType) {
|
|
78
|
-
case CONTENT_TYPE.FRAGMENT:
|
|
79
|
-
default:
|
|
80
|
-
return customContent;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { withStyles } from '@material-ui/core/styles';
|
|
3
|
-
|
|
4
|
-
const styles = (theme) => ({
|
|
5
|
-
icon: {
|
|
6
|
-
fontFamily: 'Cerebri Sans, Arial, sans-serif',
|
|
7
|
-
fontSize: theme.typography.fontSize,
|
|
8
|
-
fontWeight: 'bold',
|
|
9
|
-
lineHeight: '14px',
|
|
10
|
-
position: 'relative',
|
|
11
|
-
whiteSpace: 'nowrap',
|
|
12
|
-
},
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const HtmlModeIcon = ({ classes, isHtmlMode }) => (
|
|
16
|
-
<div className={classes.icon}>{isHtmlMode ? 'Exit <HTML> mode' : '<HTML>'}</div>
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
export default withStyles(styles)(HtmlModeIcon);
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import HtmlModeIcon from './icons';
|
|
3
|
-
import { htmlToValue, valueToHtml } from './../../serialization';
|
|
4
|
-
|
|
5
|
-
const toggleToRichText = (value, onChange, dismiss) => {
|
|
6
|
-
const plainText = value.document.text;
|
|
7
|
-
const slateValue = dismiss ? value : htmlToValue(plainText);
|
|
8
|
-
|
|
9
|
-
const change = value
|
|
10
|
-
.change()
|
|
11
|
-
.selectAll()
|
|
12
|
-
.delete()
|
|
13
|
-
.insertFragment(slateValue.document);
|
|
14
|
-
onChange(change);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export default function HtmlPlugin(opts) {
|
|
18
|
-
const { isHtmlMode, isEditedInHtmlMode, toggleHtmlMode, handleAlertDialog, currentValue } = opts || {};
|
|
19
|
-
|
|
20
|
-
const handleHtmlModeOn = (value, onChange) => {
|
|
21
|
-
const dialogProps = {
|
|
22
|
-
title: 'Warning',
|
|
23
|
-
text: 'Returning to rich text mode without saving will cause edits to be lost.',
|
|
24
|
-
onConfirmText: 'Dismiss changes',
|
|
25
|
-
onCloseText: 'Continue Editing',
|
|
26
|
-
onConfirm: () => {
|
|
27
|
-
handleAlertDialog(false);
|
|
28
|
-
toggleToRichText(currentValue, onChange, true);
|
|
29
|
-
toggleHtmlMode();
|
|
30
|
-
},
|
|
31
|
-
onClose: () => {
|
|
32
|
-
handleAlertDialog(false);
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
handleAlertDialog(true, dialogProps);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const handleHtmlModeOff = (value, onChange) => {
|
|
40
|
-
const change = value
|
|
41
|
-
.change()
|
|
42
|
-
.selectAll()
|
|
43
|
-
.delete()
|
|
44
|
-
.insertText(valueToHtml(value));
|
|
45
|
-
onChange(change);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
name: 'html',
|
|
50
|
-
toolbar: {
|
|
51
|
-
icon: <HtmlModeIcon isHtmlMode={isHtmlMode} />,
|
|
52
|
-
ariaLabel: 'Html editor',
|
|
53
|
-
buttonStyles: {
|
|
54
|
-
margin: '0 20px 0 auto',
|
|
55
|
-
},
|
|
56
|
-
type: 'html',
|
|
57
|
-
onClick: (value, onChange) => {
|
|
58
|
-
if (isHtmlMode) {
|
|
59
|
-
if (isEditedInHtmlMode) {
|
|
60
|
-
handleHtmlModeOn(value, onChange);
|
|
61
|
-
} else {
|
|
62
|
-
toggleToRichText(value, onChange);
|
|
63
|
-
toggleHtmlMode();
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
handleHtmlModeOff(value, onChange);
|
|
67
|
-
toggleHtmlMode();
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`renders correctly 1`] = `
|
|
4
|
-
Array [
|
|
5
|
-
<span>
|
|
6
|
-
|
|
7
|
-
</span>,
|
|
8
|
-
<div
|
|
9
|
-
className=""
|
|
10
|
-
style={
|
|
11
|
-
Object {
|
|
12
|
-
"justifyContent": "flex-start",
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
>
|
|
16
|
-
<div
|
|
17
|
-
className="MuiLinearProgress-root-1 MuiLinearProgress-colorPrimary-2 MuiLinearProgress-indeterminate-5"
|
|
18
|
-
mode="determinate"
|
|
19
|
-
role="progressbar"
|
|
20
|
-
>
|
|
21
|
-
<div
|
|
22
|
-
className="MuiLinearProgress-bar-11 MuiLinearProgress-barColorPrimary-12 MuiLinearProgress-bar1Indeterminate-14"
|
|
23
|
-
style={Object {}}
|
|
24
|
-
/>
|
|
25
|
-
<div
|
|
26
|
-
className="MuiLinearProgress-bar-11 MuiLinearProgress-barColorPrimary-12 MuiLinearProgress-bar2Indeterminate-17"
|
|
27
|
-
style={Object {}}
|
|
28
|
-
/>
|
|
29
|
-
</div>
|
|
30
|
-
<div>
|
|
31
|
-
<img
|
|
32
|
-
className=""
|
|
33
|
-
onLoad={[Function]}
|
|
34
|
-
style={
|
|
35
|
-
Object {
|
|
36
|
-
"height": "50px",
|
|
37
|
-
"objectFit": "contain",
|
|
38
|
-
"width": "50px",
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
/>
|
|
42
|
-
<div
|
|
43
|
-
className="resize"
|
|
44
|
-
/>
|
|
45
|
-
</div>
|
|
46
|
-
</div>,
|
|
47
|
-
<span>
|
|
48
|
-
|
|
49
|
-
</span>,
|
|
50
|
-
]
|
|
51
|
-
`;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`ImageToolbar onChange renders 1`] = `
|
|
4
|
-
<div>
|
|
5
|
-
<AlignmentButton
|
|
6
|
-
active={false}
|
|
7
|
-
alignment="left"
|
|
8
|
-
onClick={[Function]}
|
|
9
|
-
/>
|
|
10
|
-
<AlignmentButton
|
|
11
|
-
active={false}
|
|
12
|
-
alignment="center"
|
|
13
|
-
onClick={[Function]}
|
|
14
|
-
/>
|
|
15
|
-
<AlignmentButton
|
|
16
|
-
active={false}
|
|
17
|
-
alignment="right"
|
|
18
|
-
onClick={[Function]}
|
|
19
|
-
/>
|
|
20
|
-
<span
|
|
21
|
-
className="undefined"
|
|
22
|
-
onMouseDown={[Function]}
|
|
23
|
-
>
|
|
24
|
-
Alt text
|
|
25
|
-
</span>
|
|
26
|
-
</div>
|
|
27
|
-
`;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`renders correctly 1`] = `
|
|
4
|
-
<div
|
|
5
|
-
className="ImageToolbar-holder-1 holder"
|
|
6
|
-
>
|
|
7
|
-
<button
|
|
8
|
-
aria-label="left"
|
|
9
|
-
aria-pressed={false}
|
|
10
|
-
className="RawMarkButton-button-4"
|
|
11
|
-
onKeyDown={[Function]}
|
|
12
|
-
onMouseDown={[Function]}
|
|
13
|
-
tabIndex={0}
|
|
14
|
-
>
|
|
15
|
-
left
|
|
16
|
-
</button>
|
|
17
|
-
<button
|
|
18
|
-
aria-label="center"
|
|
19
|
-
aria-pressed={false}
|
|
20
|
-
className="RawMarkButton-button-4"
|
|
21
|
-
onKeyDown={[Function]}
|
|
22
|
-
onMouseDown={[Function]}
|
|
23
|
-
tabIndex={0}
|
|
24
|
-
>
|
|
25
|
-
center
|
|
26
|
-
</button>
|
|
27
|
-
<button
|
|
28
|
-
aria-label="right"
|
|
29
|
-
aria-pressed={false}
|
|
30
|
-
className="RawMarkButton-button-4"
|
|
31
|
-
onKeyDown={[Function]}
|
|
32
|
-
onMouseDown={[Function]}
|
|
33
|
-
tabIndex={0}
|
|
34
|
-
>
|
|
35
|
-
right
|
|
36
|
-
</button>
|
|
37
|
-
<span
|
|
38
|
-
className="ImageToolbar-disabled-2 ImageToolbar-altButton-3"
|
|
39
|
-
onMouseDown={[Function]}
|
|
40
|
-
>
|
|
41
|
-
Alt text
|
|
42
|
-
</span>
|
|
43
|
-
</div>
|
|
44
|
-
`;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { Data, Block } from 'slate';
|
|
2
|
-
import { Component } from '../component';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import renderer from 'react-test-renderer';
|
|
5
|
-
|
|
6
|
-
it('renders correctly', () => {
|
|
7
|
-
const node = Block.fromJSON({
|
|
8
|
-
type: 'image',
|
|
9
|
-
data: Data.create({
|
|
10
|
-
width: 50,
|
|
11
|
-
height: 50,
|
|
12
|
-
}),
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const editor = {
|
|
16
|
-
value: {},
|
|
17
|
-
change: jest.fn(),
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const onDelete = jest.fn();
|
|
21
|
-
|
|
22
|
-
const classes = {
|
|
23
|
-
active: 'active',
|
|
24
|
-
loading: 'loading',
|
|
25
|
-
pendingDelete: 'pendingDelete',
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const tree = renderer
|
|
29
|
-
.create(<Component node={node} editor={editor} classes={classes} onDelete={onDelete} />, {
|
|
30
|
-
createNodeMock: (el) => {
|
|
31
|
-
if (el.type === 'img') {
|
|
32
|
-
return {
|
|
33
|
-
naturalWidth: 100,
|
|
34
|
-
naturalHeight: 100,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
})
|
|
39
|
-
.toJSON();
|
|
40
|
-
expect(tree).toMatchSnapshot();
|
|
41
|
-
});
|