All files / roosterjs-content-model-core/lib/corePlugin/cache ParagraphMapImpl.ts

100% Statements 38/38
80% Branches 8/10
100% Functions 10/10
100% Lines 38/38

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 1021x                                         1x   1x 1x 11x 11x     11x     1x 7x 7x   7x 2x   2x   5x   5x       1x 11x   11x 4x     11x   11x 11x   11x               1x     2x   2x     1x 1x       1x 9x 9x     1x 11x       1x 9x   1x         1x 11x    
import { getParagraphMarker, setParagraphMarker } from 'roosterjs-content-model-dom';
import type {
    ContentModelParagraph,
    ContentModelParagraphCommon,
    ParagraphIndexer,
    ParagraphMap,
    ReadonlyContentModelParagraph,
} from 'roosterjs-content-model-types';
 
interface ParagraphWithMarker extends ContentModelParagraphCommon {
    _marker?: string;
}
 
/**
 * @internal, used by test code only
 */
export interface ParagraphMapReset {
    _reset(): void;
    _getMap(): { [key: string]: ReadonlyContentModelParagraph };
}
 
const idPrefix = 'paragraph';
 
class ParagraphMapImpl implements ParagraphMap, ParagraphIndexer, ParagraphMapReset {
    private static prefixNum = 0;
    private nextId = 0;
    private paragraphMap: { [key: string]: ReadonlyContentModelParagraph } = {};
 
    constructor() {
        ParagraphMapImpl.prefixNum++;
    }
 
    assignMarkerToModel(element: HTMLElement, paragraph: ContentModelParagraph): void {
        const marker = getParagraphMarker(element);
        const paragraphWithMarker = paragraph as ParagraphWithMarker;
 
        if (marker) {
            paragraphWithMarker._marker = marker;
 
            this.paragraphMap[marker] = paragraph;
        } else {
            paragraphWithMarker._marker = this.generateId();
 
            this.applyMarkerToDom(element, paragraph);
        }
    }
 
    applyMarkerToDom(element: HTMLElement, paragraph: ContentModelParagraph): void {
        const paragraphWithMarker = paragraph as ParagraphWithMarker;
 
        if (!paragraphWithMarker._marker) {
            paragraphWithMarker._marker = this.generateId();
        }
 
        const marker = paragraphWithMarker._marker;
 
        Eif (marker) {
            setParagraphMarker(element, marker);
 
            this.paragraphMap[marker] = paragraph;
        }
    }
 
    /**
     * Get paragraph using a previously marked paragraph
     * @param markedParagraph The previously marked paragraph to get
     */
    getParagraphFromMarker(
        markerParagraph: ReadonlyContentModelParagraph
    ): ReadonlyContentModelParagraph | null {
        const marker = (markerParagraph as ParagraphWithMarker)._marker;
 
        return marker ? this.paragraphMap[marker] || null : null;
    }
 
    clear() {
        this.paragraphMap = {};
    }
 
    //#region For test code only
    _reset() {
        ParagraphMapImpl.prefixNum = 0;
        this.nextId = 0;
    }
 
    _getMap() {
        return this.paragraphMap;
    }
    //#endregion
 
    private generateId() {
        return `${idPrefix}_${ParagraphMapImpl.prefixNum}_${this.nextId++}`;
    }
}
 
/**
 * @internal
 */
export function createParagraphMap(): ParagraphMap & ParagraphIndexer {
    return new ParagraphMapImpl();
}