All files / roosterjs-content-model-core/lib/coreApi/setEditorStyle setEditorStyle.ts

100% Statements 37/37
100% Branches 20/20
100% Functions 4/4
100% Lines 35/35

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 811x 1x     1x 1x         1x         549x   275x   275x 36x   36x 36x   36x 36x     275x   275x 76x 26x     76x 37x     37x                   37x 39x             19x   19x 19x   19x 35x 2x 2x 2x     35x   35x 35x     19x   19x    
import { ensureUniqueId } from './ensureUniqueId';
import { getSafeIdSelector } from 'roosterjs-content-model-dom';
import type { SetEditorStyle } from 'roosterjs-content-model-types';
 
const MAX_RULE_SELECTOR_LENGTH = 9000;
const CONTENT_DIV_ID = 'contentDiv';
 
/**
 * @internal
 */
export const setEditorStyle: SetEditorStyle = (
    core,
    key,
    cssRule,
    subSelectors,
    maxRuleLength = MAX_RULE_SELECTOR_LENGTH
) => {
    let styleElement = core.lifecycle.styleElements[key];
 
    if (!styleElement && cssRule) {
        const doc = core.physicalRoot.ownerDocument;
 
        styleElement = doc.createElement('style');
        doc.head.appendChild(styleElement);
 
        styleElement.dataset.roosterjsStyleKey = key;
        core.lifecycle.styleElements[key] = styleElement;
    }
 
    const sheet = styleElement?.sheet;
 
    if (sheet) {
        for (let i = sheet.cssRules.length - 1; i >= 0; i--) {
            sheet.deleteRule(i);
        }
 
        if (cssRule) {
            const rootSelector = getSafeIdSelector(
                ensureUniqueId(core.physicalRoot, CONTENT_DIV_ID)
            );
            const selectors = !subSelectors
                ? [rootSelector]
                : typeof subSelectors === 'string'
                ? [`${rootSelector}::${subSelectors}`]
                : buildSelectors(
                      rootSelector,
                      subSelectors,
                      maxRuleLength - cssRule.length - 3 // minus 3 for " {}"
                  );
 
            selectors.forEach(selector => {
                sheet.insertRule(`${selector} {${cssRule}}`);
            });
        }
    }
};
 
function buildSelectors(rootSelector: string, subSelectors: string[], maxLen: number): string[] {
    const result: string[] = [];
 
    let stringBuilder: string[] = [];
    let len = 0;
 
    subSelectors.forEach(subSelector => {
        if (len >= maxLen) {
            result.push(stringBuilder.join(','));
            stringBuilder = [];
            len = 0;
        }
 
        const selector = `${rootSelector} ${subSelector}`;
 
        len += selector.length + 1; // Add 1 for potential "," between selectors
        stringBuilder.push(selector);
    });
 
    result.push(stringBuilder.join(','));
 
    return result;
}