roosterjs-content-model-dom 0.26.4 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/lib/domToModel/utils/addSelectionMarker.js +15 -1
  2. package/lib/domToModel/utils/addSelectionMarker.js.map +1 -1
  3. package/lib/domUtils/entityUtils.d.ts +4 -4
  4. package/lib/domUtils/entityUtils.js +19 -2
  5. package/lib/domUtils/entityUtils.js.map +1 -1
  6. package/lib/domUtils/reuseCachedElement.js +2 -1
  7. package/lib/domUtils/reuseCachedElement.js.map +1 -1
  8. package/lib/formatHandlers/entity/entityFormatHandler.js +1 -8
  9. package/lib/formatHandlers/entity/entityFormatHandler.js.map +1 -1
  10. package/lib/index.d.ts +1 -1
  11. package/lib/index.js +2 -2
  12. package/lib/index.js.map +1 -1
  13. package/lib/modelApi/common/normalizeParagraph.js +28 -0
  14. package/lib/modelApi/common/normalizeParagraph.js.map +1 -1
  15. package/lib-amd/domToModel/utils/addSelectionMarker.js +15 -1
  16. package/lib-amd/domToModel/utils/addSelectionMarker.js.map +1 -1
  17. package/lib-amd/domUtils/entityUtils.d.ts +4 -4
  18. package/lib-amd/domUtils/entityUtils.js +19 -2
  19. package/lib-amd/domUtils/entityUtils.js.map +1 -1
  20. package/lib-amd/domUtils/reuseCachedElement.js +2 -1
  21. package/lib-amd/domUtils/reuseCachedElement.js.map +1 -1
  22. package/lib-amd/formatHandlers/entity/entityFormatHandler.js +1 -8
  23. package/lib-amd/formatHandlers/entity/entityFormatHandler.js.map +1 -1
  24. package/lib-amd/index.d.ts +1 -1
  25. package/lib-amd/index.js +2 -2
  26. package/lib-amd/index.js.map +1 -1
  27. package/lib-amd/modelApi/common/normalizeParagraph.js +28 -0
  28. package/lib-amd/modelApi/common/normalizeParagraph.js.map +1 -1
  29. package/lib-mjs/domToModel/utils/addSelectionMarker.js +15 -1
  30. package/lib-mjs/domToModel/utils/addSelectionMarker.js.map +1 -1
  31. package/lib-mjs/domUtils/entityUtils.d.ts +4 -4
  32. package/lib-mjs/domUtils/entityUtils.js +18 -1
  33. package/lib-mjs/domUtils/entityUtils.js.map +1 -1
  34. package/lib-mjs/domUtils/reuseCachedElement.js +2 -1
  35. package/lib-mjs/domUtils/reuseCachedElement.js.map +1 -1
  36. package/lib-mjs/formatHandlers/entity/entityFormatHandler.js +2 -9
  37. package/lib-mjs/formatHandlers/entity/entityFormatHandler.js.map +1 -1
  38. package/lib-mjs/index.d.ts +1 -1
  39. package/lib-mjs/index.js +1 -1
  40. package/lib-mjs/index.js.map +1 -1
  41. package/lib-mjs/modelApi/common/normalizeParagraph.js +28 -0
  42. package/lib-mjs/modelApi/common/normalizeParagraph.js.map +1 -1
  43. package/package.json +2 -2
@@ -9,12 +9,26 @@ var createSelectionMarker_1 = require("../../modelApi/creators/createSelectionMa
9
9
  * @internal
10
10
  */
11
11
  function addSelectionMarker(group, context, container, offset) {
12
+ var lastPara = group.blocks[group.blocks.length - 1];
13
+ var formatFromParagraph = !lastPara || lastPara.blockType != 'Paragraph'
14
+ ? {}
15
+ : lastPara.decorator
16
+ ? {
17
+ fontFamily: lastPara.decorator.format.fontFamily,
18
+ fontSize: lastPara.decorator.format.fontSize,
19
+ }
20
+ : lastPara.segmentFormat
21
+ ? {
22
+ fontFamily: lastPara.segmentFormat.fontFamily,
23
+ fontSize: lastPara.segmentFormat.fontSize,
24
+ }
25
+ : {};
12
26
  var pendingFormat = context.pendingFormat &&
13
27
  context.pendingFormat.posContainer === container &&
14
28
  context.pendingFormat.posOffset === offset
15
29
  ? context.pendingFormat.format
16
30
  : undefined;
17
- var segmentFormat = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, context.defaultFormat), context.segmentFormat), pendingFormat);
31
+ var segmentFormat = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, context.defaultFormat), formatFromParagraph), context.segmentFormat), pendingFormat);
18
32
  var marker = (0, createSelectionMarker_1.createSelectionMarker)(segmentFormat);
19
33
  (0, addDecorators_1.addDecorators)(marker, context);
20
34
  (0, addSegment_1.addSegment)(group, marker, context.blockFormat, segmentFormat);
@@ -1 +1 @@
1
- {"version":3,"file":"addSelectionMarker.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts"],"names":[],"mappings":";;;;AAAA,qEAAoE;AACpE,+DAA8D;AAC9D,uFAAsF;AAGtF;;GAEG;AACH,SAAgB,kBAAkB,CAC9B,KAA6B,EAC7B,OAA0B,EAC1B,SAAgB,EAChB,MAAe;IAEf,IAAM,aAAa,GACf,OAAO,CAAC,aAAa;QACrB,OAAO,CAAC,aAAa,CAAC,YAAY,KAAK,SAAS;QAChD,OAAO,CAAC,aAAa,CAAC,SAAS,KAAK,MAAM;QACtC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM;QAC9B,CAAC,CAAC,SAAS,CAAC;IACpB,IAAM,aAAa,yEACZ,OAAO,CAAC,aAAa,GACrB,OAAO,CAAC,aAAa,GACrB,aAAa,CACnB,CAAC;IACF,IAAM,MAAM,GAAG,IAAA,6CAAqB,EAAC,aAAa,CAAC,CAAC;IAEpD,IAAA,6BAAa,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/B,IAAA,uBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;AAClE,CAAC;AAtBD,gDAsBC","sourcesContent":["import { addDecorators } from '../../modelApi/common/addDecorators';\nimport { addSegment } from '../../modelApi/common/addSegment';\nimport { createSelectionMarker } from '../../modelApi/creators/createSelectionMarker';\nimport type { ContentModelBlockGroup, DomToModelContext } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function addSelectionMarker(\n group: ContentModelBlockGroup,\n context: DomToModelContext,\n container?: Node,\n offset?: number\n) {\n const pendingFormat =\n context.pendingFormat &&\n context.pendingFormat.posContainer === container &&\n context.pendingFormat.posOffset === offset\n ? context.pendingFormat.format\n : undefined;\n const segmentFormat = {\n ...context.defaultFormat,\n ...context.segmentFormat,\n ...pendingFormat,\n };\n const marker = createSelectionMarker(segmentFormat);\n\n addDecorators(marker, context);\n\n addSegment(group, marker, context.blockFormat, segmentFormat);\n}\n"]}
1
+ {"version":3,"file":"addSelectionMarker.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts"],"names":[],"mappings":";;;;AAAA,qEAAoE;AACpE,+DAA8D;AAC9D,uFAAsF;AAOtF;;GAEG;AACH,SAAgB,kBAAkB,CAC9B,KAA6B,EAC7B,OAA0B,EAC1B,SAAgB,EAChB,MAAe;IAEf,IAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvD,IAAM,mBAAmB,GACrB,CAAC,QAAQ,IAAI,QAAQ,CAAC,SAAS,IAAI,WAAW;QAC1C,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,QAAQ,CAAC,SAAS;YACpB,CAAC,CAAC;gBACI,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU;gBAChD,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ;aAC/C;YACH,CAAC,CAAC,QAAQ,CAAC,aAAa;gBACxB,CAAC,CAAC;oBACI,UAAU,EAAE,QAAQ,CAAC,aAAa,CAAC,UAAU;oBAC7C,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,QAAQ;iBAC5C;gBACH,CAAC,CAAC,EAAE,CAAC;IAEb,IAAM,aAAa,GACf,OAAO,CAAC,aAAa;QACrB,OAAO,CAAC,aAAa,CAAC,YAAY,KAAK,SAAS;QAChD,OAAO,CAAC,aAAa,CAAC,SAAS,KAAK,MAAM;QACtC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM;QAC9B,CAAC,CAAC,SAAS,CAAC;IACpB,IAAM,aAAa,+FACZ,OAAO,CAAC,aAAa,GACrB,mBAAmB,GACnB,OAAO,CAAC,aAAa,GACrB,aAAa,CACnB,CAAC;IACF,IAAM,MAAM,GAAG,IAAA,6CAAqB,EAAC,aAAa,CAAC,CAAC;IAEpD,IAAA,6BAAa,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/B,IAAA,uBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;AAClE,CAAC;AAvCD,gDAuCC","sourcesContent":["import { addDecorators } from '../../modelApi/common/addDecorators';\nimport { addSegment } from '../../modelApi/common/addSegment';\nimport { createSelectionMarker } from '../../modelApi/creators/createSelectionMarker';\nimport type {\n ContentModelBlockGroup,\n ContentModelSegmentFormat,\n DomToModelContext,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function addSelectionMarker(\n group: ContentModelBlockGroup,\n context: DomToModelContext,\n container?: Node,\n offset?: number\n) {\n const lastPara = group.blocks[group.blocks.length - 1];\n const formatFromParagraph: ContentModelSegmentFormat =\n !lastPara || lastPara.blockType != 'Paragraph'\n ? {}\n : lastPara.decorator\n ? {\n fontFamily: lastPara.decorator.format.fontFamily,\n fontSize: lastPara.decorator.format.fontSize,\n }\n : lastPara.segmentFormat\n ? {\n fontFamily: lastPara.segmentFormat.fontFamily,\n fontSize: lastPara.segmentFormat.fontSize,\n }\n : {};\n\n const pendingFormat =\n context.pendingFormat &&\n context.pendingFormat.posContainer === container &&\n context.pendingFormat.posOffset === offset\n ? context.pendingFormat.format\n : undefined;\n const segmentFormat = {\n ...context.defaultFormat,\n ...formatFromParagraph,\n ...context.segmentFormat,\n ...pendingFormat,\n };\n const marker = createSelectionMarker(segmentFormat);\n\n addDecorators(marker, context);\n\n addSegment(group, marker, context.blockFormat, segmentFormat);\n}\n"]}
@@ -10,11 +10,11 @@ export declare function isEntityElement(node: Node): boolean;
10
10
  */
11
11
  export declare function getAllEntityWrappers(root: HTMLElement): HTMLElement[];
12
12
  /**
13
- * Parse entity class names from entity wrapper element
14
- * @param className Class names of entity
15
- * @param format The output entity format object
13
+ * Parse entity format from entity wrapper element
14
+ * @param wrapper The wrapper element to parse entity format from
15
+ * @returns Entity format
16
16
  */
17
- export declare function parseEntityClassName(className: string, format: ContentModelEntityFormat): boolean | undefined;
17
+ export declare function parseEntityFormat(wrapper: HTMLElement): ContentModelEntityFormat;
18
18
  /**
19
19
  * Generate Entity class names for an entity wrapper
20
20
  * @param format The source entity format object
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.addDelimiters = exports.isEntityDelimiter = exports.generateEntityClassNames = exports.parseEntityClassName = exports.getAllEntityWrappers = exports.isEntityElement = void 0;
3
+ exports.addDelimiters = exports.isEntityDelimiter = exports.generateEntityClassNames = exports.parseEntityFormat = exports.getAllEntityWrappers = exports.isEntityElement = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  var toArray_1 = require("./toArray");
6
6
  var applyFormat_1 = require("../modelToDom/utils/applyFormat");
@@ -29,6 +29,24 @@ function getAllEntityWrappers(root) {
29
29
  return (0, toArray_1.default)(root.querySelectorAll('.' + ENTITY_INFO_NAME));
30
30
  }
31
31
  exports.getAllEntityWrappers = getAllEntityWrappers;
32
+ /**
33
+ * Parse entity format from entity wrapper element
34
+ * @param wrapper The wrapper element to parse entity format from
35
+ * @returns Entity format
36
+ */
37
+ function parseEntityFormat(wrapper) {
38
+ var isEntity = false;
39
+ var format = {};
40
+ wrapper.classList.forEach(function (name) {
41
+ isEntity = parseEntityClassName(name, format) || isEntity;
42
+ });
43
+ if (!isEntity) {
44
+ format.isFakeEntity = true;
45
+ format.isReadonly = !wrapper.isContentEditable;
46
+ }
47
+ return format;
48
+ }
49
+ exports.parseEntityFormat = parseEntityFormat;
32
50
  /**
33
51
  * Parse entity class names from entity wrapper element
34
52
  * @param className Class names of entity
@@ -48,7 +66,6 @@ function parseEntityClassName(className, format) {
48
66
  format.isReadonly = className.substring(ENTITY_READONLY_PREFIX.length) == '1';
49
67
  }
50
68
  }
51
- exports.parseEntityClassName = parseEntityClassName;
52
69
  /**
53
70
  * Generate Entity class names for an entity wrapper
54
71
  * @param format The source entity format object
@@ -1 +1 @@
1
- {"version":3,"file":"entityUtils.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/entityUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import toArray from './toArray';\nimport { applyFormat } from '../modelToDom/utils/applyFormat';\nimport { isElementOfType } from './isElementOfType';\nimport { isNodeOfType } from './isNodeOfType';\nimport type {\n ContentModelEntityFormat,\n ContentModelSegmentFormat,\n ModelToDomContext,\n} from 'roosterjs-content-model-types';\n\nconst ENTITY_INFO_NAME = '_Entity';\nconst ENTITY_TYPE_PREFIX = '_EType_';\nconst ENTITY_ID_PREFIX = '_EId_';\nconst ENTITY_READONLY_PREFIX = '_EReadonly_';\nconst ZERO_WIDTH_SPACE = '\\u200B';\nconst DELIMITER_BEFORE = 'entityDelimiterBefore';\nconst DELIMITER_AFTER = 'entityDelimiterAfter';\n\n/**\n * Check if the given DOM Node is an entity wrapper element\n */\nexport function isEntityElement(node: Node): boolean {\n return isNodeOfType(node, 'ELEMENT_NODE') && node.classList.contains(ENTITY_INFO_NAME);\n}\n\n/**\n * Get all entity wrapper elements under the given root element\n * @param root The root element to query from\n * @returns An array of entity wrapper elements\n */\nexport function getAllEntityWrappers(root: HTMLElement): HTMLElement[] {\n return toArray(root.querySelectorAll('.' + ENTITY_INFO_NAME)) as HTMLElement[];\n}\n\n/**\n * Parse entity class names from entity wrapper element\n * @param className Class names of entity\n * @param format The output entity format object\n */\nexport function parseEntityClassName(\n className: string,\n format: ContentModelEntityFormat\n): boolean | undefined {\n if (className == ENTITY_INFO_NAME) {\n return true;\n } else if (className.indexOf(ENTITY_TYPE_PREFIX) == 0) {\n format.entityType = className.substring(ENTITY_TYPE_PREFIX.length);\n } else if (className.indexOf(ENTITY_ID_PREFIX) == 0) {\n format.id = className.substring(ENTITY_ID_PREFIX.length);\n } else if (className.indexOf(ENTITY_READONLY_PREFIX) == 0) {\n format.isReadonly = className.substring(ENTITY_READONLY_PREFIX.length) == '1';\n }\n}\n\n/**\n * Generate Entity class names for an entity wrapper\n * @param format The source entity format object\n * @returns A combined CSS class name string for entity wrapper\n */\nexport function generateEntityClassNames(format: ContentModelEntityFormat): string {\n return format.isFakeEntity\n ? ''\n : `${ENTITY_INFO_NAME} ${ENTITY_TYPE_PREFIX}${format.entityType ?? ''} ${\n format.id ? `${ENTITY_ID_PREFIX}${format.id} ` : ''\n }${ENTITY_READONLY_PREFIX}${format.isReadonly ? '1' : '0'}`;\n}\n\n/**\n * Checks whether the node provided is a Entity delimiter\n * @param node the node to check\n * @return true if it is a delimiter\n */\nexport function isEntityDelimiter(element: HTMLElement): boolean {\n return (\n isElementOfType(element, 'span') &&\n (element.classList.contains(DELIMITER_AFTER) ||\n element.classList.contains(DELIMITER_BEFORE)) &&\n element.textContent === ZERO_WIDTH_SPACE\n );\n}\n\n/**\n * Adds delimiters to the element provided. If the delimiters already exists, will not be added\n * @param element the node to add the delimiters\n * @param format format to set to the delimiters, so when typing inside of one the format is not lost\n * @param context Model to Dom context to use.\n */\nexport function addDelimiters(\n doc: Document,\n element: HTMLElement,\n format?: ContentModelSegmentFormat | null,\n context?: ModelToDomContext\n): HTMLElement[] {\n let [delimiterAfter, delimiterBefore] = getDelimiters(element);\n\n if (!delimiterAfter) {\n delimiterAfter = insertDelimiter(doc, element, true /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterAfter, context.formatAppliers.segment, format, context);\n }\n }\n\n if (!delimiterBefore) {\n delimiterBefore = insertDelimiter(doc, element, false /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterBefore, context.formatAppliers.segment, format, context);\n }\n }\n\n return [delimiterAfter, delimiterBefore];\n}\n\nfunction getDelimiters(entityWrapper: HTMLElement): (HTMLElement | undefined)[] {\n const result: (HTMLElement | undefined)[] = [];\n const { nextElementSibling, previousElementSibling } = entityWrapper;\n result.push(\n isDelimiter(nextElementSibling, DELIMITER_AFTER),\n isDelimiter(previousElementSibling, DELIMITER_BEFORE)\n );\n\n return result;\n}\n\nfunction isDelimiter(el: Element | null, className: string): HTMLElement | undefined {\n return el?.classList.contains(className) && el.textContent == ZERO_WIDTH_SPACE\n ? (el as HTMLElement)\n : undefined;\n}\n\nfunction insertDelimiter(doc: Document, element: Element, isAfter: boolean) {\n const span = doc.createElement('span');\n\n span.className = isAfter ? DELIMITER_AFTER : DELIMITER_BEFORE;\n span.appendChild(doc.createTextNode(ZERO_WIDTH_SPACE));\n element.parentNode?.insertBefore(span, isAfter ? element.nextSibling : element);\n\n return span;\n}\n"]}
1
+ {"version":3,"file":"entityUtils.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/entityUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import toArray from './toArray';\nimport { applyFormat } from '../modelToDom/utils/applyFormat';\nimport { isElementOfType } from './isElementOfType';\nimport { isNodeOfType } from './isNodeOfType';\nimport type {\n ContentModelEntityFormat,\n ContentModelSegmentFormat,\n ModelToDomContext,\n} from 'roosterjs-content-model-types';\n\nconst ENTITY_INFO_NAME = '_Entity';\nconst ENTITY_TYPE_PREFIX = '_EType_';\nconst ENTITY_ID_PREFIX = '_EId_';\nconst ENTITY_READONLY_PREFIX = '_EReadonly_';\nconst ZERO_WIDTH_SPACE = '\\u200B';\nconst DELIMITER_BEFORE = 'entityDelimiterBefore';\nconst DELIMITER_AFTER = 'entityDelimiterAfter';\n\n/**\n * Check if the given DOM Node is an entity wrapper element\n */\nexport function isEntityElement(node: Node): boolean {\n return isNodeOfType(node, 'ELEMENT_NODE') && node.classList.contains(ENTITY_INFO_NAME);\n}\n\n/**\n * Get all entity wrapper elements under the given root element\n * @param root The root element to query from\n * @returns An array of entity wrapper elements\n */\nexport function getAllEntityWrappers(root: HTMLElement): HTMLElement[] {\n return toArray(root.querySelectorAll('.' + ENTITY_INFO_NAME)) as HTMLElement[];\n}\n\n/**\n * Parse entity format from entity wrapper element\n * @param wrapper The wrapper element to parse entity format from\n * @returns Entity format\n */\nexport function parseEntityFormat(wrapper: HTMLElement): ContentModelEntityFormat {\n let isEntity = false;\n const format: ContentModelEntityFormat = {};\n\n wrapper.classList.forEach(name => {\n isEntity = parseEntityClassName(name, format) || isEntity;\n });\n\n if (!isEntity) {\n format.isFakeEntity = true;\n format.isReadonly = !wrapper.isContentEditable;\n }\n\n return format;\n}\n\n/**\n * Parse entity class names from entity wrapper element\n * @param className Class names of entity\n * @param format The output entity format object\n */\nfunction parseEntityClassName(\n className: string,\n format: ContentModelEntityFormat\n): boolean | undefined {\n if (className == ENTITY_INFO_NAME) {\n return true;\n } else if (className.indexOf(ENTITY_TYPE_PREFIX) == 0) {\n format.entityType = className.substring(ENTITY_TYPE_PREFIX.length);\n } else if (className.indexOf(ENTITY_ID_PREFIX) == 0) {\n format.id = className.substring(ENTITY_ID_PREFIX.length);\n } else if (className.indexOf(ENTITY_READONLY_PREFIX) == 0) {\n format.isReadonly = className.substring(ENTITY_READONLY_PREFIX.length) == '1';\n }\n}\n\n/**\n * Generate Entity class names for an entity wrapper\n * @param format The source entity format object\n * @returns A combined CSS class name string for entity wrapper\n */\nexport function generateEntityClassNames(format: ContentModelEntityFormat): string {\n return format.isFakeEntity\n ? ''\n : `${ENTITY_INFO_NAME} ${ENTITY_TYPE_PREFIX}${format.entityType ?? ''} ${\n format.id ? `${ENTITY_ID_PREFIX}${format.id} ` : ''\n }${ENTITY_READONLY_PREFIX}${format.isReadonly ? '1' : '0'}`;\n}\n\n/**\n * Checks whether the node provided is a Entity delimiter\n * @param node the node to check\n * @return true if it is a delimiter\n */\nexport function isEntityDelimiter(element: HTMLElement): boolean {\n return (\n isElementOfType(element, 'span') &&\n (element.classList.contains(DELIMITER_AFTER) ||\n element.classList.contains(DELIMITER_BEFORE)) &&\n element.textContent === ZERO_WIDTH_SPACE\n );\n}\n\n/**\n * Adds delimiters to the element provided. If the delimiters already exists, will not be added\n * @param element the node to add the delimiters\n * @param format format to set to the delimiters, so when typing inside of one the format is not lost\n * @param context Model to Dom context to use.\n */\nexport function addDelimiters(\n doc: Document,\n element: HTMLElement,\n format?: ContentModelSegmentFormat | null,\n context?: ModelToDomContext\n): HTMLElement[] {\n let [delimiterAfter, delimiterBefore] = getDelimiters(element);\n\n if (!delimiterAfter) {\n delimiterAfter = insertDelimiter(doc, element, true /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterAfter, context.formatAppliers.segment, format, context);\n }\n }\n\n if (!delimiterBefore) {\n delimiterBefore = insertDelimiter(doc, element, false /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterBefore, context.formatAppliers.segment, format, context);\n }\n }\n\n return [delimiterAfter, delimiterBefore];\n}\n\nfunction getDelimiters(entityWrapper: HTMLElement): (HTMLElement | undefined)[] {\n const result: (HTMLElement | undefined)[] = [];\n const { nextElementSibling, previousElementSibling } = entityWrapper;\n result.push(\n isDelimiter(nextElementSibling, DELIMITER_AFTER),\n isDelimiter(previousElementSibling, DELIMITER_BEFORE)\n );\n\n return result;\n}\n\nfunction isDelimiter(el: Element | null, className: string): HTMLElement | undefined {\n return el?.classList.contains(className) && el.textContent == ZERO_WIDTH_SPACE\n ? (el as HTMLElement)\n : undefined;\n}\n\nfunction insertDelimiter(doc: Document, element: Element, isAfter: boolean) {\n const span = doc.createElement('span');\n\n span.className = isAfter ? DELIMITER_AFTER : DELIMITER_BEFORE;\n span.appendChild(doc.createTextNode(ZERO_WIDTH_SPACE));\n element.parentNode?.insertBefore(span, isAfter ? element.nextSibling : element);\n\n return span;\n}\n"]}
@@ -14,10 +14,11 @@ var entityUtils_1 = require("./entityUtils");
14
14
  function reuseCachedElement(parent, element, refNode) {
15
15
  var _a;
16
16
  if (element.parentNode == parent) {
17
+ var isEntity = (0, entityUtils_1.isEntityElement)(element);
17
18
  // Remove nodes before the one we are hitting since they don't appear in Content Model at this position.
18
19
  // But we don't want to touch entity since it would better to keep entity at its place unless it is removed
19
20
  // In that case we will remove it after we have handled all other nodes
20
- while (refNode && refNode != element && !(0, entityUtils_1.isEntityElement)(refNode)) {
21
+ while (refNode && refNode != element && (isEntity || !(0, entityUtils_1.isEntityElement)(refNode))) {
21
22
  var next = refNode.nextSibling;
22
23
  (_a = refNode.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(refNode);
23
24
  refNode = next;
@@ -1 +1 @@
1
- {"version":3,"file":"reuseCachedElement.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/reuseCachedElement.ts"],"names":[],"mappings":";;;AAAA,6CAAgD;AAEhD;;;;;;;;GAQG;AACH,SAAgB,kBAAkB,CAAC,MAAY,EAAE,OAAa,EAAE,OAAoB;;IAChF,IAAI,OAAO,CAAC,UAAU,IAAI,MAAM,EAAE;QAC9B,wGAAwG;QACxG,2GAA2G;QAC3G,uEAAuE;QACvE,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,CAAC,IAAA,6BAAe,EAAC,OAAO,CAAC,EAAE;YAC/D,IAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC;YAEjC,MAAA,OAAO,CAAC,UAAU,0CAAE,WAAW,CAAC,OAAO,CAAC,CAAC;YACzC,OAAO,GAAG,IAAI,CAAC;SAClB;QAED,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,EAAE;YAC/B,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;SACjC;aAAM;YACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;SACzC;KACJ;SAAM;QACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;KACzC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAtBD,gDAsBC;AAED;;GAEG;AACH,SAAgB,UAAU,CAAC,IAAU;;IACjC,IAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;IAC9B,MAAA,IAAI,CAAC,UAAU,0CAAE,WAAW,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,IAAI,CAAC;AAChB,CAAC;AALD,gCAKC","sourcesContent":["import { isEntityElement } from './entityUtils';\n\n/**\n * When set a DOM tree into editor, reuse the existing element in editor and no need to change it\n * @param param Parent node of the reused element\n * @param element The element to keep in parent node\n * @param refNode Reference node, it is point to current node that is being processed. It must be a child of parent node, or null.\n * We will start processing from this node, if it is not the same with element, remove it and keep processing its next sibling,\n * until we see an element that is the same with the passed in element or null.\n * @returns The new reference element\n */\nexport function reuseCachedElement(parent: Node, element: Node, refNode: Node | null): Node | null {\n if (element.parentNode == parent) {\n // Remove nodes before the one we are hitting since they don't appear in Content Model at this position.\n // But we don't want to touch entity since it would better to keep entity at its place unless it is removed\n // In that case we will remove it after we have handled all other nodes\n while (refNode && refNode != element && !isEntityElement(refNode)) {\n const next = refNode.nextSibling;\n\n refNode.parentNode?.removeChild(refNode);\n refNode = next;\n }\n\n if (refNode && refNode == element) {\n refNode = refNode.nextSibling;\n } else {\n parent.insertBefore(element, refNode);\n }\n } else {\n parent.insertBefore(element, refNode);\n }\n\n return refNode;\n}\n\n/**\n * @internal\n */\nexport function removeNode(node: Node): Node | null {\n const next = node.nextSibling;\n node.parentNode?.removeChild(node);\n\n return next;\n}\n"]}
1
+ {"version":3,"file":"reuseCachedElement.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/reuseCachedElement.ts"],"names":[],"mappings":";;;AAAA,6CAAgD;AAEhD;;;;;;;;GAQG;AACH,SAAgB,kBAAkB,CAAC,MAAY,EAAE,OAAa,EAAE,OAAoB;;IAChF,IAAI,OAAO,CAAC,UAAU,IAAI,MAAM,EAAE;QAC9B,IAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,OAAO,CAAC,CAAC;QAE1C,wGAAwG;QACxG,2GAA2G;QAC3G,uEAAuE;QACvE,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAA,6BAAe,EAAC,OAAO,CAAC,CAAC,EAAE;YAC7E,IAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC;YAEjC,MAAA,OAAO,CAAC,UAAU,0CAAE,WAAW,CAAC,OAAO,CAAC,CAAC;YACzC,OAAO,GAAG,IAAI,CAAC;SAClB;QAED,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,EAAE;YAC/B,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;SACjC;aAAM;YACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;SACzC;KACJ;SAAM;QACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;KACzC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAxBD,gDAwBC;AAED;;GAEG;AACH,SAAgB,UAAU,CAAC,IAAU;;IACjC,IAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;IAC9B,MAAA,IAAI,CAAC,UAAU,0CAAE,WAAW,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,IAAI,CAAC;AAChB,CAAC;AALD,gCAKC","sourcesContent":["import { isEntityElement } from './entityUtils';\n\n/**\n * When set a DOM tree into editor, reuse the existing element in editor and no need to change it\n * @param param Parent node of the reused element\n * @param element The element to keep in parent node\n * @param refNode Reference node, it is point to current node that is being processed. It must be a child of parent node, or null.\n * We will start processing from this node, if it is not the same with element, remove it and keep processing its next sibling,\n * until we see an element that is the same with the passed in element or null.\n * @returns The new reference element\n */\nexport function reuseCachedElement(parent: Node, element: Node, refNode: Node | null): Node | null {\n if (element.parentNode == parent) {\n const isEntity = isEntityElement(element);\n\n // Remove nodes before the one we are hitting since they don't appear in Content Model at this position.\n // But we don't want to touch entity since it would better to keep entity at its place unless it is removed\n // In that case we will remove it after we have handled all other nodes\n while (refNode && refNode != element && (isEntity || !isEntityElement(refNode))) {\n const next = refNode.nextSibling;\n\n refNode.parentNode?.removeChild(refNode);\n refNode = next;\n }\n\n if (refNode && refNode == element) {\n refNode = refNode.nextSibling;\n } else {\n parent.insertBefore(element, refNode);\n }\n } else {\n parent.insertBefore(element, refNode);\n }\n\n return refNode;\n}\n\n/**\n * @internal\n */\nexport function removeNode(node: Node): Node | null {\n const next = node.nextSibling;\n node.parentNode?.removeChild(node);\n\n return next;\n}\n"]}
@@ -7,14 +7,7 @@ var entityUtils_1 = require("../../domUtils/entityUtils");
7
7
  */
8
8
  exports.entityFormatHandler = {
9
9
  parse: function (format, element) {
10
- var isEntity = false;
11
- element.classList.forEach(function (name) {
12
- isEntity = (0, entityUtils_1.parseEntityClassName)(name, format) || isEntity;
13
- });
14
- if (!isEntity) {
15
- format.isFakeEntity = true;
16
- format.isReadonly = !element.isContentEditable;
17
- }
10
+ Object.assign(format, (0, entityUtils_1.parseEntityFormat)(element));
18
11
  },
19
12
  apply: function (format, element) {
20
13
  if (!format.isFakeEntity) {
@@ -1 +1 @@
1
- {"version":3,"file":"entityFormatHandler.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/formatHandlers/entity/entityFormatHandler.ts"],"names":[],"mappings":";;;AAAA,0DAA4F;AAI5F;;GAEG;AACU,QAAA,mBAAmB,GAA+C;IAC3E,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,UAAA,IAAI;YAC1B,QAAQ,GAAG,IAAA,kCAAoB,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,QAAQ,CAAC;QAC9D,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,EAAE;YACX,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC;YAC3B,MAAM,CAAC,UAAU,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC;SAClD;IACL,CAAC;IAED,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;YACtB,OAAO,CAAC,SAAS,GAAG,IAAA,sCAAwB,EAAC,MAAM,CAAC,CAAC;SACxD;QAED,IAAI,MAAM,CAAC,UAAU,EAAE;YACnB,OAAO,CAAC,eAAe,GAAG,OAAO,CAAC;SACrC;aAAM;YACH,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;SAC9C;IACL,CAAC;CACJ,CAAC","sourcesContent":["import { generateEntityClassNames, parseEntityClassName } from '../../domUtils/entityUtils';\nimport type { EntityInfoFormat, IdFormat } from 'roosterjs-content-model-types';\nimport type { FormatHandler } from '../FormatHandler';\n\n/**\n * @internal\n */\nexport const entityFormatHandler: FormatHandler<EntityInfoFormat & IdFormat> = {\n parse: (format, element) => {\n let isEntity = false;\n\n element.classList.forEach(name => {\n isEntity = parseEntityClassName(name, format) || isEntity;\n });\n\n if (!isEntity) {\n format.isFakeEntity = true;\n format.isReadonly = !element.isContentEditable;\n }\n },\n\n apply: (format, element) => {\n if (!format.isFakeEntity) {\n element.className = generateEntityClassNames(format);\n }\n\n if (format.isReadonly) {\n element.contentEditable = 'false';\n } else {\n element.removeAttribute('contenteditable');\n }\n },\n};\n"]}
1
+ {"version":3,"file":"entityFormatHandler.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/formatHandlers/entity/entityFormatHandler.ts"],"names":[],"mappings":";;;AAAA,0DAAyF;AAIzF;;GAEG;AACU,QAAA,mBAAmB,GAA+C;IAC3E,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAA,+BAAiB,EAAC,OAAO,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;YACtB,OAAO,CAAC,SAAS,GAAG,IAAA,sCAAwB,EAAC,MAAM,CAAC,CAAC;SACxD;QAED,IAAI,MAAM,CAAC,UAAU,EAAE;YACnB,OAAO,CAAC,eAAe,GAAG,OAAO,CAAC;SACrC;aAAM;YACH,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;SAC9C;IACL,CAAC;CACJ,CAAC","sourcesContent":["import { generateEntityClassNames, parseEntityFormat } from '../../domUtils/entityUtils';\nimport type { EntityInfoFormat, IdFormat } from 'roosterjs-content-model-types';\nimport type { FormatHandler } from '../FormatHandler';\n\n/**\n * @internal\n */\nexport const entityFormatHandler: FormatHandler<EntityInfoFormat & IdFormat> = {\n parse: (format, element) => {\n Object.assign(format, parseEntityFormat(element));\n },\n\n apply: (format, element) => {\n if (!format.isFakeEntity) {\n element.className = generateEntityClassNames(format);\n }\n\n if (format.isReadonly) {\n element.contentEditable = 'false';\n } else {\n element.removeAttribute('contenteditable');\n }\n },\n};\n"]}
package/lib/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export { getObjectKeys } from './domUtils/getObjectKeys';
15
15
  export { default as toArray } from './domUtils/toArray';
16
16
  export { moveChildNodes, wrapAllChildNodes } from './domUtils/moveChildNodes';
17
17
  export { wrap } from './domUtils/wrap';
18
- export { isEntityElement, getAllEntityWrappers, parseEntityClassName, generateEntityClassNames, addDelimiters, isEntityDelimiter, } from './domUtils/entityUtils';
18
+ export { isEntityElement, getAllEntityWrappers, parseEntityFormat, generateEntityClassNames, addDelimiters, isEntityDelimiter, } from './domUtils/entityUtils';
19
19
  export { reuseCachedElement } from './domUtils/reuseCachedElement';
20
20
  export { isWhiteSpacePreserved } from './domUtils/isWhiteSpacePreserved';
21
21
  export { createBr } from './modelApi/creators/createBr';
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizeParagraph = exports.addLink = exports.addCode = exports.addBlock = exports.createEmptyModel = exports.createListLevel = exports.createDivider = exports.createEntity = exports.createGeneralBlock = exports.createGeneralSegment = exports.createParagraphDecorator = exports.createContentModelDocument = exports.createImage = exports.createText = exports.createTableCell = exports.createTable = exports.createSelectionMarker = exports.createParagraph = exports.createFormatContainer = exports.createListItem = exports.createBr = exports.isWhiteSpacePreserved = exports.reuseCachedElement = exports.isEntityDelimiter = exports.addDelimiters = exports.generateEntityClassNames = exports.parseEntityClassName = exports.getAllEntityWrappers = exports.isEntityElement = exports.wrap = exports.wrapAllChildNodes = exports.moveChildNodes = exports.toArray = exports.getObjectKeys = exports.isElementOfType = exports.isNodeOfType = exports.hasMetadata = exports.updateMetadata = exports.isBlockElement = exports.areSameFormats = exports.parseFormat = exports.getRegularSelectionOffsets = exports.tableProcessor = exports.entityProcessor = exports.processChildNode = exports.handleRegularSelection = exports.childProcessor = exports.contentModelToText = exports.contentModelToDom = exports.domToContentModel = void 0;
3
+ exports.normalizeParagraph = exports.addLink = exports.addCode = exports.addBlock = exports.createEmptyModel = exports.createListLevel = exports.createDivider = exports.createEntity = exports.createGeneralBlock = exports.createGeneralSegment = exports.createParagraphDecorator = exports.createContentModelDocument = exports.createImage = exports.createText = exports.createTableCell = exports.createTable = exports.createSelectionMarker = exports.createParagraph = exports.createFormatContainer = exports.createListItem = exports.createBr = exports.isWhiteSpacePreserved = exports.reuseCachedElement = exports.isEntityDelimiter = exports.addDelimiters = exports.generateEntityClassNames = exports.parseEntityFormat = exports.getAllEntityWrappers = exports.isEntityElement = exports.wrap = exports.wrapAllChildNodes = exports.moveChildNodes = exports.toArray = exports.getObjectKeys = exports.isElementOfType = exports.isNodeOfType = exports.hasMetadata = exports.updateMetadata = exports.isBlockElement = exports.areSameFormats = exports.parseFormat = exports.getRegularSelectionOffsets = exports.tableProcessor = exports.entityProcessor = exports.processChildNode = exports.handleRegularSelection = exports.childProcessor = exports.contentModelToText = exports.contentModelToDom = exports.domToContentModel = void 0;
4
4
  exports.createModelToDomConfig = exports.createModelToDomContextWithConfig = exports.createModelToDomContext = exports.createDomToModelConfig = exports.createDomToModelContextWithConfig = exports.createDomToModelContext = exports.parseColor = exports.setColor = exports.getColor = exports.DeprecatedColors = exports.BorderKeys = exports.parseValueWithUnit = exports.setParagraphNotImplicit = exports.normalizeSingleSegment = exports.isEmpty = exports.addSegment = exports.unwrapBlock = exports.isGeneralSegment = exports.normalizeContentModel = void 0;
5
5
  var domToContentModel_1 = require("./domToModel/domToContentModel");
6
6
  Object.defineProperty(exports, "domToContentModel", { enumerable: true, get: function () { return domToContentModel_1.domToContentModel; } });
@@ -43,7 +43,7 @@ Object.defineProperty(exports, "wrap", { enumerable: true, get: function () { re
43
43
  var entityUtils_1 = require("./domUtils/entityUtils");
44
44
  Object.defineProperty(exports, "isEntityElement", { enumerable: true, get: function () { return entityUtils_1.isEntityElement; } });
45
45
  Object.defineProperty(exports, "getAllEntityWrappers", { enumerable: true, get: function () { return entityUtils_1.getAllEntityWrappers; } });
46
- Object.defineProperty(exports, "parseEntityClassName", { enumerable: true, get: function () { return entityUtils_1.parseEntityClassName; } });
46
+ Object.defineProperty(exports, "parseEntityFormat", { enumerable: true, get: function () { return entityUtils_1.parseEntityFormat; } });
47
47
  Object.defineProperty(exports, "generateEntityClassNames", { enumerable: true, get: function () { return entityUtils_1.generateEntityClassNames; } });
48
48
  Object.defineProperty(exports, "addDelimiters", { enumerable: true, get: function () { return entityUtils_1.addDelimiters; } });
49
49
  Object.defineProperty(exports, "isEntityDelimiter", { enumerable: true, get: function () { return entityUtils_1.isEntityDelimiter; } });
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages-content-model/roosterjs-content-model-dom/lib/index.ts"],"names":[],"mappings":"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","sourcesContent":["export { domToContentModel } from './domToModel/domToContentModel';\nexport { contentModelToDom } from './modelToDom/contentModelToDom';\nexport { contentModelToText } from './modelToText/contentModelToText';\n\nexport {\n childProcessor,\n handleRegularSelection,\n processChildNode,\n} from './domToModel/processors/childProcessor';\nexport { entityProcessor } from './domToModel/processors/entityProcessor';\nexport { tableProcessor } from './domToModel/processors/tableProcessor';\nexport { getRegularSelectionOffsets } from './domToModel/utils/getRegularSelectionOffsets';\nexport { parseFormat } from './domToModel/utils/parseFormat';\nexport { areSameFormats } from './domToModel/utils/areSameFormats';\nexport { isBlockElement } from './domToModel/utils/isBlockElement';\n\nexport { updateMetadata, hasMetadata } from './domUtils/metadata/updateMetadata';\nexport { isNodeOfType, NodeTypeMap } from './domUtils/isNodeOfType';\nexport { isElementOfType } from './domUtils/isElementOfType';\nexport { getObjectKeys } from './domUtils/getObjectKeys';\nexport { default as toArray } from './domUtils/toArray';\nexport { moveChildNodes, wrapAllChildNodes } from './domUtils/moveChildNodes';\nexport { wrap } from './domUtils/wrap';\nexport {\n isEntityElement,\n getAllEntityWrappers,\n parseEntityClassName,\n generateEntityClassNames,\n addDelimiters,\n isEntityDelimiter,\n} from './domUtils/entityUtils';\nexport { reuseCachedElement } from './domUtils/reuseCachedElement';\nexport { isWhiteSpacePreserved } from './domUtils/isWhiteSpacePreserved';\n\nexport { createBr } from './modelApi/creators/createBr';\nexport { createListItem } from './modelApi/creators/createListItem';\nexport { createFormatContainer } from './modelApi/creators/createFormatContainer';\nexport { createParagraph } from './modelApi/creators/createParagraph';\nexport { createSelectionMarker } from './modelApi/creators/createSelectionMarker';\nexport { createTable } from './modelApi/creators/createTable';\nexport { createTableCell } from './modelApi/creators/createTableCell';\nexport { createText } from './modelApi/creators/createText';\nexport { createImage } from './modelApi/creators/createImage';\nexport { createContentModelDocument } from './modelApi/creators/createContentModelDocument';\nexport { createParagraphDecorator } from './modelApi/creators/createParagraphDecorator';\nexport { createGeneralSegment } from './modelApi/creators/createGeneralSegment';\nexport { createGeneralBlock } from './modelApi/creators/createGeneralBlock';\nexport { createEntity } from './modelApi/creators/createEntity';\nexport { createDivider } from './modelApi/creators/createDivider';\nexport { createListLevel } from './modelApi/creators/createListLevel';\nexport { createEmptyModel } from './modelApi/creators/createEmptyModel';\n\nexport { addBlock } from './modelApi/common/addBlock';\nexport { addCode } from './modelApi/common/addDecorators';\nexport { addLink } from './modelApi/common/addDecorators';\nexport { normalizeParagraph } from './modelApi/common/normalizeParagraph';\n\nexport { normalizeContentModel } from './modelApi/common/normalizeContentModel';\nexport { isGeneralSegment } from './modelApi/common/isGeneralSegment';\nexport { unwrapBlock } from './modelApi/common/unwrapBlock';\nexport { addSegment } from './modelApi/common/addSegment';\nexport { isEmpty } from './modelApi/common/isEmpty';\nexport { normalizeSingleSegment } from './modelApi/common/normalizeSegment';\n\nexport { setParagraphNotImplicit } from './modelApi/block/setParagraphNotImplicit';\n\nexport { parseValueWithUnit } from './formatHandlers/utils/parseValueWithUnit';\nexport { BorderKeys } from './formatHandlers/common/borderFormatHandler';\nexport { DeprecatedColors, getColor, setColor, parseColor } from './formatHandlers/utils/color';\n\nexport {\n createDomToModelContext,\n createDomToModelContextWithConfig,\n createDomToModelConfig,\n} from './domToModel/context/createDomToModelContext';\nexport {\n createModelToDomContext,\n createModelToDomContextWithConfig,\n createModelToDomConfig,\n} from './modelToDom/context/createModelToDomContext';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages-content-model/roosterjs-content-model-dom/lib/index.ts"],"names":[],"mappings":"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","sourcesContent":["export { domToContentModel } from './domToModel/domToContentModel';\nexport { contentModelToDom } from './modelToDom/contentModelToDom';\nexport { contentModelToText } from './modelToText/contentModelToText';\n\nexport {\n childProcessor,\n handleRegularSelection,\n processChildNode,\n} from './domToModel/processors/childProcessor';\nexport { entityProcessor } from './domToModel/processors/entityProcessor';\nexport { tableProcessor } from './domToModel/processors/tableProcessor';\nexport { getRegularSelectionOffsets } from './domToModel/utils/getRegularSelectionOffsets';\nexport { parseFormat } from './domToModel/utils/parseFormat';\nexport { areSameFormats } from './domToModel/utils/areSameFormats';\nexport { isBlockElement } from './domToModel/utils/isBlockElement';\n\nexport { updateMetadata, hasMetadata } from './domUtils/metadata/updateMetadata';\nexport { isNodeOfType, NodeTypeMap } from './domUtils/isNodeOfType';\nexport { isElementOfType } from './domUtils/isElementOfType';\nexport { getObjectKeys } from './domUtils/getObjectKeys';\nexport { default as toArray } from './domUtils/toArray';\nexport { moveChildNodes, wrapAllChildNodes } from './domUtils/moveChildNodes';\nexport { wrap } from './domUtils/wrap';\nexport {\n isEntityElement,\n getAllEntityWrappers,\n parseEntityFormat,\n generateEntityClassNames,\n addDelimiters,\n isEntityDelimiter,\n} from './domUtils/entityUtils';\nexport { reuseCachedElement } from './domUtils/reuseCachedElement';\nexport { isWhiteSpacePreserved } from './domUtils/isWhiteSpacePreserved';\n\nexport { createBr } from './modelApi/creators/createBr';\nexport { createListItem } from './modelApi/creators/createListItem';\nexport { createFormatContainer } from './modelApi/creators/createFormatContainer';\nexport { createParagraph } from './modelApi/creators/createParagraph';\nexport { createSelectionMarker } from './modelApi/creators/createSelectionMarker';\nexport { createTable } from './modelApi/creators/createTable';\nexport { createTableCell } from './modelApi/creators/createTableCell';\nexport { createText } from './modelApi/creators/createText';\nexport { createImage } from './modelApi/creators/createImage';\nexport { createContentModelDocument } from './modelApi/creators/createContentModelDocument';\nexport { createParagraphDecorator } from './modelApi/creators/createParagraphDecorator';\nexport { createGeneralSegment } from './modelApi/creators/createGeneralSegment';\nexport { createGeneralBlock } from './modelApi/creators/createGeneralBlock';\nexport { createEntity } from './modelApi/creators/createEntity';\nexport { createDivider } from './modelApi/creators/createDivider';\nexport { createListLevel } from './modelApi/creators/createListLevel';\nexport { createEmptyModel } from './modelApi/creators/createEmptyModel';\n\nexport { addBlock } from './modelApi/common/addBlock';\nexport { addCode } from './modelApi/common/addDecorators';\nexport { addLink } from './modelApi/common/addDecorators';\nexport { normalizeParagraph } from './modelApi/common/normalizeParagraph';\n\nexport { normalizeContentModel } from './modelApi/common/normalizeContentModel';\nexport { isGeneralSegment } from './modelApi/common/isGeneralSegment';\nexport { unwrapBlock } from './modelApi/common/unwrapBlock';\nexport { addSegment } from './modelApi/common/addSegment';\nexport { isEmpty } from './modelApi/common/isEmpty';\nexport { normalizeSingleSegment } from './modelApi/common/normalizeSegment';\n\nexport { setParagraphNotImplicit } from './modelApi/block/setParagraphNotImplicit';\n\nexport { parseValueWithUnit } from './formatHandlers/utils/parseValueWithUnit';\nexport { BorderKeys } from './formatHandlers/common/borderFormatHandler';\nexport { DeprecatedColors, getColor, setColor, parseColor } from './formatHandlers/utils/color';\n\nexport {\n createDomToModelContext,\n createDomToModelContextWithConfig,\n createDomToModelConfig,\n} from './domToModel/context/createDomToModelContext';\nexport {\n createModelToDomContext,\n createModelToDomContextWithConfig,\n createModelToDomConfig,\n} from './modelToDom/context/createModelToDomContext';\n"]}
@@ -34,6 +34,7 @@ function normalizeParagraph(paragraph) {
34
34
  }
35
35
  removeEmptyLinks(paragraph);
36
36
  removeEmptySegments(paragraph);
37
+ moveUpSegmentFormat(paragraph);
37
38
  }
38
39
  exports.normalizeParagraph = normalizeParagraph;
39
40
  function removeEmptySegments(block) {
@@ -63,4 +64,31 @@ function removeEmptyLinks(paragraph) {
63
64
  }
64
65
  }
65
66
  }
67
+ var formatsToMoveUp = ['fontFamily', 'fontSize', 'textColor'];
68
+ // When all segments are sharing the same segment format (font name, size and color), we can move its format to paragraph
69
+ function moveUpSegmentFormat(paragraph) {
70
+ if (!paragraph.decorator) {
71
+ var segments_1 = paragraph.segments.filter(function (x) { return x.segmentType != 'SelectionMarker'; });
72
+ var target_1 = paragraph.segmentFormat || {};
73
+ var changed_1 = false;
74
+ formatsToMoveUp.forEach(function (key) {
75
+ changed_1 = internalMoveUpSegmentFormat(segments_1, target_1, key) || changed_1;
76
+ });
77
+ if (changed_1) {
78
+ paragraph.segmentFormat = target_1;
79
+ }
80
+ }
81
+ }
82
+ function internalMoveUpSegmentFormat(segments, target, formatKey) {
83
+ var _a;
84
+ var firstFormat = (_a = segments[0]) === null || _a === void 0 ? void 0 : _a.format;
85
+ if ((firstFormat === null || firstFormat === void 0 ? void 0 : firstFormat[formatKey]) &&
86
+ segments.every(function (segment) { return segment.format[formatKey] == firstFormat[formatKey]; })) {
87
+ target[formatKey] = firstFormat[formatKey];
88
+ return true;
89
+ }
90
+ else {
91
+ return false;
92
+ }
93
+ }
66
94
  //# sourceMappingURL=normalizeParagraph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalizeParagraph.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/modelApi/common/normalizeParagraph.ts"],"names":[],"mappings":"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","sourcesContent":["import { areSameFormats } from '../../domToModel/utils/areSameFormats';\nimport { createBr } from '../creators/createBr';\nimport { isSegmentEmpty } from './isEmpty';\nimport { isWhiteSpacePreserved } from '../../domUtils/isWhiteSpacePreserved';\nimport { normalizeAllSegments } from './normalizeSegment';\nimport type { ContentModelParagraph } from 'roosterjs-content-model-types';\n\n/**\n * @param paragraph The paragraph to normalize\n * Normalize a paragraph. If it is empty, add a BR segment to make sure it can insert content\n */\nexport function normalizeParagraph(paragraph: ContentModelParagraph) {\n const segments = paragraph.segments;\n\n if (!paragraph.isImplicit && segments.length > 0) {\n const last = segments[segments.length - 1];\n const secondLast = segments[segments.length - 2];\n\n if (\n last.segmentType == 'SelectionMarker' &&\n (!secondLast || secondLast.segmentType == 'Br')\n ) {\n segments.push(createBr(last.format));\n } else if (segments.length > 1 && segments[segments.length - 1].segmentType == 'Br') {\n const noMarkerSegments = segments.filter(x => x.segmentType != 'SelectionMarker');\n\n // When there is content with a <BR> tag at the end, we can remove the BR.\n // But if there are more than one <BR> at the end, do not remove them.\n if (\n noMarkerSegments.length > 1 &&\n noMarkerSegments[noMarkerSegments.length - 2].segmentType != 'Br'\n ) {\n segments.pop();\n }\n }\n }\n\n if (!isWhiteSpacePreserved(paragraph.format.whiteSpace)) {\n normalizeAllSegments(paragraph);\n }\n\n removeEmptyLinks(paragraph);\n\n removeEmptySegments(paragraph);\n}\n\nfunction removeEmptySegments(block: ContentModelParagraph) {\n for (let j = block.segments.length - 1; j >= 0; j--) {\n if (isSegmentEmpty(block.segments[j])) {\n block.segments.splice(j, 1);\n }\n }\n}\n\nfunction removeEmptyLinks(paragraph: ContentModelParagraph) {\n const marker = paragraph.segments.find(x => x.segmentType == 'SelectionMarker');\n if (marker) {\n const markerIndex = paragraph.segments.indexOf(marker);\n const prev = paragraph.segments[markerIndex - 1];\n const next = paragraph.segments[markerIndex + 1];\n if (\n (prev &&\n !prev.link &&\n areSameFormats(prev.format, marker.format) &&\n (!next || (!next.link && areSameFormats(next.format, marker.format))) &&\n marker.link) ||\n (!prev &&\n marker.link &&\n next &&\n !next.link &&\n areSameFormats(next.format, marker.format))\n ) {\n delete marker.link;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"normalizeParagraph.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/modelApi/common/normalizeParagraph.ts"],"names":[],"mappings":"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","sourcesContent":["import { areSameFormats } from '../../domToModel/utils/areSameFormats';\nimport { createBr } from '../creators/createBr';\nimport { isSegmentEmpty } from './isEmpty';\nimport { isWhiteSpacePreserved } from '../../domUtils/isWhiteSpacePreserved';\nimport { normalizeAllSegments } from './normalizeSegment';\nimport type {\n ContentModelParagraph,\n ContentModelSegment,\n ContentModelSegmentFormat,\n} from 'roosterjs-content-model-types';\n\n/**\n * @param paragraph The paragraph to normalize\n * Normalize a paragraph. If it is empty, add a BR segment to make sure it can insert content\n */\nexport function normalizeParagraph(paragraph: ContentModelParagraph) {\n const segments = paragraph.segments;\n\n if (!paragraph.isImplicit && segments.length > 0) {\n const last = segments[segments.length - 1];\n const secondLast = segments[segments.length - 2];\n\n if (\n last.segmentType == 'SelectionMarker' &&\n (!secondLast || secondLast.segmentType == 'Br')\n ) {\n segments.push(createBr(last.format));\n } else if (segments.length > 1 && segments[segments.length - 1].segmentType == 'Br') {\n const noMarkerSegments = segments.filter(x => x.segmentType != 'SelectionMarker');\n\n // When there is content with a <BR> tag at the end, we can remove the BR.\n // But if there are more than one <BR> at the end, do not remove them.\n if (\n noMarkerSegments.length > 1 &&\n noMarkerSegments[noMarkerSegments.length - 2].segmentType != 'Br'\n ) {\n segments.pop();\n }\n }\n }\n\n if (!isWhiteSpacePreserved(paragraph.format.whiteSpace)) {\n normalizeAllSegments(paragraph);\n }\n\n removeEmptyLinks(paragraph);\n\n removeEmptySegments(paragraph);\n\n moveUpSegmentFormat(paragraph);\n}\n\nfunction removeEmptySegments(block: ContentModelParagraph) {\n for (let j = block.segments.length - 1; j >= 0; j--) {\n if (isSegmentEmpty(block.segments[j])) {\n block.segments.splice(j, 1);\n }\n }\n}\n\nfunction removeEmptyLinks(paragraph: ContentModelParagraph) {\n const marker = paragraph.segments.find(x => x.segmentType == 'SelectionMarker');\n if (marker) {\n const markerIndex = paragraph.segments.indexOf(marker);\n const prev = paragraph.segments[markerIndex - 1];\n const next = paragraph.segments[markerIndex + 1];\n if (\n (prev &&\n !prev.link &&\n areSameFormats(prev.format, marker.format) &&\n (!next || (!next.link && areSameFormats(next.format, marker.format))) &&\n marker.link) ||\n (!prev &&\n marker.link &&\n next &&\n !next.link &&\n areSameFormats(next.format, marker.format))\n ) {\n delete marker.link;\n }\n }\n}\n\ntype FormatsToMoveUp = 'fontFamily' | 'fontSize' | 'textColor';\nconst formatsToMoveUp: FormatsToMoveUp[] = ['fontFamily', 'fontSize', 'textColor'];\n\n// When all segments are sharing the same segment format (font name, size and color), we can move its format to paragraph\nfunction moveUpSegmentFormat(paragraph: ContentModelParagraph) {\n if (!paragraph.decorator) {\n const segments = paragraph.segments.filter(x => x.segmentType != 'SelectionMarker');\n const target = paragraph.segmentFormat || {};\n let changed = false;\n\n formatsToMoveUp.forEach(key => {\n changed = internalMoveUpSegmentFormat(segments, target, key) || changed;\n });\n\n if (changed) {\n paragraph.segmentFormat = target;\n }\n }\n}\n\nfunction internalMoveUpSegmentFormat(\n segments: ContentModelSegment[],\n target: ContentModelSegmentFormat,\n formatKey: FormatsToMoveUp\n): boolean {\n const firstFormat = segments[0]?.format;\n\n if (\n firstFormat?.[formatKey] &&\n segments.every(segment => segment.format[formatKey] == firstFormat[formatKey])\n ) {\n target[formatKey] = firstFormat[formatKey];\n return true;\n } else {\n return false;\n }\n}\n"]}
@@ -6,12 +6,26 @@ define(["require", "exports", "tslib", "../../modelApi/common/addDecorators", ".
6
6
  * @internal
7
7
  */
8
8
  function addSelectionMarker(group, context, container, offset) {
9
+ var lastPara = group.blocks[group.blocks.length - 1];
10
+ var formatFromParagraph = !lastPara || lastPara.blockType != 'Paragraph'
11
+ ? {}
12
+ : lastPara.decorator
13
+ ? {
14
+ fontFamily: lastPara.decorator.format.fontFamily,
15
+ fontSize: lastPara.decorator.format.fontSize,
16
+ }
17
+ : lastPara.segmentFormat
18
+ ? {
19
+ fontFamily: lastPara.segmentFormat.fontFamily,
20
+ fontSize: lastPara.segmentFormat.fontSize,
21
+ }
22
+ : {};
9
23
  var pendingFormat = context.pendingFormat &&
10
24
  context.pendingFormat.posContainer === container &&
11
25
  context.pendingFormat.posOffset === offset
12
26
  ? context.pendingFormat.format
13
27
  : undefined;
14
- var segmentFormat = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, context.defaultFormat), context.segmentFormat), pendingFormat);
28
+ var segmentFormat = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, context.defaultFormat), formatFromParagraph), context.segmentFormat), pendingFormat);
15
29
  var marker = (0, createSelectionMarker_1.createSelectionMarker)(segmentFormat);
16
30
  (0, addDecorators_1.addDecorators)(marker, context);
17
31
  (0, addSegment_1.addSegment)(group, marker, context.blockFormat, segmentFormat);
@@ -1 +1 @@
1
- {"version":3,"file":"addSelectionMarker.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts"],"names":[],"mappings":";;;;IAKA;;OAEG;IACH,SAAgB,kBAAkB,CAC9B,KAA6B,EAC7B,OAA0B,EAC1B,SAAgB,EAChB,MAAe;QAEf,IAAM,aAAa,GACf,OAAO,CAAC,aAAa;YACrB,OAAO,CAAC,aAAa,CAAC,YAAY,KAAK,SAAS;YAChD,OAAO,CAAC,aAAa,CAAC,SAAS,KAAK,MAAM;YACtC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM;YAC9B,CAAC,CAAC,SAAS,CAAC;QACpB,IAAM,aAAa,yEACZ,OAAO,CAAC,aAAa,GACrB,OAAO,CAAC,aAAa,GACrB,aAAa,CACnB,CAAC;QACF,IAAM,MAAM,GAAG,IAAA,6CAAqB,EAAC,aAAa,CAAC,CAAC;QAEpD,IAAA,6BAAa,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE/B,IAAA,uBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAClE,CAAC;IAtBD,gDAsBC","sourcesContent":["import { addDecorators } from '../../modelApi/common/addDecorators';\nimport { addSegment } from '../../modelApi/common/addSegment';\nimport { createSelectionMarker } from '../../modelApi/creators/createSelectionMarker';\nimport type { ContentModelBlockGroup, DomToModelContext } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function addSelectionMarker(\n group: ContentModelBlockGroup,\n context: DomToModelContext,\n container?: Node,\n offset?: number\n) {\n const pendingFormat =\n context.pendingFormat &&\n context.pendingFormat.posContainer === container &&\n context.pendingFormat.posOffset === offset\n ? context.pendingFormat.format\n : undefined;\n const segmentFormat = {\n ...context.defaultFormat,\n ...context.segmentFormat,\n ...pendingFormat,\n };\n const marker = createSelectionMarker(segmentFormat);\n\n addDecorators(marker, context);\n\n addSegment(group, marker, context.blockFormat, segmentFormat);\n}\n"]}
1
+ {"version":3,"file":"addSelectionMarker.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts"],"names":[],"mappings":";;;;IASA;;OAEG;IACH,SAAgB,kBAAkB,CAC9B,KAA6B,EAC7B,OAA0B,EAC1B,SAAgB,EAChB,MAAe;QAEf,IAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvD,IAAM,mBAAmB,GACrB,CAAC,QAAQ,IAAI,QAAQ,CAAC,SAAS,IAAI,WAAW;YAC1C,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,QAAQ,CAAC,SAAS;gBACpB,CAAC,CAAC;oBACI,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU;oBAChD,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ;iBAC/C;gBACH,CAAC,CAAC,QAAQ,CAAC,aAAa;oBACxB,CAAC,CAAC;wBACI,UAAU,EAAE,QAAQ,CAAC,aAAa,CAAC,UAAU;wBAC7C,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,QAAQ;qBAC5C;oBACH,CAAC,CAAC,EAAE,CAAC;QAEb,IAAM,aAAa,GACf,OAAO,CAAC,aAAa;YACrB,OAAO,CAAC,aAAa,CAAC,YAAY,KAAK,SAAS;YAChD,OAAO,CAAC,aAAa,CAAC,SAAS,KAAK,MAAM;YACtC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM;YAC9B,CAAC,CAAC,SAAS,CAAC;QACpB,IAAM,aAAa,+FACZ,OAAO,CAAC,aAAa,GACrB,mBAAmB,GACnB,OAAO,CAAC,aAAa,GACrB,aAAa,CACnB,CAAC;QACF,IAAM,MAAM,GAAG,IAAA,6CAAqB,EAAC,aAAa,CAAC,CAAC;QAEpD,IAAA,6BAAa,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE/B,IAAA,uBAAU,EAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAClE,CAAC;IAvCD,gDAuCC","sourcesContent":["import { addDecorators } from '../../modelApi/common/addDecorators';\nimport { addSegment } from '../../modelApi/common/addSegment';\nimport { createSelectionMarker } from '../../modelApi/creators/createSelectionMarker';\nimport type {\n ContentModelBlockGroup,\n ContentModelSegmentFormat,\n DomToModelContext,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function addSelectionMarker(\n group: ContentModelBlockGroup,\n context: DomToModelContext,\n container?: Node,\n offset?: number\n) {\n const lastPara = group.blocks[group.blocks.length - 1];\n const formatFromParagraph: ContentModelSegmentFormat =\n !lastPara || lastPara.blockType != 'Paragraph'\n ? {}\n : lastPara.decorator\n ? {\n fontFamily: lastPara.decorator.format.fontFamily,\n fontSize: lastPara.decorator.format.fontSize,\n }\n : lastPara.segmentFormat\n ? {\n fontFamily: lastPara.segmentFormat.fontFamily,\n fontSize: lastPara.segmentFormat.fontSize,\n }\n : {};\n\n const pendingFormat =\n context.pendingFormat &&\n context.pendingFormat.posContainer === container &&\n context.pendingFormat.posOffset === offset\n ? context.pendingFormat.format\n : undefined;\n const segmentFormat = {\n ...context.defaultFormat,\n ...formatFromParagraph,\n ...context.segmentFormat,\n ...pendingFormat,\n };\n const marker = createSelectionMarker(segmentFormat);\n\n addDecorators(marker, context);\n\n addSegment(group, marker, context.blockFormat, segmentFormat);\n}\n"]}
@@ -10,11 +10,11 @@ export declare function isEntityElement(node: Node): boolean;
10
10
  */
11
11
  export declare function getAllEntityWrappers(root: HTMLElement): HTMLElement[];
12
12
  /**
13
- * Parse entity class names from entity wrapper element
14
- * @param className Class names of entity
15
- * @param format The output entity format object
13
+ * Parse entity format from entity wrapper element
14
+ * @param wrapper The wrapper element to parse entity format from
15
+ * @returns Entity format
16
16
  */
17
- export declare function parseEntityClassName(className: string, format: ContentModelEntityFormat): boolean | undefined;
17
+ export declare function parseEntityFormat(wrapper: HTMLElement): ContentModelEntityFormat;
18
18
  /**
19
19
  * Generate Entity class names for an entity wrapper
20
20
  * @param format The source entity format object
@@ -1,7 +1,7 @@
1
1
  define(["require", "exports", "tslib", "./toArray", "../modelToDom/utils/applyFormat", "./isElementOfType", "./isNodeOfType"], function (require, exports, tslib_1, toArray_1, applyFormat_1, isElementOfType_1, isNodeOfType_1) {
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.addDelimiters = exports.isEntityDelimiter = exports.generateEntityClassNames = exports.parseEntityClassName = exports.getAllEntityWrappers = exports.isEntityElement = void 0;
4
+ exports.addDelimiters = exports.isEntityDelimiter = exports.generateEntityClassNames = exports.parseEntityFormat = exports.getAllEntityWrappers = exports.isEntityElement = void 0;
5
5
  var ENTITY_INFO_NAME = '_Entity';
6
6
  var ENTITY_TYPE_PREFIX = '_EType_';
7
7
  var ENTITY_ID_PREFIX = '_EId_';
@@ -25,6 +25,24 @@ define(["require", "exports", "tslib", "./toArray", "../modelToDom/utils/applyFo
25
25
  return (0, toArray_1.default)(root.querySelectorAll('.' + ENTITY_INFO_NAME));
26
26
  }
27
27
  exports.getAllEntityWrappers = getAllEntityWrappers;
28
+ /**
29
+ * Parse entity format from entity wrapper element
30
+ * @param wrapper The wrapper element to parse entity format from
31
+ * @returns Entity format
32
+ */
33
+ function parseEntityFormat(wrapper) {
34
+ var isEntity = false;
35
+ var format = {};
36
+ wrapper.classList.forEach(function (name) {
37
+ isEntity = parseEntityClassName(name, format) || isEntity;
38
+ });
39
+ if (!isEntity) {
40
+ format.isFakeEntity = true;
41
+ format.isReadonly = !wrapper.isContentEditable;
42
+ }
43
+ return format;
44
+ }
45
+ exports.parseEntityFormat = parseEntityFormat;
28
46
  /**
29
47
  * Parse entity class names from entity wrapper element
30
48
  * @param className Class names of entity
@@ -44,7 +62,6 @@ define(["require", "exports", "tslib", "./toArray", "../modelToDom/utils/applyFo
44
62
  format.isReadonly = className.substring(ENTITY_READONLY_PREFIX.length) == '1';
45
63
  }
46
64
  }
47
- exports.parseEntityClassName = parseEntityClassName;
48
65
  /**
49
66
  * Generate Entity class names for an entity wrapper
50
67
  * @param format The source entity format object
@@ -1 +1 @@
1
- {"version":3,"file":"entityUtils.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/entityUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import toArray from './toArray';\nimport { applyFormat } from '../modelToDom/utils/applyFormat';\nimport { isElementOfType } from './isElementOfType';\nimport { isNodeOfType } from './isNodeOfType';\nimport type {\n ContentModelEntityFormat,\n ContentModelSegmentFormat,\n ModelToDomContext,\n} from 'roosterjs-content-model-types';\n\nconst ENTITY_INFO_NAME = '_Entity';\nconst ENTITY_TYPE_PREFIX = '_EType_';\nconst ENTITY_ID_PREFIX = '_EId_';\nconst ENTITY_READONLY_PREFIX = '_EReadonly_';\nconst ZERO_WIDTH_SPACE = '\\u200B';\nconst DELIMITER_BEFORE = 'entityDelimiterBefore';\nconst DELIMITER_AFTER = 'entityDelimiterAfter';\n\n/**\n * Check if the given DOM Node is an entity wrapper element\n */\nexport function isEntityElement(node: Node): boolean {\n return isNodeOfType(node, 'ELEMENT_NODE') && node.classList.contains(ENTITY_INFO_NAME);\n}\n\n/**\n * Get all entity wrapper elements under the given root element\n * @param root The root element to query from\n * @returns An array of entity wrapper elements\n */\nexport function getAllEntityWrappers(root: HTMLElement): HTMLElement[] {\n return toArray(root.querySelectorAll('.' + ENTITY_INFO_NAME)) as HTMLElement[];\n}\n\n/**\n * Parse entity class names from entity wrapper element\n * @param className Class names of entity\n * @param format The output entity format object\n */\nexport function parseEntityClassName(\n className: string,\n format: ContentModelEntityFormat\n): boolean | undefined {\n if (className == ENTITY_INFO_NAME) {\n return true;\n } else if (className.indexOf(ENTITY_TYPE_PREFIX) == 0) {\n format.entityType = className.substring(ENTITY_TYPE_PREFIX.length);\n } else if (className.indexOf(ENTITY_ID_PREFIX) == 0) {\n format.id = className.substring(ENTITY_ID_PREFIX.length);\n } else if (className.indexOf(ENTITY_READONLY_PREFIX) == 0) {\n format.isReadonly = className.substring(ENTITY_READONLY_PREFIX.length) == '1';\n }\n}\n\n/**\n * Generate Entity class names for an entity wrapper\n * @param format The source entity format object\n * @returns A combined CSS class name string for entity wrapper\n */\nexport function generateEntityClassNames(format: ContentModelEntityFormat): string {\n return format.isFakeEntity\n ? ''\n : `${ENTITY_INFO_NAME} ${ENTITY_TYPE_PREFIX}${format.entityType ?? ''} ${\n format.id ? `${ENTITY_ID_PREFIX}${format.id} ` : ''\n }${ENTITY_READONLY_PREFIX}${format.isReadonly ? '1' : '0'}`;\n}\n\n/**\n * Checks whether the node provided is a Entity delimiter\n * @param node the node to check\n * @return true if it is a delimiter\n */\nexport function isEntityDelimiter(element: HTMLElement): boolean {\n return (\n isElementOfType(element, 'span') &&\n (element.classList.contains(DELIMITER_AFTER) ||\n element.classList.contains(DELIMITER_BEFORE)) &&\n element.textContent === ZERO_WIDTH_SPACE\n );\n}\n\n/**\n * Adds delimiters to the element provided. If the delimiters already exists, will not be added\n * @param element the node to add the delimiters\n * @param format format to set to the delimiters, so when typing inside of one the format is not lost\n * @param context Model to Dom context to use.\n */\nexport function addDelimiters(\n doc: Document,\n element: HTMLElement,\n format?: ContentModelSegmentFormat | null,\n context?: ModelToDomContext\n): HTMLElement[] {\n let [delimiterAfter, delimiterBefore] = getDelimiters(element);\n\n if (!delimiterAfter) {\n delimiterAfter = insertDelimiter(doc, element, true /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterAfter, context.formatAppliers.segment, format, context);\n }\n }\n\n if (!delimiterBefore) {\n delimiterBefore = insertDelimiter(doc, element, false /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterBefore, context.formatAppliers.segment, format, context);\n }\n }\n\n return [delimiterAfter, delimiterBefore];\n}\n\nfunction getDelimiters(entityWrapper: HTMLElement): (HTMLElement | undefined)[] {\n const result: (HTMLElement | undefined)[] = [];\n const { nextElementSibling, previousElementSibling } = entityWrapper;\n result.push(\n isDelimiter(nextElementSibling, DELIMITER_AFTER),\n isDelimiter(previousElementSibling, DELIMITER_BEFORE)\n );\n\n return result;\n}\n\nfunction isDelimiter(el: Element | null, className: string): HTMLElement | undefined {\n return el?.classList.contains(className) && el.textContent == ZERO_WIDTH_SPACE\n ? (el as HTMLElement)\n : undefined;\n}\n\nfunction insertDelimiter(doc: Document, element: Element, isAfter: boolean) {\n const span = doc.createElement('span');\n\n span.className = isAfter ? DELIMITER_AFTER : DELIMITER_BEFORE;\n span.appendChild(doc.createTextNode(ZERO_WIDTH_SPACE));\n element.parentNode?.insertBefore(span, isAfter ? element.nextSibling : element);\n\n return span;\n}\n"]}
1
+ {"version":3,"file":"entityUtils.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/entityUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import toArray from './toArray';\nimport { applyFormat } from '../modelToDom/utils/applyFormat';\nimport { isElementOfType } from './isElementOfType';\nimport { isNodeOfType } from './isNodeOfType';\nimport type {\n ContentModelEntityFormat,\n ContentModelSegmentFormat,\n ModelToDomContext,\n} from 'roosterjs-content-model-types';\n\nconst ENTITY_INFO_NAME = '_Entity';\nconst ENTITY_TYPE_PREFIX = '_EType_';\nconst ENTITY_ID_PREFIX = '_EId_';\nconst ENTITY_READONLY_PREFIX = '_EReadonly_';\nconst ZERO_WIDTH_SPACE = '\\u200B';\nconst DELIMITER_BEFORE = 'entityDelimiterBefore';\nconst DELIMITER_AFTER = 'entityDelimiterAfter';\n\n/**\n * Check if the given DOM Node is an entity wrapper element\n */\nexport function isEntityElement(node: Node): boolean {\n return isNodeOfType(node, 'ELEMENT_NODE') && node.classList.contains(ENTITY_INFO_NAME);\n}\n\n/**\n * Get all entity wrapper elements under the given root element\n * @param root The root element to query from\n * @returns An array of entity wrapper elements\n */\nexport function getAllEntityWrappers(root: HTMLElement): HTMLElement[] {\n return toArray(root.querySelectorAll('.' + ENTITY_INFO_NAME)) as HTMLElement[];\n}\n\n/**\n * Parse entity format from entity wrapper element\n * @param wrapper The wrapper element to parse entity format from\n * @returns Entity format\n */\nexport function parseEntityFormat(wrapper: HTMLElement): ContentModelEntityFormat {\n let isEntity = false;\n const format: ContentModelEntityFormat = {};\n\n wrapper.classList.forEach(name => {\n isEntity = parseEntityClassName(name, format) || isEntity;\n });\n\n if (!isEntity) {\n format.isFakeEntity = true;\n format.isReadonly = !wrapper.isContentEditable;\n }\n\n return format;\n}\n\n/**\n * Parse entity class names from entity wrapper element\n * @param className Class names of entity\n * @param format The output entity format object\n */\nfunction parseEntityClassName(\n className: string,\n format: ContentModelEntityFormat\n): boolean | undefined {\n if (className == ENTITY_INFO_NAME) {\n return true;\n } else if (className.indexOf(ENTITY_TYPE_PREFIX) == 0) {\n format.entityType = className.substring(ENTITY_TYPE_PREFIX.length);\n } else if (className.indexOf(ENTITY_ID_PREFIX) == 0) {\n format.id = className.substring(ENTITY_ID_PREFIX.length);\n } else if (className.indexOf(ENTITY_READONLY_PREFIX) == 0) {\n format.isReadonly = className.substring(ENTITY_READONLY_PREFIX.length) == '1';\n }\n}\n\n/**\n * Generate Entity class names for an entity wrapper\n * @param format The source entity format object\n * @returns A combined CSS class name string for entity wrapper\n */\nexport function generateEntityClassNames(format: ContentModelEntityFormat): string {\n return format.isFakeEntity\n ? ''\n : `${ENTITY_INFO_NAME} ${ENTITY_TYPE_PREFIX}${format.entityType ?? ''} ${\n format.id ? `${ENTITY_ID_PREFIX}${format.id} ` : ''\n }${ENTITY_READONLY_PREFIX}${format.isReadonly ? '1' : '0'}`;\n}\n\n/**\n * Checks whether the node provided is a Entity delimiter\n * @param node the node to check\n * @return true if it is a delimiter\n */\nexport function isEntityDelimiter(element: HTMLElement): boolean {\n return (\n isElementOfType(element, 'span') &&\n (element.classList.contains(DELIMITER_AFTER) ||\n element.classList.contains(DELIMITER_BEFORE)) &&\n element.textContent === ZERO_WIDTH_SPACE\n );\n}\n\n/**\n * Adds delimiters to the element provided. If the delimiters already exists, will not be added\n * @param element the node to add the delimiters\n * @param format format to set to the delimiters, so when typing inside of one the format is not lost\n * @param context Model to Dom context to use.\n */\nexport function addDelimiters(\n doc: Document,\n element: HTMLElement,\n format?: ContentModelSegmentFormat | null,\n context?: ModelToDomContext\n): HTMLElement[] {\n let [delimiterAfter, delimiterBefore] = getDelimiters(element);\n\n if (!delimiterAfter) {\n delimiterAfter = insertDelimiter(doc, element, true /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterAfter, context.formatAppliers.segment, format, context);\n }\n }\n\n if (!delimiterBefore) {\n delimiterBefore = insertDelimiter(doc, element, false /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterBefore, context.formatAppliers.segment, format, context);\n }\n }\n\n return [delimiterAfter, delimiterBefore];\n}\n\nfunction getDelimiters(entityWrapper: HTMLElement): (HTMLElement | undefined)[] {\n const result: (HTMLElement | undefined)[] = [];\n const { nextElementSibling, previousElementSibling } = entityWrapper;\n result.push(\n isDelimiter(nextElementSibling, DELIMITER_AFTER),\n isDelimiter(previousElementSibling, DELIMITER_BEFORE)\n );\n\n return result;\n}\n\nfunction isDelimiter(el: Element | null, className: string): HTMLElement | undefined {\n return el?.classList.contains(className) && el.textContent == ZERO_WIDTH_SPACE\n ? (el as HTMLElement)\n : undefined;\n}\n\nfunction insertDelimiter(doc: Document, element: Element, isAfter: boolean) {\n const span = doc.createElement('span');\n\n span.className = isAfter ? DELIMITER_AFTER : DELIMITER_BEFORE;\n span.appendChild(doc.createTextNode(ZERO_WIDTH_SPACE));\n element.parentNode?.insertBefore(span, isAfter ? element.nextSibling : element);\n\n return span;\n}\n"]}
@@ -14,10 +14,11 @@ define(["require", "exports", "./entityUtils"], function (require, exports, enti
14
14
  function reuseCachedElement(parent, element, refNode) {
15
15
  var _a;
16
16
  if (element.parentNode == parent) {
17
+ var isEntity = (0, entityUtils_1.isEntityElement)(element);
17
18
  // Remove nodes before the one we are hitting since they don't appear in Content Model at this position.
18
19
  // But we don't want to touch entity since it would better to keep entity at its place unless it is removed
19
20
  // In that case we will remove it after we have handled all other nodes
20
- while (refNode && refNode != element && !(0, entityUtils_1.isEntityElement)(refNode)) {
21
+ while (refNode && refNode != element && (isEntity || !(0, entityUtils_1.isEntityElement)(refNode))) {
21
22
  var next = refNode.nextSibling;
22
23
  (_a = refNode.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(refNode);
23
24
  refNode = next;
@@ -1 +1 @@
1
- {"version":3,"file":"reuseCachedElement.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/reuseCachedElement.ts"],"names":[],"mappings":";;;;IAEA;;;;;;;;OAQG;IACH,SAAgB,kBAAkB,CAAC,MAAY,EAAE,OAAa,EAAE,OAAoB;;QAChF,IAAI,OAAO,CAAC,UAAU,IAAI,MAAM,EAAE;YAC9B,wGAAwG;YACxG,2GAA2G;YAC3G,uEAAuE;YACvE,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,CAAC,IAAA,6BAAe,EAAC,OAAO,CAAC,EAAE;gBAC/D,IAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC;gBAEjC,MAAA,OAAO,CAAC,UAAU,0CAAE,WAAW,CAAC,OAAO,CAAC,CAAC;gBACzC,OAAO,GAAG,IAAI,CAAC;aAClB;YAED,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,EAAE;gBAC/B,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;aACjC;iBAAM;gBACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;aACzC;SACJ;aAAM;YACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;SACzC;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;IAtBD,gDAsBC;IAED;;OAEG;IACH,SAAgB,UAAU,CAAC,IAAU;;QACjC,IAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;QAC9B,MAAA,IAAI,CAAC,UAAU,0CAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QAEnC,OAAO,IAAI,CAAC;IAChB,CAAC;IALD,gCAKC","sourcesContent":["import { isEntityElement } from './entityUtils';\n\n/**\n * When set a DOM tree into editor, reuse the existing element in editor and no need to change it\n * @param param Parent node of the reused element\n * @param element The element to keep in parent node\n * @param refNode Reference node, it is point to current node that is being processed. It must be a child of parent node, or null.\n * We will start processing from this node, if it is not the same with element, remove it and keep processing its next sibling,\n * until we see an element that is the same with the passed in element or null.\n * @returns The new reference element\n */\nexport function reuseCachedElement(parent: Node, element: Node, refNode: Node | null): Node | null {\n if (element.parentNode == parent) {\n // Remove nodes before the one we are hitting since they don't appear in Content Model at this position.\n // But we don't want to touch entity since it would better to keep entity at its place unless it is removed\n // In that case we will remove it after we have handled all other nodes\n while (refNode && refNode != element && !isEntityElement(refNode)) {\n const next = refNode.nextSibling;\n\n refNode.parentNode?.removeChild(refNode);\n refNode = next;\n }\n\n if (refNode && refNode == element) {\n refNode = refNode.nextSibling;\n } else {\n parent.insertBefore(element, refNode);\n }\n } else {\n parent.insertBefore(element, refNode);\n }\n\n return refNode;\n}\n\n/**\n * @internal\n */\nexport function removeNode(node: Node): Node | null {\n const next = node.nextSibling;\n node.parentNode?.removeChild(node);\n\n return next;\n}\n"]}
1
+ {"version":3,"file":"reuseCachedElement.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/reuseCachedElement.ts"],"names":[],"mappings":";;;;IAEA;;;;;;;;OAQG;IACH,SAAgB,kBAAkB,CAAC,MAAY,EAAE,OAAa,EAAE,OAAoB;;QAChF,IAAI,OAAO,CAAC,UAAU,IAAI,MAAM,EAAE;YAC9B,IAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,OAAO,CAAC,CAAC;YAE1C,wGAAwG;YACxG,2GAA2G;YAC3G,uEAAuE;YACvE,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAA,6BAAe,EAAC,OAAO,CAAC,CAAC,EAAE;gBAC7E,IAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC;gBAEjC,MAAA,OAAO,CAAC,UAAU,0CAAE,WAAW,CAAC,OAAO,CAAC,CAAC;gBACzC,OAAO,GAAG,IAAI,CAAC;aAClB;YAED,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,EAAE;gBAC/B,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;aACjC;iBAAM;gBACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;aACzC;SACJ;aAAM;YACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;SACzC;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;IAxBD,gDAwBC;IAED;;OAEG;IACH,SAAgB,UAAU,CAAC,IAAU;;QACjC,IAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;QAC9B,MAAA,IAAI,CAAC,UAAU,0CAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QAEnC,OAAO,IAAI,CAAC;IAChB,CAAC;IALD,gCAKC","sourcesContent":["import { isEntityElement } from './entityUtils';\n\n/**\n * When set a DOM tree into editor, reuse the existing element in editor and no need to change it\n * @param param Parent node of the reused element\n * @param element The element to keep in parent node\n * @param refNode Reference node, it is point to current node that is being processed. It must be a child of parent node, or null.\n * We will start processing from this node, if it is not the same with element, remove it and keep processing its next sibling,\n * until we see an element that is the same with the passed in element or null.\n * @returns The new reference element\n */\nexport function reuseCachedElement(parent: Node, element: Node, refNode: Node | null): Node | null {\n if (element.parentNode == parent) {\n const isEntity = isEntityElement(element);\n\n // Remove nodes before the one we are hitting since they don't appear in Content Model at this position.\n // But we don't want to touch entity since it would better to keep entity at its place unless it is removed\n // In that case we will remove it after we have handled all other nodes\n while (refNode && refNode != element && (isEntity || !isEntityElement(refNode))) {\n const next = refNode.nextSibling;\n\n refNode.parentNode?.removeChild(refNode);\n refNode = next;\n }\n\n if (refNode && refNode == element) {\n refNode = refNode.nextSibling;\n } else {\n parent.insertBefore(element, refNode);\n }\n } else {\n parent.insertBefore(element, refNode);\n }\n\n return refNode;\n}\n\n/**\n * @internal\n */\nexport function removeNode(node: Node): Node | null {\n const next = node.nextSibling;\n node.parentNode?.removeChild(node);\n\n return next;\n}\n"]}
@@ -7,14 +7,7 @@ define(["require", "exports", "../../domUtils/entityUtils"], function (require,
7
7
  */
8
8
  exports.entityFormatHandler = {
9
9
  parse: function (format, element) {
10
- var isEntity = false;
11
- element.classList.forEach(function (name) {
12
- isEntity = (0, entityUtils_1.parseEntityClassName)(name, format) || isEntity;
13
- });
14
- if (!isEntity) {
15
- format.isFakeEntity = true;
16
- format.isReadonly = !element.isContentEditable;
17
- }
10
+ Object.assign(format, (0, entityUtils_1.parseEntityFormat)(element));
18
11
  },
19
12
  apply: function (format, element) {
20
13
  if (!format.isFakeEntity) {
@@ -1 +1 @@
1
- {"version":3,"file":"entityFormatHandler.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/formatHandlers/entity/entityFormatHandler.ts"],"names":[],"mappings":";;;;IAIA;;OAEG;IACU,QAAA,mBAAmB,GAA+C;QAC3E,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;YACnB,IAAI,QAAQ,GAAG,KAAK,CAAC;YAErB,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,UAAA,IAAI;gBAC1B,QAAQ,GAAG,IAAA,kCAAoB,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,QAAQ,CAAC;YAC9D,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,EAAE;gBACX,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC;gBAC3B,MAAM,CAAC,UAAU,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC;aAClD;QACL,CAAC;QAED,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;YACnB,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;gBACtB,OAAO,CAAC,SAAS,GAAG,IAAA,sCAAwB,EAAC,MAAM,CAAC,CAAC;aACxD;YAED,IAAI,MAAM,CAAC,UAAU,EAAE;gBACnB,OAAO,CAAC,eAAe,GAAG,OAAO,CAAC;aACrC;iBAAM;gBACH,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;aAC9C;QACL,CAAC;KACJ,CAAC","sourcesContent":["import { generateEntityClassNames, parseEntityClassName } from '../../domUtils/entityUtils';\nimport type { EntityInfoFormat, IdFormat } from 'roosterjs-content-model-types';\nimport type { FormatHandler } from '../FormatHandler';\n\n/**\n * @internal\n */\nexport const entityFormatHandler: FormatHandler<EntityInfoFormat & IdFormat> = {\n parse: (format, element) => {\n let isEntity = false;\n\n element.classList.forEach(name => {\n isEntity = parseEntityClassName(name, format) || isEntity;\n });\n\n if (!isEntity) {\n format.isFakeEntity = true;\n format.isReadonly = !element.isContentEditable;\n }\n },\n\n apply: (format, element) => {\n if (!format.isFakeEntity) {\n element.className = generateEntityClassNames(format);\n }\n\n if (format.isReadonly) {\n element.contentEditable = 'false';\n } else {\n element.removeAttribute('contenteditable');\n }\n },\n};\n"]}
1
+ {"version":3,"file":"entityFormatHandler.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/formatHandlers/entity/entityFormatHandler.ts"],"names":[],"mappings":";;;;IAIA;;OAEG;IACU,QAAA,mBAAmB,GAA+C;QAC3E,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;YACnB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAA,+BAAiB,EAAC,OAAO,CAAC,CAAC,CAAC;QACtD,CAAC;QAED,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;YACnB,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;gBACtB,OAAO,CAAC,SAAS,GAAG,IAAA,sCAAwB,EAAC,MAAM,CAAC,CAAC;aACxD;YAED,IAAI,MAAM,CAAC,UAAU,EAAE;gBACnB,OAAO,CAAC,eAAe,GAAG,OAAO,CAAC;aACrC;iBAAM;gBACH,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;aAC9C;QACL,CAAC;KACJ,CAAC","sourcesContent":["import { generateEntityClassNames, parseEntityFormat } from '../../domUtils/entityUtils';\nimport type { EntityInfoFormat, IdFormat } from 'roosterjs-content-model-types';\nimport type { FormatHandler } from '../FormatHandler';\n\n/**\n * @internal\n */\nexport const entityFormatHandler: FormatHandler<EntityInfoFormat & IdFormat> = {\n parse: (format, element) => {\n Object.assign(format, parseEntityFormat(element));\n },\n\n apply: (format, element) => {\n if (!format.isFakeEntity) {\n element.className = generateEntityClassNames(format);\n }\n\n if (format.isReadonly) {\n element.contentEditable = 'false';\n } else {\n element.removeAttribute('contenteditable');\n }\n },\n};\n"]}
@@ -15,7 +15,7 @@ export { getObjectKeys } from './domUtils/getObjectKeys';
15
15
  export { default as toArray } from './domUtils/toArray';
16
16
  export { moveChildNodes, wrapAllChildNodes } from './domUtils/moveChildNodes';
17
17
  export { wrap } from './domUtils/wrap';
18
- export { isEntityElement, getAllEntityWrappers, parseEntityClassName, generateEntityClassNames, addDelimiters, isEntityDelimiter, } from './domUtils/entityUtils';
18
+ export { isEntityElement, getAllEntityWrappers, parseEntityFormat, generateEntityClassNames, addDelimiters, isEntityDelimiter, } from './domUtils/entityUtils';
19
19
  export { reuseCachedElement } from './domUtils/reuseCachedElement';
20
20
  export { isWhiteSpacePreserved } from './domUtils/isWhiteSpacePreserved';
21
21
  export { createBr } from './modelApi/creators/createBr';
package/lib-amd/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  define(["require", "exports", "./domToModel/domToContentModel", "./modelToDom/contentModelToDom", "./modelToText/contentModelToText", "./domToModel/processors/childProcessor", "./domToModel/processors/entityProcessor", "./domToModel/processors/tableProcessor", "./domToModel/utils/getRegularSelectionOffsets", "./domToModel/utils/parseFormat", "./domToModel/utils/areSameFormats", "./domToModel/utils/isBlockElement", "./domUtils/metadata/updateMetadata", "./domUtils/isNodeOfType", "./domUtils/isElementOfType", "./domUtils/getObjectKeys", "./domUtils/toArray", "./domUtils/moveChildNodes", "./domUtils/wrap", "./domUtils/entityUtils", "./domUtils/reuseCachedElement", "./domUtils/isWhiteSpacePreserved", "./modelApi/creators/createBr", "./modelApi/creators/createListItem", "./modelApi/creators/createFormatContainer", "./modelApi/creators/createParagraph", "./modelApi/creators/createSelectionMarker", "./modelApi/creators/createTable", "./modelApi/creators/createTableCell", "./modelApi/creators/createText", "./modelApi/creators/createImage", "./modelApi/creators/createContentModelDocument", "./modelApi/creators/createParagraphDecorator", "./modelApi/creators/createGeneralSegment", "./modelApi/creators/createGeneralBlock", "./modelApi/creators/createEntity", "./modelApi/creators/createDivider", "./modelApi/creators/createListLevel", "./modelApi/creators/createEmptyModel", "./modelApi/common/addBlock", "./modelApi/common/addDecorators", "./modelApi/common/addDecorators", "./modelApi/common/normalizeParagraph", "./modelApi/common/normalizeContentModel", "./modelApi/common/isGeneralSegment", "./modelApi/common/unwrapBlock", "./modelApi/common/addSegment", "./modelApi/common/isEmpty", "./modelApi/common/normalizeSegment", "./modelApi/block/setParagraphNotImplicit", "./formatHandlers/utils/parseValueWithUnit", "./formatHandlers/common/borderFormatHandler", "./formatHandlers/utils/color", "./domToModel/context/createDomToModelContext", "./modelToDom/context/createModelToDomContext"], function (require, exports, domToContentModel_1, contentModelToDom_1, contentModelToText_1, childProcessor_1, entityProcessor_1, tableProcessor_1, getRegularSelectionOffsets_1, parseFormat_1, areSameFormats_1, isBlockElement_1, updateMetadata_1, isNodeOfType_1, isElementOfType_1, getObjectKeys_1, toArray_1, moveChildNodes_1, wrap_1, entityUtils_1, reuseCachedElement_1, isWhiteSpacePreserved_1, createBr_1, createListItem_1, createFormatContainer_1, createParagraph_1, createSelectionMarker_1, createTable_1, createTableCell_1, createText_1, createImage_1, createContentModelDocument_1, createParagraphDecorator_1, createGeneralSegment_1, createGeneralBlock_1, createEntity_1, createDivider_1, createListLevel_1, createEmptyModel_1, addBlock_1, addDecorators_1, addDecorators_2, normalizeParagraph_1, normalizeContentModel_1, isGeneralSegment_1, unwrapBlock_1, addSegment_1, isEmpty_1, normalizeSegment_1, setParagraphNotImplicit_1, parseValueWithUnit_1, borderFormatHandler_1, color_1, createDomToModelContext_1, createModelToDomContext_1) {
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.createModelToDomConfig = exports.createModelToDomContextWithConfig = exports.createModelToDomContext = exports.createDomToModelConfig = exports.createDomToModelContextWithConfig = exports.createDomToModelContext = exports.parseColor = exports.setColor = exports.getColor = exports.DeprecatedColors = exports.BorderKeys = exports.parseValueWithUnit = exports.setParagraphNotImplicit = exports.normalizeSingleSegment = exports.isEmpty = exports.addSegment = exports.unwrapBlock = exports.isGeneralSegment = exports.normalizeContentModel = exports.normalizeParagraph = exports.addLink = exports.addCode = exports.addBlock = exports.createEmptyModel = exports.createListLevel = exports.createDivider = exports.createEntity = exports.createGeneralBlock = exports.createGeneralSegment = exports.createParagraphDecorator = exports.createContentModelDocument = exports.createImage = exports.createText = exports.createTableCell = exports.createTable = exports.createSelectionMarker = exports.createParagraph = exports.createFormatContainer = exports.createListItem = exports.createBr = exports.isWhiteSpacePreserved = exports.reuseCachedElement = exports.isEntityDelimiter = exports.addDelimiters = exports.generateEntityClassNames = exports.parseEntityClassName = exports.getAllEntityWrappers = exports.isEntityElement = exports.wrap = exports.wrapAllChildNodes = exports.moveChildNodes = exports.toArray = exports.getObjectKeys = exports.isElementOfType = exports.isNodeOfType = exports.hasMetadata = exports.updateMetadata = exports.isBlockElement = exports.areSameFormats = exports.parseFormat = exports.getRegularSelectionOffsets = exports.tableProcessor = exports.entityProcessor = exports.processChildNode = exports.handleRegularSelection = exports.childProcessor = exports.contentModelToText = exports.contentModelToDom = exports.domToContentModel = void 0;
4
+ exports.createModelToDomConfig = exports.createModelToDomContextWithConfig = exports.createModelToDomContext = exports.createDomToModelConfig = exports.createDomToModelContextWithConfig = exports.createDomToModelContext = exports.parseColor = exports.setColor = exports.getColor = exports.DeprecatedColors = exports.BorderKeys = exports.parseValueWithUnit = exports.setParagraphNotImplicit = exports.normalizeSingleSegment = exports.isEmpty = exports.addSegment = exports.unwrapBlock = exports.isGeneralSegment = exports.normalizeContentModel = exports.normalizeParagraph = exports.addLink = exports.addCode = exports.addBlock = exports.createEmptyModel = exports.createListLevel = exports.createDivider = exports.createEntity = exports.createGeneralBlock = exports.createGeneralSegment = exports.createParagraphDecorator = exports.createContentModelDocument = exports.createImage = exports.createText = exports.createTableCell = exports.createTable = exports.createSelectionMarker = exports.createParagraph = exports.createFormatContainer = exports.createListItem = exports.createBr = exports.isWhiteSpacePreserved = exports.reuseCachedElement = exports.isEntityDelimiter = exports.addDelimiters = exports.generateEntityClassNames = exports.parseEntityFormat = exports.getAllEntityWrappers = exports.isEntityElement = exports.wrap = exports.wrapAllChildNodes = exports.moveChildNodes = exports.toArray = exports.getObjectKeys = exports.isElementOfType = exports.isNodeOfType = exports.hasMetadata = exports.updateMetadata = exports.isBlockElement = exports.areSameFormats = exports.parseFormat = exports.getRegularSelectionOffsets = exports.tableProcessor = exports.entityProcessor = exports.processChildNode = exports.handleRegularSelection = exports.childProcessor = exports.contentModelToText = exports.contentModelToDom = exports.domToContentModel = void 0;
5
5
  Object.defineProperty(exports, "domToContentModel", { enumerable: true, get: function () { return domToContentModel_1.domToContentModel; } });
6
6
  Object.defineProperty(exports, "contentModelToDom", { enumerable: true, get: function () { return contentModelToDom_1.contentModelToDom; } });
7
7
  Object.defineProperty(exports, "contentModelToText", { enumerable: true, get: function () { return contentModelToText_1.contentModelToText; } });
@@ -25,7 +25,7 @@ define(["require", "exports", "./domToModel/domToContentModel", "./modelToDom/co
25
25
  Object.defineProperty(exports, "wrap", { enumerable: true, get: function () { return wrap_1.wrap; } });
26
26
  Object.defineProperty(exports, "isEntityElement", { enumerable: true, get: function () { return entityUtils_1.isEntityElement; } });
27
27
  Object.defineProperty(exports, "getAllEntityWrappers", { enumerable: true, get: function () { return entityUtils_1.getAllEntityWrappers; } });
28
- Object.defineProperty(exports, "parseEntityClassName", { enumerable: true, get: function () { return entityUtils_1.parseEntityClassName; } });
28
+ Object.defineProperty(exports, "parseEntityFormat", { enumerable: true, get: function () { return entityUtils_1.parseEntityFormat; } });
29
29
  Object.defineProperty(exports, "generateEntityClassNames", { enumerable: true, get: function () { return entityUtils_1.generateEntityClassNames; } });
30
30
  Object.defineProperty(exports, "addDelimiters", { enumerable: true, get: function () { return entityUtils_1.addDelimiters; } });
31
31
  Object.defineProperty(exports, "isEntityDelimiter", { enumerable: true, get: function () { return entityUtils_1.isEntityDelimiter; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages-content-model/roosterjs-content-model-dom/lib/index.ts"],"names":[],"mappings":";;;;IAAS,sHAAA,iBAAiB,OAAA;IACjB,sHAAA,iBAAiB,OAAA;IACjB,wHAAA,kBAAkB,OAAA;IAGvB,gHAAA,cAAc,OAAA;IACd,wHAAA,sBAAsB,OAAA;IACtB,kHAAA,gBAAgB,OAAA;IAEX,kHAAA,eAAe,OAAA;IACf,gHAAA,cAAc,OAAA;IACd,wIAAA,0BAA0B,OAAA;IAC1B,0GAAA,WAAW,OAAA;IACX,gHAAA,cAAc,OAAA;IACd,gHAAA,cAAc,OAAA;IAEd,gHAAA,cAAc,OAAA;IAAE,6GAAA,WAAW,OAAA;IAC3B,4GAAA,YAAY,OAAA;IACZ,kHAAA,eAAe,OAAA;IACf,8GAAA,aAAa,OAAA;IACb,kGAAA,OAAO,OAAW;IAClB,gHAAA,cAAc,OAAA;IAAE,mHAAA,iBAAiB,OAAA;IACjC,4FAAA,IAAI,OAAA;IAET,8GAAA,eAAe,OAAA;IACf,mHAAA,oBAAoB,OAAA;IACpB,mHAAA,oBAAoB,OAAA;IACpB,uHAAA,wBAAwB,OAAA;IACxB,4GAAA,aAAa,OAAA;IACb,gHAAA,iBAAiB,OAAA;IAEZ,wHAAA,kBAAkB,OAAA;IAClB,8HAAA,qBAAqB,OAAA;IAErB,oGAAA,QAAQ,OAAA;IACR,gHAAA,cAAc,OAAA;IACd,8HAAA,qBAAqB,OAAA;IACrB,kHAAA,eAAe,OAAA;IACf,8HAAA,qBAAqB,OAAA;IACrB,0GAAA,WAAW,OAAA;IACX,kHAAA,eAAe,OAAA;IACf,wGAAA,UAAU,OAAA;IACV,0GAAA,WAAW,OAAA;IACX,wIAAA,0BAA0B,OAAA;IAC1B,oIAAA,wBAAwB,OAAA;IACxB,4HAAA,oBAAoB,OAAA;IACpB,wHAAA,kBAAkB,OAAA;IAClB,4GAAA,YAAY,OAAA;IACZ,8GAAA,aAAa,OAAA;IACb,kHAAA,eAAe,OAAA;IACf,oHAAA,gBAAgB,OAAA;IAEhB,oGAAA,QAAQ,OAAA;IACR,wGAAA,OAAO,OAAA;IACP,wGAAA,OAAO,OAAA;IACP,wHAAA,kBAAkB,OAAA;IAElB,8HAAA,qBAAqB,OAAA;IACrB,oHAAA,gBAAgB,OAAA;IAChB,0GAAA,WAAW,OAAA;IACX,wGAAA,UAAU,OAAA;IACV,kGAAA,OAAO,OAAA;IACP,0HAAA,sBAAsB,OAAA;IAEtB,kIAAA,uBAAuB,OAAA;IAEvB,wHAAA,kBAAkB,OAAA;IAClB,iHAAA,UAAU,OAAA;IACV,yGAAA,gBAAgB,OAAA;IAAE,iGAAA,QAAQ,OAAA;IAAE,iGAAA,QAAQ,OAAA;IAAE,mGAAA,UAAU,OAAA;IAGrD,kIAAA,uBAAuB,OAAA;IACvB,4IAAA,iCAAiC,OAAA;IACjC,iIAAA,sBAAsB,OAAA;IAGtB,kIAAA,uBAAuB,OAAA;IACvB,4IAAA,iCAAiC,OAAA;IACjC,iIAAA,sBAAsB,OAAA","sourcesContent":["export { domToContentModel } from './domToModel/domToContentModel';\nexport { contentModelToDom } from './modelToDom/contentModelToDom';\nexport { contentModelToText } from './modelToText/contentModelToText';\n\nexport {\n childProcessor,\n handleRegularSelection,\n processChildNode,\n} from './domToModel/processors/childProcessor';\nexport { entityProcessor } from './domToModel/processors/entityProcessor';\nexport { tableProcessor } from './domToModel/processors/tableProcessor';\nexport { getRegularSelectionOffsets } from './domToModel/utils/getRegularSelectionOffsets';\nexport { parseFormat } from './domToModel/utils/parseFormat';\nexport { areSameFormats } from './domToModel/utils/areSameFormats';\nexport { isBlockElement } from './domToModel/utils/isBlockElement';\n\nexport { updateMetadata, hasMetadata } from './domUtils/metadata/updateMetadata';\nexport { isNodeOfType, NodeTypeMap } from './domUtils/isNodeOfType';\nexport { isElementOfType } from './domUtils/isElementOfType';\nexport { getObjectKeys } from './domUtils/getObjectKeys';\nexport { default as toArray } from './domUtils/toArray';\nexport { moveChildNodes, wrapAllChildNodes } from './domUtils/moveChildNodes';\nexport { wrap } from './domUtils/wrap';\nexport {\n isEntityElement,\n getAllEntityWrappers,\n parseEntityClassName,\n generateEntityClassNames,\n addDelimiters,\n isEntityDelimiter,\n} from './domUtils/entityUtils';\nexport { reuseCachedElement } from './domUtils/reuseCachedElement';\nexport { isWhiteSpacePreserved } from './domUtils/isWhiteSpacePreserved';\n\nexport { createBr } from './modelApi/creators/createBr';\nexport { createListItem } from './modelApi/creators/createListItem';\nexport { createFormatContainer } from './modelApi/creators/createFormatContainer';\nexport { createParagraph } from './modelApi/creators/createParagraph';\nexport { createSelectionMarker } from './modelApi/creators/createSelectionMarker';\nexport { createTable } from './modelApi/creators/createTable';\nexport { createTableCell } from './modelApi/creators/createTableCell';\nexport { createText } from './modelApi/creators/createText';\nexport { createImage } from './modelApi/creators/createImage';\nexport { createContentModelDocument } from './modelApi/creators/createContentModelDocument';\nexport { createParagraphDecorator } from './modelApi/creators/createParagraphDecorator';\nexport { createGeneralSegment } from './modelApi/creators/createGeneralSegment';\nexport { createGeneralBlock } from './modelApi/creators/createGeneralBlock';\nexport { createEntity } from './modelApi/creators/createEntity';\nexport { createDivider } from './modelApi/creators/createDivider';\nexport { createListLevel } from './modelApi/creators/createListLevel';\nexport { createEmptyModel } from './modelApi/creators/createEmptyModel';\n\nexport { addBlock } from './modelApi/common/addBlock';\nexport { addCode } from './modelApi/common/addDecorators';\nexport { addLink } from './modelApi/common/addDecorators';\nexport { normalizeParagraph } from './modelApi/common/normalizeParagraph';\n\nexport { normalizeContentModel } from './modelApi/common/normalizeContentModel';\nexport { isGeneralSegment } from './modelApi/common/isGeneralSegment';\nexport { unwrapBlock } from './modelApi/common/unwrapBlock';\nexport { addSegment } from './modelApi/common/addSegment';\nexport { isEmpty } from './modelApi/common/isEmpty';\nexport { normalizeSingleSegment } from './modelApi/common/normalizeSegment';\n\nexport { setParagraphNotImplicit } from './modelApi/block/setParagraphNotImplicit';\n\nexport { parseValueWithUnit } from './formatHandlers/utils/parseValueWithUnit';\nexport { BorderKeys } from './formatHandlers/common/borderFormatHandler';\nexport { DeprecatedColors, getColor, setColor, parseColor } from './formatHandlers/utils/color';\n\nexport {\n createDomToModelContext,\n createDomToModelContextWithConfig,\n createDomToModelConfig,\n} from './domToModel/context/createDomToModelContext';\nexport {\n createModelToDomContext,\n createModelToDomContextWithConfig,\n createModelToDomConfig,\n} from './modelToDom/context/createModelToDomContext';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages-content-model/roosterjs-content-model-dom/lib/index.ts"],"names":[],"mappings":";;;;IAAS,sHAAA,iBAAiB,OAAA;IACjB,sHAAA,iBAAiB,OAAA;IACjB,wHAAA,kBAAkB,OAAA;IAGvB,gHAAA,cAAc,OAAA;IACd,wHAAA,sBAAsB,OAAA;IACtB,kHAAA,gBAAgB,OAAA;IAEX,kHAAA,eAAe,OAAA;IACf,gHAAA,cAAc,OAAA;IACd,wIAAA,0BAA0B,OAAA;IAC1B,0GAAA,WAAW,OAAA;IACX,gHAAA,cAAc,OAAA;IACd,gHAAA,cAAc,OAAA;IAEd,gHAAA,cAAc,OAAA;IAAE,6GAAA,WAAW,OAAA;IAC3B,4GAAA,YAAY,OAAA;IACZ,kHAAA,eAAe,OAAA;IACf,8GAAA,aAAa,OAAA;IACb,kGAAA,OAAO,OAAW;IAClB,gHAAA,cAAc,OAAA;IAAE,mHAAA,iBAAiB,OAAA;IACjC,4FAAA,IAAI,OAAA;IAET,8GAAA,eAAe,OAAA;IACf,mHAAA,oBAAoB,OAAA;IACpB,gHAAA,iBAAiB,OAAA;IACjB,uHAAA,wBAAwB,OAAA;IACxB,4GAAA,aAAa,OAAA;IACb,gHAAA,iBAAiB,OAAA;IAEZ,wHAAA,kBAAkB,OAAA;IAClB,8HAAA,qBAAqB,OAAA;IAErB,oGAAA,QAAQ,OAAA;IACR,gHAAA,cAAc,OAAA;IACd,8HAAA,qBAAqB,OAAA;IACrB,kHAAA,eAAe,OAAA;IACf,8HAAA,qBAAqB,OAAA;IACrB,0GAAA,WAAW,OAAA;IACX,kHAAA,eAAe,OAAA;IACf,wGAAA,UAAU,OAAA;IACV,0GAAA,WAAW,OAAA;IACX,wIAAA,0BAA0B,OAAA;IAC1B,oIAAA,wBAAwB,OAAA;IACxB,4HAAA,oBAAoB,OAAA;IACpB,wHAAA,kBAAkB,OAAA;IAClB,4GAAA,YAAY,OAAA;IACZ,8GAAA,aAAa,OAAA;IACb,kHAAA,eAAe,OAAA;IACf,oHAAA,gBAAgB,OAAA;IAEhB,oGAAA,QAAQ,OAAA;IACR,wGAAA,OAAO,OAAA;IACP,wGAAA,OAAO,OAAA;IACP,wHAAA,kBAAkB,OAAA;IAElB,8HAAA,qBAAqB,OAAA;IACrB,oHAAA,gBAAgB,OAAA;IAChB,0GAAA,WAAW,OAAA;IACX,wGAAA,UAAU,OAAA;IACV,kGAAA,OAAO,OAAA;IACP,0HAAA,sBAAsB,OAAA;IAEtB,kIAAA,uBAAuB,OAAA;IAEvB,wHAAA,kBAAkB,OAAA;IAClB,iHAAA,UAAU,OAAA;IACV,yGAAA,gBAAgB,OAAA;IAAE,iGAAA,QAAQ,OAAA;IAAE,iGAAA,QAAQ,OAAA;IAAE,mGAAA,UAAU,OAAA;IAGrD,kIAAA,uBAAuB,OAAA;IACvB,4IAAA,iCAAiC,OAAA;IACjC,iIAAA,sBAAsB,OAAA;IAGtB,kIAAA,uBAAuB,OAAA;IACvB,4IAAA,iCAAiC,OAAA;IACjC,iIAAA,sBAAsB,OAAA","sourcesContent":["export { domToContentModel } from './domToModel/domToContentModel';\nexport { contentModelToDom } from './modelToDom/contentModelToDom';\nexport { contentModelToText } from './modelToText/contentModelToText';\n\nexport {\n childProcessor,\n handleRegularSelection,\n processChildNode,\n} from './domToModel/processors/childProcessor';\nexport { entityProcessor } from './domToModel/processors/entityProcessor';\nexport { tableProcessor } from './domToModel/processors/tableProcessor';\nexport { getRegularSelectionOffsets } from './domToModel/utils/getRegularSelectionOffsets';\nexport { parseFormat } from './domToModel/utils/parseFormat';\nexport { areSameFormats } from './domToModel/utils/areSameFormats';\nexport { isBlockElement } from './domToModel/utils/isBlockElement';\n\nexport { updateMetadata, hasMetadata } from './domUtils/metadata/updateMetadata';\nexport { isNodeOfType, NodeTypeMap } from './domUtils/isNodeOfType';\nexport { isElementOfType } from './domUtils/isElementOfType';\nexport { getObjectKeys } from './domUtils/getObjectKeys';\nexport { default as toArray } from './domUtils/toArray';\nexport { moveChildNodes, wrapAllChildNodes } from './domUtils/moveChildNodes';\nexport { wrap } from './domUtils/wrap';\nexport {\n isEntityElement,\n getAllEntityWrappers,\n parseEntityFormat,\n generateEntityClassNames,\n addDelimiters,\n isEntityDelimiter,\n} from './domUtils/entityUtils';\nexport { reuseCachedElement } from './domUtils/reuseCachedElement';\nexport { isWhiteSpacePreserved } from './domUtils/isWhiteSpacePreserved';\n\nexport { createBr } from './modelApi/creators/createBr';\nexport { createListItem } from './modelApi/creators/createListItem';\nexport { createFormatContainer } from './modelApi/creators/createFormatContainer';\nexport { createParagraph } from './modelApi/creators/createParagraph';\nexport { createSelectionMarker } from './modelApi/creators/createSelectionMarker';\nexport { createTable } from './modelApi/creators/createTable';\nexport { createTableCell } from './modelApi/creators/createTableCell';\nexport { createText } from './modelApi/creators/createText';\nexport { createImage } from './modelApi/creators/createImage';\nexport { createContentModelDocument } from './modelApi/creators/createContentModelDocument';\nexport { createParagraphDecorator } from './modelApi/creators/createParagraphDecorator';\nexport { createGeneralSegment } from './modelApi/creators/createGeneralSegment';\nexport { createGeneralBlock } from './modelApi/creators/createGeneralBlock';\nexport { createEntity } from './modelApi/creators/createEntity';\nexport { createDivider } from './modelApi/creators/createDivider';\nexport { createListLevel } from './modelApi/creators/createListLevel';\nexport { createEmptyModel } from './modelApi/creators/createEmptyModel';\n\nexport { addBlock } from './modelApi/common/addBlock';\nexport { addCode } from './modelApi/common/addDecorators';\nexport { addLink } from './modelApi/common/addDecorators';\nexport { normalizeParagraph } from './modelApi/common/normalizeParagraph';\n\nexport { normalizeContentModel } from './modelApi/common/normalizeContentModel';\nexport { isGeneralSegment } from './modelApi/common/isGeneralSegment';\nexport { unwrapBlock } from './modelApi/common/unwrapBlock';\nexport { addSegment } from './modelApi/common/addSegment';\nexport { isEmpty } from './modelApi/common/isEmpty';\nexport { normalizeSingleSegment } from './modelApi/common/normalizeSegment';\n\nexport { setParagraphNotImplicit } from './modelApi/block/setParagraphNotImplicit';\n\nexport { parseValueWithUnit } from './formatHandlers/utils/parseValueWithUnit';\nexport { BorderKeys } from './formatHandlers/common/borderFormatHandler';\nexport { DeprecatedColors, getColor, setColor, parseColor } from './formatHandlers/utils/color';\n\nexport {\n createDomToModelContext,\n createDomToModelContextWithConfig,\n createDomToModelConfig,\n} from './domToModel/context/createDomToModelContext';\nexport {\n createModelToDomContext,\n createModelToDomContextWithConfig,\n createModelToDomConfig,\n} from './modelToDom/context/createModelToDomContext';\n"]}
@@ -30,6 +30,7 @@ define(["require", "exports", "../../domToModel/utils/areSameFormats", "../creat
30
30
  }
31
31
  removeEmptyLinks(paragraph);
32
32
  removeEmptySegments(paragraph);
33
+ moveUpSegmentFormat(paragraph);
33
34
  }
34
35
  exports.normalizeParagraph = normalizeParagraph;
35
36
  function removeEmptySegments(block) {
@@ -59,5 +60,32 @@ define(["require", "exports", "../../domToModel/utils/areSameFormats", "../creat
59
60
  }
60
61
  }
61
62
  }
63
+ var formatsToMoveUp = ['fontFamily', 'fontSize', 'textColor'];
64
+ // When all segments are sharing the same segment format (font name, size and color), we can move its format to paragraph
65
+ function moveUpSegmentFormat(paragraph) {
66
+ if (!paragraph.decorator) {
67
+ var segments_1 = paragraph.segments.filter(function (x) { return x.segmentType != 'SelectionMarker'; });
68
+ var target_1 = paragraph.segmentFormat || {};
69
+ var changed_1 = false;
70
+ formatsToMoveUp.forEach(function (key) {
71
+ changed_1 = internalMoveUpSegmentFormat(segments_1, target_1, key) || changed_1;
72
+ });
73
+ if (changed_1) {
74
+ paragraph.segmentFormat = target_1;
75
+ }
76
+ }
77
+ }
78
+ function internalMoveUpSegmentFormat(segments, target, formatKey) {
79
+ var _a;
80
+ var firstFormat = (_a = segments[0]) === null || _a === void 0 ? void 0 : _a.format;
81
+ if ((firstFormat === null || firstFormat === void 0 ? void 0 : firstFormat[formatKey]) &&
82
+ segments.every(function (segment) { return segment.format[formatKey] == firstFormat[formatKey]; })) {
83
+ target[formatKey] = firstFormat[formatKey];
84
+ return true;
85
+ }
86
+ else {
87
+ return false;
88
+ }
89
+ }
62
90
  });
63
91
  //# sourceMappingURL=normalizeParagraph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalizeParagraph.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/modelApi/common/normalizeParagraph.ts"],"names":[],"mappings":"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","sourcesContent":["import { areSameFormats } from '../../domToModel/utils/areSameFormats';\nimport { createBr } from '../creators/createBr';\nimport { isSegmentEmpty } from './isEmpty';\nimport { isWhiteSpacePreserved } from '../../domUtils/isWhiteSpacePreserved';\nimport { normalizeAllSegments } from './normalizeSegment';\nimport type { ContentModelParagraph } from 'roosterjs-content-model-types';\n\n/**\n * @param paragraph The paragraph to normalize\n * Normalize a paragraph. If it is empty, add a BR segment to make sure it can insert content\n */\nexport function normalizeParagraph(paragraph: ContentModelParagraph) {\n const segments = paragraph.segments;\n\n if (!paragraph.isImplicit && segments.length > 0) {\n const last = segments[segments.length - 1];\n const secondLast = segments[segments.length - 2];\n\n if (\n last.segmentType == 'SelectionMarker' &&\n (!secondLast || secondLast.segmentType == 'Br')\n ) {\n segments.push(createBr(last.format));\n } else if (segments.length > 1 && segments[segments.length - 1].segmentType == 'Br') {\n const noMarkerSegments = segments.filter(x => x.segmentType != 'SelectionMarker');\n\n // When there is content with a <BR> tag at the end, we can remove the BR.\n // But if there are more than one <BR> at the end, do not remove them.\n if (\n noMarkerSegments.length > 1 &&\n noMarkerSegments[noMarkerSegments.length - 2].segmentType != 'Br'\n ) {\n segments.pop();\n }\n }\n }\n\n if (!isWhiteSpacePreserved(paragraph.format.whiteSpace)) {\n normalizeAllSegments(paragraph);\n }\n\n removeEmptyLinks(paragraph);\n\n removeEmptySegments(paragraph);\n}\n\nfunction removeEmptySegments(block: ContentModelParagraph) {\n for (let j = block.segments.length - 1; j >= 0; j--) {\n if (isSegmentEmpty(block.segments[j])) {\n block.segments.splice(j, 1);\n }\n }\n}\n\nfunction removeEmptyLinks(paragraph: ContentModelParagraph) {\n const marker = paragraph.segments.find(x => x.segmentType == 'SelectionMarker');\n if (marker) {\n const markerIndex = paragraph.segments.indexOf(marker);\n const prev = paragraph.segments[markerIndex - 1];\n const next = paragraph.segments[markerIndex + 1];\n if (\n (prev &&\n !prev.link &&\n areSameFormats(prev.format, marker.format) &&\n (!next || (!next.link && areSameFormats(next.format, marker.format))) &&\n marker.link) ||\n (!prev &&\n marker.link &&\n next &&\n !next.link &&\n areSameFormats(next.format, marker.format))\n ) {\n delete marker.link;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"normalizeParagraph.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/modelApi/common/normalizeParagraph.ts"],"names":[],"mappings":"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","sourcesContent":["import { areSameFormats } from '../../domToModel/utils/areSameFormats';\nimport { createBr } from '../creators/createBr';\nimport { isSegmentEmpty } from './isEmpty';\nimport { isWhiteSpacePreserved } from '../../domUtils/isWhiteSpacePreserved';\nimport { normalizeAllSegments } from './normalizeSegment';\nimport type {\n ContentModelParagraph,\n ContentModelSegment,\n ContentModelSegmentFormat,\n} from 'roosterjs-content-model-types';\n\n/**\n * @param paragraph The paragraph to normalize\n * Normalize a paragraph. If it is empty, add a BR segment to make sure it can insert content\n */\nexport function normalizeParagraph(paragraph: ContentModelParagraph) {\n const segments = paragraph.segments;\n\n if (!paragraph.isImplicit && segments.length > 0) {\n const last = segments[segments.length - 1];\n const secondLast = segments[segments.length - 2];\n\n if (\n last.segmentType == 'SelectionMarker' &&\n (!secondLast || secondLast.segmentType == 'Br')\n ) {\n segments.push(createBr(last.format));\n } else if (segments.length > 1 && segments[segments.length - 1].segmentType == 'Br') {\n const noMarkerSegments = segments.filter(x => x.segmentType != 'SelectionMarker');\n\n // When there is content with a <BR> tag at the end, we can remove the BR.\n // But if there are more than one <BR> at the end, do not remove them.\n if (\n noMarkerSegments.length > 1 &&\n noMarkerSegments[noMarkerSegments.length - 2].segmentType != 'Br'\n ) {\n segments.pop();\n }\n }\n }\n\n if (!isWhiteSpacePreserved(paragraph.format.whiteSpace)) {\n normalizeAllSegments(paragraph);\n }\n\n removeEmptyLinks(paragraph);\n\n removeEmptySegments(paragraph);\n\n moveUpSegmentFormat(paragraph);\n}\n\nfunction removeEmptySegments(block: ContentModelParagraph) {\n for (let j = block.segments.length - 1; j >= 0; j--) {\n if (isSegmentEmpty(block.segments[j])) {\n block.segments.splice(j, 1);\n }\n }\n}\n\nfunction removeEmptyLinks(paragraph: ContentModelParagraph) {\n const marker = paragraph.segments.find(x => x.segmentType == 'SelectionMarker');\n if (marker) {\n const markerIndex = paragraph.segments.indexOf(marker);\n const prev = paragraph.segments[markerIndex - 1];\n const next = paragraph.segments[markerIndex + 1];\n if (\n (prev &&\n !prev.link &&\n areSameFormats(prev.format, marker.format) &&\n (!next || (!next.link && areSameFormats(next.format, marker.format))) &&\n marker.link) ||\n (!prev &&\n marker.link &&\n next &&\n !next.link &&\n areSameFormats(next.format, marker.format))\n ) {\n delete marker.link;\n }\n }\n}\n\ntype FormatsToMoveUp = 'fontFamily' | 'fontSize' | 'textColor';\nconst formatsToMoveUp: FormatsToMoveUp[] = ['fontFamily', 'fontSize', 'textColor'];\n\n// When all segments are sharing the same segment format (font name, size and color), we can move its format to paragraph\nfunction moveUpSegmentFormat(paragraph: ContentModelParagraph) {\n if (!paragraph.decorator) {\n const segments = paragraph.segments.filter(x => x.segmentType != 'SelectionMarker');\n const target = paragraph.segmentFormat || {};\n let changed = false;\n\n formatsToMoveUp.forEach(key => {\n changed = internalMoveUpSegmentFormat(segments, target, key) || changed;\n });\n\n if (changed) {\n paragraph.segmentFormat = target;\n }\n }\n}\n\nfunction internalMoveUpSegmentFormat(\n segments: ContentModelSegment[],\n target: ContentModelSegmentFormat,\n formatKey: FormatsToMoveUp\n): boolean {\n const firstFormat = segments[0]?.format;\n\n if (\n firstFormat?.[formatKey] &&\n segments.every(segment => segment.format[formatKey] == firstFormat[formatKey])\n ) {\n target[formatKey] = firstFormat[formatKey];\n return true;\n } else {\n return false;\n }\n}\n"]}
@@ -6,12 +6,26 @@ import { createSelectionMarker } from '../../modelApi/creators/createSelectionMa
6
6
  * @internal
7
7
  */
8
8
  export function addSelectionMarker(group, context, container, offset) {
9
+ var lastPara = group.blocks[group.blocks.length - 1];
10
+ var formatFromParagraph = !lastPara || lastPara.blockType != 'Paragraph'
11
+ ? {}
12
+ : lastPara.decorator
13
+ ? {
14
+ fontFamily: lastPara.decorator.format.fontFamily,
15
+ fontSize: lastPara.decorator.format.fontSize,
16
+ }
17
+ : lastPara.segmentFormat
18
+ ? {
19
+ fontFamily: lastPara.segmentFormat.fontFamily,
20
+ fontSize: lastPara.segmentFormat.fontSize,
21
+ }
22
+ : {};
9
23
  var pendingFormat = context.pendingFormat &&
10
24
  context.pendingFormat.posContainer === container &&
11
25
  context.pendingFormat.posOffset === offset
12
26
  ? context.pendingFormat.format
13
27
  : undefined;
14
- var segmentFormat = __assign(__assign(__assign({}, context.defaultFormat), context.segmentFormat), pendingFormat);
28
+ var segmentFormat = __assign(__assign(__assign(__assign({}, context.defaultFormat), formatFromParagraph), context.segmentFormat), pendingFormat);
15
29
  var marker = createSelectionMarker(segmentFormat);
16
30
  addDecorators(marker, context);
17
31
  addSegment(group, marker, context.blockFormat, segmentFormat);
@@ -1 +1 @@
1
- {"version":3,"file":"addSelectionMarker.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+CAA+C,CAAC;AAGtF;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAC9B,KAA6B,EAC7B,OAA0B,EAC1B,SAAgB,EAChB,MAAe;IAEf,IAAM,aAAa,GACf,OAAO,CAAC,aAAa;QACrB,OAAO,CAAC,aAAa,CAAC,YAAY,KAAK,SAAS;QAChD,OAAO,CAAC,aAAa,CAAC,SAAS,KAAK,MAAM;QACtC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM;QAC9B,CAAC,CAAC,SAAS,CAAC;IACpB,IAAM,aAAa,kCACZ,OAAO,CAAC,aAAa,GACrB,OAAO,CAAC,aAAa,GACrB,aAAa,CACnB,CAAC;IACF,IAAM,MAAM,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;IAEpD,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/B,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import { addDecorators } from '../../modelApi/common/addDecorators';\nimport { addSegment } from '../../modelApi/common/addSegment';\nimport { createSelectionMarker } from '../../modelApi/creators/createSelectionMarker';\nimport type { ContentModelBlockGroup, DomToModelContext } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function addSelectionMarker(\n group: ContentModelBlockGroup,\n context: DomToModelContext,\n container?: Node,\n offset?: number\n) {\n const pendingFormat =\n context.pendingFormat &&\n context.pendingFormat.posContainer === container &&\n context.pendingFormat.posOffset === offset\n ? context.pendingFormat.format\n : undefined;\n const segmentFormat = {\n ...context.defaultFormat,\n ...context.segmentFormat,\n ...pendingFormat,\n };\n const marker = createSelectionMarker(segmentFormat);\n\n addDecorators(marker, context);\n\n addSegment(group, marker, context.blockFormat, segmentFormat);\n}\n"]}
1
+ {"version":3,"file":"addSelectionMarker.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/domToModel/utils/addSelectionMarker.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+CAA+C,CAAC;AAOtF;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAC9B,KAA6B,EAC7B,OAA0B,EAC1B,SAAgB,EAChB,MAAe;IAEf,IAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvD,IAAM,mBAAmB,GACrB,CAAC,QAAQ,IAAI,QAAQ,CAAC,SAAS,IAAI,WAAW;QAC1C,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,QAAQ,CAAC,SAAS;YACpB,CAAC,CAAC;gBACI,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU;gBAChD,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ;aAC/C;YACH,CAAC,CAAC,QAAQ,CAAC,aAAa;gBACxB,CAAC,CAAC;oBACI,UAAU,EAAE,QAAQ,CAAC,aAAa,CAAC,UAAU;oBAC7C,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,QAAQ;iBAC5C;gBACH,CAAC,CAAC,EAAE,CAAC;IAEb,IAAM,aAAa,GACf,OAAO,CAAC,aAAa;QACrB,OAAO,CAAC,aAAa,CAAC,YAAY,KAAK,SAAS;QAChD,OAAO,CAAC,aAAa,CAAC,SAAS,KAAK,MAAM;QACtC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM;QAC9B,CAAC,CAAC,SAAS,CAAC;IACpB,IAAM,aAAa,2CACZ,OAAO,CAAC,aAAa,GACrB,mBAAmB,GACnB,OAAO,CAAC,aAAa,GACrB,aAAa,CACnB,CAAC;IACF,IAAM,MAAM,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;IAEpD,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/B,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import { addDecorators } from '../../modelApi/common/addDecorators';\nimport { addSegment } from '../../modelApi/common/addSegment';\nimport { createSelectionMarker } from '../../modelApi/creators/createSelectionMarker';\nimport type {\n ContentModelBlockGroup,\n ContentModelSegmentFormat,\n DomToModelContext,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function addSelectionMarker(\n group: ContentModelBlockGroup,\n context: DomToModelContext,\n container?: Node,\n offset?: number\n) {\n const lastPara = group.blocks[group.blocks.length - 1];\n const formatFromParagraph: ContentModelSegmentFormat =\n !lastPara || lastPara.blockType != 'Paragraph'\n ? {}\n : lastPara.decorator\n ? {\n fontFamily: lastPara.decorator.format.fontFamily,\n fontSize: lastPara.decorator.format.fontSize,\n }\n : lastPara.segmentFormat\n ? {\n fontFamily: lastPara.segmentFormat.fontFamily,\n fontSize: lastPara.segmentFormat.fontSize,\n }\n : {};\n\n const pendingFormat =\n context.pendingFormat &&\n context.pendingFormat.posContainer === container &&\n context.pendingFormat.posOffset === offset\n ? context.pendingFormat.format\n : undefined;\n const segmentFormat = {\n ...context.defaultFormat,\n ...formatFromParagraph,\n ...context.segmentFormat,\n ...pendingFormat,\n };\n const marker = createSelectionMarker(segmentFormat);\n\n addDecorators(marker, context);\n\n addSegment(group, marker, context.blockFormat, segmentFormat);\n}\n"]}
@@ -10,11 +10,11 @@ export declare function isEntityElement(node: Node): boolean;
10
10
  */
11
11
  export declare function getAllEntityWrappers(root: HTMLElement): HTMLElement[];
12
12
  /**
13
- * Parse entity class names from entity wrapper element
14
- * @param className Class names of entity
15
- * @param format The output entity format object
13
+ * Parse entity format from entity wrapper element
14
+ * @param wrapper The wrapper element to parse entity format from
15
+ * @returns Entity format
16
16
  */
17
- export declare function parseEntityClassName(className: string, format: ContentModelEntityFormat): boolean | undefined;
17
+ export declare function parseEntityFormat(wrapper: HTMLElement): ContentModelEntityFormat;
18
18
  /**
19
19
  * Generate Entity class names for an entity wrapper
20
20
  * @param format The source entity format object
@@ -24,12 +24,29 @@ export function isEntityElement(node) {
24
24
  export function getAllEntityWrappers(root) {
25
25
  return toArray(root.querySelectorAll('.' + ENTITY_INFO_NAME));
26
26
  }
27
+ /**
28
+ * Parse entity format from entity wrapper element
29
+ * @param wrapper The wrapper element to parse entity format from
30
+ * @returns Entity format
31
+ */
32
+ export function parseEntityFormat(wrapper) {
33
+ var isEntity = false;
34
+ var format = {};
35
+ wrapper.classList.forEach(function (name) {
36
+ isEntity = parseEntityClassName(name, format) || isEntity;
37
+ });
38
+ if (!isEntity) {
39
+ format.isFakeEntity = true;
40
+ format.isReadonly = !wrapper.isContentEditable;
41
+ }
42
+ return format;
43
+ }
27
44
  /**
28
45
  * Parse entity class names from entity wrapper element
29
46
  * @param className Class names of entity
30
47
  * @param format The output entity format object
31
48
  */
32
- export function parseEntityClassName(className, format) {
49
+ function parseEntityClassName(className, format) {
33
50
  if (className == ENTITY_INFO_NAME) {
34
51
  return true;
35
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"entityUtils.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/entityUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import toArray from './toArray';\nimport { applyFormat } from '../modelToDom/utils/applyFormat';\nimport { isElementOfType } from './isElementOfType';\nimport { isNodeOfType } from './isNodeOfType';\nimport type {\n ContentModelEntityFormat,\n ContentModelSegmentFormat,\n ModelToDomContext,\n} from 'roosterjs-content-model-types';\n\nconst ENTITY_INFO_NAME = '_Entity';\nconst ENTITY_TYPE_PREFIX = '_EType_';\nconst ENTITY_ID_PREFIX = '_EId_';\nconst ENTITY_READONLY_PREFIX = '_EReadonly_';\nconst ZERO_WIDTH_SPACE = '\\u200B';\nconst DELIMITER_BEFORE = 'entityDelimiterBefore';\nconst DELIMITER_AFTER = 'entityDelimiterAfter';\n\n/**\n * Check if the given DOM Node is an entity wrapper element\n */\nexport function isEntityElement(node: Node): boolean {\n return isNodeOfType(node, 'ELEMENT_NODE') && node.classList.contains(ENTITY_INFO_NAME);\n}\n\n/**\n * Get all entity wrapper elements under the given root element\n * @param root The root element to query from\n * @returns An array of entity wrapper elements\n */\nexport function getAllEntityWrappers(root: HTMLElement): HTMLElement[] {\n return toArray(root.querySelectorAll('.' + ENTITY_INFO_NAME)) as HTMLElement[];\n}\n\n/**\n * Parse entity class names from entity wrapper element\n * @param className Class names of entity\n * @param format The output entity format object\n */\nexport function parseEntityClassName(\n className: string,\n format: ContentModelEntityFormat\n): boolean | undefined {\n if (className == ENTITY_INFO_NAME) {\n return true;\n } else if (className.indexOf(ENTITY_TYPE_PREFIX) == 0) {\n format.entityType = className.substring(ENTITY_TYPE_PREFIX.length);\n } else if (className.indexOf(ENTITY_ID_PREFIX) == 0) {\n format.id = className.substring(ENTITY_ID_PREFIX.length);\n } else if (className.indexOf(ENTITY_READONLY_PREFIX) == 0) {\n format.isReadonly = className.substring(ENTITY_READONLY_PREFIX.length) == '1';\n }\n}\n\n/**\n * Generate Entity class names for an entity wrapper\n * @param format The source entity format object\n * @returns A combined CSS class name string for entity wrapper\n */\nexport function generateEntityClassNames(format: ContentModelEntityFormat): string {\n return format.isFakeEntity\n ? ''\n : `${ENTITY_INFO_NAME} ${ENTITY_TYPE_PREFIX}${format.entityType ?? ''} ${\n format.id ? `${ENTITY_ID_PREFIX}${format.id} ` : ''\n }${ENTITY_READONLY_PREFIX}${format.isReadonly ? '1' : '0'}`;\n}\n\n/**\n * Checks whether the node provided is a Entity delimiter\n * @param node the node to check\n * @return true if it is a delimiter\n */\nexport function isEntityDelimiter(element: HTMLElement): boolean {\n return (\n isElementOfType(element, 'span') &&\n (element.classList.contains(DELIMITER_AFTER) ||\n element.classList.contains(DELIMITER_BEFORE)) &&\n element.textContent === ZERO_WIDTH_SPACE\n );\n}\n\n/**\n * Adds delimiters to the element provided. If the delimiters already exists, will not be added\n * @param element the node to add the delimiters\n * @param format format to set to the delimiters, so when typing inside of one the format is not lost\n * @param context Model to Dom context to use.\n */\nexport function addDelimiters(\n doc: Document,\n element: HTMLElement,\n format?: ContentModelSegmentFormat | null,\n context?: ModelToDomContext\n): HTMLElement[] {\n let [delimiterAfter, delimiterBefore] = getDelimiters(element);\n\n if (!delimiterAfter) {\n delimiterAfter = insertDelimiter(doc, element, true /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterAfter, context.formatAppliers.segment, format, context);\n }\n }\n\n if (!delimiterBefore) {\n delimiterBefore = insertDelimiter(doc, element, false /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterBefore, context.formatAppliers.segment, format, context);\n }\n }\n\n return [delimiterAfter, delimiterBefore];\n}\n\nfunction getDelimiters(entityWrapper: HTMLElement): (HTMLElement | undefined)[] {\n const result: (HTMLElement | undefined)[] = [];\n const { nextElementSibling, previousElementSibling } = entityWrapper;\n result.push(\n isDelimiter(nextElementSibling, DELIMITER_AFTER),\n isDelimiter(previousElementSibling, DELIMITER_BEFORE)\n );\n\n return result;\n}\n\nfunction isDelimiter(el: Element | null, className: string): HTMLElement | undefined {\n return el?.classList.contains(className) && el.textContent == ZERO_WIDTH_SPACE\n ? (el as HTMLElement)\n : undefined;\n}\n\nfunction insertDelimiter(doc: Document, element: Element, isAfter: boolean) {\n const span = doc.createElement('span');\n\n span.className = isAfter ? DELIMITER_AFTER : DELIMITER_BEFORE;\n span.appendChild(doc.createTextNode(ZERO_WIDTH_SPACE));\n element.parentNode?.insertBefore(span, isAfter ? element.nextSibling : element);\n\n return span;\n}\n"]}
1
+ {"version":3,"file":"entityUtils.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/entityUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import toArray from './toArray';\nimport { applyFormat } from '../modelToDom/utils/applyFormat';\nimport { isElementOfType } from './isElementOfType';\nimport { isNodeOfType } from './isNodeOfType';\nimport type {\n ContentModelEntityFormat,\n ContentModelSegmentFormat,\n ModelToDomContext,\n} from 'roosterjs-content-model-types';\n\nconst ENTITY_INFO_NAME = '_Entity';\nconst ENTITY_TYPE_PREFIX = '_EType_';\nconst ENTITY_ID_PREFIX = '_EId_';\nconst ENTITY_READONLY_PREFIX = '_EReadonly_';\nconst ZERO_WIDTH_SPACE = '\\u200B';\nconst DELIMITER_BEFORE = 'entityDelimiterBefore';\nconst DELIMITER_AFTER = 'entityDelimiterAfter';\n\n/**\n * Check if the given DOM Node is an entity wrapper element\n */\nexport function isEntityElement(node: Node): boolean {\n return isNodeOfType(node, 'ELEMENT_NODE') && node.classList.contains(ENTITY_INFO_NAME);\n}\n\n/**\n * Get all entity wrapper elements under the given root element\n * @param root The root element to query from\n * @returns An array of entity wrapper elements\n */\nexport function getAllEntityWrappers(root: HTMLElement): HTMLElement[] {\n return toArray(root.querySelectorAll('.' + ENTITY_INFO_NAME)) as HTMLElement[];\n}\n\n/**\n * Parse entity format from entity wrapper element\n * @param wrapper The wrapper element to parse entity format from\n * @returns Entity format\n */\nexport function parseEntityFormat(wrapper: HTMLElement): ContentModelEntityFormat {\n let isEntity = false;\n const format: ContentModelEntityFormat = {};\n\n wrapper.classList.forEach(name => {\n isEntity = parseEntityClassName(name, format) || isEntity;\n });\n\n if (!isEntity) {\n format.isFakeEntity = true;\n format.isReadonly = !wrapper.isContentEditable;\n }\n\n return format;\n}\n\n/**\n * Parse entity class names from entity wrapper element\n * @param className Class names of entity\n * @param format The output entity format object\n */\nfunction parseEntityClassName(\n className: string,\n format: ContentModelEntityFormat\n): boolean | undefined {\n if (className == ENTITY_INFO_NAME) {\n return true;\n } else if (className.indexOf(ENTITY_TYPE_PREFIX) == 0) {\n format.entityType = className.substring(ENTITY_TYPE_PREFIX.length);\n } else if (className.indexOf(ENTITY_ID_PREFIX) == 0) {\n format.id = className.substring(ENTITY_ID_PREFIX.length);\n } else if (className.indexOf(ENTITY_READONLY_PREFIX) == 0) {\n format.isReadonly = className.substring(ENTITY_READONLY_PREFIX.length) == '1';\n }\n}\n\n/**\n * Generate Entity class names for an entity wrapper\n * @param format The source entity format object\n * @returns A combined CSS class name string for entity wrapper\n */\nexport function generateEntityClassNames(format: ContentModelEntityFormat): string {\n return format.isFakeEntity\n ? ''\n : `${ENTITY_INFO_NAME} ${ENTITY_TYPE_PREFIX}${format.entityType ?? ''} ${\n format.id ? `${ENTITY_ID_PREFIX}${format.id} ` : ''\n }${ENTITY_READONLY_PREFIX}${format.isReadonly ? '1' : '0'}`;\n}\n\n/**\n * Checks whether the node provided is a Entity delimiter\n * @param node the node to check\n * @return true if it is a delimiter\n */\nexport function isEntityDelimiter(element: HTMLElement): boolean {\n return (\n isElementOfType(element, 'span') &&\n (element.classList.contains(DELIMITER_AFTER) ||\n element.classList.contains(DELIMITER_BEFORE)) &&\n element.textContent === ZERO_WIDTH_SPACE\n );\n}\n\n/**\n * Adds delimiters to the element provided. If the delimiters already exists, will not be added\n * @param element the node to add the delimiters\n * @param format format to set to the delimiters, so when typing inside of one the format is not lost\n * @param context Model to Dom context to use.\n */\nexport function addDelimiters(\n doc: Document,\n element: HTMLElement,\n format?: ContentModelSegmentFormat | null,\n context?: ModelToDomContext\n): HTMLElement[] {\n let [delimiterAfter, delimiterBefore] = getDelimiters(element);\n\n if (!delimiterAfter) {\n delimiterAfter = insertDelimiter(doc, element, true /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterAfter, context.formatAppliers.segment, format, context);\n }\n }\n\n if (!delimiterBefore) {\n delimiterBefore = insertDelimiter(doc, element, false /*isAfter*/);\n if (context && format) {\n applyFormat(delimiterBefore, context.formatAppliers.segment, format, context);\n }\n }\n\n return [delimiterAfter, delimiterBefore];\n}\n\nfunction getDelimiters(entityWrapper: HTMLElement): (HTMLElement | undefined)[] {\n const result: (HTMLElement | undefined)[] = [];\n const { nextElementSibling, previousElementSibling } = entityWrapper;\n result.push(\n isDelimiter(nextElementSibling, DELIMITER_AFTER),\n isDelimiter(previousElementSibling, DELIMITER_BEFORE)\n );\n\n return result;\n}\n\nfunction isDelimiter(el: Element | null, className: string): HTMLElement | undefined {\n return el?.classList.contains(className) && el.textContent == ZERO_WIDTH_SPACE\n ? (el as HTMLElement)\n : undefined;\n}\n\nfunction insertDelimiter(doc: Document, element: Element, isAfter: boolean) {\n const span = doc.createElement('span');\n\n span.className = isAfter ? DELIMITER_AFTER : DELIMITER_BEFORE;\n span.appendChild(doc.createTextNode(ZERO_WIDTH_SPACE));\n element.parentNode?.insertBefore(span, isAfter ? element.nextSibling : element);\n\n return span;\n}\n"]}
@@ -11,10 +11,11 @@ import { isEntityElement } from './entityUtils';
11
11
  export function reuseCachedElement(parent, element, refNode) {
12
12
  var _a;
13
13
  if (element.parentNode == parent) {
14
+ var isEntity = isEntityElement(element);
14
15
  // Remove nodes before the one we are hitting since they don't appear in Content Model at this position.
15
16
  // But we don't want to touch entity since it would better to keep entity at its place unless it is removed
16
17
  // In that case we will remove it after we have handled all other nodes
17
- while (refNode && refNode != element && !isEntityElement(refNode)) {
18
+ while (refNode && refNode != element && (isEntity || !isEntityElement(refNode))) {
18
19
  var next = refNode.nextSibling;
19
20
  (_a = refNode.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(refNode);
20
21
  refNode = next;
@@ -1 +1 @@
1
- {"version":3,"file":"reuseCachedElement.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/reuseCachedElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAY,EAAE,OAAa,EAAE,OAAoB;;IAChF,IAAI,OAAO,CAAC,UAAU,IAAI,MAAM,EAAE;QAC9B,wGAAwG;QACxG,2GAA2G;QAC3G,uEAAuE;QACvE,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE;YAC/D,IAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC;YAEjC,MAAA,OAAO,CAAC,UAAU,0CAAE,WAAW,CAAC,OAAO,CAAC,CAAC;YACzC,OAAO,GAAG,IAAI,CAAC;SAClB;QAED,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,EAAE;YAC/B,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;SACjC;aAAM;YACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;SACzC;KACJ;SAAM;QACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;KACzC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,IAAU;;IACjC,IAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;IAC9B,MAAA,IAAI,CAAC,UAAU,0CAAE,WAAW,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,IAAI,CAAC;AAChB,CAAC","sourcesContent":["import { isEntityElement } from './entityUtils';\n\n/**\n * When set a DOM tree into editor, reuse the existing element in editor and no need to change it\n * @param param Parent node of the reused element\n * @param element The element to keep in parent node\n * @param refNode Reference node, it is point to current node that is being processed. It must be a child of parent node, or null.\n * We will start processing from this node, if it is not the same with element, remove it and keep processing its next sibling,\n * until we see an element that is the same with the passed in element or null.\n * @returns The new reference element\n */\nexport function reuseCachedElement(parent: Node, element: Node, refNode: Node | null): Node | null {\n if (element.parentNode == parent) {\n // Remove nodes before the one we are hitting since they don't appear in Content Model at this position.\n // But we don't want to touch entity since it would better to keep entity at its place unless it is removed\n // In that case we will remove it after we have handled all other nodes\n while (refNode && refNode != element && !isEntityElement(refNode)) {\n const next = refNode.nextSibling;\n\n refNode.parentNode?.removeChild(refNode);\n refNode = next;\n }\n\n if (refNode && refNode == element) {\n refNode = refNode.nextSibling;\n } else {\n parent.insertBefore(element, refNode);\n }\n } else {\n parent.insertBefore(element, refNode);\n }\n\n return refNode;\n}\n\n/**\n * @internal\n */\nexport function removeNode(node: Node): Node | null {\n const next = node.nextSibling;\n node.parentNode?.removeChild(node);\n\n return next;\n}\n"]}
1
+ {"version":3,"file":"reuseCachedElement.js","sourceRoot":"","sources":["../../../../packages-content-model/roosterjs-content-model-dom/lib/domUtils/reuseCachedElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAY,EAAE,OAAa,EAAE,OAAoB;;IAChF,IAAI,OAAO,CAAC,UAAU,IAAI,MAAM,EAAE;QAC9B,IAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAE1C,wGAAwG;QACxG,2GAA2G;QAC3G,uEAAuE;QACvE,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,EAAE;YAC7E,IAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC;YAEjC,MAAA,OAAO,CAAC,UAAU,0CAAE,WAAW,CAAC,OAAO,CAAC,CAAC;YACzC,OAAO,GAAG,IAAI,CAAC;SAClB;QAED,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,EAAE;YAC/B,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;SACjC;aAAM;YACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;SACzC;KACJ;SAAM;QACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;KACzC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,IAAU;;IACjC,IAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;IAC9B,MAAA,IAAI,CAAC,UAAU,0CAAE,WAAW,CAAC,IAAI,CAAC,CAAC;IAEnC,OAAO,IAAI,CAAC;AAChB,CAAC","sourcesContent":["import { isEntityElement } from './entityUtils';\n\n/**\n * When set a DOM tree into editor, reuse the existing element in editor and no need to change it\n * @param param Parent node of the reused element\n * @param element The element to keep in parent node\n * @param refNode Reference node, it is point to current node that is being processed. It must be a child of parent node, or null.\n * We will start processing from this node, if it is not the same with element, remove it and keep processing its next sibling,\n * until we see an element that is the same with the passed in element or null.\n * @returns The new reference element\n */\nexport function reuseCachedElement(parent: Node, element: Node, refNode: Node | null): Node | null {\n if (element.parentNode == parent) {\n const isEntity = isEntityElement(element);\n\n // Remove nodes before the one we are hitting since they don't appear in Content Model at this position.\n // But we don't want to touch entity since it would better to keep entity at its place unless it is removed\n // In that case we will remove it after we have handled all other nodes\n while (refNode && refNode != element && (isEntity || !isEntityElement(refNode))) {\n const next = refNode.nextSibling;\n\n refNode.parentNode?.removeChild(refNode);\n refNode = next;\n }\n\n if (refNode && refNode == element) {\n refNode = refNode.nextSibling;\n } else {\n parent.insertBefore(element, refNode);\n }\n } else {\n parent.insertBefore(element, refNode);\n }\n\n return refNode;\n}\n\n/**\n * @internal\n */\nexport function removeNode(node: Node): Node | null {\n const next = node.nextSibling;\n node.parentNode?.removeChild(node);\n\n return next;\n}\n"]}
@@ -1,17 +1,10 @@
1
- import { generateEntityClassNames, parseEntityClassName } from '../../domUtils/entityUtils';
1
+ import { generateEntityClassNames, parseEntityFormat } from '../../domUtils/entityUtils';
2
2
  /**
3
3
  * @internal
4
4
  */
5
5
  export var entityFormatHandler = {
6
6
  parse: function (format, element) {
7
- var isEntity = false;
8
- element.classList.forEach(function (name) {
9
- isEntity = parseEntityClassName(name, format) || isEntity;
10
- });
11
- if (!isEntity) {
12
- format.isFakeEntity = true;
13
- format.isReadonly = !element.isContentEditable;
14
- }
7
+ Object.assign(format, parseEntityFormat(element));
15
8
  },
16
9
  apply: function (format, element) {
17
10
  if (!format.isFakeEntity) {
@@ -1 +1 @@
1
- {"version":3,"file":"entityFormatHandler.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/formatHandlers/entity/entityFormatHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAI5F;;GAEG;AACH,MAAM,CAAC,IAAM,mBAAmB,GAA+C;IAC3E,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,UAAA,IAAI;YAC1B,QAAQ,GAAG,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,QAAQ,CAAC;QAC9D,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,EAAE;YACX,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC;YAC3B,MAAM,CAAC,UAAU,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC;SAClD;IACL,CAAC;IAED,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;YACtB,OAAO,CAAC,SAAS,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;SACxD;QAED,IAAI,MAAM,CAAC,UAAU,EAAE;YACnB,OAAO,CAAC,eAAe,GAAG,OAAO,CAAC;SACrC;aAAM;YACH,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;SAC9C;IACL,CAAC;CACJ,CAAC","sourcesContent":["import { generateEntityClassNames, parseEntityClassName } from '../../domUtils/entityUtils';\nimport type { EntityInfoFormat, IdFormat } from 'roosterjs-content-model-types';\nimport type { FormatHandler } from '../FormatHandler';\n\n/**\n * @internal\n */\nexport const entityFormatHandler: FormatHandler<EntityInfoFormat & IdFormat> = {\n parse: (format, element) => {\n let isEntity = false;\n\n element.classList.forEach(name => {\n isEntity = parseEntityClassName(name, format) || isEntity;\n });\n\n if (!isEntity) {\n format.isFakeEntity = true;\n format.isReadonly = !element.isContentEditable;\n }\n },\n\n apply: (format, element) => {\n if (!format.isFakeEntity) {\n element.className = generateEntityClassNames(format);\n }\n\n if (format.isReadonly) {\n element.contentEditable = 'false';\n } else {\n element.removeAttribute('contenteditable');\n }\n },\n};\n"]}
1
+ {"version":3,"file":"entityFormatHandler.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/formatHandlers/entity/entityFormatHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAIzF;;GAEG;AACH,MAAM,CAAC,IAAM,mBAAmB,GAA+C;IAC3E,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;YACtB,OAAO,CAAC,SAAS,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;SACxD;QAED,IAAI,MAAM,CAAC,UAAU,EAAE;YACnB,OAAO,CAAC,eAAe,GAAG,OAAO,CAAC;SACrC;aAAM;YACH,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;SAC9C;IACL,CAAC;CACJ,CAAC","sourcesContent":["import { generateEntityClassNames, parseEntityFormat } from '../../domUtils/entityUtils';\nimport type { EntityInfoFormat, IdFormat } from 'roosterjs-content-model-types';\nimport type { FormatHandler } from '../FormatHandler';\n\n/**\n * @internal\n */\nexport const entityFormatHandler: FormatHandler<EntityInfoFormat & IdFormat> = {\n parse: (format, element) => {\n Object.assign(format, parseEntityFormat(element));\n },\n\n apply: (format, element) => {\n if (!format.isFakeEntity) {\n element.className = generateEntityClassNames(format);\n }\n\n if (format.isReadonly) {\n element.contentEditable = 'false';\n } else {\n element.removeAttribute('contenteditable');\n }\n },\n};\n"]}
@@ -15,7 +15,7 @@ export { getObjectKeys } from './domUtils/getObjectKeys';
15
15
  export { default as toArray } from './domUtils/toArray';
16
16
  export { moveChildNodes, wrapAllChildNodes } from './domUtils/moveChildNodes';
17
17
  export { wrap } from './domUtils/wrap';
18
- export { isEntityElement, getAllEntityWrappers, parseEntityClassName, generateEntityClassNames, addDelimiters, isEntityDelimiter, } from './domUtils/entityUtils';
18
+ export { isEntityElement, getAllEntityWrappers, parseEntityFormat, generateEntityClassNames, addDelimiters, isEntityDelimiter, } from './domUtils/entityUtils';
19
19
  export { reuseCachedElement } from './domUtils/reuseCachedElement';
20
20
  export { isWhiteSpacePreserved } from './domUtils/isWhiteSpacePreserved';
21
21
  export { createBr } from './modelApi/creators/createBr';
package/lib-mjs/index.js CHANGED
@@ -15,7 +15,7 @@ export { getObjectKeys } from './domUtils/getObjectKeys';
15
15
  export { default as toArray } from './domUtils/toArray';
16
16
  export { moveChildNodes, wrapAllChildNodes } from './domUtils/moveChildNodes';
17
17
  export { wrap } from './domUtils/wrap';
18
- export { isEntityElement, getAllEntityWrappers, parseEntityClassName, generateEntityClassNames, addDelimiters, isEntityDelimiter, } from './domUtils/entityUtils';
18
+ export { isEntityElement, getAllEntityWrappers, parseEntityFormat, generateEntityClassNames, addDelimiters, isEntityDelimiter, } from './domUtils/entityUtils';
19
19
  export { reuseCachedElement } from './domUtils/reuseCachedElement';
20
20
  export { isWhiteSpacePreserved } from './domUtils/isWhiteSpacePreserved';
21
21
  export { createBr } from './modelApi/creators/createBr';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages-content-model/roosterjs-content-model-dom/lib/index.ts"],"names":[],"mappings":"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","sourcesContent":["export { domToContentModel } from './domToModel/domToContentModel';\nexport { contentModelToDom } from './modelToDom/contentModelToDom';\nexport { contentModelToText } from './modelToText/contentModelToText';\n\nexport {\n childProcessor,\n handleRegularSelection,\n processChildNode,\n} from './domToModel/processors/childProcessor';\nexport { entityProcessor } from './domToModel/processors/entityProcessor';\nexport { tableProcessor } from './domToModel/processors/tableProcessor';\nexport { getRegularSelectionOffsets } from './domToModel/utils/getRegularSelectionOffsets';\nexport { parseFormat } from './domToModel/utils/parseFormat';\nexport { areSameFormats } from './domToModel/utils/areSameFormats';\nexport { isBlockElement } from './domToModel/utils/isBlockElement';\n\nexport { updateMetadata, hasMetadata } from './domUtils/metadata/updateMetadata';\nexport { isNodeOfType, NodeTypeMap } from './domUtils/isNodeOfType';\nexport { isElementOfType } from './domUtils/isElementOfType';\nexport { getObjectKeys } from './domUtils/getObjectKeys';\nexport { default as toArray } from './domUtils/toArray';\nexport { moveChildNodes, wrapAllChildNodes } from './domUtils/moveChildNodes';\nexport { wrap } from './domUtils/wrap';\nexport {\n isEntityElement,\n getAllEntityWrappers,\n parseEntityClassName,\n generateEntityClassNames,\n addDelimiters,\n isEntityDelimiter,\n} from './domUtils/entityUtils';\nexport { reuseCachedElement } from './domUtils/reuseCachedElement';\nexport { isWhiteSpacePreserved } from './domUtils/isWhiteSpacePreserved';\n\nexport { createBr } from './modelApi/creators/createBr';\nexport { createListItem } from './modelApi/creators/createListItem';\nexport { createFormatContainer } from './modelApi/creators/createFormatContainer';\nexport { createParagraph } from './modelApi/creators/createParagraph';\nexport { createSelectionMarker } from './modelApi/creators/createSelectionMarker';\nexport { createTable } from './modelApi/creators/createTable';\nexport { createTableCell } from './modelApi/creators/createTableCell';\nexport { createText } from './modelApi/creators/createText';\nexport { createImage } from './modelApi/creators/createImage';\nexport { createContentModelDocument } from './modelApi/creators/createContentModelDocument';\nexport { createParagraphDecorator } from './modelApi/creators/createParagraphDecorator';\nexport { createGeneralSegment } from './modelApi/creators/createGeneralSegment';\nexport { createGeneralBlock } from './modelApi/creators/createGeneralBlock';\nexport { createEntity } from './modelApi/creators/createEntity';\nexport { createDivider } from './modelApi/creators/createDivider';\nexport { createListLevel } from './modelApi/creators/createListLevel';\nexport { createEmptyModel } from './modelApi/creators/createEmptyModel';\n\nexport { addBlock } from './modelApi/common/addBlock';\nexport { addCode } from './modelApi/common/addDecorators';\nexport { addLink } from './modelApi/common/addDecorators';\nexport { normalizeParagraph } from './modelApi/common/normalizeParagraph';\n\nexport { normalizeContentModel } from './modelApi/common/normalizeContentModel';\nexport { isGeneralSegment } from './modelApi/common/isGeneralSegment';\nexport { unwrapBlock } from './modelApi/common/unwrapBlock';\nexport { addSegment } from './modelApi/common/addSegment';\nexport { isEmpty } from './modelApi/common/isEmpty';\nexport { normalizeSingleSegment } from './modelApi/common/normalizeSegment';\n\nexport { setParagraphNotImplicit } from './modelApi/block/setParagraphNotImplicit';\n\nexport { parseValueWithUnit } from './formatHandlers/utils/parseValueWithUnit';\nexport { BorderKeys } from './formatHandlers/common/borderFormatHandler';\nexport { DeprecatedColors, getColor, setColor, parseColor } from './formatHandlers/utils/color';\n\nexport {\n createDomToModelContext,\n createDomToModelContextWithConfig,\n createDomToModelConfig,\n} from './domToModel/context/createDomToModelContext';\nexport {\n createModelToDomContext,\n createModelToDomContextWithConfig,\n createModelToDomConfig,\n} from './modelToDom/context/createModelToDomContext';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages-content-model/roosterjs-content-model-dom/lib/index.ts"],"names":[],"mappings":"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","sourcesContent":["export { domToContentModel } from './domToModel/domToContentModel';\nexport { contentModelToDom } from './modelToDom/contentModelToDom';\nexport { contentModelToText } from './modelToText/contentModelToText';\n\nexport {\n childProcessor,\n handleRegularSelection,\n processChildNode,\n} from './domToModel/processors/childProcessor';\nexport { entityProcessor } from './domToModel/processors/entityProcessor';\nexport { tableProcessor } from './domToModel/processors/tableProcessor';\nexport { getRegularSelectionOffsets } from './domToModel/utils/getRegularSelectionOffsets';\nexport { parseFormat } from './domToModel/utils/parseFormat';\nexport { areSameFormats } from './domToModel/utils/areSameFormats';\nexport { isBlockElement } from './domToModel/utils/isBlockElement';\n\nexport { updateMetadata, hasMetadata } from './domUtils/metadata/updateMetadata';\nexport { isNodeOfType, NodeTypeMap } from './domUtils/isNodeOfType';\nexport { isElementOfType } from './domUtils/isElementOfType';\nexport { getObjectKeys } from './domUtils/getObjectKeys';\nexport { default as toArray } from './domUtils/toArray';\nexport { moveChildNodes, wrapAllChildNodes } from './domUtils/moveChildNodes';\nexport { wrap } from './domUtils/wrap';\nexport {\n isEntityElement,\n getAllEntityWrappers,\n parseEntityFormat,\n generateEntityClassNames,\n addDelimiters,\n isEntityDelimiter,\n} from './domUtils/entityUtils';\nexport { reuseCachedElement } from './domUtils/reuseCachedElement';\nexport { isWhiteSpacePreserved } from './domUtils/isWhiteSpacePreserved';\n\nexport { createBr } from './modelApi/creators/createBr';\nexport { createListItem } from './modelApi/creators/createListItem';\nexport { createFormatContainer } from './modelApi/creators/createFormatContainer';\nexport { createParagraph } from './modelApi/creators/createParagraph';\nexport { createSelectionMarker } from './modelApi/creators/createSelectionMarker';\nexport { createTable } from './modelApi/creators/createTable';\nexport { createTableCell } from './modelApi/creators/createTableCell';\nexport { createText } from './modelApi/creators/createText';\nexport { createImage } from './modelApi/creators/createImage';\nexport { createContentModelDocument } from './modelApi/creators/createContentModelDocument';\nexport { createParagraphDecorator } from './modelApi/creators/createParagraphDecorator';\nexport { createGeneralSegment } from './modelApi/creators/createGeneralSegment';\nexport { createGeneralBlock } from './modelApi/creators/createGeneralBlock';\nexport { createEntity } from './modelApi/creators/createEntity';\nexport { createDivider } from './modelApi/creators/createDivider';\nexport { createListLevel } from './modelApi/creators/createListLevel';\nexport { createEmptyModel } from './modelApi/creators/createEmptyModel';\n\nexport { addBlock } from './modelApi/common/addBlock';\nexport { addCode } from './modelApi/common/addDecorators';\nexport { addLink } from './modelApi/common/addDecorators';\nexport { normalizeParagraph } from './modelApi/common/normalizeParagraph';\n\nexport { normalizeContentModel } from './modelApi/common/normalizeContentModel';\nexport { isGeneralSegment } from './modelApi/common/isGeneralSegment';\nexport { unwrapBlock } from './modelApi/common/unwrapBlock';\nexport { addSegment } from './modelApi/common/addSegment';\nexport { isEmpty } from './modelApi/common/isEmpty';\nexport { normalizeSingleSegment } from './modelApi/common/normalizeSegment';\n\nexport { setParagraphNotImplicit } from './modelApi/block/setParagraphNotImplicit';\n\nexport { parseValueWithUnit } from './formatHandlers/utils/parseValueWithUnit';\nexport { BorderKeys } from './formatHandlers/common/borderFormatHandler';\nexport { DeprecatedColors, getColor, setColor, parseColor } from './formatHandlers/utils/color';\n\nexport {\n createDomToModelContext,\n createDomToModelContextWithConfig,\n createDomToModelConfig,\n} from './domToModel/context/createDomToModelContext';\nexport {\n createModelToDomContext,\n createModelToDomContextWithConfig,\n createModelToDomConfig,\n} from './modelToDom/context/createModelToDomContext';\n"]}
@@ -31,6 +31,7 @@ export function normalizeParagraph(paragraph) {
31
31
  }
32
32
  removeEmptyLinks(paragraph);
33
33
  removeEmptySegments(paragraph);
34
+ moveUpSegmentFormat(paragraph);
34
35
  }
35
36
  function removeEmptySegments(block) {
36
37
  for (var j = block.segments.length - 1; j >= 0; j--) {
@@ -59,4 +60,31 @@ function removeEmptyLinks(paragraph) {
59
60
  }
60
61
  }
61
62
  }
63
+ var formatsToMoveUp = ['fontFamily', 'fontSize', 'textColor'];
64
+ // When all segments are sharing the same segment format (font name, size and color), we can move its format to paragraph
65
+ function moveUpSegmentFormat(paragraph) {
66
+ if (!paragraph.decorator) {
67
+ var segments_1 = paragraph.segments.filter(function (x) { return x.segmentType != 'SelectionMarker'; });
68
+ var target_1 = paragraph.segmentFormat || {};
69
+ var changed_1 = false;
70
+ formatsToMoveUp.forEach(function (key) {
71
+ changed_1 = internalMoveUpSegmentFormat(segments_1, target_1, key) || changed_1;
72
+ });
73
+ if (changed_1) {
74
+ paragraph.segmentFormat = target_1;
75
+ }
76
+ }
77
+ }
78
+ function internalMoveUpSegmentFormat(segments, target, formatKey) {
79
+ var _a;
80
+ var firstFormat = (_a = segments[0]) === null || _a === void 0 ? void 0 : _a.format;
81
+ if ((firstFormat === null || firstFormat === void 0 ? void 0 : firstFormat[formatKey]) &&
82
+ segments.every(function (segment) { return segment.format[formatKey] == firstFormat[formatKey]; })) {
83
+ target[formatKey] = firstFormat[formatKey];
84
+ return true;
85
+ }
86
+ else {
87
+ return false;
88
+ }
89
+ }
62
90
  //# sourceMappingURL=normalizeParagraph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalizeParagraph.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/modelApi/common/normalizeParagraph.ts"],"names":[],"mappings":"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","sourcesContent":["import { areSameFormats } from '../../domToModel/utils/areSameFormats';\nimport { createBr } from '../creators/createBr';\nimport { isSegmentEmpty } from './isEmpty';\nimport { isWhiteSpacePreserved } from '../../domUtils/isWhiteSpacePreserved';\nimport { normalizeAllSegments } from './normalizeSegment';\nimport type { ContentModelParagraph } from 'roosterjs-content-model-types';\n\n/**\n * @param paragraph The paragraph to normalize\n * Normalize a paragraph. If it is empty, add a BR segment to make sure it can insert content\n */\nexport function normalizeParagraph(paragraph: ContentModelParagraph) {\n const segments = paragraph.segments;\n\n if (!paragraph.isImplicit && segments.length > 0) {\n const last = segments[segments.length - 1];\n const secondLast = segments[segments.length - 2];\n\n if (\n last.segmentType == 'SelectionMarker' &&\n (!secondLast || secondLast.segmentType == 'Br')\n ) {\n segments.push(createBr(last.format));\n } else if (segments.length > 1 && segments[segments.length - 1].segmentType == 'Br') {\n const noMarkerSegments = segments.filter(x => x.segmentType != 'SelectionMarker');\n\n // When there is content with a <BR> tag at the end, we can remove the BR.\n // But if there are more than one <BR> at the end, do not remove them.\n if (\n noMarkerSegments.length > 1 &&\n noMarkerSegments[noMarkerSegments.length - 2].segmentType != 'Br'\n ) {\n segments.pop();\n }\n }\n }\n\n if (!isWhiteSpacePreserved(paragraph.format.whiteSpace)) {\n normalizeAllSegments(paragraph);\n }\n\n removeEmptyLinks(paragraph);\n\n removeEmptySegments(paragraph);\n}\n\nfunction removeEmptySegments(block: ContentModelParagraph) {\n for (let j = block.segments.length - 1; j >= 0; j--) {\n if (isSegmentEmpty(block.segments[j])) {\n block.segments.splice(j, 1);\n }\n }\n}\n\nfunction removeEmptyLinks(paragraph: ContentModelParagraph) {\n const marker = paragraph.segments.find(x => x.segmentType == 'SelectionMarker');\n if (marker) {\n const markerIndex = paragraph.segments.indexOf(marker);\n const prev = paragraph.segments[markerIndex - 1];\n const next = paragraph.segments[markerIndex + 1];\n if (\n (prev &&\n !prev.link &&\n areSameFormats(prev.format, marker.format) &&\n (!next || (!next.link && areSameFormats(next.format, marker.format))) &&\n marker.link) ||\n (!prev &&\n marker.link &&\n next &&\n !next.link &&\n areSameFormats(next.format, marker.format))\n ) {\n delete marker.link;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"normalizeParagraph.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-dom/lib/modelApi/common/normalizeParagraph.ts"],"names":[],"mappings":"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","sourcesContent":["import { areSameFormats } from '../../domToModel/utils/areSameFormats';\nimport { createBr } from '../creators/createBr';\nimport { isSegmentEmpty } from './isEmpty';\nimport { isWhiteSpacePreserved } from '../../domUtils/isWhiteSpacePreserved';\nimport { normalizeAllSegments } from './normalizeSegment';\nimport type {\n ContentModelParagraph,\n ContentModelSegment,\n ContentModelSegmentFormat,\n} from 'roosterjs-content-model-types';\n\n/**\n * @param paragraph The paragraph to normalize\n * Normalize a paragraph. If it is empty, add a BR segment to make sure it can insert content\n */\nexport function normalizeParagraph(paragraph: ContentModelParagraph) {\n const segments = paragraph.segments;\n\n if (!paragraph.isImplicit && segments.length > 0) {\n const last = segments[segments.length - 1];\n const secondLast = segments[segments.length - 2];\n\n if (\n last.segmentType == 'SelectionMarker' &&\n (!secondLast || secondLast.segmentType == 'Br')\n ) {\n segments.push(createBr(last.format));\n } else if (segments.length > 1 && segments[segments.length - 1].segmentType == 'Br') {\n const noMarkerSegments = segments.filter(x => x.segmentType != 'SelectionMarker');\n\n // When there is content with a <BR> tag at the end, we can remove the BR.\n // But if there are more than one <BR> at the end, do not remove them.\n if (\n noMarkerSegments.length > 1 &&\n noMarkerSegments[noMarkerSegments.length - 2].segmentType != 'Br'\n ) {\n segments.pop();\n }\n }\n }\n\n if (!isWhiteSpacePreserved(paragraph.format.whiteSpace)) {\n normalizeAllSegments(paragraph);\n }\n\n removeEmptyLinks(paragraph);\n\n removeEmptySegments(paragraph);\n\n moveUpSegmentFormat(paragraph);\n}\n\nfunction removeEmptySegments(block: ContentModelParagraph) {\n for (let j = block.segments.length - 1; j >= 0; j--) {\n if (isSegmentEmpty(block.segments[j])) {\n block.segments.splice(j, 1);\n }\n }\n}\n\nfunction removeEmptyLinks(paragraph: ContentModelParagraph) {\n const marker = paragraph.segments.find(x => x.segmentType == 'SelectionMarker');\n if (marker) {\n const markerIndex = paragraph.segments.indexOf(marker);\n const prev = paragraph.segments[markerIndex - 1];\n const next = paragraph.segments[markerIndex + 1];\n if (\n (prev &&\n !prev.link &&\n areSameFormats(prev.format, marker.format) &&\n (!next || (!next.link && areSameFormats(next.format, marker.format))) &&\n marker.link) ||\n (!prev &&\n marker.link &&\n next &&\n !next.link &&\n areSameFormats(next.format, marker.format))\n ) {\n delete marker.link;\n }\n }\n}\n\ntype FormatsToMoveUp = 'fontFamily' | 'fontSize' | 'textColor';\nconst formatsToMoveUp: FormatsToMoveUp[] = ['fontFamily', 'fontSize', 'textColor'];\n\n// When all segments are sharing the same segment format (font name, size and color), we can move its format to paragraph\nfunction moveUpSegmentFormat(paragraph: ContentModelParagraph) {\n if (!paragraph.decorator) {\n const segments = paragraph.segments.filter(x => x.segmentType != 'SelectionMarker');\n const target = paragraph.segmentFormat || {};\n let changed = false;\n\n formatsToMoveUp.forEach(key => {\n changed = internalMoveUpSegmentFormat(segments, target, key) || changed;\n });\n\n if (changed) {\n paragraph.segmentFormat = target;\n }\n }\n}\n\nfunction internalMoveUpSegmentFormat(\n segments: ContentModelSegment[],\n target: ContentModelSegmentFormat,\n formatKey: FormatsToMoveUp\n): boolean {\n const firstFormat = segments[0]?.format;\n\n if (\n firstFormat?.[formatKey] &&\n segments.every(segment => segment.format[formatKey] == firstFormat[formatKey])\n ) {\n target[formatKey] = firstFormat[formatKey];\n return true;\n } else {\n return false;\n }\n}\n"]}
package/package.json CHANGED
@@ -3,9 +3,9 @@
3
3
  "description": "Content Model for roosterjs (Under development)",
4
4
  "dependencies": {
5
5
  "tslib": "^2.3.1",
6
- "roosterjs-content-model-types": "^0.26.4"
6
+ "roosterjs-content-model-types": "^0.27.0"
7
7
  },
8
- "version": "0.26.4",
8
+ "version": "0.27.0",
9
9
  "main": "./lib/index.js",
10
10
  "typings": "./lib/index.d.ts",
11
11
  "module": "./lib-mjs/index.js",