@zipify/wysiwyg 2.0.0-2 → 2.0.0-3
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/dist/cli.js +2 -2
- package/dist/wysiwyg.mjs +40 -15
- package/lib/enums/TextSettings.js +1 -1
- package/lib/extensions/BackgroundColor.js +1 -2
- package/lib/extensions/StylePreset.js +1 -1
- package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +25 -25
- package/lib/extensions/core/NodeProcessor.js +12 -1
- package/lib/services/normalizer/HtmlNormalizer.js +23 -0
- package/lib/services/normalizer/JsonNormalizer.js +1 -1
- package/lib/services/normalizer/__tests__/JsonNormalizer.test.js +15 -0
- package/lib/services/normalizer/__tests__/__snapshots__/JsonNormalizer.test.js.snap +37 -0
- package/lib/utils/__tests__/isNodeFullySelected.test.js +21 -30
- package/lib/utils/isNodeFullySelected.js +4 -11
- package/package.json +1 -1
package/dist/wysiwyg.mjs
CHANGED
|
@@ -26,7 +26,7 @@ var __privateMethod = (obj, member, method) => {
|
|
|
26
26
|
__accessCheck(obj, member, "access private method");
|
|
27
27
|
return method;
|
|
28
28
|
};
|
|
29
|
-
var _domParser, _parser, _NodeFilter, NodeFilter_get, _Node, Node_get, _removeComments, removeComments_fn, _createNodeIterator, createNodeIterator_fn, _iterateNodes, iterateNodes_fn, _runIterator, runIterator_fn, _removeEmptyNodes, removeEmptyNodes_fn, _normalizeListItems, normalizeListItems_fn, _isBlockNode, isBlockNode_fn, _assignElementProperties, assignElementProperties_fn, _removeStyleProperties, removeStyleProperties_fn, _normalizeBreakLines, normalizeBreakLines_fn, _normalizeBlockTextDecoration, normalizeBlockTextDecoration_fn, _moveTextDecorationToChildren, moveTextDecorationToChildren_fn, _parseTextDecoration, parseTextDecoration_fn, _wrapTextNode, wrapTextNode_fn, _iterateNodes2, iterateNodes_fn2, _iterateChildNodes, iterateChildNodes_fn, _bubbleMarks, bubbleMarks_fn, _canBubbleMark, canBubbleMark_fn, _includesMark, includesMark_fn, _includesMarkType, includesMarkType_fn, _removeMark, removeMark_fn, _addMark, addMark_fn, _findMarkIndexByType, findMarkIndexByType_fn, _buildHtml, buildHtml_fn, _buildJson, buildJson_fn, _textBlock, textBlock_fn, _normalizeTextBlockArgs, normalizeTextBlockArgs_fn;
|
|
29
|
+
var _domParser, _parser, _NodeFilter, NodeFilter_get, _Node, Node_get, _removeComments, removeComments_fn, _createNodeIterator, createNodeIterator_fn, _iterateNodes, iterateNodes_fn, _runIterator, runIterator_fn, _removeEmptyNodes, removeEmptyNodes_fn, _normalizeListItems, normalizeListItems_fn, _isBlockNode, isBlockNode_fn, _assignElementProperties, assignElementProperties_fn, _removeStyleProperties, removeStyleProperties_fn, _normalizeBreakLines, normalizeBreakLines_fn, _normalizeBlockTextDecoration, normalizeBlockTextDecoration_fn, _moveTextDecorationToChildren, moveTextDecorationToChildren_fn, _parseTextDecoration, parseTextDecoration_fn, _normalizeBlockBackgroundColor, normalizeBlockBackgroundColor_fn, _moveBackgroundColorToChildren, moveBackgroundColorToChildren_fn, _wrapTextNode, wrapTextNode_fn, _iterateNodes2, iterateNodes_fn2, _iterateChildNodes, iterateChildNodes_fn, _bubbleMarks, bubbleMarks_fn, _canBubbleMark, canBubbleMark_fn, _includesMark, includesMark_fn, _includesMarkType, includesMarkType_fn, _removeMark, removeMark_fn, _addMark, addMark_fn, _findMarkIndexByType, findMarkIndexByType_fn, _buildHtml, buildHtml_fn, _buildJson, buildJson_fn, _textBlock, textBlock_fn, _normalizeTextBlockArgs, normalizeTextBlockArgs_fn;
|
|
30
30
|
import { computed, ref, watch, inject, onUnmounted, nextTick, provide, onMounted, toRef, unref, reactive } from "vue";
|
|
31
31
|
import { ColorModel, ZipifyColorPicker } from "@zipify/colorpicker";
|
|
32
32
|
function OrderedMap(content) {
|
|
@@ -14031,7 +14031,7 @@ const TextSettings = Object.freeze({
|
|
|
14031
14031
|
return [this.ALIGNMENT, this.LINE_HEIGHT, this.MARGIN];
|
|
14032
14032
|
},
|
|
14033
14033
|
get inlineMarks() {
|
|
14034
|
-
return [this.TEXT_DECORATION, this.LINK, this.SUPERSCRIPT];
|
|
14034
|
+
return [this.TEXT_DECORATION, this.LINK, this.SUPERSCRIPT, this.BACKGROUND_COLOR];
|
|
14035
14035
|
},
|
|
14036
14036
|
get marks() {
|
|
14037
14037
|
return [
|
|
@@ -14459,15 +14459,10 @@ const resolveTextPosition = ($from, $to, node, position) => ({
|
|
|
14459
14459
|
from: Math.max(position, $from.pos),
|
|
14460
14460
|
to: Math.min(position + node.nodeSize, $to.pos)
|
|
14461
14461
|
});
|
|
14462
|
-
function
|
|
14463
|
-
const
|
|
14464
|
-
const
|
|
14465
|
-
|
|
14466
|
-
}
|
|
14467
|
-
function isNodeFullySelected($from, $to, node, position) {
|
|
14468
|
-
const offset2 = resolveNodeTextOffset($from, node);
|
|
14469
|
-
const isFromMatch = $from.pos - offset2 <= position;
|
|
14470
|
-
const isToMatch = $to.pos + offset2 >= node.nodeSize + position;
|
|
14462
|
+
function isNodeFullySelected(doc2, selection, node, position) {
|
|
14463
|
+
const offset2 = doc2.resolve(position).depth + 1;
|
|
14464
|
+
const isFromMatch = selection.from - offset2 <= position;
|
|
14465
|
+
const isToMatch = selection.to + offset2 >= node.nodeSize + position;
|
|
14471
14466
|
return isFromMatch && isToMatch;
|
|
14472
14467
|
}
|
|
14473
14468
|
function isMarkAppliedToParent(doc2, position, checkingMark) {
|
|
@@ -19558,6 +19553,8 @@ const _HtmlNormalizer = class extends BaseNormalizer {
|
|
|
19558
19553
|
__privateAdd(this, _normalizeBlockTextDecoration);
|
|
19559
19554
|
__privateAdd(this, _moveTextDecorationToChildren);
|
|
19560
19555
|
__privateAdd(this, _parseTextDecoration);
|
|
19556
|
+
__privateAdd(this, _normalizeBlockBackgroundColor);
|
|
19557
|
+
__privateAdd(this, _moveBackgroundColorToChildren);
|
|
19561
19558
|
__privateAdd(this, _wrapTextNode);
|
|
19562
19559
|
__privateAdd(this, _parser, void 0);
|
|
19563
19560
|
__privateSet(this, _parser, parser);
|
|
@@ -19574,6 +19571,7 @@ const _HtmlNormalizer = class extends BaseNormalizer {
|
|
|
19574
19571
|
__privateMethod(this, _iterateNodes, iterateNodes_fn).call(this, __privateMethod(this, _removeEmptyNodes, removeEmptyNodes_fn), __privateMethod(this, _isBlockNode, isBlockNode_fn));
|
|
19575
19572
|
__privateMethod(this, _iterateNodes, iterateNodes_fn).call(this, __privateMethod(this, _normalizeListItems, normalizeListItems_fn), (node) => node.tagName === "LI");
|
|
19576
19573
|
__privateMethod(this, _normalizeBlockTextDecoration, normalizeBlockTextDecoration_fn).call(this);
|
|
19574
|
+
__privateMethod(this, _normalizeBlockBackgroundColor, normalizeBlockBackgroundColor_fn).call(this);
|
|
19577
19575
|
}
|
|
19578
19576
|
get normalizedHTML() {
|
|
19579
19577
|
return this.dom.body.innerHTML;
|
|
@@ -19746,6 +19744,25 @@ parseTextDecoration_fn = function(element) {
|
|
|
19746
19744
|
line_through: decoration.includes("line-through")
|
|
19747
19745
|
};
|
|
19748
19746
|
};
|
|
19747
|
+
_normalizeBlockBackgroundColor = new WeakSet();
|
|
19748
|
+
normalizeBlockBackgroundColor_fn = function() {
|
|
19749
|
+
const blockEls = this.dom.querySelectorAll('[style*="background-color"]:where(p, h1, h2, h3, h4, li)');
|
|
19750
|
+
for (const blockEl of blockEls) {
|
|
19751
|
+
__privateMethod(this, _moveBackgroundColorToChildren, moveBackgroundColorToChildren_fn).call(this, blockEl);
|
|
19752
|
+
}
|
|
19753
|
+
};
|
|
19754
|
+
_moveBackgroundColorToChildren = new WeakSet();
|
|
19755
|
+
moveBackgroundColorToChildren_fn = function(blockEl) {
|
|
19756
|
+
const blockColor = blockEl.style.backgroundColor;
|
|
19757
|
+
blockEl.style.removeProperty("background-color");
|
|
19758
|
+
if (!blockEl.style.cssText)
|
|
19759
|
+
blockEl.removeAttribute("style");
|
|
19760
|
+
for (const childNode of blockEl.childNodes) {
|
|
19761
|
+
const textEl = __privateMethod(this, _wrapTextNode, wrapTextNode_fn).call(this, blockEl, childNode);
|
|
19762
|
+
const color = textEl.style.backgroundColor || blockColor;
|
|
19763
|
+
textEl.style.backgroundColor = color;
|
|
19764
|
+
}
|
|
19765
|
+
};
|
|
19749
19766
|
_wrapTextNode = new WeakSet();
|
|
19750
19767
|
wrapTextNode_fn = function(parent, node) {
|
|
19751
19768
|
if (node.nodeType !== __privateGet(this, _Node, Node_get).TEXT_NODE)
|
|
@@ -20680,7 +20697,7 @@ canBubbleMark_fn = function(node, childMark) {
|
|
|
20680
20697
|
for (const child of node.content) {
|
|
20681
20698
|
if (!child.marks)
|
|
20682
20699
|
return false;
|
|
20683
|
-
if (!__privateMethod(this,
|
|
20700
|
+
if (!__privateMethod(this, _includesMark, includesMark_fn).call(this, child, childMark))
|
|
20684
20701
|
return false;
|
|
20685
20702
|
}
|
|
20686
20703
|
return true;
|
|
@@ -24177,7 +24194,7 @@ const StylePreset = Extension.create({
|
|
|
24177
24194
|
chain().storeSelection().expandSelectionToBlock().removeMarks(TextSettings.marks).resetAttributes(NodeTypes.PARAGRAPH, TextSettings.attributes).resetAttributes(NodeTypes.HEADING, TextSettings.attributes).restoreSelection().run();
|
|
24178
24195
|
}),
|
|
24179
24196
|
removeFormat: createCommand(({ chain }) => {
|
|
24180
|
-
chain().storeSelection().expandSelectionToBlock().
|
|
24197
|
+
chain().storeSelection().expandSelectionToBlock().removeAllMarks().applyDefaultPreset().restoreSelection().run();
|
|
24181
24198
|
})
|
|
24182
24199
|
};
|
|
24183
24200
|
},
|
|
@@ -24394,7 +24411,6 @@ const FontColor = Mark.create({
|
|
|
24394
24411
|
});
|
|
24395
24412
|
const BackgroundColor = Mark.create({
|
|
24396
24413
|
name: TextSettings.BACKGROUND_COLOR,
|
|
24397
|
-
group: MarkGroups.SETTINGS,
|
|
24398
24414
|
addAttributes: () => ({
|
|
24399
24415
|
value: { required: true }
|
|
24400
24416
|
}),
|
|
@@ -26778,7 +26794,7 @@ const NodeProcessor = Extension.create({
|
|
|
26778
26794
|
tr.addMark(textPosition.from, textPosition.to, applyingMark);
|
|
26779
26795
|
return;
|
|
26780
26796
|
}
|
|
26781
|
-
if (isNodeFullySelected(
|
|
26797
|
+
if (isNodeFullySelected(tr.doc, tr.selection, node, position)) {
|
|
26782
26798
|
tr.step(new AddNodeMarkStep(position, applyingMark));
|
|
26783
26799
|
}
|
|
26784
26800
|
});
|
|
@@ -26824,6 +26840,15 @@ const NodeProcessor = Extension.create({
|
|
|
26824
26840
|
return unref(defaultRef);
|
|
26825
26841
|
});
|
|
26826
26842
|
}),
|
|
26843
|
+
removeAllMarks: createCommand(({ state, commands: commands2 }) => {
|
|
26844
|
+
const { tr, doc: doc2 } = state;
|
|
26845
|
+
const { from: from2, to } = tr.selection;
|
|
26846
|
+
doc2.nodesBetween(from2, to, (node, position) => {
|
|
26847
|
+
for (const mark of node.marks) {
|
|
26848
|
+
commands2._removeNodeMark({ tr, node, position, mark });
|
|
26849
|
+
}
|
|
26850
|
+
});
|
|
26851
|
+
}),
|
|
26827
26852
|
removeMarks: createCommand(({ state, commands: commands2 }, marks) => {
|
|
26828
26853
|
const { tr, doc: doc2 } = state;
|
|
26829
26854
|
const { from: from2, to } = tr.selection;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Mark } from '@tiptap/vue-2';
|
|
2
2
|
import { convertColor, createCommand, renderMark } from '../utils';
|
|
3
|
-
import {
|
|
3
|
+
import { TextSettings } from '../enums';
|
|
4
4
|
|
|
5
5
|
export const BackgroundColor = Mark.create({
|
|
6
6
|
name: TextSettings.BACKGROUND_COLOR,
|
|
7
|
-
group: MarkGroups.SETTINGS,
|
|
8
7
|
|
|
9
8
|
addAttributes: () => ({
|
|
10
9
|
value: { required: true }
|
|
@@ -6,18 +6,18 @@ Object {
|
|
|
6
6
|
Object {
|
|
7
7
|
"content": Array [
|
|
8
8
|
Object {
|
|
9
|
+
"marks": Array [
|
|
10
|
+
Object {
|
|
11
|
+
"attrs": Object {
|
|
12
|
+
"value": "green",
|
|
13
|
+
},
|
|
14
|
+
"type": "background_color",
|
|
15
|
+
},
|
|
16
|
+
],
|
|
9
17
|
"text": "hello world",
|
|
10
18
|
"type": "text",
|
|
11
19
|
},
|
|
12
20
|
],
|
|
13
|
-
"marks": Array [
|
|
14
|
-
Object {
|
|
15
|
-
"attrs": Object {
|
|
16
|
-
"value": "green",
|
|
17
|
-
},
|
|
18
|
-
"type": "background_color",
|
|
19
|
-
},
|
|
20
|
-
],
|
|
21
21
|
"type": "paragraph",
|
|
22
22
|
},
|
|
23
23
|
],
|
|
@@ -31,18 +31,18 @@ Object {
|
|
|
31
31
|
Object {
|
|
32
32
|
"content": Array [
|
|
33
33
|
Object {
|
|
34
|
+
"marks": Array [
|
|
35
|
+
Object {
|
|
36
|
+
"attrs": Object {
|
|
37
|
+
"value": "#FF0000",
|
|
38
|
+
},
|
|
39
|
+
"type": "background_color",
|
|
40
|
+
},
|
|
41
|
+
],
|
|
34
42
|
"text": "test",
|
|
35
43
|
"type": "text",
|
|
36
44
|
},
|
|
37
45
|
],
|
|
38
|
-
"marks": Array [
|
|
39
|
-
Object {
|
|
40
|
-
"attrs": Object {
|
|
41
|
-
"value": "#FF0000",
|
|
42
|
-
},
|
|
43
|
-
"type": "background_color",
|
|
44
|
-
},
|
|
45
|
-
],
|
|
46
46
|
"type": "paragraph",
|
|
47
47
|
},
|
|
48
48
|
],
|
|
@@ -126,18 +126,18 @@ Object {
|
|
|
126
126
|
"type": "text",
|
|
127
127
|
},
|
|
128
128
|
Object {
|
|
129
|
+
"marks": Array [
|
|
130
|
+
Object {
|
|
131
|
+
"attrs": Object {
|
|
132
|
+
"value": "#FF0000",
|
|
133
|
+
},
|
|
134
|
+
"type": "background_color",
|
|
135
|
+
},
|
|
136
|
+
],
|
|
129
137
|
"text": " ipsum",
|
|
130
138
|
"type": "text",
|
|
131
139
|
},
|
|
132
140
|
],
|
|
133
|
-
"marks": Array [
|
|
134
|
-
Object {
|
|
135
|
-
"attrs": Object {
|
|
136
|
-
"value": "#FF0000",
|
|
137
|
-
},
|
|
138
|
-
"type": "background_color",
|
|
139
|
-
},
|
|
140
|
-
],
|
|
141
141
|
"type": "paragraph",
|
|
142
142
|
},
|
|
143
143
|
],
|
|
@@ -145,4 +145,4 @@ Object {
|
|
|
145
145
|
}
|
|
146
146
|
`;
|
|
147
147
|
|
|
148
|
-
exports[`rendering should render html 1`] = `"<span style="--zw-background-color:green;" class="zw-style"
|
|
148
|
+
exports[`rendering should render html 1`] = `"<p class="zw-style"><span style="--zw-background-color:green;" class="zw-style">hello world</span></p>"`;
|
|
@@ -66,7 +66,7 @@ export const NodeProcessor = Extension.create({
|
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
if (isNodeFullySelected(
|
|
69
|
+
if (isNodeFullySelected(tr.doc, tr.selection, node, position)) {
|
|
70
70
|
tr.step(new AddNodeMarkStep(position, applyingMark));
|
|
71
71
|
}
|
|
72
72
|
});
|
|
@@ -117,6 +117,17 @@ export const NodeProcessor = Extension.create({
|
|
|
117
117
|
});
|
|
118
118
|
}),
|
|
119
119
|
|
|
120
|
+
removeAllMarks: createCommand(({ state, commands }) => {
|
|
121
|
+
const { tr, doc } = state;
|
|
122
|
+
const { from, to } = tr.selection;
|
|
123
|
+
|
|
124
|
+
doc.nodesBetween(from, to, (node, position) => {
|
|
125
|
+
for (const mark of node.marks) {
|
|
126
|
+
commands._removeNodeMark({ tr, node, position, mark });
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}),
|
|
130
|
+
|
|
120
131
|
removeMarks: createCommand(({ state, commands }, marks) => {
|
|
121
132
|
const { tr, doc } = state;
|
|
122
133
|
const { from, to } = tr.selection;
|
|
@@ -34,6 +34,7 @@ export class HtmlNormalizer extends BaseNormalizer {
|
|
|
34
34
|
this.#iterateNodes(this.#removeEmptyNodes, this.#isBlockNode);
|
|
35
35
|
this.#iterateNodes(this.#normalizeListItems, (node) => node.tagName === 'LI');
|
|
36
36
|
this.#normalizeBlockTextDecoration();
|
|
37
|
+
this.#normalizeBlockBackgroundColor();
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
get normalizedHTML() {
|
|
@@ -232,6 +233,28 @@ export class HtmlNormalizer extends BaseNormalizer {
|
|
|
232
233
|
};
|
|
233
234
|
}
|
|
234
235
|
|
|
236
|
+
#normalizeBlockBackgroundColor() {
|
|
237
|
+
const blockEls = this.dom.querySelectorAll('[style*="background-color"]:where(p, h1, h2, h3, h4, li)');
|
|
238
|
+
|
|
239
|
+
for (const blockEl of blockEls) {
|
|
240
|
+
this.#moveBackgroundColorToChildren(blockEl);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#moveBackgroundColorToChildren(blockEl) {
|
|
245
|
+
const blockColor = blockEl.style.backgroundColor;
|
|
246
|
+
|
|
247
|
+
blockEl.style.removeProperty('background-color');
|
|
248
|
+
if (!blockEl.style.cssText) blockEl.removeAttribute('style');
|
|
249
|
+
|
|
250
|
+
for (const childNode of blockEl.childNodes) {
|
|
251
|
+
const textEl = this.#wrapTextNode(blockEl, childNode);
|
|
252
|
+
const color = textEl.style.backgroundColor || blockColor;
|
|
253
|
+
|
|
254
|
+
textEl.style.backgroundColor = color;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
235
258
|
#wrapTextNode(parent, node) {
|
|
236
259
|
if (node.nodeType !== this.#Node.TEXT_NODE) return node;
|
|
237
260
|
|
|
@@ -46,7 +46,7 @@ export class JsonNormalizer extends BaseNormalizer {
|
|
|
46
46
|
|
|
47
47
|
for (const child of node.content) {
|
|
48
48
|
if (!child.marks) return false;
|
|
49
|
-
if (!this.#
|
|
49
|
+
if (!this.#includesMark(child, childMark)) return false;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
return true;
|
|
@@ -67,4 +67,19 @@ describe('normalize json content', () => {
|
|
|
67
67
|
|
|
68
68
|
expect(ContentNormalizer.normalize(input)).toMatchSnapshot();
|
|
69
69
|
});
|
|
70
|
+
|
|
71
|
+
test('should not marge mark with same type', () => {
|
|
72
|
+
const input = NodeFactory.doc([
|
|
73
|
+
NodeFactory.paragraph([
|
|
74
|
+
NodeFactory.text('lorem', [
|
|
75
|
+
NodeFactory.mark(TextSettings.FONT_WEIGHT, { value: '700' })
|
|
76
|
+
]),
|
|
77
|
+
NodeFactory.text(' ipsum', [
|
|
78
|
+
NodeFactory.mark(TextSettings.FONT_WEIGHT, { value: '400' })
|
|
79
|
+
])
|
|
80
|
+
])
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
expect(ContentNormalizer.normalize(input)).toMatchSnapshot();
|
|
84
|
+
});
|
|
70
85
|
});
|
|
@@ -157,3 +157,40 @@ Object {
|
|
|
157
157
|
"type": "doc",
|
|
158
158
|
}
|
|
159
159
|
`;
|
|
160
|
+
|
|
161
|
+
exports[`normalize json content should not marge mark with same type 1`] = `
|
|
162
|
+
Object {
|
|
163
|
+
"content": Array [
|
|
164
|
+
Object {
|
|
165
|
+
"content": Array [
|
|
166
|
+
Object {
|
|
167
|
+
"marks": Array [
|
|
168
|
+
Object {
|
|
169
|
+
"attrs": Object {
|
|
170
|
+
"value": "700",
|
|
171
|
+
},
|
|
172
|
+
"type": "font_weight",
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
"text": "lorem",
|
|
176
|
+
"type": "text",
|
|
177
|
+
},
|
|
178
|
+
Object {
|
|
179
|
+
"marks": Array [
|
|
180
|
+
Object {
|
|
181
|
+
"attrs": Object {
|
|
182
|
+
"value": "400",
|
|
183
|
+
},
|
|
184
|
+
"type": "font_weight",
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
"text": " ipsum",
|
|
188
|
+
"type": "text",
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
"type": "paragraph",
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
"type": "doc",
|
|
195
|
+
}
|
|
196
|
+
`;
|
|
@@ -1,52 +1,43 @@
|
|
|
1
1
|
import { isNodeFullySelected } from '../isNodeFullySelected';
|
|
2
2
|
|
|
3
|
-
const createResolvedPosition = (attrs = {}) => ({
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const createResolvedPosition = (attrs = {}) => ({ ...attrs });
|
|
4
|
+
const createSelection = (from, to) => ({ from, to });
|
|
5
|
+
|
|
6
|
+
const createNode = (attrs = {}) => ({
|
|
7
|
+
resolve: jest.fn(() => 0),
|
|
6
8
|
...attrs
|
|
7
9
|
});
|
|
8
10
|
|
|
9
|
-
const createNode = (attrs = {}) => ({ ...attrs });
|
|
10
|
-
|
|
11
11
|
describe('is node fully selected', () => {
|
|
12
12
|
test('should return false if selected part of text node', () => {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
);
|
|
13
|
+
const doc = createNode();
|
|
14
|
+
const paragraph = createNode({ nodeSize: 245 });
|
|
15
|
+
|
|
16
|
+
doc.resolve.mockReturnValue(createResolvedPosition({ depth: 0 }));
|
|
17
|
+
|
|
18
|
+
const isSelected = isNodeFullySelected(doc, createSelection(7, 12), paragraph, 0);
|
|
20
19
|
|
|
21
20
|
expect(isSelected).toBe(false);
|
|
22
21
|
});
|
|
23
22
|
|
|
24
23
|
test('should return true if selected paragraph node', () => {
|
|
24
|
+
const doc = createNode();
|
|
25
25
|
const paragraph = createNode({ nodeSize: 245 });
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
0
|
|
31
|
-
);
|
|
26
|
+
|
|
27
|
+
doc.resolve.mockReturnValue(createResolvedPosition({ depth: 0 }));
|
|
28
|
+
|
|
29
|
+
const isSelected = isNodeFullySelected(doc, createSelection(1, 244), paragraph, 0);
|
|
32
30
|
|
|
33
31
|
expect(isSelected).toBe(true);
|
|
34
32
|
});
|
|
35
33
|
|
|
36
34
|
test('should return true if selected list item node', () => {
|
|
35
|
+
const doc = createNode();
|
|
37
36
|
const listItem = createNode({ nodeSize: 247 });
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}),
|
|
43
|
-
createResolvedPosition({
|
|
44
|
-
pos: 246,
|
|
45
|
-
path: [createNode(), 0, 0, createNode(), 0, 1, listItem, 0, 2, createNode(), 0, 3]
|
|
46
|
-
}),
|
|
47
|
-
listItem,
|
|
48
|
-
1
|
|
49
|
-
);
|
|
37
|
+
|
|
38
|
+
doc.resolve.mockReturnValue(createResolvedPosition({ depth: 2 }));
|
|
39
|
+
|
|
40
|
+
const isSelected = isNodeFullySelected(doc, createSelection(3, 246), listItem, 1);
|
|
50
41
|
|
|
51
42
|
expect(isSelected).toBe(true);
|
|
52
43
|
});
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
function
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
return nodes.slice(index).reverse().length;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function isNodeFullySelected($from, $to, node, position) {
|
|
9
|
-
const offset = resolveNodeTextOffset($from, node);
|
|
10
|
-
const isFromMatch = $from.pos - offset <= position;
|
|
11
|
-
const isToMatch = $to.pos + offset >= node.nodeSize + position;
|
|
1
|
+
export function isNodeFullySelected(doc, selection, node, position) {
|
|
2
|
+
const offset = doc.resolve(position).depth + 1;
|
|
3
|
+
const isFromMatch = selection.from - offset <= position;
|
|
4
|
+
const isToMatch = selection.to + offset >= node.nodeSize + position;
|
|
12
5
|
|
|
13
6
|
return isFromMatch && isToMatch;
|
|
14
7
|
}
|