@heartlandone/vega 2.102.0 → 2.103.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.
- package/dist/cjs/{app-globals-49c2a999.js → app-globals-85986306.js} +10 -10
- package/dist/cjs/{code-block-06e6591f.js → code-block-72de6c4d.js} +80 -1
- package/dist/cjs/{component-value-history-controller-slimmer.abstract-f29908f8.js → component-value-history-controller-slimmer.abstract-23d2b3d8.js} +3 -3
- package/dist/cjs/{content-state-8c862e5e.js → content-state-ff40bdc6.js} +38 -5
- package/dist/cjs/{date-required-rule-b672c432.js → date-required-rule-608e704b.js} +1 -1
- package/dist/cjs/{design-token-351ffd2c.js → design-token-a101a8d0.js} +3 -3
- package/dist/cjs/{element-appender-slimmer-f932b166.js → element-appender-slimmer-b93cc564.js} +2 -2
- package/dist/cjs/{form-field-controller-slimmer-5adb86ae.js → form-field-controller-slimmer-124d54ea.js} +1 -1
- package/dist/cjs/{image-annotation-action-25907d6b.js → image-annotation-action-1ee41bc7.js} +2 -2
- package/dist/cjs/{image-extension-1cf84f27.js → image-extension-6a92c524.js} +247 -5
- package/dist/cjs/index.cjs.js +17 -17
- package/dist/cjs/{inject-keyboard-manager-84d33920.js → inject-keyboard-manager-32d7dd0e.js} +1 -1
- package/dist/cjs/{internal-calendar-period-factory-3c5236be.js → internal-calendar-period-factory-c3198ea7.js} +1 -1
- package/dist/cjs/{internal-translation-controller-eae8a8de.js → internal-translation-controller-0d67ca4d.js} +1 -0
- package/dist/cjs/{keyboard-manager-baa83a61.js → keyboard-manager-332eec89.js} +1 -1
- package/dist/cjs/{keyboard-manager-slimmer-d1974b28.js → keyboard-manager-slimmer-a2872981.js} +1 -1
- package/dist/cjs/{link-extension-2a6133b7.js → link-extension-1b4ed437.js} +3 -3
- package/dist/cjs/loader.cjs.js +12 -12
- package/dist/cjs/{month-view-generator-a6827548.js → month-view-generator-b6a2b8be.js} +1 -1
- package/dist/cjs/{public-rules-7f26e0ae.js → public-rules-2066613c.js} +7 -7
- package/dist/cjs/{range-518b95a2.js → range-712fe703.js} +1 -1
- package/dist/cjs/{responsive-format-facade-95c54444.js → responsive-format-facade-44d33457.js} +1 -1
- package/dist/cjs/{rich-text-editor-required-rule-5d0c76ec.js → rich-text-editor-required-rule-1aa75d22.js} +1 -1
- package/dist/cjs/{split-cell-operation-28f6f8d9.js → split-cell-operation-afc82323.js} +3 -3
- package/dist/cjs/{state-border-formatter-6c284859.js → state-border-formatter-49984fd6.js} +1 -1
- package/dist/cjs/{string-format-strategy.abstract-f15b6196.js → string-format-strategy.abstract-bd563c01.js} +1 -1
- package/dist/cjs/{string-input-formatter-slimmer-5a3f1b55.js → string-input-formatter-slimmer-4faebac9.js} +1 -1
- package/dist/cjs/{string-mask-strategy-af6f3ba0.js → string-mask-strategy-624c4398.js} +2 -2
- package/dist/cjs/{style-formatter-324211fd.js → style-formatter-151d89a3.js} +2 -2
- package/dist/cjs/{time-required-rule-9e714442.js → time-required-rule-8cd8f9b9.js} +1 -1
- package/dist/cjs/{token-extension-86723cad.js → token-extension-72d0cb08.js} +1011 -767
- package/dist/cjs/{translation-slimmer-0227ee24.js → translation-slimmer-1771d01f.js} +1 -1
- package/dist/cjs/{type-guard-29e01bd4.js → type-guard-cce6fe1f.js} +1 -1
- package/dist/cjs/{valid-credit-card-number-rule-4ec364af.js → valid-credit-card-number-rule-b13c2fc4.js} +1 -1
- package/dist/cjs/vega-accordion.cjs.entry.js +6 -6
- package/dist/cjs/vega-app-header-button.cjs.entry.js +5 -5
- package/dist/cjs/vega-box.cjs.entry.js +6 -6
- package/dist/cjs/vega-button-circle.cjs.entry.js +5 -5
- package/dist/cjs/vega-button.cjs.entry.js +3 -3
- package/dist/cjs/vega-calendar_5.cjs.entry.js +7 -7
- package/dist/cjs/vega-card.cjs.entry.js +5 -5
- package/dist/cjs/vega-carousel.cjs.entry.js +3 -3
- package/dist/cjs/vega-checkbox_2.cjs.entry.js +2 -2
- package/dist/cjs/vega-chip.cjs.entry.js +5 -5
- package/dist/cjs/vega-code-block.cjs.entry.js +8 -8
- package/dist/cjs/vega-color-picker.cjs.entry.js +2 -2
- package/dist/cjs/vega-color-swatch-picker.cjs.entry.js +3 -3
- package/dist/cjs/vega-color-swatch.cjs.entry.js +2 -2
- package/dist/cjs/vega-combo-box.cjs.entry.js +8 -8
- package/dist/cjs/vega-date-picker_2.cjs.entry.js +13 -13
- package/dist/cjs/vega-dialog_2.cjs.entry.js +3 -3
- package/dist/cjs/vega-divider.cjs.entry.js +5 -5
- package/dist/cjs/vega-dropdown_5.cjs.entry.js +7 -7
- package/dist/cjs/vega-env-manager-23b8b23c.js +2 -2
- package/dist/cjs/vega-field-label.cjs.entry.js +2 -2
- package/dist/cjs/vega-file-uploader.cjs.entry.js +3 -3
- package/dist/cjs/vega-flag-icon.cjs.entry.js +5 -5
- package/dist/cjs/vega-flex.cjs.entry.js +6 -6
- package/dist/cjs/vega-font.cjs.entry.js +5 -5
- package/dist/cjs/vega-form.cjs.entry.js +2 -2
- package/dist/cjs/vega-grid.cjs.entry.js +5 -5
- package/dist/cjs/vega-icon.cjs.entry.js +5 -5
- package/dist/cjs/vega-image-uploader.cjs.entry.js +5 -5
- package/dist/cjs/vega-input-credit-card.cjs.entry.js +6 -6
- package/dist/cjs/vega-input-numeric.cjs.entry.js +12 -14
- package/dist/cjs/vega-input-passcode.cjs.entry.js +5 -5
- package/dist/cjs/vega-input-phone-number.cjs.entry.js +4 -4
- package/dist/cjs/vega-input-range.cjs.entry.js +3 -3
- package/dist/cjs/vega-input-select.cjs.entry.js +5 -5
- package/dist/cjs/vega-input.cjs.entry.js +31 -27
- package/dist/cjs/vega-left-nav_5.cjs.entry.js +7 -7
- package/dist/cjs/vega-loader-wrapper_2.cjs.entry.js +3 -3
- package/dist/cjs/vega-pagination-page-size-selector-mobile.cjs.entry.js +2 -2
- package/dist/cjs/vega-pagination.cjs.entry.js +4 -4
- package/dist/cjs/vega-popover_2.cjs.entry.js +8 -8
- package/dist/cjs/vega-progress-tracker_2.cjs.entry.js +3 -3
- package/dist/cjs/vega-radio_2.cjs.entry.js +5 -5
- package/dist/cjs/vega-rich-text-bookmark-editor.cjs.entry.js +2 -2
- package/dist/cjs/vega-rich-text-content.cjs.entry.js +6 -6
- package/dist/cjs/vega-rich-text-editor_4.cjs.entry.js +474 -207
- package/dist/cjs/vega-rich-text-find-replace-panel.cjs.entry.js +1 -1
- package/dist/cjs/vega-rich-text-special-characters-panel.cjs.entry.js +5 -5
- package/dist/cjs/vega-rich-text-table-properties_3.cjs.entry.js +8 -8
- package/dist/cjs/vega-selection-chip_2.cjs.entry.js +4 -4
- package/dist/cjs/vega-selection-tile_2.cjs.entry.js +2 -2
- package/dist/cjs/vega-sidenav_3.cjs.entry.js +3 -3
- package/dist/cjs/vega-signature-capture.cjs.entry.js +7 -7
- package/dist/cjs/vega-stepper.cjs.entry.js +2 -2
- package/dist/cjs/vega-tab-group_2.cjs.entry.js +6 -6
- package/dist/cjs/vega-table_11.cjs.entry.js +4 -4
- package/dist/cjs/vega-textarea.cjs.entry.js +2 -2
- package/dist/cjs/vega-time-picker_2.cjs.entry.js +9 -9
- package/dist/cjs/vega-toggle-switch.cjs.entry.js +2 -2
- package/dist/cjs/vega-tooltip_2.cjs.entry.js +6 -6
- package/dist/cjs/vega.cjs.js +12 -12
- package/dist/collection/components/vega-input/slimmers/controllers/vega-input-state-controller.js +0 -14
- package/dist/collection/components/vega-input/slimmers/renderers/vega-input-input-container-renderer.js +11 -2
- package/dist/collection/components/vega-input/slimmers/renderers/vega-input-input-renderer.js +11 -1
- package/dist/collection/components/vega-input/vega-input.js +52 -8
- package/dist/collection/components/vega-input-numeric/slimmers/renderers/vega-input-numeric-renderer.js +7 -1
- package/dist/collection/components/vega-input-numeric/vega-input-numeric.js +0 -8
- package/dist/collection/components/vega-rich-text-editor/constants/constant.js +4 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/sequential-composition-strategy.js +31 -0
- package/dist/collection/components/vega-rich-text-editor/dto/actions/modify-content-action.abstract.js +1 -0
- package/dist/collection/components/vega-rich-text-editor/dto/actions/sequential-composition-action.js +14 -0
- package/dist/collection/components/vega-rich-text-editor/dto/content-state.js +4 -1
- package/dist/collection/components/vega-rich-text-editor/dto/flush-changes-payload.js +1 -0
- package/dist/collection/components/vega-rich-text-editor/dto/nodes/image-node.js +3 -2
- package/dist/collection/components/vega-rich-text-editor/extensions/functions/dto/function-block.js +30 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/functions/element-to-dto-strategies/div-to-function-block-strategy.js +1 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/controllers/chooser-positioner.js +107 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/controllers/paste-chooser-controller.js +91 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/controllers/paste-event-interceptor.js +47 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/controllers/selection-snapshot-service.js +54 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/parse-local-images-helper/image-extractor.js +17 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/paste-chooser-ui.js +3 -1
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/paste-extension.js +41 -354
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/pipeline/data-transfer-builder.js +36 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/pipeline/paste-dispatcher.js +23 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/pipeline/paste-processing-pipeline.js +30 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/strategies/paste-processing-strategy.abstract.js +34 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/strategies/paste-strategy-selector.js +19 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/strategies/plain-paste-strategy.js +74 -0
- package/dist/collection/components/vega-rich-text-editor/extensions/paste/type.js +1 -0
- package/dist/collection/components/vega-rich-text-editor/helpers/utils.js +67 -0
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/abstract-delete-content-handler.js +67 -11
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/backward-delete-content-handler.js +4 -17
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/base-handler.js +34 -1
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/forward-delete-content-handler.js +13 -32
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-line-break-handler.js +60 -25
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-paragraph-handler.js +55 -19
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-paste-handler.js +165 -59
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-text-handler.js +55 -21
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/user-input-controller.js +2 -16
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/value-controller.js +11 -1
- package/dist/collection/components/vega-rich-text-editor/utils/html-to-plain-text-utils.js +240 -0
- package/dist/collection/helpers/translation/locales/en.js +1 -0
- package/dist/esm/{app-globals-da5c83c2.js → app-globals-8cdfc5c9.js} +10 -10
- package/dist/esm/{code-block-d8f83d85.js → code-block-9360c331.js} +74 -2
- package/dist/esm/{component-value-history-controller-slimmer.abstract-642e7147.js → component-value-history-controller-slimmer.abstract-9ea58806.js} +3 -3
- package/dist/esm/{content-state-486eae1d.js → content-state-67a12e74.js} +38 -5
- package/dist/esm/{date-required-rule-08695d25.js → date-required-rule-66b5bf02.js} +1 -1
- package/dist/esm/{design-token-df3331d9.js → design-token-acd1efeb.js} +3 -3
- package/dist/esm/{element-appender-slimmer-f02a227f.js → element-appender-slimmer-7e5bc1e9.js} +2 -2
- package/dist/esm/{form-field-controller-slimmer-a7c0a0f8.js → form-field-controller-slimmer-d653c494.js} +1 -1
- package/dist/esm/{image-annotation-action-df744ba5.js → image-annotation-action-9525be48.js} +2 -2
- package/dist/esm/{image-extension-20b39140.js → image-extension-aea75132.js} +246 -6
- package/dist/esm/index.js +17 -17
- package/dist/esm/{inject-keyboard-manager-399ed867.js → inject-keyboard-manager-f6522d2f.js} +1 -1
- package/dist/esm/{internal-calendar-period-factory-7b866c3b.js → internal-calendar-period-factory-261df2f2.js} +1 -1
- package/dist/esm/{internal-translation-controller-4a7ee4d5.js → internal-translation-controller-3637e47e.js} +1 -0
- package/dist/esm/{keyboard-manager-f5d13a34.js → keyboard-manager-53e8d8d0.js} +1 -1
- package/dist/esm/{keyboard-manager-slimmer-f40dcb54.js → keyboard-manager-slimmer-b3de042d.js} +1 -1
- package/dist/esm/{link-extension-3f93d70d.js → link-extension-57ba9520.js} +3 -3
- package/dist/esm/loader.js +12 -12
- package/dist/esm/{month-view-generator-0c665987.js → month-view-generator-15215a09.js} +1 -1
- package/dist/esm/{public-rules-470a1dac.js → public-rules-c77a1550.js} +7 -7
- package/dist/esm/{range-8e89fb54.js → range-3c74e1c8.js} +1 -1
- package/dist/esm/{responsive-format-facade-55131a33.js → responsive-format-facade-1b325d06.js} +1 -1
- package/dist/esm/{rich-text-editor-required-rule-06caf383.js → rich-text-editor-required-rule-cfd32ba2.js} +1 -1
- package/dist/esm/{split-cell-operation-e158366a.js → split-cell-operation-85a036f9.js} +3 -3
- package/dist/esm/{state-border-formatter-2b73fa08.js → state-border-formatter-ce3495b0.js} +1 -1
- package/dist/esm/{string-format-strategy.abstract-8c7937e3.js → string-format-strategy.abstract-8ce04558.js} +1 -1
- package/dist/esm/{string-input-formatter-slimmer-681c6b71.js → string-input-formatter-slimmer-0d60ba7d.js} +1 -1
- package/dist/esm/{string-mask-strategy-b8cceee6.js → string-mask-strategy-cabc1d50.js} +2 -2
- package/dist/esm/{style-formatter-fcd70869.js → style-formatter-00fe4f1c.js} +2 -2
- package/dist/esm/{time-required-rule-ce50859b.js → time-required-rule-57ceeae9.js} +1 -1
- package/dist/esm/{token-extension-2401e753.js → token-extension-645a9520.js} +1011 -767
- package/dist/esm/{translation-slimmer-b3f3cf65.js → translation-slimmer-b69057eb.js} +1 -1
- package/dist/esm/{type-guard-08c82e08.js → type-guard-204094c6.js} +1 -1
- package/dist/esm/{valid-credit-card-number-rule-66bad519.js → valid-credit-card-number-rule-0874e19f.js} +1 -1
- package/dist/esm/vega-accordion.entry.js +6 -6
- package/dist/esm/vega-app-header-button.entry.js +5 -5
- package/dist/esm/vega-box.entry.js +6 -6
- package/dist/esm/vega-button-circle.entry.js +5 -5
- package/dist/esm/vega-button.entry.js +3 -3
- package/dist/esm/vega-calendar_5.entry.js +7 -7
- package/dist/esm/vega-card.entry.js +5 -5
- package/dist/esm/vega-carousel.entry.js +3 -3
- package/dist/esm/vega-checkbox_2.entry.js +2 -2
- package/dist/esm/vega-chip.entry.js +5 -5
- package/dist/esm/vega-code-block.entry.js +8 -8
- package/dist/esm/vega-color-picker.entry.js +2 -2
- package/dist/esm/vega-color-swatch-picker.entry.js +3 -3
- package/dist/esm/vega-color-swatch.entry.js +2 -2
- package/dist/esm/vega-combo-box.entry.js +8 -8
- package/dist/esm/vega-date-picker_2.entry.js +13 -13
- package/dist/esm/vega-dialog_2.entry.js +3 -3
- package/dist/esm/vega-divider.entry.js +5 -5
- package/dist/esm/vega-dropdown_5.entry.js +7 -7
- package/dist/esm/vega-env-manager-8f8dc473.js +2 -2
- package/dist/esm/vega-field-label.entry.js +2 -2
- package/dist/esm/vega-file-uploader.entry.js +3 -3
- package/dist/esm/vega-flag-icon.entry.js +5 -5
- package/dist/esm/vega-flex.entry.js +6 -6
- package/dist/esm/vega-font.entry.js +5 -5
- package/dist/esm/vega-form.entry.js +2 -2
- package/dist/esm/vega-grid.entry.js +5 -5
- package/dist/esm/vega-icon.entry.js +5 -5
- package/dist/esm/vega-image-uploader.entry.js +5 -5
- package/dist/esm/vega-input-credit-card.entry.js +6 -6
- package/dist/esm/vega-input-numeric.entry.js +12 -14
- package/dist/esm/vega-input-passcode.entry.js +5 -5
- package/dist/esm/vega-input-phone-number.entry.js +4 -4
- package/dist/esm/vega-input-range.entry.js +3 -3
- package/dist/esm/vega-input-select.entry.js +5 -5
- package/dist/esm/vega-input.entry.js +31 -27
- package/dist/esm/vega-left-nav_5.entry.js +7 -7
- package/dist/esm/vega-loader-wrapper_2.entry.js +3 -3
- package/dist/esm/vega-pagination-page-size-selector-mobile.entry.js +2 -2
- package/dist/esm/vega-pagination.entry.js +4 -4
- package/dist/esm/vega-popover_2.entry.js +8 -8
- package/dist/esm/vega-progress-tracker_2.entry.js +3 -3
- package/dist/esm/vega-radio_2.entry.js +5 -5
- package/dist/esm/vega-rich-text-bookmark-editor.entry.js +2 -2
- package/dist/esm/vega-rich-text-content.entry.js +6 -6
- package/dist/esm/vega-rich-text-editor_4.entry.js +474 -207
- package/dist/esm/vega-rich-text-find-replace-panel.entry.js +1 -1
- package/dist/esm/vega-rich-text-special-characters-panel.entry.js +5 -5
- package/dist/esm/vega-rich-text-table-properties_3.entry.js +8 -8
- package/dist/esm/vega-selection-chip_2.entry.js +4 -4
- package/dist/esm/vega-selection-tile_2.entry.js +2 -2
- package/dist/esm/vega-sidenav_3.entry.js +3 -3
- package/dist/esm/vega-signature-capture.entry.js +7 -7
- package/dist/esm/vega-stepper.entry.js +2 -2
- package/dist/esm/vega-tab-group_2.entry.js +6 -6
- package/dist/esm/vega-table_11.entry.js +4 -4
- package/dist/esm/vega-textarea.entry.js +2 -2
- package/dist/esm/vega-time-picker_2.entry.js +9 -9
- package/dist/esm/vega-toggle-switch.entry.js +2 -2
- package/dist/esm/vega-tooltip_2.entry.js +6 -6
- package/dist/esm/vega.js +12 -12
- package/dist/sri/vega-sri-manifest.json +321 -321
- package/dist/types/components/vega-input/slimmers/controllers/vega-input-state-controller.d.ts +0 -2
- package/dist/types/components/vega-input/slimmers/renderers/vega-input-input-container-renderer.d.ts +4 -0
- package/dist/types/components/vega-input/slimmers/renderers/vega-input-input-renderer.d.ts +2 -0
- package/dist/types/components/vega-input/vega-input.d.ts +15 -3
- package/dist/types/components/vega-input-numeric/slimmers/renderers/vega-input-numeric-renderer.d.ts +2 -0
- package/dist/types/components/vega-input-numeric/vega-input-numeric.d.ts +0 -2
- package/dist/types/components/vega-rich-text-editor/constants/constant.d.ts +4 -0
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/sequential-composition-strategy.d.ts +14 -0
- package/dist/types/components/vega-rich-text-editor/dto/actions/modify-content-action.abstract.d.ts +4 -1
- package/dist/types/components/vega-rich-text-editor/dto/actions/sequential-composition-action.d.ts +30 -0
- package/dist/types/components/vega-rich-text-editor/dto/flush-changes-payload.d.ts +16 -0
- package/dist/types/components/vega-rich-text-editor/extensions/functions/dto/function-block.d.ts +7 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/controllers/chooser-positioner.d.ts +33 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/controllers/paste-chooser-controller.d.ts +43 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/controllers/paste-event-interceptor.d.ts +22 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/controllers/selection-snapshot-service.d.ts +29 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/parse-local-images-helper/image-extractor.d.ts +13 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/parse-local-images-helper/paste-image-parser.d.ts +1 -1
- package/dist/types/components/vega-rich-text-editor/extensions/paste/parse-local-images-helper/pending-image-registry.d.ts +1 -1
- package/dist/types/components/vega-rich-text-editor/extensions/paste/paste-chooser-ui.d.ts +1 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/paste-extension.d.ts +28 -93
- package/dist/types/components/vega-rich-text-editor/extensions/paste/pipeline/data-transfer-builder.d.ts +10 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/pipeline/paste-dispatcher.d.ts +8 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/pipeline/paste-processing-pipeline.d.ts +18 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/strategies/paste-processing-strategy.abstract.d.ts +28 -6
- package/dist/types/components/vega-rich-text-editor/extensions/paste/strategies/paste-strategy-selector.d.ts +13 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/strategies/plain-paste-strategy.d.ts +29 -0
- package/dist/types/components/vega-rich-text-editor/extensions/paste/type.d.ts +35 -0
- package/dist/types/components/vega-rich-text-editor/helpers/utils.d.ts +47 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/abstract-delete-content-handler.d.ts +17 -6
- package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/backward-delete-content-handler.d.ts +5 -1
- package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/base-handler.d.ts +30 -1
- package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/forward-delete-content-handler.d.ts +5 -1
- package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-line-break-handler.d.ts +21 -4
- package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-paragraph-handler.d.ts +12 -4
- package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-paste-handler.d.ts +38 -5
- package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-text-handler.d.ts +7 -2
- package/dist/types/components/vega-rich-text-editor/slimmers/controllers/user-input-controller.d.ts +2 -0
- package/dist/types/components/vega-rich-text-editor/utils/html-to-plain-text-utils.d.ts +31 -0
- package/dist/types/components.d.ts +24 -0
- package/dist/types/helpers/translation/interface.d.ts +1 -0
- package/dist/types/types/public-api.d.ts +2 -1
- package/dist/vega/index.esm.js +1 -1
- package/dist/vega/{p-8a4cc7c2.entry.js → p-0169f71c.entry.js} +1 -1
- package/dist/vega/p-018bb83b.entry.js +1 -0
- package/dist/vega/{p-25e51acb.js → p-08bf08d2.js} +1 -1
- package/dist/vega/{p-85a940c0.entry.js → p-0b33753f.entry.js} +1 -1
- package/dist/vega/{p-a5fa260b.js → p-1537b1e4.js} +1 -1
- package/dist/vega/{p-7dfb1481.entry.js → p-17f6dc94.entry.js} +1 -1
- package/dist/vega/{p-dd673eb4.entry.js → p-1a4d1991.entry.js} +1 -1
- package/dist/vega/{p-557b64bd.js → p-1b2e5898.js} +1 -1
- package/dist/vega/{p-2256eb09.entry.js → p-1f1f93bf.entry.js} +1 -1
- package/dist/vega/{p-d86e0b01.js → p-1fb953f8.js} +1 -1
- package/dist/vega/{p-03efc67a.entry.js → p-2171b571.entry.js} +1 -1
- package/dist/vega/p-255fe20b.js +1 -0
- package/dist/vega/{p-cf5c5515.js → p-261cf764.js} +1 -1
- package/dist/vega/{p-f0b49ae4.entry.js → p-27e77ea1.entry.js} +1 -1
- package/dist/vega/{p-109f0e33.entry.js → p-28acbe42.entry.js} +1 -1
- package/dist/vega/{p-27c9c2a5.entry.js → p-2acc600a.entry.js} +1 -1
- package/dist/vega/p-2fc2299f.js +1 -0
- package/dist/vega/{p-b48caf90.entry.js → p-2ff659a1.entry.js} +1 -1
- package/dist/vega/{p-527c3211.entry.js → p-322da1eb.entry.js} +1 -1
- package/dist/vega/{p-dffe47db.js → p-3283fa2f.js} +1 -1
- package/dist/vega/p-3567dc55.entry.js +1 -0
- package/dist/vega/{p-c6419eb3.entry.js → p-36b795c6.entry.js} +1 -1
- package/dist/vega/p-37714a3a.js +1 -0
- package/dist/vega/{p-d7e59f31.js → p-3b4e2ba0.js} +1 -1
- package/dist/vega/{p-3d060d2f.entry.js → p-3b911043.entry.js} +1 -1
- package/dist/vega/{p-5c6d36ef.entry.js → p-3e270b65.entry.js} +1 -1
- package/dist/vega/{p-b68f55e2.js → p-4043508a.js} +1 -1
- package/dist/vega/p-4151d4a8.js +1 -0
- package/dist/vega/{p-c6b6987e.js → p-45af801f.js} +1 -1
- package/dist/vega/p-48c2150b.entry.js +1 -0
- package/dist/vega/p-4b253f74.entry.js +1 -0
- package/dist/vega/{p-75c7f8ea.entry.js → p-4cdc064d.entry.js} +1 -1
- package/dist/vega/{p-1d8a8507.entry.js → p-4e4b50f3.entry.js} +1 -1
- package/dist/vega/{p-d8fa2f19.entry.js → p-564110ba.entry.js} +1 -1
- package/dist/vega/p-5f377954.js +1 -1
- package/dist/vega/{p-bec31ffc.entry.js → p-608d3559.entry.js} +1 -1
- package/dist/vega/{p-3ce7521e.entry.js → p-64eb05d3.entry.js} +1 -1
- package/dist/vega/{p-2f5c4b61.entry.js → p-66bf209b.entry.js} +1 -1
- package/dist/vega/{p-83f5ef3a.entry.js → p-69eadbd8.entry.js} +1 -1
- package/dist/vega/{p-c66c6fd2.entry.js → p-6c4edee8.entry.js} +1 -1
- package/dist/vega/p-6e16bb3a.js +1 -0
- package/dist/vega/{p-7d748545.entry.js → p-76f4fdba.entry.js} +1 -1
- package/dist/vega/{p-4c6989ae.entry.js → p-7874055b.entry.js} +1 -1
- package/dist/vega/{p-ca60a74b.entry.js → p-7d3d24f6.entry.js} +1 -1
- package/dist/vega/{p-3bfb53e3.js → p-7f9ad7bc.js} +1 -1
- package/dist/vega/{p-18ddc6a4.entry.js → p-8193f4ef.entry.js} +1 -1
- package/dist/vega/{p-816064f2.entry.js → p-8197d172.entry.js} +1 -1
- package/dist/vega/{p-634b138c.entry.js → p-8ac0b1b2.entry.js} +1 -1
- package/dist/vega/{p-553510d8.entry.js → p-8c61db9d.entry.js} +1 -1
- package/dist/vega/{p-061a76c3.entry.js → p-8de29082.entry.js} +1 -1
- package/dist/vega/{p-325b804d.entry.js → p-8e59606f.entry.js} +1 -1
- package/dist/vega/p-8ea41806.js +1 -0
- package/dist/vega/{p-ff9090af.entry.js → p-9153c2f5.entry.js} +1 -1
- package/dist/vega/{p-a0c87e88.entry.js → p-92411f56.entry.js} +1 -1
- package/dist/vega/{p-049e64b1.entry.js → p-94d65dcf.entry.js} +1 -1
- package/dist/vega/{p-a261a675.entry.js → p-9a96fb05.entry.js} +1 -1
- package/dist/vega/{p-7044bb48.js → p-9fcfd738.js} +1 -1
- package/dist/vega/{p-b1e1c7d0.js → p-a2c7a3bc.js} +1 -1
- package/dist/vega/p-a2dcde12.js +1 -0
- package/dist/vega/{p-be0eb72f.js → p-a60d75d9.js} +1 -1
- package/dist/vega/{p-5a347a15.js → p-a9fc4043.js} +1 -1
- package/dist/vega/{p-efef0dfe.entry.js → p-abe5f7f0.entry.js} +1 -1
- package/dist/vega/{p-197388a5.entry.js → p-ac98c189.entry.js} +1 -1
- package/dist/vega/{p-dd273d89.entry.js → p-ade903b3.entry.js} +1 -1
- package/dist/vega/{p-c0eb8c58.js → p-affb40e8.js} +1 -1
- package/dist/vega/{p-277aab9b.js → p-b3a1cd22.js} +1 -1
- package/dist/vega/p-b63a90b3.entry.js +1 -0
- package/dist/vega/{p-f9f96030.entry.js → p-ba050d63.entry.js} +1 -1
- package/dist/vega/{p-bf0b46c1.js → p-ba67eb96.js} +1 -1
- package/dist/vega/{p-f0c6e9c5.entry.js → p-c08ac33f.entry.js} +1 -1
- package/dist/vega/{p-46be74fc.entry.js → p-c7ec97d1.entry.js} +1 -1
- package/dist/vega/{p-effbfc50.entry.js → p-ca1fe571.entry.js} +1 -1
- package/dist/vega/{p-408c3ad4.entry.js → p-cc9fc36a.entry.js} +1 -1
- package/dist/vega/{p-741e064e.entry.js → p-d044d54f.entry.js} +1 -1
- package/dist/vega/{p-0e0e66c9.entry.js → p-d3a9355c.entry.js} +1 -1
- package/dist/vega/p-d5a75228.js +1 -0
- package/dist/vega/{p-76135e80.entry.js → p-dc83fa6b.entry.js} +1 -1
- package/dist/vega/{p-92efdbf0.entry.js → p-dcfce26e.entry.js} +1 -1
- package/dist/vega/p-df9585f6.js +3 -0
- package/dist/vega/{p-f5f26b44.entry.js → p-e2c8a470.entry.js} +1 -1
- package/dist/vega/{p-23781e76.js → p-e33a954f.js} +1 -1
- package/dist/vega/{p-e577dda8.entry.js → p-e5fc6583.entry.js} +1 -1
- package/dist/vega/p-e668cf11.js +1 -0
- package/dist/vega/{p-0338f621.entry.js → p-e6b0a292.entry.js} +1 -1
- package/dist/vega/{p-381d8781.js → p-e84c2589.js} +1 -1
- package/dist/vega/{p-1b97e751.entry.js → p-eb945d34.entry.js} +1 -1
- package/dist/vega/{p-d8a0e3e0.entry.js → p-ebe1dd2b.entry.js} +1 -1
- package/dist/vega/{p-6beaf1c8.entry.js → p-f818bb20.entry.js} +1 -1
- package/dist/vega/p-f981cf2c.js +1 -0
- package/dist/vega/p-f9d09b0c.js +1 -0
- package/dist/vega/{p-4d20a56f.js → p-fdbdf12f.js} +1 -1
- package/dist/vega/{p-48100d38.entry.js → p-fee080b9.entry.js} +1 -1
- package/dist/vega/vega.esm.js +1 -1
- package/package.json +1 -1
- package/dist/vega/p-040bd9ca.js +0 -1
- package/dist/vega/p-087240db.js +0 -1
- package/dist/vega/p-15052b2e.entry.js +0 -1
- package/dist/vega/p-28c16885.js +0 -1
- package/dist/vega/p-30cc31dd.entry.js +0 -1
- package/dist/vega/p-3ec4d710.js +0 -1
- package/dist/vega/p-43ea1e86.js +0 -1
- package/dist/vega/p-7228088b.entry.js +0 -1
- package/dist/vega/p-7f711049.js +0 -1
- package/dist/vega/p-7fd15dd1.js +0 -1
- package/dist/vega/p-85695819.js +0 -1
- package/dist/vega/p-8e1f30ec.entry.js +0 -1
- package/dist/vega/p-9680dfe6.js +0 -1
- package/dist/vega/p-ae12cc3f.js +0 -3
- package/dist/vega/p-c0823f32.js +0 -1
- package/dist/vega/p-c5af2ecc.entry.js +0 -1
- package/dist/vega/p-fa43272c.js +0 -1
|
@@ -6,16 +6,16 @@ import { I as InternalVegaZIndexManager } from './internal-vega-z-index-manager-
|
|
|
6
6
|
import { c as createDynamicSlimmer } from './dynamic-slimmer-90b8af32.js';
|
|
7
7
|
import { P as PageResizeObserverSlimmer } from './page-resize-observer-slimmer-e24d36c5.js';
|
|
8
8
|
import { i as internalVegaEventManager } from './internal-vega-event-manager-6eebe8f8.js';
|
|
9
|
-
import { V as VegaInternalTranslation } from './internal-translation-controller-
|
|
10
|
-
import { I as InternalCalendarPeriodConverter } from './internal-calendar-period-factory-
|
|
11
|
-
import { M as ModifyContentAction, A as ActionHandleStrategyRegistry, R as RTETextNode, H as HTML_VOID_TAGS, a as
|
|
12
|
-
import { U as UpdateCursorPositionAction, V as VegaRTEContent, B as BlockToRTEBlockStrategyAbstract, E as ElementToDTOStrategy, h as htmlElementToAnnotationGenerator, H as HtmlBlockStrategy, I as InsertNewParagraphAction, R as RTEImageBlock, a as InsertChildrenBeforeStrategy, P as PasteContentStrategy, A as AnnotationGeneratorStrategyAbstract, S as StylePreservator, b as RTEImageNode, C as COMMIT_VALUE } from './content-state-
|
|
13
|
-
import { a as VegaRTEExtensionRenderer, b as VegaRTEExtension, e as extensionContextManager } from './link-extension-
|
|
9
|
+
import { V as VegaInternalTranslation } from './internal-translation-controller-3637e47e.js';
|
|
10
|
+
import { I as InternalCalendarPeriodConverter } from './internal-calendar-period-factory-261df2f2.js';
|
|
11
|
+
import { M as ModifyContentAction, A as ActionHandleStrategyRegistry, R as RTETextNode, H as HTML_VOID_TAGS, a as RTENode, s as stateEntityRenderingRegistry, b as RTEBlock, c as RTETextBlock, N as NodeAnnotationTypeEnum, d as RTE_BLOCK_BOUNDARY_ATTRIBUTE, e as RTEAnnotationStyle, f as ActionHandleStrategy, I as InsertChildrenAfterAction, g as AppendChildrenAction, h as InsertChildrenBeforeAction, i as InternalAnnotationTypeEnum, j as ModifyContentActionType, B as BlockAnnotation, k as AnnotationAction, l as RemoveChildrenAction, C as CommonAnnotationTypeEnum, m as CustomAttributeAnnotation, n as RTEDTOClassManager, o as RTEFilterStylesStrategy, p as RTEDecoratorNode, S as SplitBlockWithNodeAction, U as UpdateTextAction, q as RTECodeBlock, r as RTEListItemBlock, t as RTECodeBlockNode, u as CustomStyleAnnotation, v as RTEFilterStylesStrategyRegistry, w as plainPasteLinesToHtml, x as toPlainPasteLines, y as RTE_PRESERVED_WHITESPACE_DATA_TYPE, z as RTE_PASTE_MODE_DATA_TYPE, D as RTE_WORD_COUNT_KEY } from './code-block-9360c331.js';
|
|
12
|
+
import { U as UpdateCursorPositionAction, V as VegaRTEContent, B as BlockToRTEBlockStrategyAbstract, E as ElementToDTOStrategy, h as htmlElementToAnnotationGenerator, H as HtmlBlockStrategy, I as InsertNewParagraphAction, R as RTEImageBlock, a as InsertChildrenBeforeStrategy, P as PasteContentStrategy, A as AnnotationGeneratorStrategyAbstract, S as StylePreservator, b as RTEImageNode, C as COMMIT_VALUE } from './content-state-67a12e74.js';
|
|
13
|
+
import { a as VegaRTEExtensionRenderer, b as VegaRTEExtension, e as extensionContextManager } from './link-extension-57ba9520.js';
|
|
14
14
|
import { V as VegaInternalIconManager } from './internal-icon-manager-d4d534d2.js';
|
|
15
|
-
import { i as isNonNullable } from './type-guard-
|
|
15
|
+
import { i as isNonNullable } from './type-guard-204094c6.js';
|
|
16
16
|
import { v as vegaNonceManager } from './vega-nonce-manager-497e5eb5.js';
|
|
17
|
-
import { b as VegaRTEToolbarButtonRenderer, A as ActionHandlerInterceptor, R as ReplaceSelectedTextAction, I as InsertNodeToNearestRootAction } from './image-extension-
|
|
18
|
-
import { R as RTETableExtensionAnnotationTypeEnum, a as RTE_TABLE_HEAD_DEFAULT_BACKGROUND_COLOR, S as SettingEventHandler, T as TableSettingType, b as RTETableAnnotation, c as RTETableCellAnnotation, d as RTETableHeadCellBlock, e as RowOperationEventHandler, C as ColumnOperationEventHandler, M as MergeCellsOperationEventHandler, f as SplitCellOperationEventHandler, g as RTETableColorManager, h as RTETableBlock, i as generateTableBody, j as RTETableCellBlock, k as RTETableHeadBlock, l as RTETableBodyBlock, m as getParentBlockByType, n as RTETableHeadCellAnnotation, o as TableColumnStrategy, p as getAllTableRows, q as buildTableGrid, s as setSpanAttributes, r as findCellBlockById, t as getDefaultCellBlockTemplate, I as InsertTableColumnDirection, u as buildCellStartColumnMap, v as getTableColumnCount, w as getFirstNode, x as getCellSpan, y as createNewCell, z as MergeCellsOperationType, A as RTETableRowBlock, B as getActualColumnPosition, D as InsertTableRowDirection, E as RTE_TABLE_DEFAULT_COLORS, F as INSERT_TABLE_ROW_INTO_DIFFERENT_SECTION, G as INSERT_TABLE_ROW_INTO_SAME_SECTION, H as DELETE_TABLE_ROW, J as TOGGLE_HEADER_ROW, K as INSERT_TABLE_COLUMN, L as DELETE_TABLE_COLUMN, N as TOGGLE_HEADER_TABLE_COLUMN, O as ToggleHeaderTableColumnStrategy, P as SPLIT_TABLE_CELL, Q as REPLACE_TABLE_CELL, U as SPLIT_CELL_HORIZONTALLY, W as SPLIT_CELL_VERTICALLY, X as SELECT_TABLE_COLUMN, Y as MERGE_CELLS } from './split-cell-operation-
|
|
17
|
+
import { b as VegaRTEToolbarButtonRenderer, A as ActionHandlerInterceptor, R as ReplaceSelectedTextAction, h as htmlContainsTable, c as htmlToPlainText, I as InsertNodeToNearestRootAction } from './image-extension-aea75132.js';
|
|
18
|
+
import { R as RTETableExtensionAnnotationTypeEnum, a as RTE_TABLE_HEAD_DEFAULT_BACKGROUND_COLOR, S as SettingEventHandler, T as TableSettingType, b as RTETableAnnotation, c as RTETableCellAnnotation, d as RTETableHeadCellBlock, e as RowOperationEventHandler, C as ColumnOperationEventHandler, M as MergeCellsOperationEventHandler, f as SplitCellOperationEventHandler, g as RTETableColorManager, h as RTETableBlock, i as generateTableBody, j as RTETableCellBlock, k as RTETableHeadBlock, l as RTETableBodyBlock, m as getParentBlockByType, n as RTETableHeadCellAnnotation, o as TableColumnStrategy, p as getAllTableRows, q as buildTableGrid, s as setSpanAttributes, r as findCellBlockById, t as getDefaultCellBlockTemplate, I as InsertTableColumnDirection, u as buildCellStartColumnMap, v as getTableColumnCount, w as getFirstNode, x as getCellSpan, y as createNewCell, z as MergeCellsOperationType, A as RTETableRowBlock, B as getActualColumnPosition, D as InsertTableRowDirection, E as RTE_TABLE_DEFAULT_COLORS, F as INSERT_TABLE_ROW_INTO_DIFFERENT_SECTION, G as INSERT_TABLE_ROW_INTO_SAME_SECTION, H as DELETE_TABLE_ROW, J as TOGGLE_HEADER_ROW, K as INSERT_TABLE_COLUMN, L as DELETE_TABLE_COLUMN, N as TOGGLE_HEADER_TABLE_COLUMN, O as ToggleHeaderTableColumnStrategy, P as SPLIT_TABLE_CELL, Q as REPLACE_TABLE_CELL, U as SPLIT_CELL_HORIZONTALLY, W as SPLIT_CELL_VERTICALLY, X as SELECT_TABLE_COLUMN, Y as MERGE_CELLS } from './split-cell-operation-85a036f9.js';
|
|
19
19
|
import { C as ChangeManager } from './change-manager-6a7eb88c.js';
|
|
20
20
|
import { D as DomNodeSubjectObserverFactory, d as domNodeSubjectFactory } from './dom-node-subject-observer-factory-bb7e68a0.js';
|
|
21
21
|
import { V as VegaInternalRTEExtensionTableCellsSelectionAnchor, a as VegaInternalPopoverUpdateTarget, b as VegaInternalRTEExtensionTableCellSelectionChange } from './vega-internal-event-id-02093067.js';
|
|
@@ -1628,6 +1628,154 @@ const FUNCTION_ELEMENT_CLASSES = [
|
|
|
1628
1628
|
FUNCTION_SYNTAX_CLASS,
|
|
1629
1629
|
];
|
|
1630
1630
|
|
|
1631
|
+
/**
|
|
1632
|
+
* Class representing a logic control node in the rich text editor.
|
|
1633
|
+
*/
|
|
1634
|
+
class RTELogicControlNode extends RTENode {
|
|
1635
|
+
constructor(id, text, parent) {
|
|
1636
|
+
super(id);
|
|
1637
|
+
this.type = 'logic-control-node';
|
|
1638
|
+
this.text = '';
|
|
1639
|
+
this.text = text;
|
|
1640
|
+
this.parent = parent;
|
|
1641
|
+
}
|
|
1642
|
+
/**
|
|
1643
|
+
* Clone the current node instance.
|
|
1644
|
+
*
|
|
1645
|
+
* @returns {RTELogicControlNode} - A new instance of RTELogicControlNode.
|
|
1646
|
+
*/
|
|
1647
|
+
clone() {
|
|
1648
|
+
return new RTELogicControlNode(this.id, this.text, this.parent);
|
|
1649
|
+
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Convert the node to its HTML representation.
|
|
1652
|
+
*
|
|
1653
|
+
* @returns {string} - The HTML string of the logic control node.
|
|
1654
|
+
*/
|
|
1655
|
+
toHtml() {
|
|
1656
|
+
return this.text;
|
|
1657
|
+
}
|
|
1658
|
+
/**
|
|
1659
|
+
* Convert the node to a JSON representation.
|
|
1660
|
+
*
|
|
1661
|
+
* @returns {unknown} - The JSON object of the statement syntax node.
|
|
1662
|
+
*/
|
|
1663
|
+
toJSON() {
|
|
1664
|
+
return {
|
|
1665
|
+
id: this.id,
|
|
1666
|
+
type: this.type,
|
|
1667
|
+
text: this.text,
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
/**
|
|
1671
|
+
* Get the end offset of the node's range.
|
|
1672
|
+
*
|
|
1673
|
+
* @returns {number} - The end offset of the node's range.
|
|
1674
|
+
*/
|
|
1675
|
+
getRangeEndOffset() {
|
|
1676
|
+
return 1;
|
|
1677
|
+
}
|
|
1678
|
+
/**
|
|
1679
|
+
* Get the container element for the node's range.
|
|
1680
|
+
*
|
|
1681
|
+
* @returns {Nullable<Node>} - The container node for the range.
|
|
1682
|
+
*/
|
|
1683
|
+
getRangeContainer() {
|
|
1684
|
+
const element = stateEntityRenderingRegistry.getDOMByEntity(this);
|
|
1685
|
+
if (element) {
|
|
1686
|
+
return element.parentElement;
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Get the content editable state of the node.
|
|
1691
|
+
*
|
|
1692
|
+
* @returns {boolean} - The content editable state of the node.
|
|
1693
|
+
*/
|
|
1694
|
+
isContentEditable() {
|
|
1695
|
+
return false;
|
|
1696
|
+
}
|
|
1697
|
+
/**
|
|
1698
|
+
* @inheritDoc
|
|
1699
|
+
*/
|
|
1700
|
+
getPlainText() {
|
|
1701
|
+
return this.text;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
RTELogicControlNode.typeName = 'RTELogicControlNode';
|
|
1705
|
+
|
|
1706
|
+
/**
|
|
1707
|
+
* Class representing a logic control block in the rich text editor.
|
|
1708
|
+
*/
|
|
1709
|
+
class RTELogicControlBlock extends RTEBlock {
|
|
1710
|
+
constructor(id, statementText, parent) {
|
|
1711
|
+
super(id);
|
|
1712
|
+
this.type = 'logic-control-block';
|
|
1713
|
+
this.children = [];
|
|
1714
|
+
this.statementText = '';
|
|
1715
|
+
this.statementText = statementText;
|
|
1716
|
+
this.children = [new RTELogicControlNode(`${id}-node-1`, statementText, this)];
|
|
1717
|
+
if (parent) {
|
|
1718
|
+
this.parent = parent;
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
/**
|
|
1722
|
+
* Create a logic control block from a JSON representation.
|
|
1723
|
+
*
|
|
1724
|
+
* @param {VegaRTELogicControlBlock} json - The JSON object representing the logic control block.
|
|
1725
|
+
* @returns {RTELogicControlBlock} - The created logic control block.
|
|
1726
|
+
*/
|
|
1727
|
+
static from(json) {
|
|
1728
|
+
const block = new RTELogicControlBlock(json.id, json.statementText);
|
|
1729
|
+
return block;
|
|
1730
|
+
}
|
|
1731
|
+
/**
|
|
1732
|
+
* Check the block is not empty.
|
|
1733
|
+
*
|
|
1734
|
+
* @returns {boolean} - Always true for logic control block.
|
|
1735
|
+
*/
|
|
1736
|
+
isNotEmpty() {
|
|
1737
|
+
return true;
|
|
1738
|
+
}
|
|
1739
|
+
/**
|
|
1740
|
+
* Get the last node of the block.
|
|
1741
|
+
*
|
|
1742
|
+
* @returns {RTELogicControlNode} - The last node in the block.
|
|
1743
|
+
*/
|
|
1744
|
+
getLastNode() {
|
|
1745
|
+
return this.children[this.children.length - 1];
|
|
1746
|
+
}
|
|
1747
|
+
/**
|
|
1748
|
+
* Convert the block to its HTML representation.
|
|
1749
|
+
*
|
|
1750
|
+
* @returns {string} - The HTML string of the logic control block.
|
|
1751
|
+
*/
|
|
1752
|
+
toHtml() {
|
|
1753
|
+
return `<div class='${FUNCTION_SYNTAX_CLASS}' contenteditable='false'>${this.statementText}</div>`;
|
|
1754
|
+
}
|
|
1755
|
+
/**
|
|
1756
|
+
* Clone the current block instance.
|
|
1757
|
+
*
|
|
1758
|
+
* @param { RTEFunctionBlock } parent - The parent function block for the cloned instance.
|
|
1759
|
+
* @returns {RTELogicControlBlock} - A new instance of RTEStatementSyntaxBlock.
|
|
1760
|
+
*/
|
|
1761
|
+
clone(parent) {
|
|
1762
|
+
return new RTELogicControlBlock(this.id, this.statementText, parent);
|
|
1763
|
+
}
|
|
1764
|
+
/**
|
|
1765
|
+
* Get the JSON representation of the block.
|
|
1766
|
+
*
|
|
1767
|
+
* @returns {VegaRTELogicControlBlock} - The JSON object of the logic control block.
|
|
1768
|
+
*/
|
|
1769
|
+
toJSON() {
|
|
1770
|
+
return {
|
|
1771
|
+
id: this.id,
|
|
1772
|
+
type: this.type,
|
|
1773
|
+
statementText: this.statementText,
|
|
1774
|
+
};
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
RTELogicControlBlock.typeName = 'RTELogicControlBlock';
|
|
1778
|
+
|
|
1631
1779
|
/**
|
|
1632
1780
|
* RTE Function Block
|
|
1633
1781
|
*/
|
|
@@ -1652,8 +1800,36 @@ class RTEFunctionBlock extends RTEBlock {
|
|
|
1652
1800
|
? Object.assign(Object.assign({}, annotations), defaultAnnotation) : defaultAnnotation;
|
|
1653
1801
|
super.convertAnnotationsToMap(functionBlock.annotationMap, annotations);
|
|
1654
1802
|
functionBlock.children = this.generateBlockChildren(block.children, options, functionBlock);
|
|
1803
|
+
this.unwrapForeachContent(functionBlock.children);
|
|
1655
1804
|
return functionBlock;
|
|
1656
1805
|
}
|
|
1806
|
+
/**
|
|
1807
|
+
* Removes a redundant div wrapper from FOREACH content so it is rendered inline
|
|
1808
|
+
* with the FOREACH control. SHOW content retains its wrapper to preserve line breaks.
|
|
1809
|
+
*
|
|
1810
|
+
* @param {RTEFunctionBlockChild[]} children - The function block children to normalize.
|
|
1811
|
+
*/
|
|
1812
|
+
static unwrapForeachContent(children) {
|
|
1813
|
+
children.forEach((logicControlBlock, index) => {
|
|
1814
|
+
const contentBlock = children[index + 1];
|
|
1815
|
+
if (!(logicControlBlock instanceof RTELogicControlBlock) ||
|
|
1816
|
+
logicControlBlock.statementText !== 'FOREACH' ||
|
|
1817
|
+
!(contentBlock instanceof RTETextBlock)) {
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
contentBlock.children.forEach((node) => {
|
|
1821
|
+
const inlineHtml = node.getAnnotationByType(NodeAnnotationTypeEnum.INLINE_HTML);
|
|
1822
|
+
if ((inlineHtml === null || inlineHtml === void 0 ? void 0 : inlineHtml.htmlTag) !== 'div')
|
|
1823
|
+
return;
|
|
1824
|
+
if (inlineHtml.child) {
|
|
1825
|
+
node.annotationMap.set(NodeAnnotationTypeEnum.INLINE_HTML, inlineHtml.child);
|
|
1826
|
+
}
|
|
1827
|
+
else {
|
|
1828
|
+
node.annotationMap.delete(NodeAnnotationTypeEnum.INLINE_HTML);
|
|
1829
|
+
}
|
|
1830
|
+
});
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1657
1833
|
/**
|
|
1658
1834
|
* Converts the RTEFunctionBlock and its children to an HTML string.
|
|
1659
1835
|
*
|
|
@@ -1827,218 +2003,70 @@ class InsertFunctionBlockStrategy extends ActionHandleStrategy {
|
|
|
1827
2003
|
}
|
|
1828
2004
|
|
|
1829
2005
|
/**
|
|
1830
|
-
*
|
|
2006
|
+
* Function toolbar button renderer class.
|
|
1831
2007
|
*/
|
|
1832
|
-
class
|
|
1833
|
-
constructor(id, text, parent) {
|
|
1834
|
-
super(id);
|
|
1835
|
-
this.type = 'logic-control-node';
|
|
1836
|
-
this.text = '';
|
|
1837
|
-
this.text = text;
|
|
1838
|
-
this.parent = parent;
|
|
1839
|
-
}
|
|
1840
|
-
/**
|
|
1841
|
-
* Clone the current node instance.
|
|
1842
|
-
*
|
|
1843
|
-
* @returns {RTELogicControlNode} - A new instance of RTELogicControlNode.
|
|
1844
|
-
*/
|
|
1845
|
-
clone() {
|
|
1846
|
-
return new RTELogicControlNode(this.id, this.text, this.parent);
|
|
1847
|
-
}
|
|
2008
|
+
class FunctionToolbarButtonRenderer extends VegaRTEToolbarButtonRenderer {
|
|
1848
2009
|
/**
|
|
1849
|
-
*
|
|
1850
|
-
*
|
|
1851
|
-
* @returns {string} - The HTML string of the logic control node.
|
|
2010
|
+
* @inheritDoc
|
|
1852
2011
|
*/
|
|
1853
|
-
|
|
1854
|
-
return this.
|
|
2012
|
+
render(h, editorContext) {
|
|
2013
|
+
return this.renderDropdown(h, editorContext, {}, [
|
|
2014
|
+
this.renderButton(h, editorContext, {
|
|
2015
|
+
label: 'Functions',
|
|
2016
|
+
ariaLabel: 'Functions',
|
|
2017
|
+
showArrowIcon: true,
|
|
2018
|
+
tooltip: { text: 'Insert function' },
|
|
2019
|
+
}),
|
|
2020
|
+
this.renderDropdownListTemplate(h, FunctionToolbarButtonRenderer.FUNCTION_LIST, editorContext),
|
|
2021
|
+
]);
|
|
1855
2022
|
}
|
|
1856
2023
|
/**
|
|
1857
|
-
*
|
|
2024
|
+
* Overrides the isDisabled method to determine if the button should be disabled.
|
|
1858
2025
|
*
|
|
1859
|
-
* @
|
|
2026
|
+
* @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
|
|
2027
|
+
* @returns {boolean} - true if the button should be disabled, false otherwise.
|
|
1860
2028
|
*/
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
2029
|
+
isDisabled(editorContext) {
|
|
2030
|
+
const context = this.getExtensionContext(editorContext.host);
|
|
2031
|
+
if (context) {
|
|
2032
|
+
const { host, getSelectedNodes } = context;
|
|
2033
|
+
const focusNode = getSelectedNodes()[0];
|
|
2034
|
+
let enableInsert = true;
|
|
2035
|
+
if (focusNode) {
|
|
2036
|
+
enableInsert = ActionHandleStrategyRegistry.canHandle(INSERT_FUNCTION_BLOCK, focusNode.parent);
|
|
2037
|
+
}
|
|
2038
|
+
return host.disabled || !enableInsert;
|
|
2039
|
+
}
|
|
2040
|
+
return false;
|
|
1867
2041
|
}
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
*/
|
|
1873
|
-
getRangeEndOffset() {
|
|
1874
|
-
return 1;
|
|
2042
|
+
/* istanbul ignore next */
|
|
2043
|
+
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
2044
|
+
handleButtonClick() {
|
|
2045
|
+
throw new Error('Method not implemented.');
|
|
1875
2046
|
}
|
|
1876
2047
|
/**
|
|
1877
|
-
*
|
|
2048
|
+
* Handles dropdown click event
|
|
1878
2049
|
*
|
|
1879
|
-
* @
|
|
2050
|
+
* @param {RTEExtensionFunctionType} itemKey - key of the clicked item
|
|
2051
|
+
* @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
|
|
1880
2052
|
*/
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
getPlainText() {
|
|
1899
|
-
return this.text;
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
RTELogicControlNode.typeName = 'RTELogicControlNode';
|
|
1903
|
-
|
|
1904
|
-
/**
|
|
1905
|
-
* Class representing a logic control block in the rich text editor.
|
|
1906
|
-
*/
|
|
1907
|
-
class RTELogicControlBlock extends RTEBlock {
|
|
1908
|
-
constructor(id, statementText, parent) {
|
|
1909
|
-
super(id);
|
|
1910
|
-
this.type = 'logic-control-block';
|
|
1911
|
-
this.children = [];
|
|
1912
|
-
this.statementText = '';
|
|
1913
|
-
this.statementText = statementText;
|
|
1914
|
-
this.children = [new RTELogicControlNode(`${id}-node-1`, statementText, this)];
|
|
1915
|
-
if (parent) {
|
|
1916
|
-
this.parent = parent;
|
|
1917
|
-
}
|
|
1918
|
-
}
|
|
1919
|
-
/**
|
|
1920
|
-
* Create a logic control block from a JSON representation.
|
|
1921
|
-
*
|
|
1922
|
-
* @param {VegaRTELogicControlBlock} json - The JSON object representing the logic control block.
|
|
1923
|
-
* @returns {RTELogicControlBlock} - The created logic control block.
|
|
1924
|
-
*/
|
|
1925
|
-
static from(json) {
|
|
1926
|
-
const block = new RTELogicControlBlock(json.id, json.statementText);
|
|
1927
|
-
return block;
|
|
1928
|
-
}
|
|
1929
|
-
/**
|
|
1930
|
-
* Check the block is not empty.
|
|
1931
|
-
*
|
|
1932
|
-
* @returns {boolean} - Always true for logic control block.
|
|
1933
|
-
*/
|
|
1934
|
-
isNotEmpty() {
|
|
1935
|
-
return true;
|
|
1936
|
-
}
|
|
1937
|
-
/**
|
|
1938
|
-
* Get the last node of the block.
|
|
1939
|
-
*
|
|
1940
|
-
* @returns {RTELogicControlNode} - The last node in the block.
|
|
1941
|
-
*/
|
|
1942
|
-
getLastNode() {
|
|
1943
|
-
return this.children[this.children.length - 1];
|
|
1944
|
-
}
|
|
1945
|
-
/**
|
|
1946
|
-
* Convert the block to its HTML representation.
|
|
1947
|
-
*
|
|
1948
|
-
* @returns {string} - The HTML string of the logic control block.
|
|
1949
|
-
*/
|
|
1950
|
-
toHtml() {
|
|
1951
|
-
return `<div class='${FUNCTION_SYNTAX_CLASS}' contenteditable='false'>${this.statementText}</div>`;
|
|
1952
|
-
}
|
|
1953
|
-
/**
|
|
1954
|
-
* Clone the current block instance.
|
|
1955
|
-
*
|
|
1956
|
-
* @param { RTEFunctionBlock } parent - The parent function block for the cloned instance.
|
|
1957
|
-
* @returns {RTELogicControlBlock} - A new instance of RTEStatementSyntaxBlock.
|
|
1958
|
-
*/
|
|
1959
|
-
clone(parent) {
|
|
1960
|
-
return new RTELogicControlBlock(this.id, this.statementText, parent);
|
|
1961
|
-
}
|
|
1962
|
-
/**
|
|
1963
|
-
* Get the JSON representation of the block.
|
|
1964
|
-
*
|
|
1965
|
-
* @returns {VegaRTELogicControlBlock} - The JSON object of the logic control block.
|
|
1966
|
-
*/
|
|
1967
|
-
toJSON() {
|
|
1968
|
-
return {
|
|
1969
|
-
id: this.id,
|
|
1970
|
-
type: this.type,
|
|
1971
|
-
statementText: this.statementText,
|
|
1972
|
-
};
|
|
1973
|
-
}
|
|
1974
|
-
}
|
|
1975
|
-
RTELogicControlBlock.typeName = 'RTELogicControlBlock';
|
|
1976
|
-
|
|
1977
|
-
/**
|
|
1978
|
-
* Function toolbar button renderer class.
|
|
1979
|
-
*/
|
|
1980
|
-
class FunctionToolbarButtonRenderer extends VegaRTEToolbarButtonRenderer {
|
|
1981
|
-
/**
|
|
1982
|
-
* @inheritDoc
|
|
1983
|
-
*/
|
|
1984
|
-
render(h, editorContext) {
|
|
1985
|
-
return this.renderDropdown(h, editorContext, {}, [
|
|
1986
|
-
this.renderButton(h, editorContext, {
|
|
1987
|
-
label: 'Functions',
|
|
1988
|
-
ariaLabel: 'Functions',
|
|
1989
|
-
showArrowIcon: true,
|
|
1990
|
-
tooltip: { text: 'Insert function' },
|
|
1991
|
-
}),
|
|
1992
|
-
this.renderDropdownListTemplate(h, FunctionToolbarButtonRenderer.FUNCTION_LIST, editorContext),
|
|
1993
|
-
]);
|
|
1994
|
-
}
|
|
1995
|
-
/**
|
|
1996
|
-
* Overrides the isDisabled method to determine if the button should be disabled.
|
|
1997
|
-
*
|
|
1998
|
-
* @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
|
|
1999
|
-
* @returns {boolean} - true if the button should be disabled, false otherwise.
|
|
2000
|
-
*/
|
|
2001
|
-
isDisabled(editorContext) {
|
|
2002
|
-
const context = this.getExtensionContext(editorContext.host);
|
|
2003
|
-
if (context) {
|
|
2004
|
-
const { host, getSelectedNodes } = context;
|
|
2005
|
-
const focusNode = getSelectedNodes()[0];
|
|
2006
|
-
let enableInsert = true;
|
|
2007
|
-
if (focusNode) {
|
|
2008
|
-
enableInsert = ActionHandleStrategyRegistry.canHandle(INSERT_FUNCTION_BLOCK, focusNode.parent);
|
|
2009
|
-
}
|
|
2010
|
-
return host.disabled || !enableInsert;
|
|
2011
|
-
}
|
|
2012
|
-
return false;
|
|
2013
|
-
}
|
|
2014
|
-
/* istanbul ignore next */
|
|
2015
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
2016
|
-
handleButtonClick() {
|
|
2017
|
-
throw new Error('Method not implemented.');
|
|
2018
|
-
}
|
|
2019
|
-
/**
|
|
2020
|
-
* Handles dropdown click event
|
|
2021
|
-
*
|
|
2022
|
-
* @param {RTEExtensionFunctionType} itemKey - key of the clicked item
|
|
2023
|
-
* @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
|
|
2024
|
-
*/
|
|
2025
|
-
handleDropdownClick(itemKey, editorContext) {
|
|
2026
|
-
if (editorContext) {
|
|
2027
|
-
const context = this.getExtensionContext(editorContext.host);
|
|
2028
|
-
if (context) {
|
|
2029
|
-
const { host, getSelectedNodes } = context;
|
|
2030
|
-
const focusNode = getSelectedNodes()[0];
|
|
2031
|
-
const action = new InsertFunctionBlockAction(itemKey);
|
|
2032
|
-
if (!focusNode) {
|
|
2033
|
-
host.value.apply(action);
|
|
2034
|
-
}
|
|
2035
|
-
else if (focusNode.parent) {
|
|
2036
|
-
focusNode.parent.apply(action);
|
|
2037
|
-
}
|
|
2038
|
-
if (action.nextFocusNode) {
|
|
2039
|
-
host.value.apply(new UpdateCursorPositionAction(action.nextFocusNode, 1));
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2053
|
+
handleDropdownClick(itemKey, editorContext) {
|
|
2054
|
+
if (editorContext) {
|
|
2055
|
+
const context = this.getExtensionContext(editorContext.host);
|
|
2056
|
+
if (context) {
|
|
2057
|
+
const { host, getSelectedNodes } = context;
|
|
2058
|
+
const focusNode = getSelectedNodes()[0];
|
|
2059
|
+
const action = new InsertFunctionBlockAction(itemKey);
|
|
2060
|
+
if (!focusNode) {
|
|
2061
|
+
host.value.apply(action);
|
|
2062
|
+
}
|
|
2063
|
+
else if (focusNode.parent) {
|
|
2064
|
+
focusNode.parent.apply(action);
|
|
2065
|
+
}
|
|
2066
|
+
if (action.nextFocusNode) {
|
|
2067
|
+
host.value.apply(new UpdateCursorPositionAction(action.nextFocusNode, 1));
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2042
2070
|
}
|
|
2043
2071
|
}
|
|
2044
2072
|
}
|
|
@@ -2192,6 +2220,7 @@ class DivToFunctionBlockStrategy extends ElementToDTOStrategy {
|
|
|
2192
2220
|
* @inheritDoc
|
|
2193
2221
|
*/
|
|
2194
2222
|
appendChildBlocks(currentBlock, childBlocks) {
|
|
2223
|
+
RTEFunctionBlock.unwrapForeachContent(childBlocks);
|
|
2195
2224
|
currentBlock.children = childBlocks.map((block) => {
|
|
2196
2225
|
block.parent = currentBlock;
|
|
2197
2226
|
return block;
|
|
@@ -11492,6 +11521,7 @@ VegaRTEFullscreenExtension.controllerStore = VegaRTEFullscreenExtension.createSt
|
|
|
11492
11521
|
var RTEPasteMode;
|
|
11493
11522
|
(function (RTEPasteMode) {
|
|
11494
11523
|
RTEPasteMode["RICH"] = "rich";
|
|
11524
|
+
RTEPasteMode["PLAIN"] = "plain";
|
|
11495
11525
|
RTEPasteMode["WORD"] = "word";
|
|
11496
11526
|
})(RTEPasteMode || (RTEPasteMode = {}));
|
|
11497
11527
|
/**
|
|
@@ -11543,185 +11573,63 @@ class AbstractPasteProcessingStrategy {
|
|
|
11543
11573
|
get supportsImageProcessing() {
|
|
11544
11574
|
return false;
|
|
11545
11575
|
}
|
|
11546
|
-
}
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
icon: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path fill="currentColor" d="M80 96v16c0 17.7 14.3 32 32 32h60.8c16.6-28.7 47.6-48 83.2-48h62c-7.1-27.6-32.2-48-62-48H215.4C211.6 20.9 188.2 0 160 0s-51.6 20.9-55.4 48H64C28.7 48 0 76.7 0 112V384c0 35.3 28.7 64 64 64h96V400H64c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16H80zm64-40a16 16 0 1 1 32 0 16 16 0 1 1 -32 0zM256 464c-8.8 0-16-7.2-16-16V192c0-8.8 7.2-16 16-16H384v48c0 17.7 14.3 32 32 32h48V448c0 8.8-7.2 16-16 16H256zm192 48c35.3 0 64-28.7 64-64V227.9c0-12.7-5.1-24.9-14.1-33.9l-51.9-51.9c-9-9-21.2-14.1-33.9-14.1H256c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H448z"/></svg>`,
|
|
11550
|
-
};
|
|
11551
|
-
|
|
11552
|
-
/**
|
|
11553
|
-
* Renders and manages the paste format chooser UI.
|
|
11554
|
-
*/
|
|
11555
|
-
class RTEPasteChooserUI {
|
|
11556
|
-
constructor(hostRoot, callbacks, options = {}) {
|
|
11557
|
-
this.hostRoot = hostRoot;
|
|
11558
|
-
this.callbacks = callbacks;
|
|
11559
|
-
this.options = options;
|
|
11560
|
-
this.chooserEl = null;
|
|
11561
|
-
this.dropdownEl = null;
|
|
11562
|
-
this.triggerButtonEl = null;
|
|
11576
|
+
/** @returns {boolean} Whether this strategy consumes `text/plain` instead of `text/html` (default: false). */
|
|
11577
|
+
get consumesPlainText() {
|
|
11578
|
+
return false;
|
|
11563
11579
|
}
|
|
11564
11580
|
/**
|
|
11565
|
-
*
|
|
11581
|
+
* Owns the complete content policy for this paste mode. Subclasses that
|
|
11582
|
+
* only need a different source string should override {@link getSourceContent}
|
|
11583
|
+
* instead of re-implementing this method.
|
|
11566
11584
|
*
|
|
11567
|
-
* @param {
|
|
11585
|
+
* @param {PasteInput} input Complete clipboard payload.
|
|
11586
|
+
* @returns {PasteOutput} Complete downstream paste contract.
|
|
11568
11587
|
*/
|
|
11569
|
-
|
|
11570
|
-
this.
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
dropdownEl.placement = position.placement;
|
|
11580
|
-
chooser.append(dropdownEl);
|
|
11581
|
-
this.hostRoot.appendChild(chooser);
|
|
11582
|
-
this.chooserEl = chooser;
|
|
11583
|
-
this.dropdownEl = dropdownEl;
|
|
11584
|
-
dropdownEl.addEventListener('vegaShow', () => {
|
|
11585
|
-
if (this.triggerButtonEl) {
|
|
11586
|
-
this.triggerButtonEl.selected = true;
|
|
11587
|
-
}
|
|
11588
|
-
});
|
|
11589
|
-
dropdownEl.addEventListener('vegaHide', () => {
|
|
11590
|
-
if (this.triggerButtonEl) {
|
|
11591
|
-
this.triggerButtonEl.selected = false;
|
|
11592
|
-
}
|
|
11593
|
-
});
|
|
11588
|
+
transform(input) {
|
|
11589
|
+
const content = this.getSourceContent(input);
|
|
11590
|
+
return {
|
|
11591
|
+
html: this.process(content),
|
|
11592
|
+
text: this.consumesPlainText ? content : input.text,
|
|
11593
|
+
mode: this.type,
|
|
11594
|
+
markers: {},
|
|
11595
|
+
extractImages: this.supportsImageProcessing,
|
|
11596
|
+
imagesToExtract: this.supportsImageProcessing ? input.files : [],
|
|
11597
|
+
};
|
|
11594
11598
|
}
|
|
11595
11599
|
/**
|
|
11596
|
-
*
|
|
11600
|
+
* Resolves the source string passed to {@link process}. Defaults to
|
|
11601
|
+
* `input.text` when {@link consumesPlainText} is true, otherwise `input.html`.
|
|
11602
|
+
*
|
|
11603
|
+
* @param {PasteInput} input Complete clipboard payload.
|
|
11604
|
+
* @returns {string} Content to feed into `process`.
|
|
11597
11605
|
*/
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
if (this.dropdownEl && typeof this.dropdownEl.hide === 'function') {
|
|
11601
|
-
void this.dropdownEl.hide();
|
|
11602
|
-
}
|
|
11603
|
-
if ((_a = this.chooserEl) === null || _a === void 0 ? void 0 : _a.parentNode) {
|
|
11604
|
-
this.chooserEl.parentNode.removeChild(this.chooserEl);
|
|
11605
|
-
}
|
|
11606
|
-
if (this.triggerButtonEl) {
|
|
11607
|
-
this.triggerButtonEl.selected = false;
|
|
11608
|
-
}
|
|
11609
|
-
this.dropdownEl = null;
|
|
11610
|
-
this.chooserEl = null;
|
|
11611
|
-
this.triggerButtonEl = null;
|
|
11606
|
+
getSourceContent(input) {
|
|
11607
|
+
return this.consumesPlainText ? input.text : input.html;
|
|
11612
11608
|
}
|
|
11609
|
+
}
|
|
11610
|
+
|
|
11611
|
+
/**
|
|
11612
|
+
* Default paste processing strategy that acts as a fallback when no other
|
|
11613
|
+
* strategy matches. This strategy always accepts the content and passes it
|
|
11614
|
+
* through unchanged — the normal RTE paste pipeline (DOMParser +
|
|
11615
|
+
* ElementToDtoStrategyProcessor) handles the rest.
|
|
11616
|
+
*/
|
|
11617
|
+
class DefaultPasteProcessingStrategy extends AbstractPasteProcessingStrategy {
|
|
11613
11618
|
/**
|
|
11614
|
-
*
|
|
11619
|
+
* Always matches as the terminal fallback strategy.
|
|
11615
11620
|
*
|
|
11616
|
-
* @param {
|
|
11617
|
-
* @returns {boolean} `true
|
|
11621
|
+
* @param {string} html Raw clipboard HTML.
|
|
11622
|
+
* @returns {boolean} Always `true`.
|
|
11618
11623
|
*/
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
}
|
|
11623
|
-
const isDropdownContentClick = eventPath.some((target) => {
|
|
11624
|
-
return 'tagName' in target && target.tagName === 'VEGA-DROPDOWN-CONTENT-BOX';
|
|
11625
|
-
});
|
|
11626
|
-
return eventPath.includes(this.chooserEl) || isDropdownContentClick;
|
|
11624
|
+
canHandle(html) {
|
|
11625
|
+
// Default strategy is the fallback — always returns true.
|
|
11626
|
+
return html !== undefined;
|
|
11627
11627
|
}
|
|
11628
11628
|
/**
|
|
11629
|
-
*
|
|
11629
|
+
* Returns the original HTML unchanged.
|
|
11630
11630
|
*
|
|
11631
|
-
* @param {
|
|
11632
|
-
* @
|
|
11633
|
-
* @returns {HTMLElement} Configured dropdown element.
|
|
11634
|
-
*/
|
|
11635
|
-
createPasteChooserDropdown(doc, placement) {
|
|
11636
|
-
const dropdownEl = doc.createElement('vega-dropdown');
|
|
11637
|
-
dropdownEl.trigger = 'click';
|
|
11638
|
-
dropdownEl.selectType = 'single';
|
|
11639
|
-
dropdownEl.selectedSourceKey = 'rich';
|
|
11640
|
-
dropdownEl.maxWidth = 220;
|
|
11641
|
-
dropdownEl.alignment = 'start';
|
|
11642
|
-
dropdownEl.itemDisplayRule = 'ellipsis';
|
|
11643
|
-
dropdownEl.isScreenPosition = true;
|
|
11644
|
-
const triggerButton = doc.createElement('vega-rich-text-editor-toolbar-button');
|
|
11645
|
-
const arrowIcon = placement[0] === 'top' ? 'chevron-up' : 'chevron-down';
|
|
11646
|
-
triggerButton.setAttribute(RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR, 'true');
|
|
11647
|
-
triggerButton.setAttribute('aria-label', VegaInternalTranslation.t('Paste options'));
|
|
11648
|
-
triggerButton.setAttribute('arrow-icon', arrowIcon);
|
|
11649
|
-
triggerButton.icon = 'rte-paste';
|
|
11650
|
-
triggerButton.showArrowIcon = true;
|
|
11651
|
-
triggerButton.selected = false;
|
|
11652
|
-
this.triggerButtonEl = triggerButton;
|
|
11653
|
-
const tooltipEl = doc.createElement('vega-tooltip');
|
|
11654
|
-
tooltipEl.text = VegaInternalTranslation.t('Paste options');
|
|
11655
|
-
tooltipEl.placement = ['bottom', 'top'];
|
|
11656
|
-
tooltipEl.append(triggerButton);
|
|
11657
|
-
dropdownEl.append(tooltipEl);
|
|
11658
|
-
const itemsContainer = doc.createElement('div');
|
|
11659
|
-
itemsContainer.setAttribute('slot', 'items');
|
|
11660
|
-
const dropdownItems = [
|
|
11661
|
-
this.createDropdownItem(doc, RTEPasteMode.RICH, VegaInternalTranslation.t('Use rich text'), RTEPasteChooserUI.CHOOSER_RICH_ATTR),
|
|
11662
|
-
];
|
|
11663
|
-
if (this.options.showWordOption) {
|
|
11664
|
-
dropdownItems.push(this.createDropdownItem(doc, RTEPasteMode.WORD, VegaInternalTranslation.t('Use Word'), RTEPasteChooserUI.CHOOSER_WORD_ATTR));
|
|
11665
|
-
}
|
|
11666
|
-
itemsContainer.append(...dropdownItems);
|
|
11667
|
-
dropdownEl.append(itemsContainer);
|
|
11668
|
-
dropdownEl.addEventListener('vegaDropdownClick', (event) => {
|
|
11669
|
-
const mode = event.detail;
|
|
11670
|
-
if (mode === RTEPasteMode.RICH || mode === RTEPasteMode.WORD) {
|
|
11671
|
-
this.callbacks.onModeSelect(mode);
|
|
11672
|
-
}
|
|
11673
|
-
});
|
|
11674
|
-
return dropdownEl;
|
|
11675
|
-
}
|
|
11676
|
-
/**
|
|
11677
|
-
* Creates a single dropdown item element for a paste mode.
|
|
11678
|
-
*
|
|
11679
|
-
* @param {Document} doc Document used to create the element.
|
|
11680
|
-
* @param {RTEPasteMode} key Paste mode key for the item.
|
|
11681
|
-
* @param {string} label Display label for the item.
|
|
11682
|
-
* @param {string} dataAttrName Data attribute marker for the item.
|
|
11683
|
-
* @returns {HTMLVegaDropdownItemElement} Configured dropdown item element.
|
|
11684
|
-
*/
|
|
11685
|
-
createDropdownItem(doc, key, label, dataAttrName) {
|
|
11686
|
-
const itemEl = doc.createElement('vega-dropdown-item');
|
|
11687
|
-
itemEl.itemKey = key;
|
|
11688
|
-
itemEl.label = label;
|
|
11689
|
-
itemEl.setAttribute(dataAttrName, 'true');
|
|
11690
|
-
return itemEl;
|
|
11691
|
-
}
|
|
11692
|
-
}
|
|
11693
|
-
(() => {
|
|
11694
|
-
VegaInternalIconManager.register({
|
|
11695
|
-
'rte-paste': paste,
|
|
11696
|
-
});
|
|
11697
|
-
})();
|
|
11698
|
-
RTEPasteChooserUI.CHOOSER_ATTR = 'data-rte-paste-chooser';
|
|
11699
|
-
RTEPasteChooserUI.CHOOSER_RICH_ATTR = 'data-rte-paste-type-rich';
|
|
11700
|
-
RTEPasteChooserUI.CHOOSER_WORD_ATTR = 'data-rte-paste-type-word';
|
|
11701
|
-
RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR = 'data-rte-paste-trigger';
|
|
11702
|
-
|
|
11703
|
-
/**
|
|
11704
|
-
* Default paste processing strategy that acts as a fallback when no other
|
|
11705
|
-
* strategy matches. This strategy always accepts the content and passes it
|
|
11706
|
-
* through unchanged — the normal RTE paste pipeline (DOMParser +
|
|
11707
|
-
* ElementToDtoStrategyProcessor) handles the rest.
|
|
11708
|
-
*/
|
|
11709
|
-
class DefaultPasteProcessingStrategy extends AbstractPasteProcessingStrategy {
|
|
11710
|
-
/**
|
|
11711
|
-
* Always matches as the terminal fallback strategy.
|
|
11712
|
-
*
|
|
11713
|
-
* @param {string} html Raw clipboard HTML.
|
|
11714
|
-
* @returns {boolean} Always `true`.
|
|
11715
|
-
*/
|
|
11716
|
-
canHandle(html) {
|
|
11717
|
-
// Default strategy is the fallback — always returns true.
|
|
11718
|
-
return html !== undefined;
|
|
11719
|
-
}
|
|
11720
|
-
/**
|
|
11721
|
-
* Returns the original HTML unchanged.
|
|
11722
|
-
*
|
|
11723
|
-
* @param {string} html Raw clipboard HTML.
|
|
11724
|
-
* @returns {string} Unchanged HTML.
|
|
11631
|
+
* @param {string} html Raw clipboard HTML.
|
|
11632
|
+
* @returns {string} Unchanged HTML.
|
|
11725
11633
|
*/
|
|
11726
11634
|
process(html) {
|
|
11727
11635
|
// Current default behavior: pass through unchanged
|
|
@@ -13717,6 +13625,76 @@ WordPasteProcessingStrategy.WORD_SIGNATURE_PATTERNS = [
|
|
|
13717
13625
|
/<\/?o:p>/i,
|
|
13718
13626
|
];
|
|
13719
13627
|
|
|
13628
|
+
/** Converts plain-text clipboard to paragraph-per-line HTML. */
|
|
13629
|
+
class PlainPasteProcessingStrategy extends AbstractPasteProcessingStrategy {
|
|
13630
|
+
/** @returns {RTEPasteMode} Plain-text paste mode. */
|
|
13631
|
+
get type() {
|
|
13632
|
+
return RTEPasteMode.PLAIN;
|
|
13633
|
+
}
|
|
13634
|
+
/** @returns {boolean} Always `true`; consumes `text/plain` instead of `text/html`. */
|
|
13635
|
+
get consumesPlainText() {
|
|
13636
|
+
return true;
|
|
13637
|
+
}
|
|
13638
|
+
/** @returns {boolean} Always `false`; never auto-selected. */
|
|
13639
|
+
canHandle() {
|
|
13640
|
+
return false;
|
|
13641
|
+
}
|
|
13642
|
+
/**
|
|
13643
|
+
* Converts plain text to paragraph HTML; every `\n` starts a new paragraph.
|
|
13644
|
+
*
|
|
13645
|
+
* @param {string} text - Clipboard `text/plain` payload.
|
|
13646
|
+
* @param {boolean} decodeEncodedWhitespace - Decode markers emitted by HTML conversion.
|
|
13647
|
+
* @returns {string} Paragraph HTML.
|
|
13648
|
+
*/
|
|
13649
|
+
process(text, decodeEncodedWhitespace = false) {
|
|
13650
|
+
if (!text) {
|
|
13651
|
+
return '';
|
|
13652
|
+
}
|
|
13653
|
+
const safeDocument = tryGetDocument();
|
|
13654
|
+
if (!safeDocument) {
|
|
13655
|
+
return '';
|
|
13656
|
+
}
|
|
13657
|
+
// Line splitting and boundary whitespace handling live in `toPlainPasteLines` so the
|
|
13658
|
+
// emitted HTML and the RTE nodes built by `InsertPasteHandler` share one conversion.
|
|
13659
|
+
return plainPasteLinesToHtml(toPlainPasteLines(text, decodeEncodedWhitespace));
|
|
13660
|
+
}
|
|
13661
|
+
/**
|
|
13662
|
+
* @param {PasteInput} input Complete clipboard payload.
|
|
13663
|
+
* @returns {PasteOutput} Plain HTML, canonical text, and whitespace marker contract.
|
|
13664
|
+
*/
|
|
13665
|
+
transform(input) {
|
|
13666
|
+
const source = this.getPlainTextSource(input);
|
|
13667
|
+
return {
|
|
13668
|
+
html: this.process(source.text, source.hasEncodedWhitespace),
|
|
13669
|
+
text: source.text,
|
|
13670
|
+
mode: this.type,
|
|
13671
|
+
markers: source.hasEncodedWhitespace ? { [RTE_PRESERVED_WHITESPACE_DATA_TYPE]: 'true' } : {},
|
|
13672
|
+
extractImages: false,
|
|
13673
|
+
imagesToExtract: [],
|
|
13674
|
+
};
|
|
13675
|
+
}
|
|
13676
|
+
/**
|
|
13677
|
+
* @param {PasteInput} input Clipboard content used to derive canonical plain text.
|
|
13678
|
+
* @returns {PlainTextSource} Canonical text and whether it contains whitespace sentinels.
|
|
13679
|
+
*/
|
|
13680
|
+
getPlainTextSource(input) {
|
|
13681
|
+
if (!input.html) {
|
|
13682
|
+
return { text: input.text || '', hasEncodedWhitespace: false };
|
|
13683
|
+
}
|
|
13684
|
+
const containsTable = htmlContainsTable(input.html);
|
|
13685
|
+
if (input.text && input.text.includes('\t') && containsTable) {
|
|
13686
|
+
return { text: input.text, hasEncodedWhitespace: false };
|
|
13687
|
+
}
|
|
13688
|
+
const derived = htmlToPlainText(input.html, {
|
|
13689
|
+
preserveBoundaryBlankLines: !containsTable,
|
|
13690
|
+
keepPreservedWhitespaceMarkers: true,
|
|
13691
|
+
});
|
|
13692
|
+
return derived
|
|
13693
|
+
? { text: derived, hasEncodedWhitespace: true }
|
|
13694
|
+
: { text: input.text || '', hasEncodedWhitespace: false };
|
|
13695
|
+
}
|
|
13696
|
+
}
|
|
13697
|
+
|
|
13720
13698
|
/**
|
|
13721
13699
|
* Centralized selector for paste processing strategies.
|
|
13722
13700
|
*
|
|
@@ -13729,10 +13707,27 @@ class PasteStrategySelector {
|
|
|
13729
13707
|
constructor() {
|
|
13730
13708
|
this.defaultStrategy = new DefaultPasteProcessingStrategy();
|
|
13731
13709
|
this.strategies = [
|
|
13710
|
+
new PlainPasteProcessingStrategy(),
|
|
13732
13711
|
new WordPasteProcessingStrategy(),
|
|
13733
13712
|
this.defaultStrategy, // Fallback
|
|
13734
13713
|
];
|
|
13735
13714
|
}
|
|
13715
|
+
/**
|
|
13716
|
+
* Selects the strategy that will process this paste.
|
|
13717
|
+
*
|
|
13718
|
+
* When `explicitMode` is provided and not `rich`, the strategy registered for that mode
|
|
13719
|
+
* is used. Otherwise the highest-priority strategy whose `canHandle` matches the HTML
|
|
13720
|
+
* wins, falling back to the default pass-through strategy.
|
|
13721
|
+
*
|
|
13722
|
+
* @param {PasteInput} input Captured clipboard payload used for auto-detection.
|
|
13723
|
+
* @param {RTEPasteMode} [explicitMode] Paste mode the user picked from the chooser.
|
|
13724
|
+
* @returns {AbstractPasteProcessingStrategy} Strategy to run for this paste.
|
|
13725
|
+
*/
|
|
13726
|
+
select(input, explicitMode) {
|
|
13727
|
+
return explicitMode && explicitMode !== RTEPasteMode.RICH
|
|
13728
|
+
? this.selectStrategyByType(explicitMode)
|
|
13729
|
+
: this.selectStrategy(input.html);
|
|
13730
|
+
}
|
|
13736
13731
|
/**
|
|
13737
13732
|
* Select the appropriate strategy for the given HTML content.
|
|
13738
13733
|
* Returns the highest-priority strategy that can handle the content.
|
|
@@ -14219,271 +14214,79 @@ class PendingImageRegistry {
|
|
|
14219
14214
|
*/
|
|
14220
14215
|
PendingImageRegistry.pendingImages = new Map();
|
|
14221
14216
|
|
|
14222
|
-
/**
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
constructor(options = {}) {
|
|
14228
|
-
super();
|
|
14229
|
-
this.editableEl = null;
|
|
14230
|
-
this.contentHostEl = null;
|
|
14231
|
-
this.chooserUI = null;
|
|
14232
|
-
this.pendingPastePayload = null;
|
|
14233
|
-
this.listenerDocument = null;
|
|
14234
|
-
this.listenerWindow = null;
|
|
14235
|
-
this.options = {};
|
|
14236
|
-
this.strategySelector = new PasteStrategySelector();
|
|
14237
|
-
this.clipboardFileContent = null;
|
|
14238
|
-
this.imageParser = new PasteImageParser();
|
|
14239
|
-
/** Owns pending pasted-image previews awaiting upload and their URL replacement. */
|
|
14240
|
-
this.pendingImageRegistry = new PendingImageRegistry();
|
|
14241
|
-
/**
|
|
14242
|
-
* Handles a native paste event by capturing the clipboard payload and
|
|
14243
|
-
* rendering the paste-mode chooser.
|
|
14244
|
-
*
|
|
14245
|
-
* @param {ClipboardEvent} event Native clipboard paste event.
|
|
14246
|
-
*/
|
|
14247
|
-
this.handlePasteEvent = (event) => {
|
|
14248
|
-
var _a, _b;
|
|
14249
|
-
const clipboardData = event.clipboardData;
|
|
14250
|
-
if (!clipboardData) {
|
|
14251
|
-
return;
|
|
14252
|
-
}
|
|
14253
|
-
// HTML is sanitized via DOMParser and ElementToDtoStrategyProcessor pipeline
|
|
14254
|
-
const html = clipboardData.getData('text/html') || '';
|
|
14255
|
-
const text = clipboardData.getData('text/plain') || '';
|
|
14256
|
-
// RTF must be read synchronously here: the paste event's DataTransfer is only
|
|
14257
|
-
// readable during event dispatch, so reading it later (after the chooser) returns ''.
|
|
14258
|
-
const rtf = clipboardData.getData('text/rtf') || '';
|
|
14259
|
-
if (!html && !text) {
|
|
14260
|
-
// Empty clipboard paste should not mutate editor content.
|
|
14261
|
-
event.preventDefault();
|
|
14262
|
-
event.stopPropagation();
|
|
14263
|
-
return;
|
|
14264
|
-
}
|
|
14265
|
-
event.preventDefault();
|
|
14266
|
-
event.stopPropagation();
|
|
14267
|
-
const range = this.cloneCurrentSelectionRange();
|
|
14268
|
-
const selectedNodes = ((_b = (_a = this.extensionContext) === null || _a === void 0 ? void 0 : _a.getSelectedNodes) === null || _b === void 0 ? void 0 : _b.call(_a)) || [];
|
|
14269
|
-
this.pendingPastePayload = { html, text, range, selectedNodes: [...selectedNodes] };
|
|
14270
|
-
this.clipboardFileContent = {
|
|
14271
|
-
files: clipboardData.files ? Array.from(clipboardData.files) : [],
|
|
14272
|
-
rtf,
|
|
14273
|
-
};
|
|
14274
|
-
this.renderPasteChooser(event);
|
|
14275
|
-
};
|
|
14276
|
-
/**
|
|
14277
|
-
* Dismisses the chooser when a pointer interaction occurs outside of it.
|
|
14278
|
-
*
|
|
14279
|
-
* @param {Event} event Pointer event captured on the document.
|
|
14280
|
-
*/
|
|
14281
|
-
this.handleOutsidePointerDown = (event) => {
|
|
14282
|
-
if (!this.chooserUI) {
|
|
14283
|
-
return;
|
|
14284
|
-
}
|
|
14285
|
-
const eventPath = typeof event.composedPath === 'function' ? event.composedPath() : [];
|
|
14286
|
-
if (this.chooserUI.includesEventPath(eventPath)) {
|
|
14287
|
-
return;
|
|
14288
|
-
}
|
|
14289
|
-
this.clearPasteChooser();
|
|
14290
|
-
};
|
|
14291
|
-
/**
|
|
14292
|
-
* Dismisses the chooser when the Escape key is pressed.
|
|
14293
|
-
*
|
|
14294
|
-
* @param {KeyboardEvent} event Keyboard event captured on the document.
|
|
14295
|
-
*/
|
|
14296
|
-
this.handleOutsideKeyDown = (event) => {
|
|
14297
|
-
if (event.key === 'Escape') {
|
|
14298
|
-
this.clearPasteChooser();
|
|
14299
|
-
}
|
|
14300
|
-
};
|
|
14301
|
-
/**
|
|
14302
|
-
* Dismisses the chooser when any relevant scroll container scrolls.
|
|
14303
|
-
*/
|
|
14304
|
-
this.handleOutsideScroll = () => {
|
|
14305
|
-
this.clearPasteChooser();
|
|
14306
|
-
};
|
|
14307
|
-
this.options = options;
|
|
14308
|
-
}
|
|
14309
|
-
/** @inheritDoc */
|
|
14310
|
-
initialExtensionAfterLoad(context) {
|
|
14311
|
-
super.initialExtensionAfterLoad(context);
|
|
14312
|
-
this.hostEl = context.host;
|
|
14313
|
-
this.attachPasteListener();
|
|
14314
|
-
}
|
|
14315
|
-
/** @inheritDoc */
|
|
14316
|
-
destroyExtension() {
|
|
14317
|
-
this.detachPasteListener();
|
|
14318
|
-
this.clearPasteChooser();
|
|
14319
|
-
this.pendingImageRegistry.discardUnsentPreviews();
|
|
14217
|
+
/** Computes paste chooser placement from the paste pointer or saved caret range. */
|
|
14218
|
+
class ChooserPositioner {
|
|
14219
|
+
constructor(getHostElement, getSelectionRange) {
|
|
14220
|
+
this.getHostElement = getHostElement;
|
|
14221
|
+
this.getSelectionRange = getSelectionRange;
|
|
14320
14222
|
}
|
|
14321
14223
|
/**
|
|
14322
|
-
*
|
|
14224
|
+
* @param {ClipboardEvent} event Originating paste event.
|
|
14225
|
+
* @returns {ChooserPosition} Position in viewport coordinates.
|
|
14323
14226
|
*/
|
|
14324
|
-
|
|
14325
|
-
|
|
14326
|
-
|
|
14327
|
-
|
|
14328
|
-
|
|
14329
|
-
|
|
14227
|
+
compute(event) {
|
|
14228
|
+
var _a, _b, _c;
|
|
14229
|
+
const hostEl = this.getHostElement();
|
|
14230
|
+
if (!hostEl) {
|
|
14231
|
+
return { left: 0, top: 0, placement: ['bottom', 'top'] };
|
|
14232
|
+
}
|
|
14233
|
+
const hostRect = hostEl.getBoundingClientRect();
|
|
14234
|
+
const viewportHeight = (_b = (_a = hostEl.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.innerHeight) !== null && _b !== void 0 ? _b : window.innerHeight;
|
|
14235
|
+
const pointerEvent = event;
|
|
14236
|
+
const hasPointer = typeof pointerEvent.clientX === 'number' &&
|
|
14237
|
+
pointerEvent.clientX > 0 &&
|
|
14238
|
+
typeof pointerEvent.clientY === 'number' &&
|
|
14239
|
+
pointerEvent.clientY > 0;
|
|
14240
|
+
const caretRect = hasPointer ? null : this.getCaretRect();
|
|
14241
|
+
const CHOOSER_GAP_PX = 8;
|
|
14242
|
+
const CHOOSER_MIN_MARGIN_PX = 12;
|
|
14243
|
+
const CHOOSER_WIDTH_PX = 220;
|
|
14244
|
+
const CHOOSER_FALLBACK_OFFSET_PX = 40;
|
|
14245
|
+
const CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX = 88;
|
|
14246
|
+
const baseLeft = hasPointer
|
|
14247
|
+
? pointerEvent.clientX
|
|
14248
|
+
: (_c = caretRect === null || caretRect === void 0 ? void 0 : caretRect.left) !== null && _c !== void 0 ? _c : hostRect.left + CHOOSER_MIN_MARGIN_PX;
|
|
14249
|
+
const baseTop = hasPointer
|
|
14250
|
+
? pointerEvent.clientY
|
|
14251
|
+
: caretRect
|
|
14252
|
+
? caretRect.bottom
|
|
14253
|
+
: hostRect.top + CHOOSER_FALLBACK_OFFSET_PX;
|
|
14254
|
+
const maxLeft = Math.max(hostRect.left + CHOOSER_MIN_MARGIN_PX, hostRect.right - CHOOSER_WIDTH_PX);
|
|
14255
|
+
const left = Math.min(Math.max(baseLeft, hostRect.left + CHOOSER_MIN_MARGIN_PX), maxLeft);
|
|
14256
|
+
const top = Math.max(baseTop + CHOOSER_GAP_PX, hostRect.top + CHOOSER_MIN_MARGIN_PX);
|
|
14257
|
+
const availableBelow = viewportHeight - top - CHOOSER_MIN_MARGIN_PX;
|
|
14258
|
+
const availableAbove = top - CHOOSER_MIN_MARGIN_PX;
|
|
14259
|
+
const placement = availableBelow >= CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX || availableBelow >= availableAbove
|
|
14260
|
+
? ['bottom', 'top']
|
|
14261
|
+
: ['top', 'bottom'];
|
|
14262
|
+
return { left, top, placement };
|
|
14263
|
+
}
|
|
14264
|
+
/** @returns {DOMRect | null} Best available caret rectangle. */
|
|
14265
|
+
getCaretRect() {
|
|
14266
|
+
const range = this.getSelectionRange();
|
|
14267
|
+
if (!range) {
|
|
14268
|
+
return null;
|
|
14269
|
+
}
|
|
14270
|
+
const rect = range.getBoundingClientRect();
|
|
14271
|
+
if (!this.isUnavailableRect(rect)) {
|
|
14272
|
+
return rect;
|
|
14273
|
+
}
|
|
14274
|
+
const domRectList = range.getClientRects();
|
|
14275
|
+
if (domRectList.length > 0) {
|
|
14276
|
+
return domRectList[0];
|
|
14330
14277
|
}
|
|
14278
|
+
return this.getRangeContainerRect(range);
|
|
14331
14279
|
}
|
|
14332
14280
|
/**
|
|
14333
|
-
*
|
|
14281
|
+
* @param {DOMRect} rect Rectangle to inspect.
|
|
14282
|
+
* @returns {boolean} Whether the rectangle has no usable position or dimensions.
|
|
14334
14283
|
*/
|
|
14335
|
-
|
|
14336
|
-
|
|
14337
|
-
this.editableEl.removeEventListener('paste', this.handlePasteEvent);
|
|
14338
|
-
}
|
|
14339
|
-
this.editableEl = null;
|
|
14340
|
-
this.contentHostEl = null;
|
|
14284
|
+
isUnavailableRect(rect) {
|
|
14285
|
+
return rect.width === 0 && rect.height === 0 && rect.left === 0 && rect.top === 0;
|
|
14341
14286
|
}
|
|
14342
14287
|
/**
|
|
14343
|
-
*
|
|
14344
|
-
*
|
|
14345
|
-
* @returns {EditorElements} Editor elements.
|
|
14346
|
-
*/
|
|
14347
|
-
getEditorElements() {
|
|
14348
|
-
var _a, _b, _c, _d, _e;
|
|
14349
|
-
const contentHostEl = (_c = (_b = (_a = this.hostEl) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('vega-rich-text-content')) !== null && _c !== void 0 ? _c : null;
|
|
14350
|
-
const editableEl = (_e = (_d = contentHostEl === null || contentHostEl === void 0 ? void 0 : contentHostEl.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector('.rich-text-content')) !== null && _e !== void 0 ? _e : null;
|
|
14351
|
-
return { editableEl, contentHostEl };
|
|
14352
|
-
}
|
|
14353
|
-
/**
|
|
14354
|
-
* Resolves the editable content element from the host shadow tree.
|
|
14355
|
-
*
|
|
14356
|
-
* @returns {HTMLDivElement | null} Editable element or `null` when unavailable.
|
|
14357
|
-
*/
|
|
14358
|
-
getEditableElement() {
|
|
14359
|
-
const { editableEl } = this.getEditorElements();
|
|
14360
|
-
return editableEl;
|
|
14361
|
-
}
|
|
14362
|
-
/**
|
|
14363
|
-
* Clones the current selection range so it can be restored after the user
|
|
14364
|
-
* chooses a paste mode.
|
|
14365
|
-
*
|
|
14366
|
-
* @returns {Range | null} Cloned range or `null` when there is no selection.
|
|
14367
|
-
*/
|
|
14368
|
-
cloneCurrentSelectionRange() {
|
|
14369
|
-
var _a;
|
|
14370
|
-
const selection = (_a = this.extensionContext) === null || _a === void 0 ? void 0 : _a.getSelection();
|
|
14371
|
-
if (selection && selection.rangeCount > 0) {
|
|
14372
|
-
return selection.getRangeAt(0).cloneRange();
|
|
14373
|
-
}
|
|
14374
|
-
return null;
|
|
14375
|
-
}
|
|
14376
|
-
/**
|
|
14377
|
-
* Renders the paste-mode chooser and wires up dismissal listeners.
|
|
14378
|
-
*
|
|
14379
|
-
* @param {ClipboardEvent} pasteEvent Originating paste event used for positioning.
|
|
14380
|
-
*/
|
|
14381
|
-
renderPasteChooser(pasteEvent) {
|
|
14382
|
-
var _a, _b, _c;
|
|
14383
|
-
const hostRoot = (_b = (_a = this.hostEl) === null || _a === void 0 ? void 0 : _a.shadowRoot) !== null && _b !== void 0 ? _b : null;
|
|
14384
|
-
if (!hostRoot) {
|
|
14385
|
-
return;
|
|
14386
|
-
}
|
|
14387
|
-
this.clearPasteChooser(false);
|
|
14388
|
-
const position = this.computeChooserPosition(pasteEvent);
|
|
14389
|
-
this.chooserUI = new RTEPasteChooserUI(hostRoot, {
|
|
14390
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
14391
|
-
onModeSelect: (mode) => {
|
|
14392
|
-
this.applyPasteMode(mode);
|
|
14393
|
-
},
|
|
14394
|
-
}, {
|
|
14395
|
-
showWordOption: ((_c = this.options) === null || _c === void 0 ? void 0 : _c.enableWordPaste) === true,
|
|
14396
|
-
});
|
|
14397
|
-
this.chooserUI.open(position);
|
|
14398
|
-
this.listenerDocument = this.hostEl.ownerDocument;
|
|
14399
|
-
this.listenerWindow = this.listenerDocument.defaultView;
|
|
14400
|
-
this.listenerDocument.addEventListener('mousedown', this.handleOutsidePointerDown, true);
|
|
14401
|
-
this.listenerDocument.addEventListener('keydown', this.handleOutsideKeyDown, true);
|
|
14402
|
-
this.listenerDocument.addEventListener('scroll', this.handleOutsideScroll, true);
|
|
14403
|
-
if (this.listenerWindow) {
|
|
14404
|
-
this.listenerWindow.addEventListener('scroll', this.handleOutsideScroll, true);
|
|
14405
|
-
}
|
|
14406
|
-
if (this.contentHostEl) {
|
|
14407
|
-
this.contentHostEl.addEventListener('scroll', this.handleOutsideScroll);
|
|
14408
|
-
}
|
|
14409
|
-
}
|
|
14410
|
-
/**
|
|
14411
|
-
* Computes the on-screen position for the chooser based on pointer or caret.
|
|
14412
|
-
*
|
|
14413
|
-
* @param {ClipboardEvent} event Originating paste event.
|
|
14414
|
-
* @returns {ChooserPosition} Position in viewport coordinates.
|
|
14415
|
-
*/
|
|
14416
|
-
computeChooserPosition(event) {
|
|
14417
|
-
var _a, _b, _c;
|
|
14418
|
-
const hostRect = this.hostEl.getBoundingClientRect();
|
|
14419
|
-
const viewportHeight = (_b = (_a = this.hostEl.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.innerHeight) !== null && _b !== void 0 ? _b : window.innerHeight;
|
|
14420
|
-
const pointerEvent = event;
|
|
14421
|
-
const hasPointer = typeof pointerEvent.clientX === 'number' &&
|
|
14422
|
-
pointerEvent.clientX > 0 &&
|
|
14423
|
-
typeof pointerEvent.clientY === 'number' &&
|
|
14424
|
-
pointerEvent.clientY > 0;
|
|
14425
|
-
// For keyboard-initiated paste (Command/Control+V) clientX/Y are 0, so anchor
|
|
14426
|
-
// the chooser to the current caret instead of a fixed host-relative spot.
|
|
14427
|
-
const caretRect = hasPointer ? null : this.getCaretRect();
|
|
14428
|
-
const CHOOSER_GAP_PX = 8;
|
|
14429
|
-
const CHOOSER_MIN_MARGIN_PX = 12;
|
|
14430
|
-
const CHOOSER_WIDTH_PX = 220;
|
|
14431
|
-
const CHOOSER_FALLBACK_OFFSET_PX = 40;
|
|
14432
|
-
const CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX = 88;
|
|
14433
|
-
const baseLeft = hasPointer
|
|
14434
|
-
? pointerEvent.clientX
|
|
14435
|
-
: (_c = caretRect === null || caretRect === void 0 ? void 0 : caretRect.left) !== null && _c !== void 0 ? _c : hostRect.left + CHOOSER_MIN_MARGIN_PX;
|
|
14436
|
-
const baseTop = hasPointer
|
|
14437
|
-
? pointerEvent.clientY
|
|
14438
|
-
: caretRect
|
|
14439
|
-
? caretRect.bottom
|
|
14440
|
-
: hostRect.top + CHOOSER_FALLBACK_OFFSET_PX;
|
|
14441
|
-
const maxLeft = Math.max(hostRect.left + CHOOSER_MIN_MARGIN_PX, hostRect.right - CHOOSER_WIDTH_PX);
|
|
14442
|
-
const left = Math.min(Math.max(baseLeft, hostRect.left + CHOOSER_MIN_MARGIN_PX), maxLeft);
|
|
14443
|
-
const top = Math.max(baseTop + CHOOSER_GAP_PX, hostRect.top + CHOOSER_MIN_MARGIN_PX);
|
|
14444
|
-
const availableBelow = viewportHeight - top - CHOOSER_MIN_MARGIN_PX;
|
|
14445
|
-
const availableAbove = top - CHOOSER_MIN_MARGIN_PX;
|
|
14446
|
-
const placement = availableBelow >= CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX || availableBelow >= availableAbove
|
|
14447
|
-
? ['bottom', 'top']
|
|
14448
|
-
: ['top', 'bottom'];
|
|
14449
|
-
return { left, top, placement };
|
|
14450
|
-
}
|
|
14451
|
-
/**
|
|
14452
|
-
* Resolves the bounding rect of the pending caret position.
|
|
14453
|
-
*
|
|
14454
|
-
* @returns {DOMRect | null} Caret rect or `null` when it cannot be determined.
|
|
14455
|
-
*/
|
|
14456
|
-
getCaretRect() {
|
|
14457
|
-
var _a, _b;
|
|
14458
|
-
const range = (_b = (_a = this.pendingPastePayload) === null || _a === void 0 ? void 0 : _a.range) !== null && _b !== void 0 ? _b : this.cloneCurrentSelectionRange();
|
|
14459
|
-
if (!range) {
|
|
14460
|
-
return null;
|
|
14461
|
-
}
|
|
14462
|
-
const rect = range.getBoundingClientRect();
|
|
14463
|
-
if (this.isUnavailableRect(rect)) {
|
|
14464
|
-
// eslint-disable-next-line spellcheck/spell-checker
|
|
14465
|
-
const domRectList = range.getClientRects();
|
|
14466
|
-
if (domRectList.length > 0) {
|
|
14467
|
-
return domRectList[0];
|
|
14468
|
-
}
|
|
14469
|
-
return this.getRangeContainerRect(range);
|
|
14470
|
-
}
|
|
14471
|
-
return rect;
|
|
14472
|
-
}
|
|
14473
|
-
/**
|
|
14474
|
-
* Returns whether the browser could not resolve a meaningful caret rectangle.
|
|
14475
|
-
*
|
|
14476
|
-
* @param {DOMRect} rect Candidate caret rect.
|
|
14477
|
-
* @returns {boolean} Whether the rect is unusable.
|
|
14478
|
-
*/
|
|
14479
|
-
isUnavailableRect(rect) {
|
|
14480
|
-
return rect.width === 0 && rect.height === 0 && rect.left === 0 && rect.top === 0;
|
|
14481
|
-
}
|
|
14482
|
-
/**
|
|
14483
|
-
* Falls back to the range container or neighbor child node bounds.
|
|
14484
|
-
*
|
|
14485
|
-
* @param {Range} range Caret/selection range.
|
|
14486
|
-
* @returns {DOMRect | null} Best-effort caret anchor rectangle.
|
|
14288
|
+
* @param {Range} range Selection range whose container should be measured.
|
|
14289
|
+
* @returns {DOMRect | null} Best available rectangle for the range container.
|
|
14487
14290
|
*/
|
|
14488
14291
|
getRangeContainerRect(range) {
|
|
14489
14292
|
var _a, _b, _c, _d, _e, _f;
|
|
@@ -14500,10 +14303,8 @@ class VegaRTEPasteExtension extends VegaRTEExtension {
|
|
|
14500
14303
|
return (_f = this.getNodeRect(containerNode)) !== null && _f !== void 0 ? _f : this.getNodeRect(containerNode.parentNode);
|
|
14501
14304
|
}
|
|
14502
14305
|
/**
|
|
14503
|
-
*
|
|
14504
|
-
*
|
|
14505
|
-
* @param {Node | null} node Candidate node.
|
|
14506
|
-
* @returns {DOMRect | null} Node rectangle when resolvable.
|
|
14306
|
+
* @param {Node | null} node DOM node to measure.
|
|
14307
|
+
* @returns {DOMRect | null} Element-backed rectangle for the node.
|
|
14507
14308
|
*/
|
|
14508
14309
|
getNodeRect(node) {
|
|
14509
14310
|
var _a, _b;
|
|
@@ -14519,73 +14320,145 @@ class VegaRTEPasteExtension extends VegaRTEExtension {
|
|
|
14519
14320
|
}
|
|
14520
14321
|
return null;
|
|
14521
14322
|
}
|
|
14323
|
+
}
|
|
14324
|
+
|
|
14325
|
+
/** Extracts local image previews from strategy output. */
|
|
14326
|
+
class ImageExtractor {
|
|
14327
|
+
constructor(parser = new PasteImageParser()) {
|
|
14328
|
+
this.parser = parser;
|
|
14329
|
+
}
|
|
14522
14330
|
/**
|
|
14523
|
-
*
|
|
14524
|
-
*
|
|
14525
|
-
*
|
|
14526
|
-
*
|
|
14527
|
-
*
|
|
14528
|
-
* @param {RTEPasteMode} mode Selected paste mode.
|
|
14331
|
+
* @param {string} html HTML content containing local image references.
|
|
14332
|
+
* @param {File[]} files Clipboard image files.
|
|
14333
|
+
* @param {string} rtf Rich text clipboard content used to resolve images.
|
|
14334
|
+
* @returns {ParseLocalImagesResult} HTML and extracted local image previews.
|
|
14529
14335
|
*/
|
|
14530
|
-
|
|
14531
|
-
|
|
14532
|
-
|
|
14533
|
-
|
|
14534
|
-
|
|
14336
|
+
extract(html, files, rtf) {
|
|
14337
|
+
const clipboardFileContent = { files, rtf };
|
|
14338
|
+
return this.parser.parseLocalImages(html, clipboardFileContent);
|
|
14339
|
+
}
|
|
14340
|
+
}
|
|
14341
|
+
|
|
14342
|
+
/** Selects and executes one paste strategy, then performs declared post-processing. */
|
|
14343
|
+
class PasteProcessingPipeline {
|
|
14344
|
+
constructor(selector, imageExtractor, pendingImageRegistry) {
|
|
14345
|
+
this.selector = selector;
|
|
14346
|
+
this.imageExtractor = imageExtractor;
|
|
14347
|
+
this.pendingImageRegistry = pendingImageRegistry;
|
|
14348
|
+
}
|
|
14349
|
+
/**
|
|
14350
|
+
* @param {PendingPastePayload} payload Captured clipboard and selection data.
|
|
14351
|
+
* @param {RTEPasteMode} explicitMode Paste mode selected by the user.
|
|
14352
|
+
* @returns {PasteOutput} Processed paste output and image extraction metadata.
|
|
14353
|
+
*/
|
|
14354
|
+
process(payload, explicitMode) {
|
|
14355
|
+
const input = {
|
|
14356
|
+
html: payload.html,
|
|
14357
|
+
text: payload.text,
|
|
14358
|
+
files: payload.files,
|
|
14359
|
+
rtf: payload.rtf,
|
|
14360
|
+
};
|
|
14361
|
+
const output = this.selector.select(input, explicitMode).transform(input);
|
|
14362
|
+
if (!output.extractImages) {
|
|
14363
|
+
return output;
|
|
14535
14364
|
}
|
|
14536
|
-
const
|
|
14537
|
-
if (
|
|
14538
|
-
this.
|
|
14539
|
-
return;
|
|
14365
|
+
const extraction = this.imageExtractor.extract(output.html, output.imagesToExtract, input.rtf);
|
|
14366
|
+
if (extraction.previews.length > 0) {
|
|
14367
|
+
this.pendingImageRegistry.register(extraction.previews);
|
|
14540
14368
|
}
|
|
14541
|
-
|
|
14542
|
-
this.restoreSelectionRange(this.pendingPastePayload.range);
|
|
14543
|
-
this.restoreSelectionControllerState(this.pendingPastePayload);
|
|
14544
|
-
const strategy = mode === RTEPasteMode.RICH
|
|
14545
|
-
? this.strategySelector.selectStrategy(this.pendingPastePayload.html)
|
|
14546
|
-
: this.strategySelector.selectStrategyByType(mode);
|
|
14547
|
-
let processedHtml = strategy.process(this.pendingPastePayload.html);
|
|
14548
|
-
// If the strategy supports image processing and there is clipboard file content, parse local images.
|
|
14549
|
-
if (strategy.supportsImageProcessing && this.clipboardFileContent) {
|
|
14550
|
-
processedHtml = this.parseLocalImages(processedHtml, this.clipboardFileContent);
|
|
14551
|
-
}
|
|
14552
|
-
this.clipboardFileContent = null;
|
|
14553
|
-
const dataTransfer = this.createDataTransfer(processedHtml, this.pendingPastePayload.text, strategy.type);
|
|
14554
|
-
this.dispatchBeforeInputPaste(editableEl, dataTransfer);
|
|
14555
|
-
this.clearPasteChooser();
|
|
14556
|
-
this.emitLocalImageInsertedEvent();
|
|
14369
|
+
return Object.assign(Object.assign({}, output), { html: extraction.html });
|
|
14557
14370
|
}
|
|
14371
|
+
}
|
|
14372
|
+
|
|
14373
|
+
/** Builds the DataTransfer contract consumed by InsertPasteHandler. */
|
|
14374
|
+
class PasteDataTransferBuilder {
|
|
14558
14375
|
/**
|
|
14559
|
-
*
|
|
14560
|
-
*
|
|
14561
|
-
* @param {string} html HTML content to parse.
|
|
14562
|
-
* @param {ClipboardFileContent} clipboardFileContent Clipboard file content for image extraction.
|
|
14563
|
-
* @returns {string} Processed HTML with local image references replaced.
|
|
14376
|
+
* @param {PasteOutput} output Processed paste output to serialize.
|
|
14377
|
+
* @returns {DataTransfer} Data transfer payload consumed by the paste handler.
|
|
14564
14378
|
*/
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
14379
|
+
build(output) {
|
|
14380
|
+
// Reserved keys always win over `markers` so a strategy cannot clobber the base contract.
|
|
14381
|
+
const safeMarkers = Object.assign({}, output.markers);
|
|
14382
|
+
PasteDataTransferBuilder.RESERVED_KEYS.forEach((key) => delete safeMarkers[key]);
|
|
14383
|
+
const values = Object.assign(Object.assign({}, safeMarkers), { 'text/html': output.html, 'text/plain': output.text, [RTE_PASTE_MODE_DATA_TYPE]: output.mode });
|
|
14384
|
+
if (typeof DataTransfer !== 'undefined') {
|
|
14385
|
+
const dataTransfer = new DataTransfer();
|
|
14386
|
+
Object.keys(values).forEach((type) => {
|
|
14387
|
+
const value = values[type];
|
|
14388
|
+
if (value) {
|
|
14389
|
+
dataTransfer.setData(type, value);
|
|
14390
|
+
}
|
|
14391
|
+
});
|
|
14392
|
+
return dataTransfer;
|
|
14569
14393
|
}
|
|
14570
|
-
return
|
|
14394
|
+
return {
|
|
14395
|
+
/**
|
|
14396
|
+
* @param {string} type Clipboard data type to read.
|
|
14397
|
+
* @returns {string} Clipboard value for the requested type.
|
|
14398
|
+
*/
|
|
14399
|
+
getData: (type) => { var _a; return (_a = values[type]) !== null && _a !== void 0 ? _a : ''; },
|
|
14400
|
+
};
|
|
14571
14401
|
}
|
|
14402
|
+
}
|
|
14403
|
+
PasteDataTransferBuilder.RESERVED_KEYS = [
|
|
14404
|
+
'text/html',
|
|
14405
|
+
'text/plain',
|
|
14406
|
+
RTE_PASTE_MODE_DATA_TYPE,
|
|
14407
|
+
];
|
|
14408
|
+
|
|
14409
|
+
/** Dispatches processed paste data through the editor's existing beforeinput pipeline. */
|
|
14410
|
+
class PasteDispatcher {
|
|
14572
14411
|
/**
|
|
14573
|
-
*
|
|
14574
|
-
*
|
|
14412
|
+
* @param {HTMLDivElement} editableEl Editable content element receiving the event.
|
|
14413
|
+
* @param {DataTransfer} dataTransfer Processed clipboard payload.
|
|
14575
14414
|
*/
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14415
|
+
dispatch(editableEl, dataTransfer) {
|
|
14416
|
+
const beforeInputEvent = new CustomEvent('beforeinput', {
|
|
14417
|
+
bubbles: true,
|
|
14418
|
+
cancelable: true,
|
|
14419
|
+
});
|
|
14420
|
+
try {
|
|
14421
|
+
Object.defineProperties(beforeInputEvent, {
|
|
14422
|
+
inputType: { value: 'insertFromPaste', configurable: true },
|
|
14423
|
+
dataTransfer: { value: dataTransfer, configurable: true },
|
|
14424
|
+
});
|
|
14425
|
+
}
|
|
14426
|
+
catch (_a) {
|
|
14427
|
+
Object.assign(beforeInputEvent, { inputType: 'insertFromPaste', dataTransfer });
|
|
14579
14428
|
}
|
|
14429
|
+
editableEl.dispatchEvent(beforeInputEvent);
|
|
14430
|
+
}
|
|
14431
|
+
}
|
|
14432
|
+
|
|
14433
|
+
/** Captures and restores native and editor selection state around chooser interaction. */
|
|
14434
|
+
class SelectionSnapshotService {
|
|
14435
|
+
constructor(getContext) {
|
|
14436
|
+
this.getContext = getContext;
|
|
14580
14437
|
}
|
|
14581
14438
|
/**
|
|
14582
|
-
*
|
|
14583
|
-
|
|
14584
|
-
|
|
14585
|
-
|
|
14439
|
+
* @returns {SelectionSnapshot} Captured native and editor selection state.
|
|
14440
|
+
*/
|
|
14441
|
+
capture() {
|
|
14442
|
+
var _a;
|
|
14443
|
+
const context = this.getContext();
|
|
14444
|
+
const selection = context === null || context === void 0 ? void 0 : context.getSelection();
|
|
14445
|
+
const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0).cloneRange() : null;
|
|
14446
|
+
const selectedNodes = ((_a = context === null || context === void 0 ? void 0 : context.getSelectedNodes) === null || _a === void 0 ? void 0 : _a.call(context)) || [];
|
|
14447
|
+
return { range, selectedNodes: [...selectedNodes] };
|
|
14448
|
+
}
|
|
14449
|
+
/**
|
|
14450
|
+
* @param {PendingPastePayload} payload Paste payload containing captured selection state.
|
|
14451
|
+
*/
|
|
14452
|
+
restore(payload) {
|
|
14453
|
+
this.restoreRange(payload.range);
|
|
14454
|
+
this.restoreControllerState(payload);
|
|
14455
|
+
}
|
|
14456
|
+
/**
|
|
14457
|
+
* @param {PendingPastePayload} payload Paste payload containing editor selection state.
|
|
14586
14458
|
*/
|
|
14587
|
-
|
|
14588
|
-
|
|
14459
|
+
restoreControllerState(payload) {
|
|
14460
|
+
const context = this.getContext();
|
|
14461
|
+
if (!payload.range || !context) {
|
|
14589
14462
|
return;
|
|
14590
14463
|
}
|
|
14591
14464
|
const rangeOptions = {
|
|
@@ -14594,121 +14467,492 @@ class VegaRTEPasteExtension extends VegaRTEExtension {
|
|
|
14594
14467
|
startOffset: payload.range.startOffset,
|
|
14595
14468
|
endOffset: payload.range.endOffset,
|
|
14596
14469
|
};
|
|
14597
|
-
|
|
14470
|
+
context.setSelectedNodes(payload.selectedNodes || [], rangeOptions);
|
|
14598
14471
|
}
|
|
14599
14472
|
/**
|
|
14600
|
-
*
|
|
14601
|
-
*
|
|
14602
|
-
* @param {Range | null} range Range to restore.
|
|
14473
|
+
* @param {Range | null} range Native selection range to restore.
|
|
14603
14474
|
*/
|
|
14604
|
-
|
|
14475
|
+
restoreRange(range) {
|
|
14605
14476
|
var _a;
|
|
14606
14477
|
if (!range) {
|
|
14607
14478
|
return;
|
|
14608
14479
|
}
|
|
14609
|
-
const selection = (_a = this.
|
|
14480
|
+
const selection = (_a = this.getContext()) === null || _a === void 0 ? void 0 : _a.getSelection();
|
|
14610
14481
|
if (selection) {
|
|
14611
14482
|
selection.removeAllRanges();
|
|
14612
14483
|
selection.addRange(range);
|
|
14613
14484
|
}
|
|
14614
14485
|
}
|
|
14486
|
+
}
|
|
14487
|
+
|
|
14488
|
+
/** Owns the native paste listener and synchronous clipboard payload capture. */
|
|
14489
|
+
class PasteEventInterceptor {
|
|
14490
|
+
constructor(selectionSnapshotService, onPasteCaptured) {
|
|
14491
|
+
this.selectionSnapshotService = selectionSnapshotService;
|
|
14492
|
+
this.onPasteCaptured = onPasteCaptured;
|
|
14493
|
+
this.editableEl = null;
|
|
14494
|
+
/**
|
|
14495
|
+
* @param {ClipboardEvent} event Native paste event to capture.
|
|
14496
|
+
*/
|
|
14497
|
+
this.handlePasteEvent = (event) => {
|
|
14498
|
+
const clipboardData = event.clipboardData;
|
|
14499
|
+
if (!clipboardData) {
|
|
14500
|
+
return;
|
|
14501
|
+
}
|
|
14502
|
+
const html = clipboardData.getData('text/html') || '';
|
|
14503
|
+
const text = clipboardData.getData('text/plain') || '';
|
|
14504
|
+
const rtf = clipboardData.getData('text/rtf') || '';
|
|
14505
|
+
if (!html && !text) {
|
|
14506
|
+
event.preventDefault();
|
|
14507
|
+
event.stopPropagation();
|
|
14508
|
+
return;
|
|
14509
|
+
}
|
|
14510
|
+
event.preventDefault();
|
|
14511
|
+
event.stopPropagation();
|
|
14512
|
+
const snapshot = this.selectionSnapshotService.capture();
|
|
14513
|
+
const files = clipboardData.files ? Array.from(clipboardData.files) : [];
|
|
14514
|
+
this.onPasteCaptured({ html, text, range: snapshot.range, selectedNodes: snapshot.selectedNodes, files, rtf }, event);
|
|
14515
|
+
};
|
|
14516
|
+
}
|
|
14615
14517
|
/**
|
|
14616
|
-
*
|
|
14617
|
-
*
|
|
14618
|
-
* @param {HTMLDivElement} editableEl Editable content element.
|
|
14619
|
-
* @param {DataTransfer} dataTransfer Clipboard payload for the paste.
|
|
14518
|
+
* @param {HTMLDivElement | null} editableEl Editable content element to observe.
|
|
14620
14519
|
*/
|
|
14621
|
-
|
|
14622
|
-
|
|
14623
|
-
|
|
14624
|
-
|
|
14625
|
-
|
|
14626
|
-
cancelable: true,
|
|
14627
|
-
});
|
|
14628
|
-
try {
|
|
14629
|
-
Object.defineProperties(beforeInputEvent, {
|
|
14630
|
-
inputType: {
|
|
14631
|
-
value: 'insertFromPaste',
|
|
14632
|
-
configurable: true,
|
|
14633
|
-
},
|
|
14634
|
-
dataTransfer: {
|
|
14635
|
-
value: dataTransfer,
|
|
14636
|
-
configurable: true,
|
|
14637
|
-
},
|
|
14638
|
-
});
|
|
14639
|
-
}
|
|
14640
|
-
catch (_a) {
|
|
14641
|
-
Object.assign(beforeInputEvent, {
|
|
14642
|
-
inputType: 'insertFromPaste',
|
|
14643
|
-
dataTransfer,
|
|
14644
|
-
});
|
|
14645
|
-
}
|
|
14646
|
-
editableEl.dispatchEvent(beforeInputEvent);
|
|
14520
|
+
attach(editableEl) {
|
|
14521
|
+
var _a;
|
|
14522
|
+
this.detach();
|
|
14523
|
+
this.editableEl = editableEl;
|
|
14524
|
+
(_a = this.editableEl) === null || _a === void 0 ? void 0 : _a.addEventListener('paste', this.handlePasteEvent);
|
|
14647
14525
|
}
|
|
14648
14526
|
/**
|
|
14649
|
-
*
|
|
14650
|
-
*
|
|
14651
|
-
* @param {string} html HTML clipboard content.
|
|
14652
|
-
* @param {string} text Plain text clipboard content.
|
|
14653
|
-
* @param {RTEPasteMode} [mode] Selected paste mode marker.
|
|
14654
|
-
* @returns {DataTransfer} Populated data transfer payload.
|
|
14527
|
+
* Detaches the current native paste listener.
|
|
14655
14528
|
*/
|
|
14656
|
-
|
|
14657
|
-
|
|
14658
|
-
|
|
14659
|
-
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
|
|
14665
|
-
|
|
14666
|
-
|
|
14667
|
-
|
|
14668
|
-
|
|
14669
|
-
|
|
14670
|
-
|
|
14671
|
-
|
|
14672
|
-
|
|
14673
|
-
|
|
14674
|
-
|
|
14675
|
-
|
|
14676
|
-
|
|
14677
|
-
|
|
14678
|
-
}
|
|
14679
|
-
if (type === RTE_PASTE_MODE_DATA_TYPE) {
|
|
14680
|
-
return mode !== null && mode !== void 0 ? mode : '';
|
|
14681
|
-
}
|
|
14682
|
-
return '';
|
|
14683
|
-
},
|
|
14684
|
-
};
|
|
14529
|
+
detach() {
|
|
14530
|
+
var _a;
|
|
14531
|
+
(_a = this.editableEl) === null || _a === void 0 ? void 0 : _a.removeEventListener('paste', this.handlePasteEvent);
|
|
14532
|
+
this.editableEl = null;
|
|
14533
|
+
}
|
|
14534
|
+
}
|
|
14535
|
+
|
|
14536
|
+
const paste = {
|
|
14537
|
+
icon: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path fill="currentColor" d="M80 96v16c0 17.7 14.3 32 32 32h60.8c16.6-28.7 47.6-48 83.2-48h62c-7.1-27.6-32.2-48-62-48H215.4C211.6 20.9 188.2 0 160 0s-51.6 20.9-55.4 48H64C28.7 48 0 76.7 0 112V384c0 35.3 28.7 64 64 64h96V400H64c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16H80zm64-40a16 16 0 1 1 32 0 16 16 0 1 1 -32 0zM256 464c-8.8 0-16-7.2-16-16V192c0-8.8 7.2-16 16-16H384v48c0 17.7 14.3 32 32 32h48V448c0 8.8-7.2 16-16 16H256zm192 48c35.3 0 64-28.7 64-64V227.9c0-12.7-5.1-24.9-14.1-33.9l-51.9-51.9c-9-9-21.2-14.1-33.9-14.1H256c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H448z"/></svg>`,
|
|
14538
|
+
};
|
|
14539
|
+
|
|
14540
|
+
/**
|
|
14541
|
+
* Renders and manages the paste format chooser UI.
|
|
14542
|
+
*/
|
|
14543
|
+
class RTEPasteChooserUI {
|
|
14544
|
+
constructor(hostRoot, callbacks, options = {}) {
|
|
14545
|
+
this.hostRoot = hostRoot;
|
|
14546
|
+
this.callbacks = callbacks;
|
|
14547
|
+
this.options = options;
|
|
14548
|
+
this.chooserEl = null;
|
|
14549
|
+
this.dropdownEl = null;
|
|
14550
|
+
this.triggerButtonEl = null;
|
|
14685
14551
|
}
|
|
14686
14552
|
/**
|
|
14687
|
-
*
|
|
14553
|
+
* Opens the paste-mode chooser at the given position.
|
|
14688
14554
|
*
|
|
14689
|
-
* @param {
|
|
14555
|
+
* @param {PasteChooserPosition} position Viewport position for the chooser.
|
|
14690
14556
|
*/
|
|
14691
|
-
|
|
14692
|
-
|
|
14693
|
-
|
|
14557
|
+
open(position) {
|
|
14558
|
+
this.destroy();
|
|
14559
|
+
const doc = this.hostRoot.ownerDocument;
|
|
14560
|
+
const chooser = doc.createElement('div');
|
|
14561
|
+
chooser.setAttribute(RTEPasteChooserUI.CHOOSER_ATTR, 'true');
|
|
14562
|
+
chooser.style.position = 'fixed';
|
|
14563
|
+
chooser.style.zIndex = '1000';
|
|
14564
|
+
chooser.style.left = `${position.left}px`;
|
|
14565
|
+
chooser.style.top = `${position.top}px`;
|
|
14566
|
+
const dropdownEl = this.createPasteChooserDropdown(doc, position.placement);
|
|
14567
|
+
dropdownEl.placement = position.placement;
|
|
14568
|
+
chooser.append(dropdownEl);
|
|
14569
|
+
this.hostRoot.appendChild(chooser);
|
|
14570
|
+
this.chooserEl = chooser;
|
|
14571
|
+
this.dropdownEl = dropdownEl;
|
|
14572
|
+
dropdownEl.addEventListener('vegaShow', () => {
|
|
14573
|
+
if (this.triggerButtonEl) {
|
|
14574
|
+
this.triggerButtonEl.selected = true;
|
|
14575
|
+
}
|
|
14576
|
+
});
|
|
14577
|
+
dropdownEl.addEventListener('vegaHide', () => {
|
|
14578
|
+
if (this.triggerButtonEl) {
|
|
14579
|
+
this.triggerButtonEl.selected = false;
|
|
14580
|
+
}
|
|
14581
|
+
});
|
|
14582
|
+
}
|
|
14583
|
+
/**
|
|
14584
|
+
* Removes the chooser from the DOM.
|
|
14585
|
+
*/
|
|
14586
|
+
destroy() {
|
|
14587
|
+
var _a;
|
|
14588
|
+
if (this.dropdownEl && typeof this.dropdownEl.hide === 'function') {
|
|
14589
|
+
void this.dropdownEl.hide();
|
|
14590
|
+
}
|
|
14591
|
+
if ((_a = this.chooserEl) === null || _a === void 0 ? void 0 : _a.parentNode) {
|
|
14592
|
+
this.chooserEl.parentNode.removeChild(this.chooserEl);
|
|
14593
|
+
}
|
|
14594
|
+
if (this.triggerButtonEl) {
|
|
14595
|
+
this.triggerButtonEl.selected = false;
|
|
14596
|
+
}
|
|
14597
|
+
this.dropdownEl = null;
|
|
14598
|
+
this.chooserEl = null;
|
|
14599
|
+
this.triggerButtonEl = null;
|
|
14600
|
+
}
|
|
14601
|
+
/**
|
|
14602
|
+
* Determines whether the given event path targets the chooser.
|
|
14603
|
+
*
|
|
14604
|
+
* @param {EventTarget[]} eventPath Composed path of an event.
|
|
14605
|
+
* @returns {boolean} `true` when the path includes the chooser.
|
|
14606
|
+
*/
|
|
14607
|
+
includesEventPath(eventPath) {
|
|
14608
|
+
if (!this.chooserEl) {
|
|
14609
|
+
return false;
|
|
14610
|
+
}
|
|
14611
|
+
const isDropdownContentClick = eventPath.some((target) => {
|
|
14612
|
+
return 'tagName' in target && target.tagName === 'VEGA-DROPDOWN-CONTENT-BOX';
|
|
14613
|
+
});
|
|
14614
|
+
return eventPath.includes(this.chooserEl) || isDropdownContentClick;
|
|
14615
|
+
}
|
|
14616
|
+
/**
|
|
14617
|
+
* Builds the dropdown element with the rich text paste option.
|
|
14618
|
+
*
|
|
14619
|
+
* @param {Document} doc Document used to create elements.
|
|
14620
|
+
* @param {['bottom', 'top'] | ['top', 'bottom']} placement Preferred placement order.
|
|
14621
|
+
* @returns {HTMLElement} Configured dropdown element.
|
|
14622
|
+
*/
|
|
14623
|
+
createPasteChooserDropdown(doc, placement) {
|
|
14624
|
+
const dropdownEl = doc.createElement('vega-dropdown');
|
|
14625
|
+
dropdownEl.trigger = 'click';
|
|
14626
|
+
dropdownEl.selectType = 'single';
|
|
14627
|
+
dropdownEl.selectedSourceKey = 'rich';
|
|
14628
|
+
dropdownEl.maxWidth = 220;
|
|
14629
|
+
dropdownEl.alignment = 'start';
|
|
14630
|
+
dropdownEl.itemDisplayRule = 'ellipsis';
|
|
14631
|
+
dropdownEl.isScreenPosition = true;
|
|
14632
|
+
const triggerButton = doc.createElement('vega-rich-text-editor-toolbar-button');
|
|
14633
|
+
const arrowIcon = placement[0] === 'top' ? 'chevron-up' : 'chevron-down';
|
|
14634
|
+
triggerButton.setAttribute(RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR, 'true');
|
|
14635
|
+
triggerButton.setAttribute('aria-label', VegaInternalTranslation.t('Paste options'));
|
|
14636
|
+
triggerButton.setAttribute('arrow-icon', arrowIcon);
|
|
14637
|
+
triggerButton.icon = 'rte-paste';
|
|
14638
|
+
triggerButton.showArrowIcon = true;
|
|
14639
|
+
triggerButton.selected = false;
|
|
14640
|
+
this.triggerButtonEl = triggerButton;
|
|
14641
|
+
const tooltipEl = doc.createElement('vega-tooltip');
|
|
14642
|
+
tooltipEl.text = VegaInternalTranslation.t('Paste options');
|
|
14643
|
+
tooltipEl.placement = ['bottom', 'top'];
|
|
14644
|
+
tooltipEl.append(triggerButton);
|
|
14645
|
+
dropdownEl.append(tooltipEl);
|
|
14646
|
+
const itemsContainer = doc.createElement('div');
|
|
14647
|
+
itemsContainer.setAttribute('slot', 'items');
|
|
14648
|
+
const dropdownItems = [
|
|
14649
|
+
this.createDropdownItem(doc, RTEPasteMode.RICH, VegaInternalTranslation.t('Use rich text'), RTEPasteChooserUI.CHOOSER_RICH_ATTR),
|
|
14650
|
+
this.createDropdownItem(doc, RTEPasteMode.PLAIN, VegaInternalTranslation.t('Use plain text'), RTEPasteChooserUI.CHOOSER_PLAIN_ATTR),
|
|
14651
|
+
];
|
|
14652
|
+
if (this.options.showWordOption) {
|
|
14653
|
+
dropdownItems.push(this.createDropdownItem(doc, RTEPasteMode.WORD, VegaInternalTranslation.t('Use Word'), RTEPasteChooserUI.CHOOSER_WORD_ATTR));
|
|
14694
14654
|
}
|
|
14695
|
-
|
|
14696
|
-
|
|
14697
|
-
|
|
14655
|
+
itemsContainer.append(...dropdownItems);
|
|
14656
|
+
dropdownEl.append(itemsContainer);
|
|
14657
|
+
dropdownEl.addEventListener('vegaDropdownClick', (event) => {
|
|
14658
|
+
const mode = event.detail;
|
|
14659
|
+
if (mode === RTEPasteMode.RICH || mode === RTEPasteMode.PLAIN || mode === RTEPasteMode.WORD) {
|
|
14660
|
+
this.callbacks.onModeSelect(mode);
|
|
14661
|
+
}
|
|
14662
|
+
});
|
|
14663
|
+
return dropdownEl;
|
|
14664
|
+
}
|
|
14665
|
+
/**
|
|
14666
|
+
* Creates a single dropdown item element for a paste mode.
|
|
14667
|
+
*
|
|
14668
|
+
* @param {Document} doc Document used to create the element.
|
|
14669
|
+
* @param {RTEPasteMode} key Paste mode key for the item.
|
|
14670
|
+
* @param {string} label Display label for the item.
|
|
14671
|
+
* @param {string} dataAttrName Data attribute marker for the item.
|
|
14672
|
+
* @returns {HTMLVegaDropdownItemElement} Configured dropdown item element.
|
|
14673
|
+
*/
|
|
14674
|
+
createDropdownItem(doc, key, label, dataAttrName) {
|
|
14675
|
+
const itemEl = doc.createElement('vega-dropdown-item');
|
|
14676
|
+
itemEl.itemKey = key;
|
|
14677
|
+
itemEl.label = label;
|
|
14678
|
+
itemEl.setAttribute(dataAttrName, 'true');
|
|
14679
|
+
return itemEl;
|
|
14680
|
+
}
|
|
14681
|
+
}
|
|
14682
|
+
(() => {
|
|
14683
|
+
VegaInternalIconManager.register({
|
|
14684
|
+
'rte-paste': paste,
|
|
14685
|
+
});
|
|
14686
|
+
})();
|
|
14687
|
+
RTEPasteChooserUI.CHOOSER_ATTR = 'data-rte-paste-chooser';
|
|
14688
|
+
RTEPasteChooserUI.CHOOSER_RICH_ATTR = 'data-rte-paste-type-rich';
|
|
14689
|
+
RTEPasteChooserUI.CHOOSER_PLAIN_ATTR = 'data-rte-paste-type-plain';
|
|
14690
|
+
RTEPasteChooserUI.CHOOSER_WORD_ATTR = 'data-rte-paste-type-word';
|
|
14691
|
+
RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR = 'data-rte-paste-trigger';
|
|
14692
|
+
|
|
14693
|
+
/** Owns chooser rendering and all listener bookkeeping used to dismiss it. */
|
|
14694
|
+
class PasteChooserController {
|
|
14695
|
+
constructor(positioner, onModeSelect, onClearPayload) {
|
|
14696
|
+
this.positioner = positioner;
|
|
14697
|
+
this.onModeSelect = onModeSelect;
|
|
14698
|
+
this.onClearPayload = onClearPayload;
|
|
14699
|
+
this.chooserUI = null;
|
|
14700
|
+
this.listenerDocument = null;
|
|
14701
|
+
this.listenerWindow = null;
|
|
14702
|
+
this.contentHostEl = null;
|
|
14703
|
+
/**
|
|
14704
|
+
* @param {Event} event Pointer event captured on the document.
|
|
14705
|
+
*/
|
|
14706
|
+
this.handleOutsidePointerDown = (event) => {
|
|
14707
|
+
if (!this.chooserUI) {
|
|
14708
|
+
return;
|
|
14709
|
+
}
|
|
14710
|
+
const eventPath = typeof event.composedPath === 'function' ? event.composedPath() : [];
|
|
14711
|
+
if (!this.chooserUI.includesEventPath(eventPath)) {
|
|
14712
|
+
this.clear();
|
|
14713
|
+
}
|
|
14714
|
+
};
|
|
14715
|
+
/**
|
|
14716
|
+
* @param {KeyboardEvent} event Keyboard event captured on the document.
|
|
14717
|
+
*/
|
|
14718
|
+
this.handleOutsideKeyDown = (event) => {
|
|
14719
|
+
if (event.key === 'Escape') {
|
|
14720
|
+
this.clear();
|
|
14721
|
+
}
|
|
14722
|
+
};
|
|
14723
|
+
/**
|
|
14724
|
+
* Clears the chooser when a relevant scroll container scrolls.
|
|
14725
|
+
*
|
|
14726
|
+
* @returns {void}
|
|
14727
|
+
*/
|
|
14728
|
+
this.handleOutsideScroll = () => this.clear();
|
|
14729
|
+
}
|
|
14730
|
+
/**
|
|
14731
|
+
* @returns {RTEPasteChooserUI | null} Current chooser UI, or `null` when closed.
|
|
14732
|
+
*/
|
|
14733
|
+
get ui() {
|
|
14734
|
+
return this.chooserUI;
|
|
14735
|
+
}
|
|
14736
|
+
/**
|
|
14737
|
+
* @param {HTMLElement | null} hostEl Rich text editor host element.
|
|
14738
|
+
* @param {HTMLElement | null} contentHostEl Scrollable content host element.
|
|
14739
|
+
* @param {ClipboardEvent} pasteEvent Originating paste event used for positioning.
|
|
14740
|
+
* @param {boolean} showWordOption Whether to display the Word paste option.
|
|
14741
|
+
*/
|
|
14742
|
+
open(hostEl, contentHostEl, pasteEvent, showWordOption) {
|
|
14743
|
+
var _a, _b, _c;
|
|
14744
|
+
const hostRoot = (_a = hostEl === null || hostEl === void 0 ? void 0 : hostEl.shadowRoot) !== null && _a !== void 0 ? _a : null;
|
|
14745
|
+
if (!hostRoot || !hostEl) {
|
|
14746
|
+
return;
|
|
14698
14747
|
}
|
|
14748
|
+
this.clear(false);
|
|
14749
|
+
const position = this.positioner.compute(pasteEvent);
|
|
14750
|
+
this.chooserUI = new RTEPasteChooserUI(hostRoot, { onModeSelect: this.onModeSelect }, { showWordOption });
|
|
14751
|
+
this.chooserUI.open(position);
|
|
14752
|
+
this.contentHostEl = contentHostEl;
|
|
14753
|
+
this.listenerDocument = hostEl.ownerDocument;
|
|
14754
|
+
this.listenerWindow = this.listenerDocument.defaultView;
|
|
14755
|
+
this.listenerDocument.addEventListener('mousedown', this.handleOutsidePointerDown, true);
|
|
14756
|
+
this.listenerDocument.addEventListener('keydown', this.handleOutsideKeyDown, true);
|
|
14757
|
+
this.listenerDocument.addEventListener('scroll', this.handleOutsideScroll, true);
|
|
14758
|
+
(_b = this.listenerWindow) === null || _b === void 0 ? void 0 : _b.addEventListener('scroll', this.handleOutsideScroll, true);
|
|
14759
|
+
(_c = this.contentHostEl) === null || _c === void 0 ? void 0 : _c.addEventListener('scroll', this.handleOutsideScroll);
|
|
14760
|
+
}
|
|
14761
|
+
/**
|
|
14762
|
+
* @param {boolean} [clearPayload] Whether to also clear the pending paste payload.
|
|
14763
|
+
*/
|
|
14764
|
+
clear(clearPayload = true) {
|
|
14765
|
+
var _a, _b, _c;
|
|
14766
|
+
(_a = this.contentHostEl) === null || _a === void 0 ? void 0 : _a.removeEventListener('scroll', this.handleOutsideScroll);
|
|
14767
|
+
this.contentHostEl = null;
|
|
14768
|
+
(_b = this.listenerWindow) === null || _b === void 0 ? void 0 : _b.removeEventListener('scroll', this.handleOutsideScroll, true);
|
|
14769
|
+
this.listenerWindow = null;
|
|
14699
14770
|
if (this.listenerDocument) {
|
|
14700
14771
|
this.listenerDocument.removeEventListener('mousedown', this.handleOutsidePointerDown, true);
|
|
14701
14772
|
this.listenerDocument.removeEventListener('keydown', this.handleOutsideKeyDown, true);
|
|
14702
14773
|
this.listenerDocument.removeEventListener('scroll', this.handleOutsideScroll, true);
|
|
14703
14774
|
this.listenerDocument = null;
|
|
14704
14775
|
}
|
|
14705
|
-
|
|
14706
|
-
this.chooserUI.destroy();
|
|
14707
|
-
}
|
|
14776
|
+
(_c = this.chooserUI) === null || _c === void 0 ? void 0 : _c.destroy();
|
|
14708
14777
|
this.chooserUI = null;
|
|
14709
14778
|
if (clearPayload) {
|
|
14779
|
+
this.onClearPayload();
|
|
14780
|
+
}
|
|
14781
|
+
}
|
|
14782
|
+
}
|
|
14783
|
+
|
|
14784
|
+
/**
|
|
14785
|
+
* Vega Rich Text Editor paste extension.
|
|
14786
|
+
* Intercepts keyboard paste and allows users to choose paste mode.
|
|
14787
|
+
*/
|
|
14788
|
+
class VegaRTEPasteExtension extends VegaRTEExtension {
|
|
14789
|
+
constructor(options = {}) {
|
|
14790
|
+
super();
|
|
14791
|
+
this.editableEl = null;
|
|
14792
|
+
this.contentHostEl = null;
|
|
14793
|
+
this.pendingPastePayload = null;
|
|
14794
|
+
/**
|
|
14795
|
+
* Handles a native paste event by capturing the clipboard payload and
|
|
14796
|
+
* rendering the paste-mode chooser.
|
|
14797
|
+
*
|
|
14798
|
+
* @param {ClipboardEvent} event Native clipboard paste event.
|
|
14799
|
+
*/
|
|
14800
|
+
this.handlePasteEvent = (event) => {
|
|
14801
|
+
this.pasteEventInterceptor.handlePasteEvent(event);
|
|
14802
|
+
};
|
|
14803
|
+
/**
|
|
14804
|
+
* Dismisses the chooser when a pointer interaction occurs outside of it.
|
|
14805
|
+
*
|
|
14806
|
+
* @param {Event} event Pointer event captured on the document.
|
|
14807
|
+
*/
|
|
14808
|
+
this.handleOutsidePointerDown = (event) => {
|
|
14809
|
+
this.pasteChooserController.handleOutsidePointerDown(event);
|
|
14810
|
+
};
|
|
14811
|
+
/**
|
|
14812
|
+
* Dismisses the chooser when the Escape key is pressed.
|
|
14813
|
+
*
|
|
14814
|
+
* @param {KeyboardEvent} event Keyboard event captured on the document.
|
|
14815
|
+
*/
|
|
14816
|
+
this.handleOutsideKeyDown = (event) => {
|
|
14817
|
+
this.pasteChooserController.handleOutsideKeyDown(event);
|
|
14818
|
+
};
|
|
14819
|
+
/**
|
|
14820
|
+
* Dismisses the chooser when any relevant scroll container scrolls.
|
|
14821
|
+
*/
|
|
14822
|
+
this.handleOutsideScroll = () => {
|
|
14823
|
+
this.pasteChooserController.handleOutsideScroll();
|
|
14824
|
+
};
|
|
14825
|
+
this.options = options;
|
|
14826
|
+
this.strategySelector = new PasteStrategySelector();
|
|
14827
|
+
this.imageParser = new PasteImageParser();
|
|
14828
|
+
this.pendingImageRegistry = new PendingImageRegistry();
|
|
14829
|
+
this.chooserPositioner = new ChooserPositioner(() => this.hostEl, () => { var _a, _b; return (_b = (_a = this.pendingPastePayload) === null || _a === void 0 ? void 0 : _a.range) !== null && _b !== void 0 ? _b : this.cloneCurrentSelectionRange(); });
|
|
14830
|
+
this.processingPipeline = new PasteProcessingPipeline(this.strategySelector, new ImageExtractor(this.imageParser), this.pendingImageRegistry);
|
|
14831
|
+
this.dataTransferBuilder = new PasteDataTransferBuilder();
|
|
14832
|
+
this.pasteDispatcher = new PasteDispatcher();
|
|
14833
|
+
this.selectionSnapshotService = new SelectionSnapshotService(() => this.extensionContext);
|
|
14834
|
+
this.pasteEventInterceptor = new PasteEventInterceptor(this.selectionSnapshotService, (payload, event) => {
|
|
14835
|
+
this.pendingPastePayload = payload;
|
|
14836
|
+
this.renderPasteChooser(event);
|
|
14837
|
+
});
|
|
14838
|
+
this.pasteChooserController = new PasteChooserController(this.chooserPositioner, (mode) => this.applyPasteMode(mode), () => {
|
|
14710
14839
|
this.pendingPastePayload = null;
|
|
14840
|
+
});
|
|
14841
|
+
}
|
|
14842
|
+
/** @inheritDoc */
|
|
14843
|
+
initialExtensionAfterLoad(context) {
|
|
14844
|
+
super.initialExtensionAfterLoad(context);
|
|
14845
|
+
this.hostEl = context.host;
|
|
14846
|
+
this.attachPasteListener();
|
|
14847
|
+
}
|
|
14848
|
+
/** @inheritDoc */
|
|
14849
|
+
destroyExtension() {
|
|
14850
|
+
this.detachPasteListener();
|
|
14851
|
+
this.clearPasteChooser();
|
|
14852
|
+
this.pendingImageRegistry.discardUnsentPreviews();
|
|
14853
|
+
}
|
|
14854
|
+
/** @returns {RTEPasteChooserUI | null} Currently open chooser UI, or `null` when closed. */
|
|
14855
|
+
get chooserUI() {
|
|
14856
|
+
return this.pasteChooserController.ui;
|
|
14857
|
+
}
|
|
14858
|
+
/**
|
|
14859
|
+
* Attaches the paste listener to the editable element.
|
|
14860
|
+
*/
|
|
14861
|
+
attachPasteListener() {
|
|
14862
|
+
const { editableEl, contentHostEl, } = this.getEditorElements();
|
|
14863
|
+
this.editableEl = editableEl;
|
|
14864
|
+
this.contentHostEl = contentHostEl;
|
|
14865
|
+
this.pasteEventInterceptor.attach(this.editableEl);
|
|
14866
|
+
}
|
|
14867
|
+
/**
|
|
14868
|
+
* Detaches the paste listener from the editable element.
|
|
14869
|
+
*/
|
|
14870
|
+
detachPasteListener() {
|
|
14871
|
+
this.pasteEventInterceptor.detach();
|
|
14872
|
+
this.editableEl = null;
|
|
14873
|
+
this.contentHostEl = null;
|
|
14874
|
+
}
|
|
14875
|
+
/**
|
|
14876
|
+
* Resolves the content host and editable element from the host shadow tree.
|
|
14877
|
+
*
|
|
14878
|
+
* @returns {EditorElements} Editor elements.
|
|
14879
|
+
*/
|
|
14880
|
+
getEditorElements() {
|
|
14881
|
+
var _a, _b, _c, _d, _e;
|
|
14882
|
+
const contentHostEl = (_c = (_b = (_a = this.hostEl) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('vega-rich-text-content')) !== null && _c !== void 0 ? _c : null;
|
|
14883
|
+
const editableEl = (_e = (_d = contentHostEl === null || contentHostEl === void 0 ? void 0 : contentHostEl.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector('.rich-text-content')) !== null && _e !== void 0 ? _e : null;
|
|
14884
|
+
return { editableEl, contentHostEl };
|
|
14885
|
+
}
|
|
14886
|
+
/**
|
|
14887
|
+
* Resolves the editable content element from the host shadow tree.
|
|
14888
|
+
*
|
|
14889
|
+
* @returns {HTMLDivElement | null} Editable element or `null` when unavailable.
|
|
14890
|
+
*/
|
|
14891
|
+
getEditableElement() {
|
|
14892
|
+
const { editableEl } = this.getEditorElements();
|
|
14893
|
+
return editableEl;
|
|
14894
|
+
}
|
|
14895
|
+
/**
|
|
14896
|
+
* Clones the current selection range so it can be restored after the user
|
|
14897
|
+
* chooses a paste mode.
|
|
14898
|
+
*
|
|
14899
|
+
* @returns {Range | null} Cloned range or `null` when there is no selection.
|
|
14900
|
+
*/
|
|
14901
|
+
cloneCurrentSelectionRange() {
|
|
14902
|
+
return this.selectionSnapshotService.capture().range;
|
|
14903
|
+
}
|
|
14904
|
+
/**
|
|
14905
|
+
* Renders the paste-mode chooser and wires up dismissal listeners.
|
|
14906
|
+
*
|
|
14907
|
+
* @param {ClipboardEvent} pasteEvent Originating paste event used for positioning.
|
|
14908
|
+
*/
|
|
14909
|
+
renderPasteChooser(pasteEvent) {
|
|
14910
|
+
var _a;
|
|
14911
|
+
this.pasteChooserController.open(this.hostEl, this.contentHostEl, pasteEvent, ((_a = this.options) === null || _a === void 0 ? void 0 : _a.enableWordPaste) === true);
|
|
14912
|
+
}
|
|
14913
|
+
/**
|
|
14914
|
+
* Applies the chosen paste mode by dispatching a synthetic paste input event.
|
|
14915
|
+
*
|
|
14916
|
+
* `rich` keeps auto-detection enabled; any other explicit mode forces the
|
|
14917
|
+
* corresponding registered strategy.
|
|
14918
|
+
*
|
|
14919
|
+
* @param {RTEPasteMode} mode Selected paste mode.
|
|
14920
|
+
*/
|
|
14921
|
+
applyPasteMode(mode) {
|
|
14922
|
+
var _a;
|
|
14923
|
+
if (!this.pendingPastePayload) {
|
|
14924
|
+
this.clearPasteChooser();
|
|
14925
|
+
return;
|
|
14711
14926
|
}
|
|
14927
|
+
const editableEl = (_a = this.editableEl) !== null && _a !== void 0 ? _a : this.getEditableElement();
|
|
14928
|
+
if (!editableEl) {
|
|
14929
|
+
this.clearPasteChooser();
|
|
14930
|
+
return;
|
|
14931
|
+
}
|
|
14932
|
+
editableEl.focus();
|
|
14933
|
+
this.selectionSnapshotService.restore(this.pendingPastePayload);
|
|
14934
|
+
const output = this.processingPipeline.process(this.pendingPastePayload, mode);
|
|
14935
|
+
const dataTransfer = this.dataTransferBuilder.build(output);
|
|
14936
|
+
this.pasteDispatcher.dispatch(editableEl, dataTransfer);
|
|
14937
|
+
this.clearPasteChooser();
|
|
14938
|
+
this.emitLocalImageInsertedEvent();
|
|
14939
|
+
}
|
|
14940
|
+
/**
|
|
14941
|
+
* Emits the `imageInsertedCallback` for any pending previews, allowing the
|
|
14942
|
+
* consumer to upload them and resolve their URLs.
|
|
14943
|
+
*/
|
|
14944
|
+
emitLocalImageInsertedEvent() {
|
|
14945
|
+
if (this.pendingImageRegistry.hasPendingNotifications()) {
|
|
14946
|
+
this.pendingImageRegistry.notifyInserted(this.options.imageInsertedCallback, () => { var _a; return (_a = this.editableEl) !== null && _a !== void 0 ? _a : this.getEditableElement(); }, (imageElement) => this.getDTOEntityByDom(imageElement));
|
|
14947
|
+
}
|
|
14948
|
+
}
|
|
14949
|
+
/**
|
|
14950
|
+
* Tears down the chooser UI and removes dismissal listeners.
|
|
14951
|
+
*
|
|
14952
|
+
* @param {boolean} [clearPayload] Whether to also clear the pending payload.
|
|
14953
|
+
*/
|
|
14954
|
+
clearPasteChooser(clearPayload = true) {
|
|
14955
|
+
this.pasteChooserController.clear(clearPayload);
|
|
14712
14956
|
}
|
|
14713
14957
|
}
|
|
14714
14958
|
(() => {
|