Skip to content

Commit 3822e48

Browse files
authored
Merge pull request #6 from edumudu/develop
solved color functionality and bugs in text align
2 parents 4ba4a36 + 561fcd7 commit 3822e48

File tree

5 files changed

+92
-60
lines changed

5 files changed

+92
-60
lines changed

src/assets/scss/editor/main.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
padding: 20px 25px;
66
background-color: #FFF;
77
border-radius: 5px;
8+
box-shadow: 0 0 7px #ccc;
89

910
&-menu {
1011
display: flex;

src/assets/scss/unique/the-header.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ header {
66
color: #FFF;
77
font-size: 2.4rem;
88
font-weight: 600;
9+
box-shadow: 0 0 8px #000;
910
}

src/components/editor/VEditor.vue

Lines changed: 80 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -30,53 +30,76 @@ import { CommandsItem } from '@/@types/index';
3030
const useCommandsHandler = () => {
3131
const actions: Record<string, Function> = {
3232
textAlign(el: HTMLDivElement, value: string) {
33-
const { range, moveCursorToEnd } = useRange();
33+
const { range, setRange, moveCursorToEnd } = useRange();
34+
const { getParentByTagName } = useDOMManipulation();
3435
const common = range.commonAncestorContainer;
3536
let newElement;
3637
37-
if (!el.contains(common) || common.isSameNode(el)) return;
38+
if (!el.contains(common)) return moveCursorToEnd(common.lastChild || common);
39+
40+
if (common.isSameNode(el)) {
41+
if (!el.childElementCount) {
42+
newElement = document.createElement('div');
43+
newElement.style.textAlign = value;
44+
newElement.textContent = '\u200B';
45+
common.appendChild(newElement);
46+
47+
return moveCursorToEnd(newElement || common.lastChild || common);
48+
}
49+
50+
let element = common.firstChild as HTMLElement;
51+
const { startContainer, endContainer, startOffset, endOffset } = range;
52+
let wrapper;
53+
54+
if (element.nodeType === 3) {
55+
wrapper = document.createElement('div');
56+
wrapper.appendChild(element.cloneNode());
57+
common.replaceChild(wrapper, element);
58+
element = wrapper;
59+
}
60+
61+
const start = {
62+
node: startContainer as Text,
63+
offSet: startOffset,
64+
};
65+
66+
const end = {
67+
node: endContainer as Text,
68+
offSet: endOffset,
69+
};
70+
71+
while (!element.contains(wrapper || startContainer)) {
72+
element = element.nextSibling as HTMLElement;
73+
}
74+
75+
while (element) {
76+
element.style.textAlign = value;
77+
element = element.nextSibling as HTMLElement;
78+
}
79+
80+
return setRange(start, end);
81+
}
3882
39-
if (common.parentElement?.isSameNode(el) && common.parentElement?.nodeType === 3) {
40-
newElement = document.createElement('div');
83+
if (common.parentElement?.isSameNode(el)) {
84+
newElement = (common.nodeType === 3 ? document.createElement('div') : common) as HTMLElement;
4185
newElement.appendChild(common.cloneNode());
4286
el.replaceChild(newElement, common);
4387
} else {
44-
newElement = (common.nodeType === 3 ? common.parentElement : common) as HTMLElement;
45-
}
46-
47-
newElement.style.textAlign = value;
48-
moveCursorToEnd(newElement.lastChild as HTMLElement);
49-
},
50-
51-
list(el: HTMLDivElement, value: string) {
52-
const { range, moveCursorToEnd } = useRange();
53-
const common = range.commonAncestorContainer;
54-
55-
if (!el.contains(common) || common.isSameNode(el)) return;
56-
57-
const getChild = (node: HTMLElement | Node): HTMLElement => {
58-
if (node.parentElement?.isSameNode(el)) return node as HTMLElement;
59-
60-
return getChild(node.parentElement as HTMLElement);
61-
};
88+
const parent = getParentByTagName(common, ['div', 'li']) as HTMLElement;
6289
63-
const myNode = getChild(common);
64-
const newEl = document.createElement(value);
65-
const li = document.createElement('li');
90+
if (parent.isSameNode(el)) {
91+
newElement = document.createElement('div');
6692
67-
if (myNode.firstChild?.nodeName === 'LI') {
68-
newEl.append(...Array.from(myNode.children));
69-
} else {
70-
newEl.appendChild(li);
71-
72-
Array.from(myNode.childNodes.length ? myNode.childNodes : [myNode.cloneNode()], (item) => {
73-
li.appendChild(item);
74-
return item;
75-
});
93+
newElement.append(...el.childNodes);
94+
el.appendChild(newElement);
95+
} else {
96+
newElement = parent;
97+
}
7698
}
7799
78-
el.replaceChild(newEl, myNode);
79-
moveCursorToEnd(newEl);
100+
newElement.style.textAlign = value;
101+
102+
return moveCursorToEnd(newElement.lastChild as HTMLElement);
80103
},
81104
82105
color(el: HTMLDivElement, value: string): void {
@@ -85,19 +108,36 @@ const useCommandsHandler = () => {
85108
const { startContainer, startOffset, endOffset, endContainer } = range as Range & { startContainer: Text };
86109
const endSpan = document.createElement('span');
87110
const startSpan = document.createElement('span');
88-
const startTextNode = document.createTextNode(startContainer.textContent?.slice(startOffset) || '\u200B');
111+
const startTextNode = document.createTextNode('');
89112
const endTextNode = document.createTextNode('');
90113
91114
if (!el.contains(startContainer)) return moveCursorToEnd(el.lastChild || el);
92115
116+
startContainer.textContent = startContainer.textContent?.replace(/\s/g, '\u0020') || '';
117+
endContainer.textContent = endContainer.textContent?.replace(/\s/g, '\u0020') || '';
118+
startTextNode.textContent = startContainer.textContent?.slice(startOffset) || '\u200B';
93119
startSpan.style.color = value;
94120
endSpan.style.color = value;
121+
122+
if (startContainer.isSameNode(endContainer)) {
123+
const nodeValue = startTextNode.textContent || '';
124+
const offSetDiff = endOffset - startOffset;
125+
const afterTextNode = document.createTextNode(nodeValue.slice(offSetDiff));
126+
127+
startTextNode.textContent = nodeValue.slice(0, offSetDiff);
128+
129+
startSpan.appendChild(startTextNode);
130+
startContainer.replaceData(startOffset, -1, '');
131+
startContainer.after(startSpan);
132+
startSpan.after(afterTextNode);
133+
134+
return range.selectNodeContents(startSpan);
135+
}
136+
95137
startSpan.appendChild(startTextNode);
96-
startContainer.replaceData(startOffset, -1, '');
138+
startContainer.replaceData(startOffset, startTextNode.nodeValue?.length || -1, '');
97139
startContainer.after(startSpan);
98140
99-
if (startContainer.isSameNode(endContainer)) return setRange({ node: startTextNode }, { node: startTextNode });
100-
101141
const endNode = getEndNode(startTextNode, endContainer, (n) => {
102142
const sibling = (n.nodeType === 3 ? n.parentElement : n) as HTMLElement;
103143
sibling.style.color = value;

src/components/editor/VEditorHead.vue

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@
66
@changeCommand="onChangeCommand"
77
/>
88

9-
<v-editor-group
10-
:items="commands.lists"
11-
:selected="listType"
12-
@changeCommand="onChangeCommand"
13-
/>
14-
159
<input
1610
type="color"
1711
:value="fontColor"
@@ -75,19 +69,6 @@ export default defineComponent({
7569
icon: 'format-align-justify',
7670
},
7771
],
78-
79-
lists: [
80-
{
81-
command: 'list',
82-
value: 'ul',
83-
icon: 'format-list-bulleted',
84-
},
85-
{
86-
command: 'list',
87-
value: 'ol',
88-
icon: 'format-list-numbered',
89-
},
90-
],
9172
});
9273
9374
const { onChangeCommand } = useExecuteCommand(emit);

src/shared/DOMManipulation.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,14 @@ export const useDOMManipulation = () => {
1616
return getEndNode(n.parentNode as NodeText, endNode, wrapCallback);
1717
};
1818

19-
return { getEndNode };
19+
const getParentByTagName = (node: Node, names: string | string[]): Node => {
20+
const namesUpperCase = typeof names === 'string' ? [names.toLowerCase()] : names.map((name) => name.toUpperCase());
21+
22+
return namesUpperCase.includes(node.nodeName) ? node : getParentByTagName(node.parentNode as Node, names);
23+
};
24+
25+
return {
26+
getEndNode,
27+
getParentByTagName,
28+
};
2029
};

0 commit comments

Comments
 (0)