@@ -4,9 +4,23 @@ import {genEmptyBlock} from "../../block/util";
44import * as dayjs from "dayjs" ;
55import { Constants } from "../../constants" ;
66import { moveToPrevious , removeBlock } from "./remove" ;
7- import { hasClosestBlock , hasClosestByClassName , isBlockElement } from "../util/hasClosest" ;
7+ import { hasClosestByClassName , isBlockElement } from "../util/hasClosest" ;
88import { setFold } from "../../menus/protyle" ;
99
10+ const getLastChildBlock = ( element : Element ) : Element | null => {
11+ if ( ! element || ! element . lastElementChild ) {
12+ return null ;
13+ }
14+ let current = element . lastElementChild . previousElementSibling ;
15+ while ( current ) {
16+ if ( isBlockElement ( current ) ) {
17+ return current ;
18+ }
19+ current = current . previousElementSibling ;
20+ }
21+ return null ;
22+ } ;
23+
1024export const updateListOrder = ( listElement : Element , sIndex ?: number ) => {
1125 if ( listElement . getAttribute ( "data-subtype" ) !== "o" ) {
1226 return ;
@@ -73,7 +87,10 @@ export const addSubList = (protyle: IProtyle, nodeElement: Element, range: Range
7387
7488 // 无列表块:在列表项块的最后一个子块后面插入新的列表块
7589 if ( ! listElement ) {
76- const lastChildBlock = liElement . lastElementChild . previousElementSibling ;
90+ const lastChildBlock = getLastChildBlock ( liElement ) ;
91+ if ( ! lastChildBlock ) {
92+ return ;
93+ }
7794 const subType = liElement . getAttribute ( "data-subtype" ) || "u" ;
7895 const id = Lute . NewNodeID ( ) ;
7996 const newListItemElement = genListItemElement ( liElement , 0 , true , 1 ) ;
@@ -93,7 +110,7 @@ export const addSubList = (protyle: IProtyle, nodeElement: Element, range: Range
93110 }
94111
95112 // 有列表块:在列表块的最后一个列表项块后插入新的列表项块
96- const lastSubItem = listElement . lastElementChild . previousElementSibling ;
113+ const lastSubItem = getLastChildBlock ( listElement ) ;
97114 if ( lastSubItem ) {
98115 const newListElement = genListItemElement ( lastSubItem , 0 , true ) ;
99116 const id = newListElement . getAttribute ( "data-node-id" ) ;
@@ -141,15 +158,17 @@ export const listIndent = (protyle: IProtyle, liItemElements: Element[], range:
141158 range . collapse ( false ) ;
142159 range . insertNode ( document . createElement ( "wbr" ) ) ;
143160 const html = previousElement . parentElement . outerHTML ;
144- if ( previousElement . lastElementChild . previousElementSibling . getAttribute ( "data-type" ) === "NodeList" ) {
161+ const previousLastBlock = getLastChildBlock ( previousElement ) ;
162+ if ( previousLastBlock && previousLastBlock . getAttribute ( "data-type" ) === "NodeList" ) {
145163 // 上一个列表的最后一项为子列表
146- const previousLastListHTML = previousElement . lastElementChild . previousElementSibling . outerHTML ;
164+ const previousLastListHTML = previousLastBlock . outerHTML ;
147165
148166 const doOperations : IOperation [ ] = [ ] ;
149167 const undoOperations : IOperation [ ] = [ ] ;
150168
151- const subtype = previousElement . lastElementChild . previousElementSibling . getAttribute ( "data-subtype" ) ;
152- let previousID = previousElement . lastElementChild . previousElementSibling . lastElementChild . previousElementSibling . getAttribute ( "data-node-id" ) ;
169+ const subtype = previousLastBlock . getAttribute ( "data-subtype" ) ;
170+ const previousLastListLastBlock = getLastChildBlock ( previousLastBlock ) ;
171+ let previousID = previousLastListLastBlock ? previousLastListLastBlock . getAttribute ( "data-node-id" ) : undefined ;
153172 liItemElements . forEach ( ( item , index ) => {
154173 doOperations . push ( {
155174 action : "move" ,
@@ -167,23 +186,23 @@ export const listIndent = (protyle: IProtyle, liItemElements: Element[], range:
167186 if ( subtype === "o" ) {
168187 actionElement . classList . add ( "protyle-action--order" ) ;
169188 actionElement . classList . remove ( "protyle-action--task" ) ;
170- previousElement . lastElementChild . previousElementSibling . lastElementChild . before ( item ) ;
189+ previousLastBlock . lastElementChild . before ( item ) ;
171190 } else if ( subtype === "t" ) {
172191 item . setAttribute ( "data-marker" , "*" ) ;
173192 actionElement . innerHTML = `<svg><use xlink:href="#icon${ item . classList . contains ( "protyle-task--done" ) ? "Check" : "Uncheck" } "></use></svg>` ;
174193 actionElement . classList . remove ( "protyle-action--order" ) ;
175194 actionElement . classList . add ( "protyle-action--task" ) ;
176- previousElement . lastElementChild . previousElementSibling . lastElementChild . before ( item ) ;
195+ previousLastBlock . lastElementChild . before ( item ) ;
177196 } else {
178197 item . setAttribute ( "data-marker" , "*" ) ;
179198 actionElement . innerHTML = '<svg><use xlink:href="#iconDot"></use></svg>' ;
180199 actionElement . classList . remove ( "protyle-action--order" , "protyle-action--task" ) ;
181- previousElement . lastElementChild . previousElementSibling . lastElementChild . before ( item ) ;
200+ previousLastBlock . lastElementChild . before ( item ) ;
182201 }
183202 } ) ;
184203
185204 if ( subtype === "o" ) {
186- updateListOrder ( previousElement . lastElementChild . previousElementSibling ) ;
205+ updateListOrder ( previousLastBlock ) ;
187206 updateListOrder ( previousElement . parentElement ) ;
188207 } else if ( previousElement . getAttribute ( "data-subtype" ) === "o" ) {
189208 updateListOrder ( previousElement . parentElement ) ;
@@ -192,13 +211,13 @@ export const listIndent = (protyle: IProtyle, liItemElements: Element[], range:
192211 if ( previousElement . parentElement . classList . contains ( "protyle-wysiwyg" ) ) {
193212 doOperations . push ( {
194213 action : "update" ,
195- data : previousElement . lastElementChild . previousElementSibling . outerHTML ,
196- id : previousElement . lastElementChild . previousElementSibling . getAttribute ( "data-node-id" )
214+ data : previousLastBlock . outerHTML ,
215+ id : previousLastBlock . getAttribute ( "data-node-id" )
197216 } ) ;
198217 undoOperations . push ( {
199218 action : "update" ,
200219 data : previousLastListHTML ,
201- id : previousElement . lastElementChild . previousElementSibling . getAttribute ( "data-node-id" )
220+ id : previousLastBlock . getAttribute ( "data-node-id" )
202221 } ) ;
203222 transaction ( protyle , doOperations , undoOperations ) ;
204223 }
@@ -212,11 +231,12 @@ export const listIndent = (protyle: IProtyle, liItemElements: Element[], range:
212231 newListElement . setAttribute ( "class" , "list" ) ;
213232 newListElement . setAttribute ( "data-subtype" , subType ) ;
214233 newListElement . innerHTML = '<div class="protyle-attr" contenteditable="false"></div>' ;
234+ const previousLastBlockForNewList = getLastChildBlock ( previousElement ) ;
215235 const doOperations : IOperation [ ] = [ {
216236 action : "insert" ,
217237 data : newListElement . outerHTML ,
218238 id : newListId ,
219- previousID : previousElement . lastElementChild . previousElementSibling . getAttribute ( "data-node-id" )
239+ previousID : previousLastBlockForNewList ? previousLastBlockForNewList . getAttribute ( "data-node-id" ) : undefined
220240 } ] ;
221241 previousElement . lastElementChild . before ( newListElement ) ;
222242 const undoOperations : IOperation [ ] = [ ] ;
@@ -414,7 +434,7 @@ export const listOutdent = (protyle: IProtyle, liItemElements: Element[], range:
414434 let topPreviousID = liId ;
415435 let previousElement : Element = liElement ;
416436 let nextElement = liItemElements [ liItemElements . length - 1 ] . nextElementSibling ;
417- let lastBlockElement = liItemElements [ liItemElements . length - 1 ] . lastElementChild . previousElementSibling ;
437+ let lastBlockElement = getLastChildBlock ( liItemElements [ liItemElements . length - 1 ] ) ;
418438 liItemElements . forEach ( item => {
419439 Array . from ( item . children ) . forEach ( ( blockElement , index ) => {
420440 const id = blockElement . getAttribute ( "data-node-id" ) ;
@@ -442,7 +462,7 @@ export const listOutdent = (protyle: IProtyle, liItemElements: Element[], range:
442462 if ( ! window . siyuan . config . editor . listLogicalOutdent && ! nextElement . classList . contains ( "protyle-attr" ) ) {
443463 // 传统缩进
444464 let newId ;
445- if ( lastBlockElement . getAttribute ( "data-subtype" ) !== nextElement . getAttribute ( "data-subtype" ) ) {
465+ if ( ! lastBlockElement || lastBlockElement . getAttribute ( "data-subtype" ) !== nextElement . getAttribute ( "data-subtype" ) ) {
446466 newId = Lute . NewNodeID ( ) ;
447467 lastBlockElement = document . createElement ( "div" ) ;
448468 lastBlockElement . classList . add ( "list" ) ;
@@ -461,10 +481,11 @@ export const listOutdent = (protyle: IProtyle, liItemElements: Element[], range:
461481 }
462482 let topOldPreviousID ;
463483 while ( nextElement && ! nextElement . classList . contains ( "protyle-attr" ) ) {
484+ const lastBlockLastBlock = lastBlockElement ? getLastChildBlock ( lastBlockElement ) : null ;
464485 topDoOperations . push ( {
465486 action : "move" ,
466487 id : nextElement . getAttribute ( "data-node-id" ) ,
467- previousID : topOldPreviousID || lastBlockElement . lastElementChild . previousElementSibling ? .getAttribute ( "data-node-id" ) ,
488+ previousID : topOldPreviousID || ( lastBlockLastBlock ? lastBlockLastBlock . getAttribute ( "data-node-id" ) : undefined ) ,
468489 parentID : lastBlockElement . getAttribute ( "data-node-id" )
469490 } ) ;
470491 topUndoOperations . push ( {
@@ -586,7 +607,7 @@ export const listOutdent = (protyle: IProtyle, liItemElements: Element[], range:
586607 }
587608 const html = parentLiItemElement . parentElement . outerHTML ;
588609 let nextElement = liItemElements [ liItemElements . length - 1 ] . nextElementSibling ;
589- let lastBlockElement = liItemElements [ liItemElements . length - 1 ] . lastElementChild . previousElementSibling ;
610+ let lastBlockElement = getLastChildBlock ( liItemElements [ liItemElements . length - 1 ] ) ;
590611 liItemElements . reverse ( ) . forEach ( item => {
591612 const itemId = item . getAttribute ( "data-node-id" ) ;
592613 doOperations . push ( {
@@ -652,7 +673,7 @@ export const listOutdent = (protyle: IProtyle, liItemElements: Element[], range:
652673 if ( ! window . siyuan . config . editor . listLogicalOutdent && ! nextElement . classList . contains ( "protyle-attr" ) ) {
653674 // 传统缩进
654675 let newId ;
655- if ( ! lastBlockElement . classList . contains ( "list" ) ) {
676+ if ( ! lastBlockElement || ! lastBlockElement . classList . contains ( "list" ) ) {
656677 newId = Lute . NewNodeID ( ) ;
657678 lastBlockElement = document . createElement ( "div" ) ;
658679 lastBlockElement . classList . add ( "list" ) ;
@@ -661,11 +682,12 @@ export const listOutdent = (protyle: IProtyle, liItemElements: Element[], range:
661682 lastBlockElement . setAttribute ( "data-type" , "NodeList" ) ;
662683 lastBlockElement . setAttribute ( "updated" , dayjs ( ) . format ( "YYYYMMDDHHmmss" ) ) ;
663684 lastBlockElement . innerHTML = `<div class="protyle-attr" contenteditable="false">${ Constants . ZWSP } </div>` ;
685+ const firstItemLastBlock = getLastChildBlock ( liItemElements [ 0 ] ) ;
664686 doOperations . push ( {
665687 action : "insert" ,
666688 id : newId ,
667689 data : lastBlockElement . outerHTML ,
668- previousID : liItemElements [ 0 ] . lastElementChild . previousElementSibling . getAttribute ( "data-node-id" ) ,
690+ previousID : firstItemLastBlock ? firstItemLastBlock . getAttribute ( "data-node-id" ) : undefined ,
669691 } ) ;
670692 liItemElements [ 0 ] . lastElementChild . before ( lastBlockElement ) ;
671693 }
@@ -687,10 +709,11 @@ export const listOutdent = (protyle: IProtyle, liItemElements: Element[], range:
687709 data : nextElement . outerHTML
688710 } ) ;
689711 }
712+ const lastBlockLastBlock = getLastChildBlock ( lastBlockElement ) ;
690713 doOperations . push ( {
691714 action : "move" ,
692715 id : nextId ,
693- previousID : subPreviousID || lastBlockElement . lastElementChild . previousElementSibling ? .getAttribute ( "data-node-id" ) ,
716+ previousID : subPreviousID || ( lastBlockLastBlock ? lastBlockLastBlock . getAttribute ( "data-node-id" ) : undefined ) ,
694717 parentID : lastBlockElement . getAttribute ( "data-node-id" )
695718 } ) ;
696719 undoOperations . push ( {
0 commit comments