import { Undo } from 'roosterjs-editor-core' ; import { UndoSnapshotsService } from 'roosterjs-editor-core' ; import { hasPlaceholder , ImageManagerInteface , UpdatePlaceholdersResult } from '../utils/ImageManager' ; const MAXSIZELIMIT = 10000000 ; interface Snapshot { value : string ; hasPlaceholder : boolean ; } class UndoSnapshotsWithImage implements UndoSnapshotsService { private snapshots : Snapshot [ ] ; private totalSize : number ; private currentIndex : number ; constructor ( private imageManager , private maxSize ) { this . snapshots = [ ] ; this . totalSize = 0 ; this . currentIndex = - 1 ; } public canMove ( delta ) { const newIndex = this . currentIndex + delta ; return newIndex >= 0 && newIndex < this . snapshots . length ; } public move ( delta ) { if ( ! this . canMove ( delta ) ) { return null ; } const lastIndex = this . currentIndex ; this . currentIndex += delta ; const snapshot = this . snapshots [ this . currentIndex ] ; if ( snapshot . hasPlaceholder ) { const originalValue = snapshot . value ; const result = this . imageManager . updatePlaceholders ( originalValue ) ; snapshot . hasPlaceholder = ! result . resolvedAll ; snapshot . value = result . html ; const sizeDelta = originalValue . length - result . html . length ; const lastSnapshot = this . snapshots [ lastIndex ] ; if ( lastSnapshot && lastSnapshot . value === snapshot . value && delta !== 0 ) { this . totalSize -= snapshot . value . length ; this . snapshots . splice ( lastIndex ) ; return this . move ( delta < 0 ? - 1 : 1 ) ; } else { this . totalSize -= sizeDelta ; } } return snapshot . value ; } public addSnapshot ( value ) { if ( this . currentIndex > - 1 && value === this . snapshots [ this . currentIndex ] . value ) { return ; } this . clearRedo ( ) ; this . snapshots . push ( { value , hasPlaceholder : hasPlaceholder ( value ) } ) ; ++ this . currentIndex ; this . totalSize += value . length ; let removeCount = 0 ; while ( removeCount < this . snapshots . length && this . totalSize > this . maxSize ) { this . totalSize -= this . snapshots [ removeCount ] . value . length ; removeCount ++ ; } if ( removeCount > 0 ) { this . snapshots . splice ( 0 , removeCount ) ; this . currentIndex -= removeCount ; } } public clearRedo ( ) { if ( ! this . canMove ( 1 ) ) { return ; } let removedSize = 0 ; for ( let i = this . currentIndex + 1 ; i < this . snapshots . length ; ++ i ) { removedSize += this . snapshots [ i ] . value . length ; } this . snapshots . splice ( this . currentIndex + 1 ) ; this . totalSize -= removedSize ; } } export default class UndoWithImagePlugin extends Undo { param preserveSnapshots param bufferSize constructor ( private imageManager , preserveSnapshots ? , private bufferSize = MAXSIZELIMIT ) { super ( preserveSnapshots , bufferSize ) ; } protected getSnapshotsManager ( ) { if ( ! this . undoSnapshots ) { this . undoSnapshots = new UndoSnapshotsWithImage ( this . imageManager , this . bufferSize ) ; } return this . undoSnapshots ; } public reset ( initialContent ) { this . clear ( ) ; this . getSnapshotsManager ( ) . addSnapshot ( initialContent ) ; } }