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         523x   262x   262x 36x   36x 36x   36x 36x     262x   262x 66x 26x     66x 49x     49x                   49x 51x             25x   25x 25x   25x 41x 2x 2x 2x     41x   41x 41x     25x   25x    
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;
}