roosterjs-content-model-dom 9.52.0 → 9.54.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 (76) hide show
  1. package/lib/domToModel/context/createDomToModelContext.d.ts +1 -1
  2. package/lib/domToModel/context/createDomToModelContext.js.map +1 -1
  3. package/lib/domToModel/processors/formatContainerProcessor.js +3 -1
  4. package/lib/domToModel/processors/formatContainerProcessor.js.map +1 -1
  5. package/lib/formatHandlers/block/directionFormatHandler.js +4 -2
  6. package/lib/formatHandlers/block/directionFormatHandler.js.map +1 -1
  7. package/lib/formatHandlers/common/borderFormatHandler.js +12 -1
  8. package/lib/formatHandlers/common/borderFormatHandler.js.map +1 -1
  9. package/lib/modelApi/common/addTextSegment.js +6 -1
  10. package/lib/modelApi/common/addTextSegment.js.map +1 -1
  11. package/lib/modelApi/common/stripInvisibleUnicode.d.ts +7 -0
  12. package/lib/modelApi/common/stripInvisibleUnicode.js +18 -0
  13. package/lib/modelApi/common/stripInvisibleUnicode.js.map +1 -0
  14. package/lib/modelApi/creators/createSelectionMarker.js +11 -2
  15. package/lib/modelApi/creators/createSelectionMarker.js.map +1 -1
  16. package/lib/modelApi/selection/setSelection.js +32 -6
  17. package/lib/modelApi/selection/setSelection.js.map +1 -1
  18. package/lib/modelToDom/handlers/handleBlockGroupChildren.js +9 -2
  19. package/lib/modelToDom/handlers/handleBlockGroupChildren.js.map +1 -1
  20. package/lib/modelToDom/handlers/handleFormatContainer.js +9 -7
  21. package/lib/modelToDom/handlers/handleFormatContainer.js.map +1 -1
  22. package/lib/modelToDom/handlers/handleListItem.js +3 -1
  23. package/lib/modelToDom/handlers/handleListItem.js.map +1 -1
  24. package/lib/modelToDom/handlers/handleTable.js +3 -1
  25. package/lib/modelToDom/handlers/handleTable.js.map +1 -1
  26. package/lib-amd/domToModel/context/createDomToModelContext.d.ts +1 -1
  27. package/lib-amd/domToModel/context/createDomToModelContext.js.map +1 -1
  28. package/lib-amd/domToModel/processors/formatContainerProcessor.js +3 -1
  29. package/lib-amd/domToModel/processors/formatContainerProcessor.js.map +1 -1
  30. package/lib-amd/formatHandlers/block/directionFormatHandler.js +4 -2
  31. package/lib-amd/formatHandlers/block/directionFormatHandler.js.map +1 -1
  32. package/lib-amd/formatHandlers/common/borderFormatHandler.js +12 -2
  33. package/lib-amd/formatHandlers/common/borderFormatHandler.js.map +1 -1
  34. package/lib-amd/modelApi/common/addTextSegment.js +6 -2
  35. package/lib-amd/modelApi/common/addTextSegment.js.map +1 -1
  36. package/lib-amd/modelApi/common/stripInvisibleUnicode.d.ts +7 -0
  37. package/lib-amd/modelApi/common/stripInvisibleUnicode.js +20 -0
  38. package/lib-amd/modelApi/common/stripInvisibleUnicode.js.map +1 -0
  39. package/lib-amd/modelApi/creators/createSelectionMarker.js +10 -2
  40. package/lib-amd/modelApi/creators/createSelectionMarker.js.map +1 -1
  41. package/lib-amd/modelApi/selection/setSelection.js +32 -7
  42. package/lib-amd/modelApi/selection/setSelection.js.map +1 -1
  43. package/lib-amd/modelToDom/handlers/handleBlockGroupChildren.js +9 -2
  44. package/lib-amd/modelToDom/handlers/handleBlockGroupChildren.js.map +1 -1
  45. package/lib-amd/modelToDom/handlers/handleFormatContainer.js +9 -7
  46. package/lib-amd/modelToDom/handlers/handleFormatContainer.js.map +1 -1
  47. package/lib-amd/modelToDom/handlers/handleListItem.js +3 -1
  48. package/lib-amd/modelToDom/handlers/handleListItem.js.map +1 -1
  49. package/lib-amd/modelToDom/handlers/handleTable.js +3 -1
  50. package/lib-amd/modelToDom/handlers/handleTable.js.map +1 -1
  51. package/lib-mjs/domToModel/context/createDomToModelContext.d.ts +1 -1
  52. package/lib-mjs/domToModel/context/createDomToModelContext.js.map +1 -1
  53. package/lib-mjs/domToModel/processors/formatContainerProcessor.js +3 -1
  54. package/lib-mjs/domToModel/processors/formatContainerProcessor.js.map +1 -1
  55. package/lib-mjs/formatHandlers/block/directionFormatHandler.js +4 -2
  56. package/lib-mjs/formatHandlers/block/directionFormatHandler.js.map +1 -1
  57. package/lib-mjs/formatHandlers/common/borderFormatHandler.js +12 -1
  58. package/lib-mjs/formatHandlers/common/borderFormatHandler.js.map +1 -1
  59. package/lib-mjs/modelApi/common/addTextSegment.js +6 -1
  60. package/lib-mjs/modelApi/common/addTextSegment.js.map +1 -1
  61. package/lib-mjs/modelApi/common/stripInvisibleUnicode.d.ts +7 -0
  62. package/lib-mjs/modelApi/common/stripInvisibleUnicode.js +14 -0
  63. package/lib-mjs/modelApi/common/stripInvisibleUnicode.js.map +1 -0
  64. package/lib-mjs/modelApi/creators/createSelectionMarker.js +11 -2
  65. package/lib-mjs/modelApi/creators/createSelectionMarker.js.map +1 -1
  66. package/lib-mjs/modelApi/selection/setSelection.js +32 -6
  67. package/lib-mjs/modelApi/selection/setSelection.js.map +1 -1
  68. package/lib-mjs/modelToDom/handlers/handleBlockGroupChildren.js +9 -2
  69. package/lib-mjs/modelToDom/handlers/handleBlockGroupChildren.js.map +1 -1
  70. package/lib-mjs/modelToDom/handlers/handleFormatContainer.js +9 -7
  71. package/lib-mjs/modelToDom/handlers/handleFormatContainer.js.map +1 -1
  72. package/lib-mjs/modelToDom/handlers/handleListItem.js +3 -1
  73. package/lib-mjs/modelToDom/handlers/handleListItem.js.map +1 -1
  74. package/lib-mjs/modelToDom/handlers/handleTable.js +3 -1
  75. package/lib-mjs/modelToDom/handlers/handleTable.js.map +1 -1
  76. package/package.json +2 -2
@@ -10,7 +10,7 @@ export declare function createDomToModelContext(editorContext?: EditorContext, .
10
10
  * @param config A full config object to define how to convert DOM tree to Content Model
11
11
  * @param editorContext Context of editor
12
12
  */
13
- export declare function createDomToModelContextWithConfig(config: DomToModelSettings, editorContext?: EditorContext): any;
13
+ export declare function createDomToModelContextWithConfig(config: DomToModelSettings, editorContext?: EditorContext): DomToModelContext;
14
14
  /**
15
15
  * Create Dom to Content Model Config object
16
16
  * @param options All customizations of content model creation
@@ -1 +1 @@
1
- {"version":3,"file":"createDomToModelContext.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/domToModel/context/createDomToModelContext.ts"],"names":[],"mappings":";;;;AAAA,yDAA0D;AAC1D,8DAA6D;AAC7D,oFAGoD;AAgBpD;;;;GAIG;AACH,SAAgB,uBAAuB,CACnC,aAA6B;IAC7B,iBAA4C;SAA5C,UAA4C,EAA5C,qBAA4C,EAA5C,IAA4C;QAA5C,gCAA4C;;IAE5C,OAAO,iCAAiC,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC;AAC7F,CAAC;AALD,0DAKC;AAED;;;;GAIG;AACH,SAAgB,iCAAiC,CAC7C,MAA0B,EAC1B,aAA6B;IAE7B,OAAO,MAAM,CAAC,MAAM,CAChB,EAAE,EACF,aAAa,EACb,gCAAgC,EAAE,EAClC,6BAA6B,CAAC,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,SAAS,CAAC,EACvD,gCAAgC,EAAE,EAClC,MAAM,CACT,CAAC;AACN,CAAC;AAZD,8EAYC;AAED,SAAS,gCAAgC;IACrC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;AACpC,CAAC;AAED,SAAS,6BAA6B,CAAC,SAAmB;IACtD,IAAM,WAAW,GAA4B,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAEnF,OAAO;QACH,WAAW,aAAA;QACX,aAAa,EAAE,EAAE;QAEjB,UAAU,EAAE;YACR,MAAM,EAAE,EAAE;YACV,gBAAgB,EAAE,EAAE;SACvB;KACJ,CAAC;AACN,CAAC;AAED,SAAS,gCAAgC;IACrC,OAAO;QACH,IAAI,EAAE;YACF,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;SACd;QACD,IAAI,EAAE;YACF,MAAM,EAAE,EAAE;SACb;QACD,cAAc,EAAE;YACZ,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;SACd;KACJ,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,sBAAsB,CAClC,OAAyC;IAEzC,OAAO;QACH,iBAAiB,EAAE,MAAM,CAAC,MAAM,OAAb,MAAM,8BACrB,EAAE;YACF,uCAAmB,uBAChB,OAAO,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,iBAAiB,EAApB,CAAoB,CAAC,UAC5C;QACD,aAAa,EAAE,kBAAkB,CAC7B,OAAO,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,oBAAoB,EAAvB,CAAuB,CAAC,EACzC,OAAO,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,uBAAuB,EAA1B,CAA0B,CAAC,CAC/C;QACD,wBAAwB,EAAE,uCAAmB;QAC7C,oBAAoB,8CAAA;QACpB,yBAAyB,EAAE,OAAO,CAAC,IAAI,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,CAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,yBAAyB,CAAA,EAA9B,CAA8B,CAAC;KAC/E,CAAC;AACN,CAAC;AAjBD,wDAiBC;AAED;;;;;;GAMG;AACH,SAAgB,kBAAkB,CAC9B,SAAsD,EACtD,sBAA8E;IAD9E,0BAAA,EAAA,cAAsD;IACtD,uCAAA,EAAA,2BAA8E;IAE9E,IAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,OAAb,MAAM,8BAAQ,EAAE,uBAAK,SAAS,UAAC,CAAC;IAE1D,IAAM,MAAM,GAAG,IAAA,6BAAa,EAAC,oDAA4B,CAAC,CAAC,MAAM,CAC7D,UAAC,MAAM,EAAE,GAAG;;QACR,IAAM,KAAK,GAAG,CAAA,KAAA,oDAA4B,CAAC,GAAG,CAAC;aAC1C,GAAG,CACA,UAAA,SAAS;YACL,OAAA,CAAC,iBAAiB,CAAC,SAAS,CAAC,KAAK,SAAS;gBACvC,CAAC,CAAC,4CAAoB,CAAC,SAAS,CAAC;gBACjC,CAAC,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAsB;QAFxD,CAEwD,CAC/D,CAAA;aACA,MAAM,8DACA,sBAAsB,CAAC,GAAG,CACzB,UAAA,OAAO,YAAI,OAAA,CAAC,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,GAAG,CAAC,mCAAI,EAAE,CAAwB,CAAA,EAAA,CAC3D,UACJ,CAAC;QAEN,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAEpB,OAAO,MAAM,CAAC;IAClB,CAAC,EACD;QACI,IAAI,EAAE,EAAwB;KACL,CAChC,CAAC;IAEF,sBAAsB,CAAC,OAAO,CAAC,UAAA,OAAO;QAClC,IAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,IAAI,EAAE;YACf,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;SAClD;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAClB,CAAC;AArCD,gDAqCC","sourcesContent":["import { defaultProcessorMap } from './defaultProcessors';\nimport { getObjectKeys } from '../../domUtils/getObjectKeys';\nimport {\n defaultFormatKeysPerCategory,\n defaultFormatParsers,\n} from '../../formatHandlers/defaultFormatHandlers';\nimport type {\n ContentModelBlockFormat,\n DomToModelContext,\n DomToModelDecoratorContext,\n DomToModelFormatContext,\n DomToModelOption,\n DomToModelSelectionContext,\n DomToModelSettings,\n EditorContext,\n FormatParser,\n FormatParsers,\n FormatParsersPerCategory,\n TextFormatParser,\n} from 'roosterjs-content-model-types';\n\n/**\n * Create context object for DOM to Content Model conversion\n * @param editorContext Context of editor\n * @param options Option array to customize the DOM to Model conversion behavior\n */\nexport function createDomToModelContext(\n editorContext?: EditorContext,\n ...options: (DomToModelOption | undefined)[]\n): DomToModelContext {\n return createDomToModelContextWithConfig(createDomToModelConfig(options), editorContext);\n}\n\n/**\n * Create context object for DOM to Content Model conversion with an existing configure\n * @param config A full config object to define how to convert DOM tree to Content Model\n * @param editorContext Context of editor\n */\nexport function createDomToModelContextWithConfig(\n config: DomToModelSettings,\n editorContext?: EditorContext\n) {\n return Object.assign(\n {},\n editorContext,\n createDomToModelSelectionContext(),\n createDomToModelFormatContext(editorContext?.isRootRtl),\n createDomToModelDecoratorContext(),\n config\n );\n}\n\nfunction createDomToModelSelectionContext(): DomToModelSelectionContext {\n return { isInSelection: false };\n}\n\nfunction createDomToModelFormatContext(isRootRtl?: boolean): DomToModelFormatContext {\n const blockFormat: ContentModelBlockFormat = isRootRtl ? { direction: 'rtl' } : {};\n\n return {\n blockFormat,\n segmentFormat: {},\n\n listFormat: {\n levels: [],\n threadItemCounts: [],\n },\n };\n}\n\nfunction createDomToModelDecoratorContext(): DomToModelDecoratorContext {\n return {\n link: {\n format: {},\n dataset: {},\n },\n code: {\n format: {},\n },\n blockDecorator: {\n format: {},\n tagName: '',\n },\n };\n}\n\n/**\n * Create Dom to Content Model Config object\n * @param options All customizations of content model creation\n */\nexport function createDomToModelConfig(\n options: (DomToModelOption | undefined)[]\n): DomToModelSettings {\n return {\n elementProcessors: Object.assign(\n {},\n defaultProcessorMap,\n ...options.map(x => x?.processorOverride)\n ),\n formatParsers: buildFormatParsers(\n options.map(x => x?.formatParserOverride),\n options.map(x => x?.additionalFormatParsers)\n ),\n defaultElementProcessors: defaultProcessorMap,\n defaultFormatParsers,\n processNonVisibleElements: options.some(x => !!x?.processNonVisibleElements),\n };\n}\n\n/**\n * @internal Export for test only\n * Build format parsers used by DOM to Content Model conversion\n * @param override\n * @param additionalParsersArray\n * @returns\n */\nexport function buildFormatParsers(\n overrides: (Partial<FormatParsers> | undefined)[] = [],\n additionalParsersArray: (Partial<FormatParsersPerCategory> | undefined)[] = []\n): FormatParsersPerCategory {\n const combinedOverrides = Object.assign({}, ...overrides);\n\n const result = getObjectKeys(defaultFormatKeysPerCategory).reduce(\n (result, key) => {\n const value = defaultFormatKeysPerCategory[key]\n .map(\n formatKey =>\n (combinedOverrides[formatKey] === undefined\n ? defaultFormatParsers[formatKey]\n : combinedOverrides[formatKey]) as FormatParser<any>\n )\n .concat(\n ...additionalParsersArray.map(\n parsers => (parsers?.[key] ?? []) as FormatParser<any>[]\n )\n );\n\n result[key] = value;\n\n return result;\n },\n {\n text: [] as TextFormatParser[],\n } as FormatParsersPerCategory\n );\n\n additionalParsersArray.forEach(parsers => {\n if (parsers?.text) {\n result.text = result.text.concat(parsers.text);\n }\n });\n\n return result;\n}\n"]}
1
+ {"version":3,"file":"createDomToModelContext.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/domToModel/context/createDomToModelContext.ts"],"names":[],"mappings":"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","sourcesContent":["import { defaultProcessorMap } from './defaultProcessors';\nimport { getObjectKeys } from '../../domUtils/getObjectKeys';\nimport {\n defaultFormatKeysPerCategory,\n defaultFormatParsers,\n} from '../../formatHandlers/defaultFormatHandlers';\nimport type {\n ContentModelBlockFormat,\n DomToModelContext,\n DomToModelDecoratorContext,\n DomToModelFormatContext,\n DomToModelOption,\n DomToModelSelectionContext,\n DomToModelSettings,\n EditorContext,\n FormatParser,\n FormatParsers,\n FormatParsersPerCategory,\n TextFormatParser,\n} from 'roosterjs-content-model-types';\n\n/**\n * Create context object for DOM to Content Model conversion\n * @param editorContext Context of editor\n * @param options Option array to customize the DOM to Model conversion behavior\n */\nexport function createDomToModelContext(\n editorContext?: EditorContext,\n ...options: (DomToModelOption | undefined)[]\n): DomToModelContext {\n return createDomToModelContextWithConfig(createDomToModelConfig(options), editorContext);\n}\n\n/**\n * Create context object for DOM to Content Model conversion with an existing configure\n * @param config A full config object to define how to convert DOM tree to Content Model\n * @param editorContext Context of editor\n */\nexport function createDomToModelContextWithConfig(\n config: DomToModelSettings,\n editorContext?: EditorContext\n): DomToModelContext {\n return Object.assign(\n {},\n editorContext,\n createDomToModelSelectionContext(),\n createDomToModelFormatContext(editorContext?.isRootRtl),\n createDomToModelDecoratorContext(),\n config\n );\n}\n\nfunction createDomToModelSelectionContext(): DomToModelSelectionContext {\n return { isInSelection: false };\n}\n\nfunction createDomToModelFormatContext(isRootRtl?: boolean): DomToModelFormatContext {\n const blockFormat: ContentModelBlockFormat = isRootRtl ? { direction: 'rtl' } : {};\n\n return {\n blockFormat,\n segmentFormat: {},\n\n listFormat: {\n levels: [],\n threadItemCounts: [],\n },\n };\n}\n\nfunction createDomToModelDecoratorContext(): DomToModelDecoratorContext {\n return {\n link: {\n format: {},\n dataset: {},\n },\n code: {\n format: {},\n },\n blockDecorator: {\n format: {},\n tagName: '',\n },\n };\n}\n\n/**\n * Create Dom to Content Model Config object\n * @param options All customizations of content model creation\n */\nexport function createDomToModelConfig(\n options: (DomToModelOption | undefined)[]\n): DomToModelSettings {\n return {\n elementProcessors: Object.assign(\n {},\n defaultProcessorMap,\n ...options.map(x => x?.processorOverride)\n ),\n formatParsers: buildFormatParsers(\n options.map(x => x?.formatParserOverride),\n options.map(x => x?.additionalFormatParsers)\n ),\n defaultElementProcessors: defaultProcessorMap,\n defaultFormatParsers,\n processNonVisibleElements: options.some(x => !!x?.processNonVisibleElements),\n };\n}\n\n/**\n * @internal Export for test only\n * Build format parsers used by DOM to Content Model conversion\n * @param override\n * @param additionalParsersArray\n * @returns\n */\nexport function buildFormatParsers(\n overrides: (Partial<FormatParsers> | undefined)[] = [],\n additionalParsersArray: (Partial<FormatParsersPerCategory> | undefined)[] = []\n): FormatParsersPerCategory {\n const combinedOverrides = Object.assign({}, ...overrides);\n\n const result = getObjectKeys(defaultFormatKeysPerCategory).reduce(\n (result, key) => {\n const value = defaultFormatKeysPerCategory[key]\n .map(\n formatKey =>\n (combinedOverrides[formatKey] === undefined\n ? defaultFormatParsers[formatKey]\n : combinedOverrides[formatKey]) as FormatParser<any>\n )\n .concat(\n ...additionalParsersArray.map(\n parsers => (parsers?.[key] ?? []) as FormatParser<any>[]\n )\n );\n\n result[key] = value;\n\n return result;\n },\n {\n text: [] as TextFormatParser[],\n } as FormatParsersPerCategory\n );\n\n additionalParsersArray.forEach(parsers => {\n if (parsers?.text) {\n result.text = result.text.concat(parsers.text);\n }\n });\n\n return result;\n}\n"]}
@@ -55,7 +55,9 @@ var formatContainerProcessorInternal = function (group, element, context, forceF
55
55
  if (element.style.fontSize && parseInt(element.style.fontSize) == 0) {
56
56
  formatContainer.zeroFontSize = true;
57
57
  }
58
- if (shouldFallbackToParagraph(formatContainer) && !forceFormatContainer) {
58
+ if (!context.skipFormatContainerFallbackCheck &&
59
+ shouldFallbackToParagraph(formatContainer) &&
60
+ !forceFormatContainer) {
59
61
  // For DIV container that only has one paragraph child, container style can be merged into paragraph
60
62
  // and no need to have this container
61
63
  var paragraph = formatContainer.blocks[0];
@@ -1 +1 @@
1
- {"version":3,"file":"formatContainerProcessor.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/domToModel/processors/formatContainerProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["import { addBlock } from '../../modelApi/common/addBlock';\nimport { createFormatContainer } from '../../modelApi/creators/createFormatContainer';\nimport { createParagraph } from '../../modelApi/creators/createParagraph';\nimport { getDefaultStyle } from '../utils/getDefaultStyle';\nimport { parseFormat } from '../utils/parseFormat';\nimport { setParagraphNotImplicit } from '../../modelApi/block/setParagraphNotImplicit';\nimport { stackFormat } from '../utils/stackFormat';\nimport type {\n ContentModelBlockGroup,\n ContentModelFormatContainer,\n ContentModelFormatContainerFormat,\n ContentModelParagraph,\n DomToModelContext,\n ElementProcessor,\n MarginFormat,\n PaddingFormat,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport const ContextStyles: (keyof (MarginFormat & PaddingFormat))[] = [\n 'marginLeft',\n 'marginRight',\n 'paddingLeft',\n 'paddingRight',\n];\n\n/**\n * Content Model Element Processor for format container elements (e.g., blockquote, div)\n * Processes elements that create FormatContainer blocks in the content model.\n * This processor can be used in processorOverride to customize how specific elements are processed.\n * @param group The parent block group\n * @param element The DOM element to process\n * @param context DOM to Content Model context\n */\nexport const formatContainerProcessor: ElementProcessor<HTMLElement> = (\n group,\n element,\n context\n) => {\n formatContainerProcessorInternal(group, element, context, false /* forceFormatContainer */);\n};\n\n/**\n * @internal\n */\nexport const forceFormatContainerProcessor: ElementProcessor<HTMLElement> = (\n group,\n element,\n context\n) => {\n formatContainerProcessorInternal(group, element, context, true /* forceFormatContainer */);\n};\n\nconst formatContainerProcessorInternal = (\n group: ContentModelBlockGroup,\n element: HTMLElement,\n context: DomToModelContext,\n forceFormatContainer: boolean\n) => {\n stackFormat(context, { segment: 'shallowCloneForBlock', paragraph: 'shallowClone' }, () => {\n parseFormat(element, context.formatParsers.block, context.blockFormat, context);\n parseFormat(element, context.formatParsers.segmentOnBlock, context.segmentFormat, context);\n\n const format: ContentModelFormatContainerFormat = {\n ...context.blockFormat,\n };\n\n parseFormat(element, context.formatParsers.container, format, context);\n\n const tagName =\n getDefaultStyle(element).display == 'block' ? element.tagName.toLowerCase() : 'div';\n const formatContainer = createFormatContainer(tagName, format);\n\n // It is possible to inherit margin left/right styles from parent DIV or other containers,\n // since we are going into a deeper level of format container now,\n // the container will render these styles so no need to keep them in context format\n ContextStyles.forEach(style => {\n delete context.blockFormat[style];\n });\n\n context.elementProcessors.child(formatContainer, element, context);\n\n if (element.style.fontSize && parseInt(element.style.fontSize) == 0) {\n formatContainer.zeroFontSize = true;\n }\n\n if (shouldFallbackToParagraph(formatContainer) && !forceFormatContainer) {\n // For DIV container that only has one paragraph child, container style can be merged into paragraph\n // and no need to have this container\n const paragraph = formatContainer.blocks[0] as ContentModelParagraph;\n\n if (formatContainer.zeroFontSize) {\n paragraph.segmentFormat = Object.assign({}, paragraph.segmentFormat, {\n fontSize: '0',\n });\n }\n\n Object.assign(paragraph.format, formatContainer.format);\n setParagraphNotImplicit(paragraph);\n addBlock(group, paragraph);\n } else {\n addBlock(group, formatContainer);\n }\n });\n\n addBlock(group, createParagraph(true /*isImplicit*/, context.blockFormat));\n};\n\nfunction shouldFallbackToParagraph(formatContainer: ContentModelFormatContainer) {\n const firstChild = formatContainer.blocks[0];\n\n return (\n formatContainer.tagName == 'div' &&\n formatContainer.blocks.length == 1 &&\n firstChild.blockType == 'Paragraph' &&\n firstChild.isImplicit\n );\n}\n"]}
1
+ {"version":3,"file":"formatContainerProcessor.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/domToModel/processors/formatContainerProcessor.ts"],"names":[],"mappings":";;;;AAAA,2DAA0D;AAC1D,uFAAsF;AACtF,2EAA0E;AAC1E,4DAA2D;AAC3D,oDAAmD;AACnD,wFAAuF;AACvF,oDAAmD;AAYnD;;GAEG;AACU,QAAA,aAAa,GAA6C;IACnE,YAAY;IACZ,aAAa;IACb,aAAa;IACb,cAAc;CACjB,CAAC;AAEF;;;;;;;GAOG;AACI,IAAM,wBAAwB,GAAkC,UACnE,KAAK,EACL,OAAO,EACP,OAAO;IAEP,gCAAgC,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAChG,CAAC,CAAC;AANW,QAAA,wBAAwB,4BAMnC;AAEF;;GAEG;AACI,IAAM,6BAA6B,GAAkC,UACxE,KAAK,EACL,OAAO,EACP,OAAO;IAEP,gCAAgC,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,0BAA0B,CAAC,CAAC;AAC/F,CAAC,CAAC;AANW,QAAA,6BAA6B,iCAMxC;AAEF,IAAM,gCAAgC,GAAG,UACrC,KAA6B,EAC7B,OAAoB,EACpB,OAA0B,EAC1B,oBAA6B;IAE7B,IAAA,yBAAW,EAAC,OAAO,EAAE,EAAE,OAAO,EAAE,sBAAsB,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE;QACjF,IAAA,yBAAW,EAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAChF,IAAA,yBAAW,EAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,cAAc,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAE3F,IAAM,MAAM,6BACL,OAAO,CAAC,WAAW,CACzB,CAAC;QAEF,IAAA,yBAAW,EAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAEvE,IAAM,OAAO,GACT,IAAA,iCAAe,EAAC,OAAO,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QACxF,IAAM,eAAe,GAAG,IAAA,6CAAqB,EAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAE/D,0FAA0F;QAC1F,kEAAkE;QAClE,mFAAmF;QACnF,qBAAa,CAAC,OAAO,CAAC,UAAA,KAAK;YACvB,OAAO,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,eAAe,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAEnE,IAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,IAAI,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;YACjE,eAAe,CAAC,YAAY,GAAG,IAAI,CAAC;SACvC;QAED,IACI,CAAC,OAAO,CAAC,gCAAgC;YACzC,yBAAyB,CAAC,eAAe,CAAC;YAC1C,CAAC,oBAAoB,EACvB;YACE,oGAAoG;YACpG,qCAAqC;YACrC,IAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAA0B,CAAC;YAErE,IAAI,eAAe,CAAC,YAAY,EAAE;gBAC9B,SAAS,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,CAAC,aAAa,EAAE;oBACjE,QAAQ,EAAE,GAAG;iBAChB,CAAC,CAAC;aACN;YAED,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;YACxD,IAAA,iDAAuB,EAAC,SAAS,CAAC,CAAC;YACnC,IAAA,mBAAQ,EAAC,KAAK,EAAE,SAAS,CAAC,CAAC;SAC9B;aAAM;YACH,IAAA,mBAAQ,EAAC,KAAK,EAAE,eAAe,CAAC,CAAC;SACpC;IACL,CAAC,CAAC,CAAC;IAEH,IAAA,mBAAQ,EAAC,KAAK,EAAE,IAAA,iCAAe,EAAC,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;AAC/E,CAAC,CAAC;AAEF,SAAS,yBAAyB,CAAC,eAA4C;IAC3E,IAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAE7C,OAAO,CACH,eAAe,CAAC,OAAO,IAAI,KAAK;QAChC,eAAe,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC;QAClC,UAAU,CAAC,SAAS,IAAI,WAAW;QACnC,UAAU,CAAC,UAAU,CACxB,CAAC;AACN,CAAC","sourcesContent":["import { addBlock } from '../../modelApi/common/addBlock';\nimport { createFormatContainer } from '../../modelApi/creators/createFormatContainer';\nimport { createParagraph } from '../../modelApi/creators/createParagraph';\nimport { getDefaultStyle } from '../utils/getDefaultStyle';\nimport { parseFormat } from '../utils/parseFormat';\nimport { setParagraphNotImplicit } from '../../modelApi/block/setParagraphNotImplicit';\nimport { stackFormat } from '../utils/stackFormat';\nimport type {\n ContentModelBlockGroup,\n ContentModelFormatContainer,\n ContentModelFormatContainerFormat,\n ContentModelParagraph,\n DomToModelContext,\n ElementProcessor,\n MarginFormat,\n PaddingFormat,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport const ContextStyles: (keyof (MarginFormat & PaddingFormat))[] = [\n 'marginLeft',\n 'marginRight',\n 'paddingLeft',\n 'paddingRight',\n];\n\n/**\n * Content Model Element Processor for format container elements (e.g., blockquote, div)\n * Processes elements that create FormatContainer blocks in the content model.\n * This processor can be used in processorOverride to customize how specific elements are processed.\n * @param group The parent block group\n * @param element The DOM element to process\n * @param context DOM to Content Model context\n */\nexport const formatContainerProcessor: ElementProcessor<HTMLElement> = (\n group,\n element,\n context\n) => {\n formatContainerProcessorInternal(group, element, context, false /* forceFormatContainer */);\n};\n\n/**\n * @internal\n */\nexport const forceFormatContainerProcessor: ElementProcessor<HTMLElement> = (\n group,\n element,\n context\n) => {\n formatContainerProcessorInternal(group, element, context, true /* forceFormatContainer */);\n};\n\nconst formatContainerProcessorInternal = (\n group: ContentModelBlockGroup,\n element: HTMLElement,\n context: DomToModelContext,\n forceFormatContainer: boolean\n) => {\n stackFormat(context, { segment: 'shallowCloneForBlock', paragraph: 'shallowClone' }, () => {\n parseFormat(element, context.formatParsers.block, context.blockFormat, context);\n parseFormat(element, context.formatParsers.segmentOnBlock, context.segmentFormat, context);\n\n const format: ContentModelFormatContainerFormat = {\n ...context.blockFormat,\n };\n\n parseFormat(element, context.formatParsers.container, format, context);\n\n const tagName =\n getDefaultStyle(element).display == 'block' ? element.tagName.toLowerCase() : 'div';\n const formatContainer = createFormatContainer(tagName, format);\n\n // It is possible to inherit margin left/right styles from parent DIV or other containers,\n // since we are going into a deeper level of format container now,\n // the container will render these styles so no need to keep them in context format\n ContextStyles.forEach(style => {\n delete context.blockFormat[style];\n });\n\n context.elementProcessors.child(formatContainer, element, context);\n\n if (element.style.fontSize && parseInt(element.style.fontSize) == 0) {\n formatContainer.zeroFontSize = true;\n }\n\n if (\n !context.skipFormatContainerFallbackCheck &&\n shouldFallbackToParagraph(formatContainer) &&\n !forceFormatContainer\n ) {\n // For DIV container that only has one paragraph child, container style can be merged into paragraph\n // and no need to have this container\n const paragraph = formatContainer.blocks[0] as ContentModelParagraph;\n\n if (formatContainer.zeroFontSize) {\n paragraph.segmentFormat = Object.assign({}, paragraph.segmentFormat, {\n fontSize: '0',\n });\n }\n\n Object.assign(paragraph.format, formatContainer.format);\n setParagraphNotImplicit(paragraph);\n addBlock(group, paragraph);\n } else {\n addBlock(group, formatContainer);\n }\n });\n\n addBlock(group, createParagraph(true /*isImplicit*/, context.blockFormat));\n};\n\nfunction shouldFallbackToParagraph(formatContainer: ContentModelFormatContainer) {\n const firstChild = formatContainer.blocks[0];\n\n return (\n formatContainer.tagName == 'div' &&\n formatContainer.blocks.length == 1 &&\n firstChild.blockType == 'Paragraph' &&\n firstChild.isImplicit\n );\n}\n"]}
@@ -12,11 +12,13 @@ exports.directionFormatHandler = {
12
12
  format.direction = dir == 'rtl' ? 'rtl' : 'ltr';
13
13
  }
14
14
  },
15
- apply: function (format, element) {
15
+ apply: function (format, element, context) {
16
16
  if (format.direction) {
17
17
  element.style.direction = format.direction;
18
18
  }
19
- if (format.direction == 'rtl' && (0, isElementOfType_1.isElementOfType)(element, 'table')) {
19
+ if (format.direction == 'rtl' &&
20
+ (0, isElementOfType_1.isElementOfType)(element, 'table') &&
21
+ context.implicitFormat.direction != 'rtl') {
20
22
  element.style.justifySelf = 'flex-end';
21
23
  }
22
24
  },
@@ -1 +1 @@
1
- {"version":3,"file":"directionFormatHandler.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/formatHandlers/block/directionFormatHandler.ts"],"names":[],"mappings":";;;AAAA,kEAAiE;AAIjE;;GAEG;AACU,QAAA,sBAAsB,GAAmC;IAClE,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,YAAY;QACpC,IAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,IAAI,YAAY,CAAC,SAAS,CAAC;QAE7E,IAAI,GAAG,EAAE;YACL,MAAM,CAAC,SAAS,GAAG,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;SACnD;IACL,CAAC;IACD,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,IAAI,MAAM,CAAC,SAAS,EAAE;YAClB,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;SAC9C;QAED,IAAI,MAAM,CAAC,SAAS,IAAI,KAAK,IAAI,IAAA,iCAAe,EAAC,OAAO,EAAE,OAAO,CAAC,EAAE;YAChE,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG,UAAU,CAAC;SAC1C;IACL,CAAC;CACJ,CAAC","sourcesContent":["import { isElementOfType } from '../../domUtils/isElementOfType';\nimport type { DirectionFormat } from 'roosterjs-content-model-types';\nimport type { FormatHandler } from '../FormatHandler';\n\n/**\n * @internal\n */\nexport const directionFormatHandler: FormatHandler<DirectionFormat> = {\n parse: (format, element, _, defaultStyle) => {\n const dir = element.style.direction || element.dir || defaultStyle.direction;\n\n if (dir) {\n format.direction = dir == 'rtl' ? 'rtl' : 'ltr';\n }\n },\n apply: (format, element) => {\n if (format.direction) {\n element.style.direction = format.direction;\n }\n\n if (format.direction == 'rtl' && isElementOfType(element, 'table')) {\n element.style.justifySelf = 'flex-end';\n }\n },\n};\n"]}
1
+ {"version":3,"file":"directionFormatHandler.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/formatHandlers/block/directionFormatHandler.ts"],"names":[],"mappings":";;;AAAA,kEAAiE;AAIjE;;GAEG;AACU,QAAA,sBAAsB,GAAmC;IAClE,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,YAAY;QACpC,IAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,IAAI,YAAY,CAAC,SAAS,CAAC;QAE7E,IAAI,GAAG,EAAE;YACL,MAAM,CAAC,SAAS,GAAG,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;SACnD;IACL,CAAC;IACD,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO,EAAE,OAAO;QAC5B,IAAI,MAAM,CAAC,SAAS,EAAE;YAClB,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;SAC9C;QAED,IACI,MAAM,CAAC,SAAS,IAAI,KAAK;YACzB,IAAA,iCAAe,EAAC,OAAO,EAAE,OAAO,CAAC;YACjC,OAAO,CAAC,cAAc,CAAC,SAAS,IAAI,KAAK,EAC3C;YACE,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG,UAAU,CAAC;SAC1C;IACL,CAAC;CACJ,CAAC","sourcesContent":["import { isElementOfType } from '../../domUtils/isElementOfType';\nimport type { DirectionFormat } from 'roosterjs-content-model-types';\nimport type { FormatHandler } from '../FormatHandler';\n\n/**\n * @internal\n */\nexport const directionFormatHandler: FormatHandler<DirectionFormat> = {\n parse: (format, element, _, defaultStyle) => {\n const dir = element.style.direction || element.dir || defaultStyle.direction;\n\n if (dir) {\n format.direction = dir == 'rtl' ? 'rtl' : 'ltr';\n }\n },\n apply: (format, element, context) => {\n if (format.direction) {\n element.style.direction = format.direction;\n }\n\n if (\n format.direction == 'rtl' &&\n isElementOfType(element, 'table') &&\n context.implicitFormat.direction != 'rtl'\n ) {\n element.style.justifySelf = 'flex-end';\n }\n },\n};\n"]}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.borderFormatHandler = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  var borderKeys_1 = require("../utils/borderKeys");
6
+ var borderValues_1 = require("../../domUtils/style/borderValues");
6
7
  // This array needs to match BorderKeys array
7
8
  var BorderWidthKeys = [
8
9
  'borderTopWidth',
@@ -31,7 +32,17 @@ exports.borderFormatHandler = {
31
32
  width = '0px';
32
33
  }
33
34
  if (value && width != defaultWidth) {
34
- format[key] = value == 'none' ? '' : value;
35
+ var result = value;
36
+ if (result.includes('initial')) {
37
+ // Remove 'initial' from the last part (color) of the border value
38
+ // since browsers ignore it when setting the inline style property
39
+ var border = (0, borderValues_1.extractBorderValues)(value);
40
+ if (border.color === 'initial') {
41
+ border.color = '';
42
+ }
43
+ result = (0, borderValues_1.combineBorderValue)(border);
44
+ }
45
+ format[key] = result == 'none' ? '' : result;
35
46
  }
36
47
  });
37
48
  var borderRadius = element.style.borderRadius;
@@ -1 +1 @@
1
- {"version":3,"file":"borderFormatHandler.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/formatHandlers/common/borderFormatHandler.ts"],"names":[],"mappings":";;;;AAAA,kDAAiD;AAIjD,6CAA6C;AAC7C,IAAM,eAAe,GAAkC;IACnD,gBAAgB;IAChB,kBAAkB;IAClB,mBAAmB;IACnB,iBAAiB;CACpB,CAAC;AAEF,IAAM,gBAAgB,GAAuD;IACzE,qBAAqB;IACrB,sBAAsB;IACtB,wBAAwB;IACxB,yBAAyB;CAC5B,CAAC;AAEF,IAAM,OAAO,iFAAO,uBAAU,+BAAK,gBAAgB,SAAC,CAAC;AAErD;;GAEG;AACU,QAAA,mBAAmB,GAAgC;IAC5D,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,YAAY;QACpC,uBAAU,CAAC,OAAO,CAAC,UAAC,GAAG,EAAE,CAAC;;YACtB,IAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACjC,IAAM,YAAY,GAAG,MAAA,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,mCAAI,KAAK,CAAC;YAC/D,IAAI,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;YAE9C,IAAI,KAAK,IAAI,GAAG,EAAE;gBACd,KAAK,GAAG,KAAK,CAAC;aACjB;YAED,IAAI,KAAK,IAAI,KAAK,IAAI,YAAY,EAAE;gBAChC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;aAC9C;QACL,CAAC,CAAC,CAAC;QAEH,IAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC;QAEhD,IAAI,YAAY,EAAE;YACd,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC;SACtC;aAAM;YACH,gBAAgB,CAAC,OAAO,CAAC,UAAA,GAAG;gBACxB,IAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAEjC,IAAI,KAAK,EAAE;oBACP,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;iBACvB;YACL,CAAC,CAAC,CAAC;SACN;IACL,CAAC;IACD,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,OAAO,CAAC,OAAO,CAAC,UAAA,GAAG;YACf,IAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAE1B,IAAI,KAAK,EAAE;gBACP,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;aAC9B;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,YAAY,EAAE;YACrB,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;SACpD;IACL,CAAC;CACJ,CAAC","sourcesContent":["import { BorderKeys } from '../utils/borderKeys';\nimport type { BorderFormat } from 'roosterjs-content-model-types';\nimport type { FormatHandler } from '../FormatHandler';\n\n// This array needs to match BorderKeys array\nconst BorderWidthKeys: (keyof CSSStyleDeclaration)[] = [\n 'borderTopWidth',\n 'borderRightWidth',\n 'borderBottomWidth',\n 'borderLeftWidth',\n];\n\nconst BorderRadiusKeys: (keyof BorderFormat & keyof CSSStyleDeclaration)[] = [\n 'borderTopLeftRadius',\n 'borderTopRightRadius',\n 'borderBottomLeftRadius',\n 'borderBottomRightRadius',\n];\n\nconst AllKeys = [...BorderKeys, ...BorderRadiusKeys];\n\n/**\n * @internal\n */\nexport const borderFormatHandler: FormatHandler<BorderFormat> = {\n parse: (format, element, _, defaultStyle) => {\n BorderKeys.forEach((key, i) => {\n const value = element.style[key];\n const defaultWidth = defaultStyle[BorderWidthKeys[i]] ?? '0px';\n let width = element.style[BorderWidthKeys[i]];\n\n if (width == '0') {\n width = '0px';\n }\n\n if (value && width != defaultWidth) {\n format[key] = value == 'none' ? '' : value;\n }\n });\n\n const borderRadius = element.style.borderRadius;\n\n if (borderRadius) {\n format.borderRadius = borderRadius;\n } else {\n BorderRadiusKeys.forEach(key => {\n const value = element.style[key];\n\n if (value) {\n format[key] = value;\n }\n });\n }\n },\n apply: (format, element) => {\n AllKeys.forEach(key => {\n const value = format[key];\n\n if (value) {\n element.style[key] = value;\n }\n });\n\n if (format.borderRadius) {\n element.style.borderRadius = format.borderRadius;\n }\n },\n};\n"]}
1
+ {"version":3,"file":"borderFormatHandler.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/formatHandlers/common/borderFormatHandler.ts"],"names":[],"mappings":";;;;AAAA,kDAAiD;AAEjD,kEAA4F;AAG5F,6CAA6C;AAC7C,IAAM,eAAe,GAAkC;IACnD,gBAAgB;IAChB,kBAAkB;IAClB,mBAAmB;IACnB,iBAAiB;CACpB,CAAC;AAEF,IAAM,gBAAgB,GAAuD;IACzE,qBAAqB;IACrB,sBAAsB;IACtB,wBAAwB;IACxB,yBAAyB;CAC5B,CAAC;AAEF,IAAM,OAAO,iFAAO,uBAAU,+BAAK,gBAAgB,SAAC,CAAC;AAErD;;GAEG;AACU,QAAA,mBAAmB,GAAgC;IAC5D,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,YAAY;QACpC,uBAAU,CAAC,OAAO,CAAC,UAAC,GAAG,EAAE,CAAC;;YACtB,IAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACjC,IAAM,YAAY,GAAG,MAAA,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,mCAAI,KAAK,CAAC;YAC/D,IAAI,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;YAE9C,IAAI,KAAK,IAAI,GAAG,EAAE;gBACd,KAAK,GAAG,KAAK,CAAC;aACjB;YAED,IAAI,KAAK,IAAI,KAAK,IAAI,YAAY,EAAE;gBAChC,IAAI,MAAM,GAAG,KAAK,CAAC;gBACnB,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE;oBAC5B,kEAAkE;oBAClE,kEAAkE;oBAClE,IAAM,MAAM,GAAG,IAAA,kCAAmB,EAAC,KAAK,CAAC,CAAC;oBAC1C,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE;wBAC5B,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC;qBACrB;oBACD,MAAM,GAAG,IAAA,iCAAkB,EAAC,MAAM,CAAC,CAAC;iBACvC;gBACD,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;aAChD;QACL,CAAC,CAAC,CAAC;QAEH,IAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC;QAEhD,IAAI,YAAY,EAAE;YACd,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC;SACtC;aAAM;YACH,gBAAgB,CAAC,OAAO,CAAC,UAAA,GAAG;gBACxB,IAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAEjC,IAAI,KAAK,EAAE;oBACP,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;iBACvB;YACL,CAAC,CAAC,CAAC;SACN;IACL,CAAC;IACD,KAAK,EAAE,UAAC,MAAM,EAAE,OAAO;QACnB,OAAO,CAAC,OAAO,CAAC,UAAA,GAAG;YACf,IAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAE1B,IAAI,KAAK,EAAE;gBACP,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;aAC9B;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,YAAY,EAAE;YACrB,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;SACpD;IACL,CAAC;CACJ,CAAC","sourcesContent":["import { BorderKeys } from '../utils/borderKeys';\nimport type { BorderFormat } from 'roosterjs-content-model-types';\nimport { combineBorderValue, extractBorderValues } from '../../domUtils/style/borderValues';\nimport type { FormatHandler } from '../FormatHandler';\n\n// This array needs to match BorderKeys array\nconst BorderWidthKeys: (keyof CSSStyleDeclaration)[] = [\n 'borderTopWidth',\n 'borderRightWidth',\n 'borderBottomWidth',\n 'borderLeftWidth',\n];\n\nconst BorderRadiusKeys: (keyof BorderFormat & keyof CSSStyleDeclaration)[] = [\n 'borderTopLeftRadius',\n 'borderTopRightRadius',\n 'borderBottomLeftRadius',\n 'borderBottomRightRadius',\n];\n\nconst AllKeys = [...BorderKeys, ...BorderRadiusKeys];\n\n/**\n * @internal\n */\nexport const borderFormatHandler: FormatHandler<BorderFormat> = {\n parse: (format, element, _, defaultStyle) => {\n BorderKeys.forEach((key, i) => {\n const value = element.style[key];\n const defaultWidth = defaultStyle[BorderWidthKeys[i]] ?? '0px';\n let width = element.style[BorderWidthKeys[i]];\n\n if (width == '0') {\n width = '0px';\n }\n\n if (value && width != defaultWidth) {\n let result = value;\n if (result.includes('initial')) {\n // Remove 'initial' from the last part (color) of the border value\n // since browsers ignore it when setting the inline style property\n const border = extractBorderValues(value);\n if (border.color === 'initial') {\n border.color = '';\n }\n result = combineBorderValue(border);\n }\n format[key] = result == 'none' ? '' : result;\n }\n });\n\n const borderRadius = element.style.borderRadius;\n\n if (borderRadius) {\n format.borderRadius = borderRadius;\n } else {\n BorderRadiusKeys.forEach(key => {\n const value = element.style[key];\n\n if (value) {\n format[key] = value;\n }\n });\n }\n },\n apply: (format, element) => {\n AllKeys.forEach(key => {\n const value = format[key];\n\n if (value) {\n element.style[key] = value;\n }\n });\n\n if (format.borderRadius) {\n element.style.borderRadius = format.borderRadius;\n }\n },\n};\n"]}
@@ -7,6 +7,7 @@ var createText_1 = require("../creators/createText");
7
7
  var ensureParagraph_1 = require("./ensureParagraph");
8
8
  var hasSpacesOnly_1 = require("./hasSpacesOnly");
9
9
  var isWhiteSpacePreserved_1 = require("../../domUtils/isWhiteSpacePreserved");
10
+ var stripInvisibleUnicode_1 = require("./stripInvisibleUnicode");
10
11
  /**
11
12
  * Add a new text segment to current paragraph
12
13
  * @param group Current BlockGroup that the paragraph belong to
@@ -22,7 +23,11 @@ function addTextSegment(group, text, context) {
22
23
  if (!(0, hasSpacesOnly_1.hasSpacesOnly)(text) ||
23
24
  ((_a = paragraph === null || paragraph === void 0 ? void 0 : paragraph.segments.length) !== null && _a !== void 0 ? _a : 0) > 0 ||
24
25
  (0, isWhiteSpacePreserved_1.isWhiteSpacePreserved)(paragraph === null || paragraph === void 0 ? void 0 : paragraph.format.whiteSpace)) {
25
- textModel = (0, createText_1.createText)(text, context.segmentFormat);
26
+ var filteredText = context.experimentalFeatures &&
27
+ context.experimentalFeatures.indexOf('FilterInvisibleUnicode') > -1
28
+ ? (0, stripInvisibleUnicode_1.stripInvisibleUnicode)(text)
29
+ : text;
30
+ textModel = (0, createText_1.createText)(filteredText, context.segmentFormat);
26
31
  if (context.isInSelection) {
27
32
  textModel.isSelected = true;
28
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"addTextSegment.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelApi/common/addTextSegment.ts"],"names":[],"mappings":";;;AAAA,iDAAgD;AAChD,2CAA0C;AAC1C,qDAAoD;AACpD,qDAAoD;AACpD,iDAAgD;AAChD,8EAA6E;AAO7E;;;;;;GAMG;AACH,SAAgB,cAAc,CAC1B,KAA6B,EAC7B,IAAY,EACZ,OAA0B;;IAE1B,IAAI,SAAuC,CAAC;IAE5C,IAAI,IAAI,EAAE;QACN,IAAM,SAAS,GAAG,IAAA,iCAAe,EAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;QAE9D,IACI,CAAC,IAAA,6BAAa,EAAC,IAAI,CAAC;YACpB,CAAC,MAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,QAAQ,CAAC,MAAM,mCAAI,CAAC,CAAC,GAAG,CAAC;YACrC,IAAA,6CAAqB,EAAC,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,MAAM,CAAC,UAAU,CAAC,EACrD;YACE,SAAS,GAAG,IAAA,uBAAU,EAAC,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;YAEpD,IAAI,OAAO,CAAC,aAAa,EAAE;gBACvB,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC;aAC/B;YAED,IAAA,6BAAa,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAElC,IAAA,uBAAU,EAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;SACrD;KACJ;IAED,OAAO,SAAS,CAAC;AACrB,CAAC;AA5BD,wCA4BC","sourcesContent":["import { addDecorators } from './addDecorators';\nimport { addSegment } from './addSegment';\nimport { createText } from '../creators/createText';\nimport { ensureParagraph } from './ensureParagraph';\nimport { hasSpacesOnly } from './hasSpacesOnly';\nimport { isWhiteSpacePreserved } from '../../domUtils/isWhiteSpacePreserved';\nimport type {\n ContentModelBlockGroup,\n ContentModelText,\n DomToModelContext,\n} from 'roosterjs-content-model-types';\n\n/**\n * Add a new text segment to current paragraph\n * @param group Current BlockGroup that the paragraph belong to\n * @param text Text content of the text segment\n * @param context Current DOM to Model context\n * @returns A new Text segment, or undefined if the input text is empty\n */\nexport function addTextSegment(\n group: ContentModelBlockGroup,\n text: string,\n context: DomToModelContext\n): ContentModelText | undefined {\n let textModel: ContentModelText | undefined;\n\n if (text) {\n const paragraph = ensureParagraph(group, context.blockFormat);\n\n if (\n !hasSpacesOnly(text) ||\n (paragraph?.segments.length ?? 0) > 0 ||\n isWhiteSpacePreserved(paragraph?.format.whiteSpace)\n ) {\n textModel = createText(text, context.segmentFormat);\n\n if (context.isInSelection) {\n textModel.isSelected = true;\n }\n\n addDecorators(textModel, context);\n\n addSegment(group, textModel, context.blockFormat);\n }\n }\n\n return textModel;\n}\n"]}
1
+ {"version":3,"file":"addTextSegment.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelApi/common/addTextSegment.ts"],"names":[],"mappings":";;;AAAA,iDAAgD;AAChD,2CAA0C;AAC1C,qDAAoD;AACpD,qDAAoD;AACpD,iDAAgD;AAChD,8EAA6E;AAC7E,iEAAgE;AAOhE;;;;;;GAMG;AACH,SAAgB,cAAc,CAC1B,KAA6B,EAC7B,IAAY,EACZ,OAA0B;;IAE1B,IAAI,SAAuC,CAAC;IAE5C,IAAI,IAAI,EAAE;QACN,IAAM,SAAS,GAAG,IAAA,iCAAe,EAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;QAE9D,IACI,CAAC,IAAA,6BAAa,EAAC,IAAI,CAAC;YACpB,CAAC,MAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,QAAQ,CAAC,MAAM,mCAAI,CAAC,CAAC,GAAG,CAAC;YACrC,IAAA,6CAAqB,EAAC,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,MAAM,CAAC,UAAU,CAAC,EACrD;YACE,IAAM,YAAY,GACd,OAAO,CAAC,oBAAoB;gBAC5B,OAAO,CAAC,oBAAoB,CAAC,OAAO,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC;gBAC/D,CAAC,CAAC,IAAA,6CAAqB,EAAC,IAAI,CAAC;gBAC7B,CAAC,CAAC,IAAI,CAAC;YAEf,SAAS,GAAG,IAAA,uBAAU,EAAC,YAAY,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;YAE5D,IAAI,OAAO,CAAC,aAAa,EAAE;gBACvB,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC;aAC/B;YAED,IAAA,6BAAa,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAElC,IAAA,uBAAU,EAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;SACrD;KACJ;IAED,OAAO,SAAS,CAAC;AACrB,CAAC;AAlCD,wCAkCC","sourcesContent":["import { addDecorators } from './addDecorators';\nimport { addSegment } from './addSegment';\nimport { createText } from '../creators/createText';\nimport { ensureParagraph } from './ensureParagraph';\nimport { hasSpacesOnly } from './hasSpacesOnly';\nimport { isWhiteSpacePreserved } from '../../domUtils/isWhiteSpacePreserved';\nimport { stripInvisibleUnicode } from './stripInvisibleUnicode';\nimport type {\n ContentModelBlockGroup,\n ContentModelText,\n DomToModelContext,\n} from 'roosterjs-content-model-types';\n\n/**\n * Add a new text segment to current paragraph\n * @param group Current BlockGroup that the paragraph belong to\n * @param text Text content of the text segment\n * @param context Current DOM to Model context\n * @returns A new Text segment, or undefined if the input text is empty\n */\nexport function addTextSegment(\n group: ContentModelBlockGroup,\n text: string,\n context: DomToModelContext\n): ContentModelText | undefined {\n let textModel: ContentModelText | undefined;\n\n if (text) {\n const paragraph = ensureParagraph(group, context.blockFormat);\n\n if (\n !hasSpacesOnly(text) ||\n (paragraph?.segments.length ?? 0) > 0 ||\n isWhiteSpacePreserved(paragraph?.format.whiteSpace)\n ) {\n const filteredText =\n context.experimentalFeatures &&\n context.experimentalFeatures.indexOf('FilterInvisibleUnicode') > -1\n ? stripInvisibleUnicode(text)\n : text;\n\n textModel = createText(filteredText, context.segmentFormat);\n\n if (context.isInSelection) {\n textModel.isSelected = true;\n }\n\n addDecorators(textModel, context);\n\n addSegment(group, textModel, context.blockFormat);\n }\n }\n\n return textModel;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @internal
3
+ * Strip invisible unicode characters from the given string
4
+ * @param value The string to be processed
5
+ * @returns The string with invisible unicode characters removed
6
+ */
7
+ export declare function stripInvisibleUnicode(value: string): string;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stripInvisibleUnicode = void 0;
4
+ // According to https://embracethered.com/blog/posts/2024/hiding-and-finding-text-with-unicode-tags/
5
+ // there are some invisible unicode characters in the range of U+E0000 to U+EFFFF, which are used for hiding text in HTML.
6
+ // We need to strip them out before processing the pasted content, otherwise they will be treated as normal text and cause unexpected behavior.
7
+ var INVISIBLE_UNICODE_REGEX = /[\u{E0000}-\u{EFFFF}]/gu;
8
+ /**
9
+ * @internal
10
+ * Strip invisible unicode characters from the given string
11
+ * @param value The string to be processed
12
+ * @returns The string with invisible unicode characters removed
13
+ */
14
+ function stripInvisibleUnicode(value) {
15
+ return value.replace(INVISIBLE_UNICODE_REGEX, '');
16
+ }
17
+ exports.stripInvisibleUnicode = stripInvisibleUnicode;
18
+ //# sourceMappingURL=stripInvisibleUnicode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stripInvisibleUnicode.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelApi/common/stripInvisibleUnicode.ts"],"names":[],"mappings":";;;AAAA,oGAAoG;AACpG,0HAA0H;AAC1H,+IAA+I;AAC/I,IAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAE1D;;;;;GAKG;AACH,SAAgB,qBAAqB,CAAC,KAAa;IAC/C,OAAO,KAAK,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAFD,sDAEC","sourcesContent":["// According to https://embracethered.com/blog/posts/2024/hiding-and-finding-text-with-unicode-tags/\n// there are some invisible unicode characters in the range of U+E0000 to U+EFFFF, which are used for hiding text in HTML.\n// We need to strip them out before processing the pasted content, otherwise they will be treated as normal text and cause unexpected behavior.\nconst INVISIBLE_UNICODE_REGEX = /[\\u{E0000}-\\u{EFFFF}]/gu;\n\n/**\n * @internal\n * Strip invisible unicode characters from the given string\n * @param value The string to be processed\n * @returns The string with invisible unicode characters removed\n */\nexport function stripInvisibleUnicode(value: string): string {\n return value.replace(INVISIBLE_UNICODE_REGEX, '');\n}\n"]}
@@ -1,16 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createSelectionMarker = void 0;
4
- var tslib_1 = require("tslib");
4
+ var EmptySegmentFormat_1 = require("../../constants/EmptySegmentFormat");
5
+ var getObjectKeys_1 = require("../../domUtils/getObjectKeys");
5
6
  /**
6
7
  * Create a ContentModelSelectionMarker model
7
8
  * @param format @optional The format of this model
8
9
  */
9
10
  function createSelectionMarker(format) {
11
+ var filteredFormat = {};
12
+ if (format) {
13
+ (0, getObjectKeys_1.getObjectKeys)(EmptySegmentFormat_1.EmptySegmentFormat).forEach(function (key) {
14
+ if (key in format) {
15
+ filteredFormat[key] = format[key];
16
+ }
17
+ });
18
+ }
10
19
  return {
11
20
  segmentType: 'SelectionMarker',
12
21
  isSelected: true,
13
- format: (0, tslib_1.__assign)({}, format),
22
+ format: filteredFormat,
14
23
  };
15
24
  }
16
25
  exports.createSelectionMarker = createSelectionMarker;
@@ -1 +1 @@
1
- {"version":3,"file":"createSelectionMarker.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelApi/creators/createSelectionMarker.ts"],"names":[],"mappings":";;;;AAKA;;;GAGG;AACH,SAAgB,qBAAqB,CACjC,MAA4C;IAE5C,OAAO;QACH,WAAW,EAAE,iBAAiB;QAC9B,UAAU,EAAE,IAAI;QAChB,MAAM,4BAAO,MAAM,CAAE;KACxB,CAAC;AACN,CAAC;AARD,sDAQC","sourcesContent":["import type {\n ContentModelSegmentFormat,\n ContentModelSelectionMarker,\n} from 'roosterjs-content-model-types';\n\n/**\n * Create a ContentModelSelectionMarker model\n * @param format @optional The format of this model\n */\nexport function createSelectionMarker(\n format?: Readonly<ContentModelSegmentFormat>\n): ContentModelSelectionMarker {\n return {\n segmentType: 'SelectionMarker',\n isSelected: true,\n format: { ...format },\n };\n}\n"]}
1
+ {"version":3,"file":"createSelectionMarker.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelApi/creators/createSelectionMarker.ts"],"names":[],"mappings":";;;AAAA,yEAAwE;AACxE,8DAA6D;AAM7D;;;GAGG;AACH,SAAgB,qBAAqB,CACjC,MAA4C;IAE5C,IAAM,cAAc,GAA8B,EAAE,CAAC;IAErD,IAAI,MAAM,EAAE;QACR,IAAA,6BAAa,EAAC,uCAAkB,CAAC,CAAC,OAAO,CAAC,UAAA,GAAG;YACzC,IAAI,GAAG,IAAI,MAAM,EAAE;gBACd,cAAc,CAAC,GAAG,CAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;aAC9C;QACL,CAAC,CAAC,CAAC;KACN;IAED,OAAO;QACH,WAAW,EAAE,iBAAiB;QAC9B,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,cAAc;KACzB,CAAC;AACN,CAAC;AAlBD,sDAkBC","sourcesContent":["import { EmptySegmentFormat } from '../../constants/EmptySegmentFormat';\nimport { getObjectKeys } from '../../domUtils/getObjectKeys';\nimport type {\n ContentModelSegmentFormat,\n ContentModelSelectionMarker,\n} from 'roosterjs-content-model-types';\n\n/**\n * Create a ContentModelSelectionMarker model\n * @param format @optional The format of this model\n */\nexport function createSelectionMarker(\n format?: Readonly<ContentModelSegmentFormat>\n): ContentModelSelectionMarker {\n const filteredFormat: ContentModelSegmentFormat = {};\n\n if (format) {\n getObjectKeys(EmptySegmentFormat).forEach(key => {\n if (key in format) {\n (filteredFormat[key] as any) = format[key];\n }\n });\n }\n\n return {\n segmentType: 'SelectionMarker',\n isSelected: true,\n format: filteredFormat,\n };\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.setSelection = void 0;
4
+ var tslib_1 = require("tslib");
4
5
  var isGeneralSegment_1 = require("../typeCheck/isGeneralSegment");
5
6
  var mutate_1 = require("../common/mutate");
6
7
  /**
@@ -38,6 +39,7 @@ function setSelectionToBlockGroup(group, isInSelection, start, end) {
38
39
  });
39
40
  }
40
41
  function setSelectionToBlock(block, isInSelection, start, end) {
42
+ var _a;
41
43
  switch (block.blockType) {
42
44
  case 'BlockGroup':
43
45
  return setSelectionToBlockGroup(block, isInSelection, start, end);
@@ -58,16 +60,31 @@ function setSelectionToBlock(block, isInSelection, start, end) {
58
60
  return isInSelection;
59
61
  });
60
62
  case 'Paragraph':
61
- var segmentsToDelete_1 = [];
63
+ var state_1 = {
64
+ segmentsToDelete: [],
65
+ boundaryMarkers: [],
66
+ hasSelectedNonMarker: false,
67
+ };
62
68
  block.segments.forEach(function (segment, i) {
63
69
  isInSelection = handleSelection(isInSelection, segment, start, end, function (isInSelection) {
64
- return setSelectionToSegment(block, segment, isInSelection, segmentsToDelete_1, start, end, i);
70
+ return setSelectionToSegment(block, segment, isInSelection, state_1, start, end, i);
65
71
  });
66
72
  });
67
- if (segmentsToDelete_1.length > 0) {
73
+ if (state_1.hasSelectedNonMarker) {
74
+ // This paragraph contains a real (non-marker) selected segment, so any leading/trailing
75
+ // selection marker of the range is redundant within this paragraph and can be removed.
76
+ // We only do this within the same paragraph: a boundary marker at a paragraph edge must be
77
+ // kept to distinguish "selection starts at the beginning of this line" from "selection
78
+ // starts at the end of the previous line".
79
+ (_a = state_1.segmentsToDelete).push.apply(_a, (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(state_1.boundaryMarkers), false));
80
+ }
81
+ if (state_1.segmentsToDelete.length > 0) {
68
82
  var mutablePara = (0, mutate_1.mutateBlock)(block);
69
83
  var index = void 0;
70
- while ((index = segmentsToDelete_1.pop()) !== undefined) {
84
+ // Sort ascending so the pop()-based splice below always removes the highest index first,
85
+ // keeping the remaining indices valid (boundary markers may sit before queued deletions).
86
+ state_1.segmentsToDelete.sort(function (a, b) { return a - b; });
87
+ while ((index = state_1.segmentsToDelete.pop()) !== undefined) {
71
88
  if (index >= 0) {
72
89
  mutablePara.segments.splice(index, 1);
73
90
  }
@@ -116,14 +133,23 @@ function findCell(table, cell) {
116
133
  : -1;
117
134
  return { row: row, col: col };
118
135
  }
119
- function setSelectionToSegment(paragraph, segment, isInSelection, segmentsToDelete, start, end, i) {
136
+ function setSelectionToSegment(paragraph, segment, isInSelection, state, start, end, i) {
137
+ if (segment.segmentType != 'SelectionMarker' && isInSelection) {
138
+ state.hasSelectedNonMarker = true;
139
+ }
120
140
  switch (segment.segmentType) {
121
141
  case 'SelectionMarker':
122
142
  if (!isInSelection || (segment != start && segment != end)) {
123
143
  // Delete the selection marker when
124
144
  // 1. It is not in selection any more. Or
125
145
  // 2. It is in middle of selection, so no need to have it
126
- segmentsToDelete.push(i);
146
+ state.segmentsToDelete.push(i);
147
+ }
148
+ else {
149
+ // It is a leading/trailing selection marker of a range selection. Keep it for now, but
150
+ // remember it so it can be removed later if this same paragraph also contains a real
151
+ // (non-marker) selected segment, in which case the marker is redundant.
152
+ state.boundaryMarkers.push(i);
127
153
  }
128
154
  return isInSelection;
129
155
  case 'General':
@@ -1 +1 @@
1
- {"version":3,"file":"setSelection.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelApi/selection/setSelection.ts"],"names":[],"mappings":"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","sourcesContent":["import { isGeneralSegment } from '../typeCheck/isGeneralSegment';\nimport { mutateBlock, mutateSegment } from '../common/mutate';\nimport type {\n MutableType,\n ReadonlyContentModelBlock,\n ReadonlyContentModelBlockGroup,\n ReadonlyContentModelParagraph,\n ReadonlyContentModelSegment,\n ReadonlyContentModelTable,\n ReadonlySelectable,\n ShallowMutableSelectable,\n TableCellCoordinate,\n} from 'roosterjs-content-model-types';\n\n/**\n * Set selection into Content Model. If the Content Model already has selection, existing selection will be overwritten by the new one.\n * @param group The root level group of Content Model\n * @param start The start selected element. If not passed, existing selection of content model will be cleared\n * @param end The end selected element. If not passed, only the start element will be selected. If passed, all elements between start and end elements will be selected\n */\nexport function setSelection(\n group: ReadonlyContentModelBlockGroup,\n start?: ReadonlySelectable,\n end?: ReadonlySelectable\n) {\n setSelectionToBlockGroup(group, false /*isInSelection*/, start || null, end || null);\n}\n\nfunction setSelectionToBlockGroup(\n group: ReadonlyContentModelBlockGroup,\n isInSelection: boolean,\n start: ReadonlySelectable | null,\n end: ReadonlySelectable | null\n): boolean {\n return handleSelection(isInSelection, group, start, end, isInSelection => {\n if (isGeneralSegment(group) && needToSetSelection(group, isInSelection)) {\n setIsSelected(mutateBlock(group), isInSelection);\n }\n\n const blocksToDelete: number[] = [];\n\n group.blocks.forEach((block, i) => {\n isInSelection = setSelectionToBlock(block, isInSelection, start, end);\n\n if (block.blockType == 'Paragraph' && block.segments.length == 0 && block.isImplicit) {\n blocksToDelete.push(i);\n }\n });\n\n let index: number | undefined;\n\n if (blocksToDelete.length > 0) {\n const mutableGroup = mutateBlock(group);\n\n while ((index = blocksToDelete.pop()) !== undefined) {\n if (index >= 0) {\n mutableGroup.blocks.splice(index, 1);\n }\n }\n }\n\n return isInSelection;\n });\n}\n\nfunction setSelectionToBlock(\n block: ReadonlyContentModelBlock,\n isInSelection: boolean,\n start: ReadonlySelectable | null,\n end: ReadonlySelectable | null\n) {\n switch (block.blockType) {\n case 'BlockGroup':\n return setSelectionToBlockGroup(block, isInSelection, start, end);\n\n case 'Table':\n return setSelectionToTable(block, isInSelection, start, end);\n\n case 'Divider':\n case 'Entity':\n return handleSelection(isInSelection, block, start, end, isInSelection => {\n if (needToSetSelection(block, isInSelection)) {\n const mutableBlock = mutateBlock(block);\n\n if (isInSelection) {\n mutableBlock.isSelected = true;\n } else {\n delete mutableBlock.isSelected;\n }\n }\n\n return isInSelection;\n });\n\n case 'Paragraph':\n const segmentsToDelete: number[] = [];\n\n block.segments.forEach((segment, i) => {\n isInSelection = handleSelection(\n isInSelection,\n segment,\n start,\n end,\n isInSelection => {\n return setSelectionToSegment(\n block,\n segment,\n isInSelection,\n segmentsToDelete,\n start,\n end,\n i\n );\n }\n );\n });\n\n if (segmentsToDelete.length > 0) {\n const mutablePara = mutateBlock(block);\n\n let index: number | undefined;\n\n while ((index = segmentsToDelete.pop()) !== undefined) {\n if (index >= 0) {\n mutablePara.segments.splice(index, 1);\n }\n }\n }\n\n return isInSelection;\n\n default:\n return isInSelection;\n }\n}\n\nfunction setSelectionToTable(\n table: ReadonlyContentModelTable,\n isInSelection: boolean,\n start: ReadonlySelectable | null,\n end: ReadonlySelectable | null\n): boolean {\n const first = findCell(table, start);\n const last = end ? findCell(table, end) : first;\n\n if (!isInSelection) {\n for (let row = 0; row < table.rows.length; row++) {\n const currentRow = table.rows[row];\n for (let col = 0; col < currentRow.cells.length; col++) {\n const currentCell = table.rows[row].cells[col];\n const isSelected =\n row >= first.row && row <= last.row && col >= first.col && col <= last.col;\n\n if (needToSetSelection(currentCell, isSelected)) {\n setIsSelected(mutateBlock(currentCell), isSelected);\n }\n\n if (!isSelected) {\n setSelectionToBlockGroup(currentCell, false /*isInSelection*/, start, end);\n }\n }\n }\n } else {\n table.rows.forEach(row =>\n row.cells.forEach(cell => {\n const wasInSelection = isInSelection;\n\n isInSelection = setSelectionToBlockGroup(cell, isInSelection, start, end);\n\n if (wasInSelection && isInSelection) {\n mutateBlock(cell).isSelected = true;\n }\n })\n );\n }\n\n return isInSelection;\n}\n\nfunction findCell(\n table: ReadonlyContentModelTable,\n cell: ReadonlySelectable | null\n): TableCellCoordinate {\n let col = -1;\n const row = cell\n ? table.rows.findIndex(\n row => (col = (row.cells as ReadonlyArray<ReadonlySelectable>).indexOf(cell)) >= 0\n )\n : -1;\n\n return { row, col };\n}\n\nfunction setSelectionToSegment(\n paragraph: ReadonlyContentModelParagraph,\n segment: ReadonlyContentModelSegment,\n isInSelection: boolean,\n segmentsToDelete: number[],\n start: ReadonlySelectable | null,\n end: ReadonlySelectable | null,\n i: number\n) {\n switch (segment.segmentType) {\n case 'SelectionMarker':\n if (!isInSelection || (segment != start && segment != end)) {\n // Delete the selection marker when\n // 1. It is not in selection any more. Or\n // 2. It is in middle of selection, so no need to have it\n segmentsToDelete.push(i);\n }\n return isInSelection;\n\n case 'General':\n internalSetSelectionToSegment(paragraph, segment, isInSelection);\n\n return segment != start && segment != end\n ? setSelectionToBlockGroup(segment, isInSelection, start, end)\n : isInSelection;\n\n case 'Image':\n const isSelectedAsImageSelection = start == segment && (!end || end == segment);\n\n internalSetSelectionToSegment(\n paragraph,\n segment,\n isInSelection,\n !segment.isSelectedAsImageSelection != !isSelectedAsImageSelection\n ? image => (image.isSelectedAsImageSelection = isSelectedAsImageSelection)\n : undefined\n );\n\n return isInSelection;\n default:\n internalSetSelectionToSegment(paragraph, segment, isInSelection);\n return isInSelection;\n }\n}\n\nfunction internalSetSelectionToSegment<T extends ReadonlyContentModelSegment>(\n paragraph: ReadonlyContentModelParagraph,\n segment: T,\n isInSelection: boolean,\n additionAction?: (segment: MutableType<T>) => void\n) {\n if (additionAction || needToSetSelection(segment, isInSelection)) {\n mutateSegment(paragraph, segment, mutableSegment => {\n setIsSelected(mutableSegment, isInSelection);\n additionAction?.(mutableSegment);\n });\n }\n}\n\nfunction needToSetSelection(selectable: ReadonlySelectable, isSelected: boolean) {\n return !selectable.isSelected != !isSelected;\n}\n\nfunction setIsSelected(selectable: ShallowMutableSelectable, value: boolean) {\n if (value) {\n selectable.isSelected = true;\n } else {\n delete selectable.isSelected;\n }\n\n return value;\n}\n\nfunction handleSelection(\n isInSelection: boolean,\n model: ReadonlyContentModelBlockGroup | ReadonlyContentModelBlock | ReadonlyContentModelSegment,\n start: ReadonlySelectable | null,\n end: ReadonlySelectable | null,\n callback: (isInSelection: boolean) => boolean\n) {\n isInSelection = isInSelection || model == start;\n isInSelection = callback(isInSelection);\n return isInSelection && !!end && model != end;\n}\n"]}
1
+ {"version":3,"file":"setSelection.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelApi/selection/setSelection.ts"],"names":[],"mappings":"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","sourcesContent":["import { isGeneralSegment } from '../typeCheck/isGeneralSegment';\nimport { mutateBlock, mutateSegment } from '../common/mutate';\nimport type {\n MutableType,\n ReadonlyContentModelBlock,\n ReadonlyContentModelBlockGroup,\n ReadonlyContentModelParagraph,\n ReadonlyContentModelSegment,\n ReadonlyContentModelTable,\n ReadonlySelectable,\n ShallowMutableSelectable,\n TableCellCoordinate,\n} from 'roosterjs-content-model-types';\n\n/**\n * Set selection into Content Model. If the Content Model already has selection, existing selection will be overwritten by the new one.\n * @param group The root level group of Content Model\n * @param start The start selected element. If not passed, existing selection of content model will be cleared\n * @param end The end selected element. If not passed, only the start element will be selected. If passed, all elements between start and end elements will be selected\n */\nexport function setSelection(\n group: ReadonlyContentModelBlockGroup,\n start?: ReadonlySelectable,\n end?: ReadonlySelectable\n) {\n setSelectionToBlockGroup(group, false /*isInSelection*/, start || null, end || null);\n}\n\nfunction setSelectionToBlockGroup(\n group: ReadonlyContentModelBlockGroup,\n isInSelection: boolean,\n start: ReadonlySelectable | null,\n end: ReadonlySelectable | null\n): boolean {\n return handleSelection(isInSelection, group, start, end, isInSelection => {\n if (isGeneralSegment(group) && needToSetSelection(group, isInSelection)) {\n setIsSelected(mutateBlock(group), isInSelection);\n }\n\n const blocksToDelete: number[] = [];\n\n group.blocks.forEach((block, i) => {\n isInSelection = setSelectionToBlock(block, isInSelection, start, end);\n\n if (block.blockType == 'Paragraph' && block.segments.length == 0 && block.isImplicit) {\n blocksToDelete.push(i);\n }\n });\n\n let index: number | undefined;\n\n if (blocksToDelete.length > 0) {\n const mutableGroup = mutateBlock(group);\n\n while ((index = blocksToDelete.pop()) !== undefined) {\n if (index >= 0) {\n mutableGroup.blocks.splice(index, 1);\n }\n }\n }\n\n return isInSelection;\n });\n}\n\nfunction setSelectionToBlock(\n block: ReadonlyContentModelBlock,\n isInSelection: boolean,\n start: ReadonlySelectable | null,\n end: ReadonlySelectable | null\n) {\n switch (block.blockType) {\n case 'BlockGroup':\n return setSelectionToBlockGroup(block, isInSelection, start, end);\n\n case 'Table':\n return setSelectionToTable(block, isInSelection, start, end);\n\n case 'Divider':\n case 'Entity':\n return handleSelection(isInSelection, block, start, end, isInSelection => {\n if (needToSetSelection(block, isInSelection)) {\n const mutableBlock = mutateBlock(block);\n\n if (isInSelection) {\n mutableBlock.isSelected = true;\n } else {\n delete mutableBlock.isSelected;\n }\n }\n\n return isInSelection;\n });\n\n case 'Paragraph':\n const state: ParagraphSelectionState = {\n segmentsToDelete: [],\n boundaryMarkers: [],\n hasSelectedNonMarker: false,\n };\n\n block.segments.forEach((segment, i) => {\n isInSelection = handleSelection(\n isInSelection,\n segment,\n start,\n end,\n isInSelection => {\n return setSelectionToSegment(\n block,\n segment,\n isInSelection,\n state,\n start,\n end,\n i\n );\n }\n );\n });\n\n if (state.hasSelectedNonMarker) {\n // This paragraph contains a real (non-marker) selected segment, so any leading/trailing\n // selection marker of the range is redundant within this paragraph and can be removed.\n // We only do this within the same paragraph: a boundary marker at a paragraph edge must be\n // kept to distinguish \"selection starts at the beginning of this line\" from \"selection\n // starts at the end of the previous line\".\n state.segmentsToDelete.push(...state.boundaryMarkers);\n }\n\n if (state.segmentsToDelete.length > 0) {\n const mutablePara = mutateBlock(block);\n\n let index: number | undefined;\n\n // Sort ascending so the pop()-based splice below always removes the highest index first,\n // keeping the remaining indices valid (boundary markers may sit before queued deletions).\n state.segmentsToDelete.sort((a, b) => a - b);\n\n while ((index = state.segmentsToDelete.pop()) !== undefined) {\n if (index >= 0) {\n mutablePara.segments.splice(index, 1);\n }\n }\n }\n\n return isInSelection;\n\n default:\n return isInSelection;\n }\n}\n\nfunction setSelectionToTable(\n table: ReadonlyContentModelTable,\n isInSelection: boolean,\n start: ReadonlySelectable | null,\n end: ReadonlySelectable | null\n): boolean {\n const first = findCell(table, start);\n const last = end ? findCell(table, end) : first;\n\n if (!isInSelection) {\n for (let row = 0; row < table.rows.length; row++) {\n const currentRow = table.rows[row];\n for (let col = 0; col < currentRow.cells.length; col++) {\n const currentCell = table.rows[row].cells[col];\n const isSelected =\n row >= first.row && row <= last.row && col >= first.col && col <= last.col;\n\n if (needToSetSelection(currentCell, isSelected)) {\n setIsSelected(mutateBlock(currentCell), isSelected);\n }\n\n if (!isSelected) {\n setSelectionToBlockGroup(currentCell, false /*isInSelection*/, start, end);\n }\n }\n }\n } else {\n table.rows.forEach(row =>\n row.cells.forEach(cell => {\n const wasInSelection = isInSelection;\n\n isInSelection = setSelectionToBlockGroup(cell, isInSelection, start, end);\n\n if (wasInSelection && isInSelection) {\n mutateBlock(cell).isSelected = true;\n }\n })\n );\n }\n\n return isInSelection;\n}\n\nfunction findCell(\n table: ReadonlyContentModelTable,\n cell: ReadonlySelectable | null\n): TableCellCoordinate {\n let col = -1;\n const row = cell\n ? table.rows.findIndex(\n row => (col = (row.cells as ReadonlyArray<ReadonlySelectable>).indexOf(cell)) >= 0\n )\n : -1;\n\n return { row, col };\n}\n\ninterface ParagraphSelectionState {\n // Indexes of segments to delete after the paragraph is fully processed\n segmentsToDelete: number[];\n\n // Indexes of leading/trailing selection markers of the range that are kept for now, but will be\n // removed if this paragraph also contains a real (non-marker) selected segment\n boundaryMarkers: number[];\n\n // Whether this paragraph contains at least one selected segment that is not a selection marker\n hasSelectedNonMarker: boolean;\n}\n\nfunction setSelectionToSegment(\n paragraph: ReadonlyContentModelParagraph,\n segment: ReadonlyContentModelSegment,\n isInSelection: boolean,\n state: ParagraphSelectionState,\n start: ReadonlySelectable | null,\n end: ReadonlySelectable | null,\n i: number\n) {\n if (segment.segmentType != 'SelectionMarker' && isInSelection) {\n state.hasSelectedNonMarker = true;\n }\n\n switch (segment.segmentType) {\n case 'SelectionMarker':\n if (!isInSelection || (segment != start && segment != end)) {\n // Delete the selection marker when\n // 1. It is not in selection any more. Or\n // 2. It is in middle of selection, so no need to have it\n state.segmentsToDelete.push(i);\n } else {\n // It is a leading/trailing selection marker of a range selection. Keep it for now, but\n // remember it so it can be removed later if this same paragraph also contains a real\n // (non-marker) selected segment, in which case the marker is redundant.\n state.boundaryMarkers.push(i);\n }\n return isInSelection;\n\n case 'General':\n internalSetSelectionToSegment(paragraph, segment, isInSelection);\n\n return segment != start && segment != end\n ? setSelectionToBlockGroup(segment, isInSelection, start, end)\n : isInSelection;\n\n case 'Image':\n const isSelectedAsImageSelection = start == segment && (!end || end == segment);\n\n internalSetSelectionToSegment(\n paragraph,\n segment,\n isInSelection,\n !segment.isSelectedAsImageSelection != !isSelectedAsImageSelection\n ? image => (image.isSelectedAsImageSelection = isSelectedAsImageSelection)\n : undefined\n );\n\n return isInSelection;\n default:\n internalSetSelectionToSegment(paragraph, segment, isInSelection);\n return isInSelection;\n }\n}\n\nfunction internalSetSelectionToSegment<T extends ReadonlyContentModelSegment>(\n paragraph: ReadonlyContentModelParagraph,\n segment: T,\n isInSelection: boolean,\n additionAction?: (segment: MutableType<T>) => void\n) {\n if (additionAction || needToSetSelection(segment, isInSelection)) {\n mutateSegment(paragraph, segment, mutableSegment => {\n setIsSelected(mutableSegment, isInSelection);\n additionAction?.(mutableSegment);\n });\n }\n}\n\nfunction needToSetSelection(selectable: ReadonlySelectable, isSelected: boolean) {\n return !selectable.isSelected != !isSelected;\n}\n\nfunction setIsSelected(selectable: ShallowMutableSelectable, value: boolean) {\n if (value) {\n selectable.isSelected = true;\n } else {\n delete selectable.isSelected;\n }\n\n return value;\n}\n\nfunction handleSelection(\n isInSelection: boolean,\n model: ReadonlyContentModelBlockGroup | ReadonlyContentModelBlock | ReadonlyContentModelSegment,\n start: ReadonlySelectable | null,\n end: ReadonlySelectable | null,\n callback: (isInSelection: boolean) => boolean\n) {\n isInSelection = isInSelection || model == start;\n isInSelection = callback(isInSelection);\n return isInSelection && !!end && model != end;\n}\n"]}
@@ -29,7 +29,7 @@ var handleBlockGroupChildren = function (doc, parent, group, context) {
29
29
  (_a = context.domIndexer) === null || _a === void 0 ? void 0 : _a.onBlockEntity(childBlock, group);
30
30
  }
31
31
  });
32
- cleanUpNodeStack(listFormat.nodeStack, context);
32
+ cleanUpNodeStack(listFormat.nodeStack, context, parent);
33
33
  // Remove all rest node if any since they don't appear in content model
34
34
  (0, cleanUpRestNodes_1.cleanUpRestNodes)(refNode, context.rewriteFromModel);
35
35
  }
@@ -38,7 +38,7 @@ var handleBlockGroupChildren = function (doc, parent, group, context) {
38
38
  }
39
39
  };
40
40
  exports.handleBlockGroupChildren = handleBlockGroupChildren;
41
- function cleanUpNodeStack(nodeStack, context) {
41
+ function cleanUpNodeStack(nodeStack, context, leavingParent) {
42
42
  var _a, _b;
43
43
  if (nodeStack.length > 0) {
44
44
  // Clear list stack, only run to nodeStack[1] because nodeStack[0] is the parent node
@@ -46,6 +46,13 @@ function cleanUpNodeStack(nodeStack, context) {
46
46
  var node = (_b = (_a = nodeStack.pop()) === null || _a === void 0 ? void 0 : _a.refNode) !== null && _b !== void 0 ? _b : null;
47
47
  (0, cleanUpRestNodes_1.cleanUpRestNodes)(node, context.rewriteFromModel);
48
48
  }
49
+ if (leavingParent && nodeStack[0].node == leavingParent) {
50
+ // When leaving a parent node that is the same with the root of node stack
51
+ // It means the whole list node stack is being invalidated, so we clear it
52
+ while (nodeStack.length > 0) {
53
+ nodeStack.pop();
54
+ }
55
+ }
49
56
  }
50
57
  }
51
58
  //# sourceMappingURL=handleBlockGroupChildren.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handleBlockGroupChildren.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelToDom/handlers/handleBlockGroupChildren.ts"],"names":[],"mappings":";;;AAAA,8DAA6D;AAQ7D;;GAEG;AACI,IAAM,wBAAwB,GAAgD,UACjF,GAAa,EACb,MAAY,EACZ,KAA6B,EAC7B,OAA0B;IAElB,IAAA,UAAU,GAAK,OAAO,WAAZ,CAAa;IAC/B,IAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;IACvC,IAAI,OAAO,GAAgB,MAAM,CAAC,UAAU,CAAC;IAE7C,IAAI;QACA,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,UAAC,UAAU,EAAE,KAAK;;YACnC,2CAA2C;YAC3C,wEAAwE;YACxE,sFAAsF;YACtF,+FAA+F;YAC/F,IACI,KAAK,IAAI,CAAC;gBACV,UAAU,CAAC,SAAS,IAAI,YAAY;gBACpC,UAAU,CAAC,cAAc,IAAI,UAAU,EACzC;gBACE,gBAAgB,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAEhD,IAAI,UAAU,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;oBACjC,UAAU,CAAC,SAAS,GAAG,EAAE,CAAC;iBAC7B;aACJ;YAED,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YAEjF,IAAI,UAAU,CAAC,SAAS,IAAI,QAAQ,EAAE;gBAClC,MAAA,OAAO,CAAC,UAAU,0CAAE,aAAa,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;aACxD;QACL,CAAC,CAAC,CAAC;QAEH,gBAAgB,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAEhD,uEAAuE;QACvE,IAAA,mCAAgB,EAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;KACvD;YAAS;QACN,UAAU,CAAC,SAAS,GAAG,SAAS,CAAC;KACpC;AACL,CAAC,CAAC;AA1CW,QAAA,wBAAwB,4BA0CnC;AAEF,SAAS,gBAAgB,CAAC,SAAoC,EAAE,OAA0B;;IACtF,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;QACtB,qFAAqF;QACrF,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YAC3C,IAAM,IAAI,GAAG,MAAA,MAAA,SAAS,CAAC,GAAG,EAAE,0CAAE,OAAO,mCAAI,IAAI,CAAC;YAE9C,IAAA,mCAAgB,EAAC,IAAI,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;SACpD;KACJ;AACL,CAAC","sourcesContent":["import { cleanUpRestNodes } from '../utils/cleanUpRestNodes';\nimport type {\n ContentModelBlockGroup,\n ContentModelHandler,\n ModelToDomContext,\n ModelToDomListStackItem,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport const handleBlockGroupChildren: ContentModelHandler<ContentModelBlockGroup> = (\n doc: Document,\n parent: Node,\n group: ContentModelBlockGroup,\n context: ModelToDomContext\n) => {\n const { listFormat } = context;\n const nodeStack = listFormat.nodeStack;\n let refNode: Node | null = parent.firstChild;\n\n try {\n group.blocks.forEach((childBlock, index) => {\n // When process list, we need a node stack.\n // When there are two continuous lists, they should share the same stack\n // so that list items with same type/threadId can be merged into the same list element\n // In other cases, clear the stack so that two separate lists won't share the same list element\n if (\n index == 0 ||\n childBlock.blockType != 'BlockGroup' ||\n childBlock.blockGroupType != 'ListItem'\n ) {\n cleanUpNodeStack(listFormat.nodeStack, context);\n\n if (listFormat.nodeStack.length > 0) {\n listFormat.nodeStack = [];\n }\n }\n\n refNode = context.modelHandlers.block(doc, parent, childBlock, context, refNode);\n\n if (childBlock.blockType == 'Entity') {\n context.domIndexer?.onBlockEntity(childBlock, group);\n }\n });\n\n cleanUpNodeStack(listFormat.nodeStack, context);\n\n // Remove all rest node if any since they don't appear in content model\n cleanUpRestNodes(refNode, context.rewriteFromModel);\n } finally {\n listFormat.nodeStack = nodeStack;\n }\n};\n\nfunction cleanUpNodeStack(nodeStack: ModelToDomListStackItem[], context: ModelToDomContext) {\n if (nodeStack.length > 0) {\n // Clear list stack, only run to nodeStack[1] because nodeStack[0] is the parent node\n for (let i = nodeStack.length - 1; i > 0; i--) {\n const node = nodeStack.pop()?.refNode ?? null;\n\n cleanUpRestNodes(node, context.rewriteFromModel);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"handleBlockGroupChildren.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelToDom/handlers/handleBlockGroupChildren.ts"],"names":[],"mappings":";;;AAAA,8DAA6D;AAQ7D;;GAEG;AACI,IAAM,wBAAwB,GAAgD,UACjF,GAAa,EACb,MAAY,EACZ,KAA6B,EAC7B,OAA0B;IAElB,IAAA,UAAU,GAAK,OAAO,WAAZ,CAAa;IAC/B,IAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;IACvC,IAAI,OAAO,GAAgB,MAAM,CAAC,UAAU,CAAC;IAE7C,IAAI;QACA,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,UAAC,UAAU,EAAE,KAAK;;YACnC,2CAA2C;YAC3C,wEAAwE;YACxE,sFAAsF;YACtF,+FAA+F;YAC/F,IACI,KAAK,IAAI,CAAC;gBACV,UAAU,CAAC,SAAS,IAAI,YAAY;gBACpC,UAAU,CAAC,cAAc,IAAI,UAAU,EACzC;gBACE,gBAAgB,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAEhD,IAAI,UAAU,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;oBACjC,UAAU,CAAC,SAAS,GAAG,EAAE,CAAC;iBAC7B;aACJ;YAED,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YAEjF,IAAI,UAAU,CAAC,SAAS,IAAI,QAAQ,EAAE;gBAClC,MAAA,OAAO,CAAC,UAAU,0CAAE,aAAa,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;aACxD;QACL,CAAC,CAAC,CAAC;QAEH,gBAAgB,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAExD,uEAAuE;QACvE,IAAA,mCAAgB,EAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;KACvD;YAAS;QACN,UAAU,CAAC,SAAS,GAAG,SAAS,CAAC;KACpC;AACL,CAAC,CAAC;AA1CW,QAAA,wBAAwB,4BA0CnC;AAEF,SAAS,gBAAgB,CACrB,SAAoC,EACpC,OAA0B,EAC1B,aAAoB;;IAEpB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;QACtB,qFAAqF;QACrF,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YAC3C,IAAM,IAAI,GAAG,MAAA,MAAA,SAAS,CAAC,GAAG,EAAE,0CAAE,OAAO,mCAAI,IAAI,CAAC;YAE9C,IAAA,mCAAgB,EAAC,IAAI,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;SACpD;QAED,IAAI,aAAa,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,aAAa,EAAE;YACrD,0EAA0E;YAC1E,0EAA0E;YAC1E,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;gBACzB,SAAS,CAAC,GAAG,EAAE,CAAC;aACnB;SACJ;KACJ;AACL,CAAC","sourcesContent":["import { cleanUpRestNodes } from '../utils/cleanUpRestNodes';\nimport type {\n ContentModelBlockGroup,\n ContentModelHandler,\n ModelToDomContext,\n ModelToDomListStackItem,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport const handleBlockGroupChildren: ContentModelHandler<ContentModelBlockGroup> = (\n doc: Document,\n parent: Node,\n group: ContentModelBlockGroup,\n context: ModelToDomContext\n) => {\n const { listFormat } = context;\n const nodeStack = listFormat.nodeStack;\n let refNode: Node | null = parent.firstChild;\n\n try {\n group.blocks.forEach((childBlock, index) => {\n // When process list, we need a node stack.\n // When there are two continuous lists, they should share the same stack\n // so that list items with same type/threadId can be merged into the same list element\n // In other cases, clear the stack so that two separate lists won't share the same list element\n if (\n index == 0 ||\n childBlock.blockType != 'BlockGroup' ||\n childBlock.blockGroupType != 'ListItem'\n ) {\n cleanUpNodeStack(listFormat.nodeStack, context);\n\n if (listFormat.nodeStack.length > 0) {\n listFormat.nodeStack = [];\n }\n }\n\n refNode = context.modelHandlers.block(doc, parent, childBlock, context, refNode);\n\n if (childBlock.blockType == 'Entity') {\n context.domIndexer?.onBlockEntity(childBlock, group);\n }\n });\n\n cleanUpNodeStack(listFormat.nodeStack, context, parent);\n\n // Remove all rest node if any since they don't appear in content model\n cleanUpRestNodes(refNode, context.rewriteFromModel);\n } finally {\n listFormat.nodeStack = nodeStack;\n }\n};\n\nfunction cleanUpNodeStack(\n nodeStack: ModelToDomListStackItem[],\n context: ModelToDomContext,\n leavingParent?: Node\n) {\n if (nodeStack.length > 0) {\n // Clear list stack, only run to nodeStack[1] because nodeStack[0] is the parent node\n for (let i = nodeStack.length - 1; i > 0; i--) {\n const node = nodeStack.pop()?.refNode ?? null;\n\n cleanUpRestNodes(node, context.rewriteFromModel);\n }\n\n if (leavingParent && nodeStack[0].node == leavingParent) {\n // When leaving a parent node that is the same with the root of node stack\n // It means the whole list node stack is being invalidated, so we clear it\n while (nodeStack.length > 0) {\n nodeStack.pop();\n }\n }\n }\n}\n"]}
@@ -31,14 +31,16 @@ var handleFormatContainer = function (doc, parent, container, context, refNode)
31
31
  (0, applyFormat_1.applyFormat)(containerNode_1, context.formatAppliers.segmentOnBlock, container.format, context);
32
32
  (0, applyFormat_1.applyFormat)(containerNode_1, context.formatAppliers.container, container.format, context);
33
33
  });
34
- if (container.tagName == 'pre') {
35
- (0, stackFormat_1.stackFormat)(context, PreChildFormat, function () {
34
+ (0, stackFormat_1.stackFormat)(context, container.format.direction ? { direction: container.format.direction } : null, function () {
35
+ if (container.tagName == 'pre') {
36
+ (0, stackFormat_1.stackFormat)(context, PreChildFormat, function () {
37
+ context.modelHandlers.blockGroupChildren(doc, containerNode_1, container, context);
38
+ });
39
+ }
40
+ else {
36
41
  context.modelHandlers.blockGroupChildren(doc, containerNode_1, container, context);
37
- });
38
- }
39
- else {
40
- context.modelHandlers.blockGroupChildren(doc, containerNode_1, container, context);
41
- }
42
+ }
43
+ });
42
44
  element = containerNode_1;
43
45
  }
44
46
  if (element) {
@@ -1 +1 @@
1
- {"version":3,"file":"handleFormatContainer.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelToDom/handlers/handleFormatContainer.ts"],"names":[],"mappings":";;;AAAA,oDAAmD;AACnD,yDAAkE;AAClE,wEAAuE;AACvE,oDAAmD;AASnD,IAAM,cAAc,GAAwD;IACxE,UAAU,EAAE,WAAW;IACvB,UAAU,EAAE,KAAK;CACpB,CAAC;AAEF;;GAEG;AACI,IAAM,qBAAqB,GAA0D,UACxF,GAAa,EACb,MAAY,EACZ,SAAsC,EACtC,OAA0B,EAC1B,OAAoB;;IAEpB,IAAI,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;IAE9E,IAAI,OAAO,EAAE;QACT,OAAO,GAAG,IAAA,uCAAkB,EAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAEjF,OAAO,CAAC,aAAa,CAAC,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;KAC9E;SAAM,IAAI,CAAC,IAAA,2BAAiB,EAAC,SAAS,CAAC,EAAE;QACtC,IAAM,eAAa,GAAG,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAE3D,IAAI,OAAO,CAAC,iBAAiB,EAAE;YAC3B,SAAS,CAAC,aAAa,GAAG,eAAa,CAAC;SAC3C;QAED,MAAM,CAAC,YAAY,CAAC,eAAa,EAAE,OAAO,CAAC,CAAC;QAC5C,OAAO,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,IAAI,CAAC,eAAa,CAAC,CAAC;QAEhE,IAAA,yBAAW,EAAC,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE;YACpC,IAAA,yBAAW,EAAC,eAAa,EAAE,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACxF,IAAA,yBAAW,EACP,eAAa,EACb,OAAO,CAAC,cAAc,CAAC,cAAc,EACrC,SAAS,CAAC,MAAM,EAChB,OAAO,CACV,CAAC;YAEF,IAAA,yBAAW,EAAC,eAAa,EAAE,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC5F,CAAC,CAAC,CAAC;QAEH,IAAI,SAAS,CAAC,OAAO,IAAI,KAAK,EAAE;YAC5B,IAAA,yBAAW,EAAC,OAAO,EAAE,cAAc,EAAE;gBACjC,OAAO,CAAC,aAAa,CAAC,kBAAkB,CAAC,GAAG,EAAE,eAAa,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YACrF,CAAC,CAAC,CAAC;SACN;aAAM;YACH,OAAO,CAAC,aAAa,CAAC,kBAAkB,CAAC,GAAG,EAAE,eAAa,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;SACpF;QAED,OAAO,GAAG,eAAa,CAAC;KAC3B;IAED,IAAI,OAAO,EAAE;QACT,MAAA,OAAO,CAAC,aAAa,+CAArB,OAAO,EAAiB,SAAS,EAAE,OAAO,CAAC,CAAC;KAC/C;IAED,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC;AAnDW,QAAA,qBAAqB,yBAmDhC","sourcesContent":["import { applyFormat } from '../utils/applyFormat';\nimport { isBlockGroupEmpty } from '../../modelApi/common/isEmpty';\nimport { reuseCachedElement } from '../../domUtils/reuseCachedElement';\nimport { stackFormat } from '../utils/stackFormat';\nimport type {\n ContentModelBlockFormat,\n ContentModelBlockHandler,\n ContentModelFormatContainer,\n ContentModelSegmentFormat,\n ModelToDomContext,\n} from 'roosterjs-content-model-types';\n\nconst PreChildFormat: ContentModelSegmentFormat & ContentModelBlockFormat = {\n fontFamily: 'monospace',\n whiteSpace: 'pre',\n};\n\n/**\n * @internal\n */\nexport const handleFormatContainer: ContentModelBlockHandler<ContentModelFormatContainer> = (\n doc: Document,\n parent: Node,\n container: ContentModelFormatContainer,\n context: ModelToDomContext,\n refNode: Node | null\n) => {\n let element = context.allowCacheElement ? container.cachedElement : undefined;\n\n if (element) {\n refNode = reuseCachedElement(parent, element, refNode, context.rewriteFromModel);\n\n context.modelHandlers.blockGroupChildren(doc, element, container, context);\n } else if (!isBlockGroupEmpty(container)) {\n const containerNode = doc.createElement(container.tagName);\n\n if (context.allowCacheElement) {\n container.cachedElement = containerNode;\n }\n\n parent.insertBefore(containerNode, refNode);\n context.rewriteFromModel.addedBlockElements.push(containerNode);\n\n stackFormat(context, container.tagName, () => {\n applyFormat(containerNode, context.formatAppliers.container, container.format, context);\n applyFormat(\n containerNode,\n context.formatAppliers.segmentOnBlock,\n container.format,\n context\n );\n\n applyFormat(containerNode, context.formatAppliers.container, container.format, context);\n });\n\n if (container.tagName == 'pre') {\n stackFormat(context, PreChildFormat, () => {\n context.modelHandlers.blockGroupChildren(doc, containerNode, container, context);\n });\n } else {\n context.modelHandlers.blockGroupChildren(doc, containerNode, container, context);\n }\n\n element = containerNode;\n }\n\n if (element) {\n context.onNodeCreated?.(container, element);\n }\n\n return refNode;\n};\n"]}
1
+ {"version":3,"file":"handleFormatContainer.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-dom/lib/modelToDom/handlers/handleFormatContainer.ts"],"names":[],"mappings":";;;AAAA,oDAAmD;AACnD,yDAAkE;AAClE,wEAAuE;AACvE,oDAAmD;AASnD,IAAM,cAAc,GAAwD;IACxE,UAAU,EAAE,WAAW;IACvB,UAAU,EAAE,KAAK;CACpB,CAAC;AAEF;;GAEG;AACI,IAAM,qBAAqB,GAA0D,UACxF,GAAa,EACb,MAAY,EACZ,SAAsC,EACtC,OAA0B,EAC1B,OAAoB;;IAEpB,IAAI,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;IAE9E,IAAI,OAAO,EAAE;QACT,OAAO,GAAG,IAAA,uCAAkB,EAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAEjF,OAAO,CAAC,aAAa,CAAC,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;KAC9E;SAAM,IAAI,CAAC,IAAA,2BAAiB,EAAC,SAAS,CAAC,EAAE;QACtC,IAAM,eAAa,GAAG,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAE3D,IAAI,OAAO,CAAC,iBAAiB,EAAE;YAC3B,SAAS,CAAC,aAAa,GAAG,eAAa,CAAC;SAC3C;QAED,MAAM,CAAC,YAAY,CAAC,eAAa,EAAE,OAAO,CAAC,CAAC;QAC5C,OAAO,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,IAAI,CAAC,eAAa,CAAC,CAAC;QAEhE,IAAA,yBAAW,EAAC,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE;YACpC,IAAA,yBAAW,EAAC,eAAa,EAAE,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACxF,IAAA,yBAAW,EACP,eAAa,EACb,OAAO,CAAC,cAAc,CAAC,cAAc,EACrC,SAAS,CAAC,MAAM,EAChB,OAAO,CACV,CAAC;YAEF,IAAA,yBAAW,EAAC,eAAa,EAAE,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC5F,CAAC,CAAC,CAAC;QAEH,IAAA,yBAAW,EACP,OAAO,EACP,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,EAC7E;YACI,IAAI,SAAS,CAAC,OAAO,IAAI,KAAK,EAAE;gBAC5B,IAAA,yBAAW,EAAC,OAAO,EAAE,cAAc,EAAE;oBACjC,OAAO,CAAC,aAAa,CAAC,kBAAkB,CACpC,GAAG,EACH,eAAa,EACb,SAAS,EACT,OAAO,CACV,CAAC;gBACN,CAAC,CAAC,CAAC;aACN;iBAAM;gBACH,OAAO,CAAC,aAAa,CAAC,kBAAkB,CACpC,GAAG,EACH,eAAa,EACb,SAAS,EACT,OAAO,CACV,CAAC;aACL;QACL,CAAC,CACJ,CAAC;QAEF,OAAO,GAAG,eAAa,CAAC;KAC3B;IAED,IAAI,OAAO,EAAE;QACT,MAAA,OAAO,CAAC,aAAa,+CAArB,OAAO,EAAiB,SAAS,EAAE,OAAO,CAAC,CAAC;KAC/C;IAED,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC;AAnEW,QAAA,qBAAqB,yBAmEhC","sourcesContent":["import { applyFormat } from '../utils/applyFormat';\nimport { isBlockGroupEmpty } from '../../modelApi/common/isEmpty';\nimport { reuseCachedElement } from '../../domUtils/reuseCachedElement';\nimport { stackFormat } from '../utils/stackFormat';\nimport type {\n ContentModelBlockFormat,\n ContentModelBlockHandler,\n ContentModelFormatContainer,\n ContentModelSegmentFormat,\n ModelToDomContext,\n} from 'roosterjs-content-model-types';\n\nconst PreChildFormat: ContentModelSegmentFormat & ContentModelBlockFormat = {\n fontFamily: 'monospace',\n whiteSpace: 'pre',\n};\n\n/**\n * @internal\n */\nexport const handleFormatContainer: ContentModelBlockHandler<ContentModelFormatContainer> = (\n doc: Document,\n parent: Node,\n container: ContentModelFormatContainer,\n context: ModelToDomContext,\n refNode: Node | null\n) => {\n let element = context.allowCacheElement ? container.cachedElement : undefined;\n\n if (element) {\n refNode = reuseCachedElement(parent, element, refNode, context.rewriteFromModel);\n\n context.modelHandlers.blockGroupChildren(doc, element, container, context);\n } else if (!isBlockGroupEmpty(container)) {\n const containerNode = doc.createElement(container.tagName);\n\n if (context.allowCacheElement) {\n container.cachedElement = containerNode;\n }\n\n parent.insertBefore(containerNode, refNode);\n context.rewriteFromModel.addedBlockElements.push(containerNode);\n\n stackFormat(context, container.tagName, () => {\n applyFormat(containerNode, context.formatAppliers.container, container.format, context);\n applyFormat(\n containerNode,\n context.formatAppliers.segmentOnBlock,\n container.format,\n context\n );\n\n applyFormat(containerNode, context.formatAppliers.container, container.format, context);\n });\n\n stackFormat(\n context,\n container.format.direction ? { direction: container.format.direction } : null,\n () => {\n if (container.tagName == 'pre') {\n stackFormat(context, PreChildFormat, () => {\n context.modelHandlers.blockGroupChildren(\n doc,\n containerNode,\n container,\n context\n );\n });\n } else {\n context.modelHandlers.blockGroupChildren(\n doc,\n containerNode,\n container,\n context\n );\n }\n }\n );\n\n element = containerNode;\n }\n\n if (element) {\n context.onNodeCreated?.(container, element);\n }\n\n return refNode;\n};\n"]}
@@ -52,7 +52,9 @@ var handleListItem = function (doc, parent, listItem, context, refNode) {
52
52
  // Need to apply listItemElement formats after applying metadata since the list numbers value relies on the result of metadata handling
53
53
  (0, applyFormat_1.applyFormat)(li, context.formatAppliers.listItemElement, listItem.format, context);
54
54
  (0, stackFormat_1.stackFormat)(context, listItem.formatHolder.format, function () {
55
- context.modelHandlers.blockGroupChildren(doc, li, listItem, context);
55
+ (0, stackFormat_1.stackFormat)(context, listItem.format.direction ? { direction: listItem.format.direction } : null, function () {
56
+ context.modelHandlers.blockGroupChildren(doc, li, listItem, context);
57
+ });
56
58
  });
57
59
  }
58
60
  else {