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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 1x 1x 1x 1x 1x 28x 28x 28x 14x 14x 14x 28x 70x 42x 42x 42x 42x 42x 42x 42x 1x 29x 29x 1x 28x 28x 14x 14x 266x 266x 266x 266x 266x 266x 266x 266x 266x 1415x 1415x 1149x 1149x 1149x 266x 394x 266x 28x | import { getObjectKeys } from 'roosterjs-content-model-dom';
import type { WordMetadata } from './WordMetadata';
const FORMATING_REGEX = /[\n\t'{}"]+/g;
const STYLE_TAG = '<style';
const STYLE_TAG_END = '</style>';
const nonWordCharacterRegex = /\W/;
function extractStyleTagsFromHtml(htmlContent: string): string[] {
const styles: string[] = [];
let { styleIndex, styleEndIndex } = extractHtmlIndexes(htmlContent);
while (styleIndex >= 0 && styleEndIndex >= 0) {
const styleContent = htmlContent
.substring(styleIndex + STYLE_TAG.length, styleEndIndex)
.trim();
styles.push(styleContent);
({ styleIndex, styleEndIndex } = extractHtmlIndexes(htmlContent, styleEndIndex + 1));
}
return styles;
}
function extractHtmlIndexes(html: string, startIndex: number = 0) {
const htmlLowercase = html.toLowerCase();
let styleIndex = htmlLowercase.indexOf(STYLE_TAG, startIndex);
let currentIndex = styleIndex + STYLE_TAG.length;
let nextChar = html.substring(currentIndex, currentIndex + 1);
while (!nonWordCharacterRegex.test(nextChar) && styleIndex > -1) {
styleIndex = htmlLowercase.indexOf(STYLE_TAG, styleIndex + 1);
currentIndex = styleIndex + STYLE_TAG.length;
nextChar = html.substring(currentIndex, currentIndex + 1);
}
const styleEndIndex = htmlLowercase.indexOf(STYLE_TAG_END, startIndex);
return { styleIndex, styleEndIndex };
}
/**
* @internal
* Word Desktop content has a style tag that contains data for the lists.
* So this function query that style tag and extract the data from the innerHTML, since it is not available from the HTMLStyleElement.sheet.
*
* The format is like:
* example of style element content
* @list l0:level1 {
* styleTag: styleValue;
* ...
* }
*
* To extract the data:
* 1. Substring the value of the style selector, using @ index and { index
* 2. Substring the value of the style rules by Substring the content between { and }
* 3. Split the value of the rules using ; as separator { styleTag: styleValue; styleTag1: StyleValue1 } = ['styleTag: styleValue', 'styleTag1: StyleValue1']
* 4. Split the value of the rule using : as separator: styleTag: styleValue = [styleTag, styleValue]
* 5. Save data in record and only use the required information.
*
*/
export function getStyleMetadata(htmlString: string) {
const metadataMap: Map<string, WordMetadata> = new Map();
if (!htmlString) {
return metadataMap;
}
const headStyles = extractStyleTagsFromHtml(htmlString);
headStyles.forEach(text => {
let index = 0;
while (index >= 0) {
const indexAt = text.indexOf('@', index + 1);
const indexCurlyEnd = text.indexOf('}', indexAt);
const indexCurlyStart = text.indexOf('{', indexAt);
index = indexAt;
// 1.
const metadataName = text
.substring(indexAt + 1, indexCurlyStart)
.replace(FORMATING_REGEX, '')
.replace('list', '')
.trimRight()
.trimLeft();
// 2.
const dataName = text
.substring(indexCurlyStart, indexCurlyEnd + 1)
.trimLeft()
.trimRight();
const record: Record<string, string> = {};
// 3.
const entries = dataName.split(';');
entries.forEach(entry => {
// 4.
const [key, value] = entry.split(':');
if (key && value) {
const formatedKey = key.replace(FORMATING_REGEX, '').trimRight().trimLeft();
const formatedValue = value.replace(FORMATING_REGEX, '').trimRight().trimLeft();
// 5.
record[formatedKey] = formatedValue;
}
});
const data: WordMetadata = {
'mso-level-number-format': record['mso-level-number-format'],
'mso-level-start-at': record['mso-level-start-at'] || '1',
'mso-level-text': record['mso-level-text'],
};
Eif (getObjectKeys(data).some(key => !!data[key])) {
metadataMap.set(metadataName, data);
}
}
});
return metadataMap;
}
|