@@ -30,53 +30,76 @@ import { CommandsItem } from '@/@types/index';
3030const 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 ;
0 commit comments