import { fixInsert , insertAfterNode , insertBeforeNode } from "../tree/insert" ; import { Color , PageContent } from "../pageModel" ; import { SENTINEL_INDEX , EMPTY_TREE_ROOT } from "../tree/tree" ; import { Buffer , ContentNode } from "./contentModel" ; import { getLineStarts , getNodeContent , updateContentTreeMetadata , } from "./tree" ; import { InsertContentDOM } from "./actions" ; import { insertStructureNode } from "../structureTree/insert" ; import { generateNewId } from "../structureTree/tree" ; import { TagType } from "../structureTree/structureModel" ; param action param page function createNodeCreateBuffer ( action , page ) { const newBuffer = { content : action . content , isReadOnly : false , lineStarts : getLineStarts ( action . content ) , } ; const newNode = { bufferIndex : page . buffers . length , color : Color . Red , end : { column : newBuffer . content . length - newBuffer . lineStarts [ newBuffer . lineStarts . length - 1 ] , line : newBuffer . lineStarts . length - 1 , } , left : SENTINEL_INDEX , leftCharCount : 0 , leftLineFeedCount : 0 , length : action . content . length , lineFeedCount : newBuffer . lineStarts . length - 1 , parent : SENTINEL_INDEX , right : SENTINEL_INDEX , start : { column : 0 , line : 0 } , } ; page . previouslyInsertedContentNodeIndex = page . content . nodes . length ; page . previouslyInsertedContentNodeOffset = action . content . length ; page . buffers . push ( newBuffer ) ; if ( action . localOffset === 0 ) { insertBeforeNode ( page . content , newNode , action . start . nodeIndex ) ; } else { insertAfterNode ( page . content , newNode , action . end . nodeIndex ) ; } } param action param page function createNodeAppendToBuffer ( action , page ) { const oldBuffer = page . buffers [ page . buffers . length - 1 ] ; const newContent = oldBuffer . content + action . content ; const updatedBuffer = { content : newContent , isReadOnly : oldBuffer . isReadOnly , lineStarts : getLineStarts ( newContent ) , } ; const newNode = { bufferIndex : page . buffers . length - 1 , color : Color . Red , end : { column : updatedBuffer . content . length - updatedBuffer . lineStarts [ updatedBuffer . lineStarts . length - 1 ] , line : updatedBuffer . lineStarts . length - 1 , } , left : SENTINEL_INDEX , leftCharCount : 0 , leftLineFeedCount : 0 , length : action . content . length , lineFeedCount : updatedBuffer . lineStarts . length - oldBuffer . lineStarts . length , parent : SENTINEL_INDEX , right : SENTINEL_INDEX , start : { column : oldBuffer . content . length - oldBuffer . lineStarts [ oldBuffer . lineStarts . length - 1 ] , line : oldBuffer . lineStarts . length - 1 , } , } ; page . buffers [ page . buffers . length - 1 ] = updatedBuffer ; page . previouslyInsertedContentNodeIndex = page . content . nodes . length ; page . previouslyInsertedContentNodeOffset = newNode . length ; if ( action . localOffset === 0 ) { insertBeforeNode ( page . content , newNode , action . start . nodeIndex ) ; } else { insertAfterNode ( page . content , newNode , action . end . nodeIndex ) ; } } param action param page param maxBufferLength function insertAtNodeExtremity ( action , page , maxBufferLength ) { if ( action . content . length + page . buffers [ page . buffers . length - 1 ] . content . length <= maxBufferLength && page . buffers [ page . buffers . length - 1 ] . isReadOnly === false ) { createNodeAppendToBuffer ( action , page ) ; } else { createNodeCreateBuffer ( action , page ) ; } } param action param page param maxBufferLength function insertInsideNode ( action , page , maxBufferLength ) { const node = page . content . nodes [ action . start . nodeIndex ] ; const nodeContent = getNodeContent ( page , action . start . nodeIndex ) ; const firstPartContent = nodeContent . slice ( 0 , action . localOffset ) ; const firstPartLineStarts = getLineStarts ( firstPartContent ) ; const firstPartNode = { ... node , end : { column : firstPartContent . length - firstPartLineStarts [ firstPartLineStarts . length - 1 ] + node . start . column , line : firstPartLineStarts . length - 1 + node . start . line , } , length : firstPartContent . length , lineFeedCount : firstPartLineStarts . length - 1 , } ; page . content . nodes [ action . start . nodeIndex ] = firstPartNode ; const secondPartNode = { bufferIndex : node . bufferIndex , color : Color . Red , end : node . end , left : SENTINEL_INDEX , leftCharCount : 0 , leftLineFeedCount : 0 , length : node . length - firstPartNode . length , lineFeedCount : node . lineFeedCount - firstPartNode . lineFeedCount , parent : SENTINEL_INDEX , right : SENTINEL_INDEX , start : firstPartNode . end , } ; updateContentTreeMetadata ( page . content , action . start . nodeIndex , - secondPartNode . length , - secondPartNode . lineFeedCount ) ; insertAfterNode ( page . content , secondPartNode , action . end . nodeIndex ) ; fixInsert ( page . content , page . content . nodes . length - 1 ) ; insertAtNodeExtremity ( action , page , maxBufferLength ) ; page . previouslyInsertedContentNodeIndex = page . content . nodes . length - 1 ; page . previouslyInsertedContentNodeOffset = action . content . length ; } param action param page param maxBufferLength function insertAtEndPreviouslyInsertedNode ( action , page , maxBufferLength ) { if ( action . content . length + page . buffers [ page . buffers . length - 1 ] . content . length <= maxBufferLength ) { const oldBuffer = page . buffers [ page . buffers . length - 1 ] ; const newContent = oldBuffer . content + action . content ; const buffer = { content : newContent , isReadOnly : oldBuffer . isReadOnly , lineStarts : getLineStarts ( newContent ) , } ; const node = page . content . nodes [ page . content . nodes . length - 1 ] ; node . end = { column : buffer . content . length - buffer . lineStarts [ buffer . lineStarts . length - 1 ] , line : buffer . lineStarts . length - 1 , } ; node . lineFeedCount = buffer . lineStarts . length - 1 ; node . length += action . content . length ; page . buffers [ page . buffers . length - 1 ] = buffer ; } else { createNodeCreateBuffer ( action , page ) ; } } param action param page param maxBufferLength param updateStructureNode export function insertContentDOM ( page , action , maxBufferLength , updateStructureNode = false ) { if ( page . content . root === EMPTY_TREE_ROOT ) { createNodeCreateBuffer ( action , page ) ; page . content . root = 1 ; const contentNode = page . content . nodes [ 1 ] ; contentNode . color = Color . Black ; contentNode . left = SENTINEL_INDEX ; contentNode . parent = SENTINEL_INDEX ; contentNode . right = SENTINEL_INDEX ; if ( updateStructureNode ) { insertStructureNode ( page , { id : generateNewId ( "p" ) , length : action . content . length , offset : 0 , tag : "p" , tagType : TagType . StartTag , } ) ; insertStructureNode ( page , { id : generateNewId ( "p" ) , insertAfterNode : page . content . root , length : action . content . length , offset : 0 , tag : "p" , tagType : TagType . EndTag , } ) ; } return ; } let previouslyInsertedNode ; if ( page . previouslyInsertedContentNodeIndex !== null && page . previouslyInsertedContentNodeOffset !== null && page . previouslyInsertedContentNodeIndex === action . start . nodeIndex ) { previouslyInsertedNode = page . content . nodes [ page . previouslyInsertedContentNodeIndex ] ; } if ( previouslyInsertedNode !== undefined && action . localOffset === previouslyInsertedNode . length ) { insertAtEndPreviouslyInsertedNode ( action , page , maxBufferLength ) ; } else { const node = page . content . nodes [ action . start . nodeIndex ] ; if ( action . localOffset > 0 && action . localOffset < node . length ) { insertInsideNode ( action , page , maxBufferLength ) ; } else { insertAtNodeExtremity ( action , page , maxBufferLength ) ; } } if ( updateStructureNode && action . structureNodeIndex !== SENTINEL_INDEX ) { page . structure . nodes [ action . structureNodeIndex ] . length += action . content . length ; } fixInsert ( page . content , page . content . nodes . length - 1 ) ; }