{"version":3,"file":"app-01e92561.f584a1446b2fc034d810.bundle.js","mappings":"AAGA","sources":["webpack://lernplattform-admin-frontend/./src/resources/elements/tri-state-checkbox/tri-state-checkbox.html","webpack://lernplattform-admin-frontend/./src/resources/elements/uce-composable-block/uce-composable-block.html","webpack://lernplattform-admin-frontend/./src/resources/elements/uce-composable-layout-container/uce-composable-layout-container.html","webpack://lernplattform-admin-frontend/./src/resources/elements/uce-course-learn-page-header/uce-course-learn-page-header.html","webpack://lernplattform-admin-frontend/./src/resources/elements/tri-state-checkbox/tri-state-checkbox.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/uce-composable-block/uce-composable-block.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/uce-composable-layout-container/uce-composable-layout-container.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/uce-course-learn-page-header/index.ts","webpack://lernplattform-admin-frontend/./src/resources/elements/uce-course-learn-page-header/uce-course-learn-page-header.ts"],"sourcesContent":["// Module\nvar code = \"<template class=\\\"tri-state-checkbox tri-state-checkbox--style-${state} ${ disabled ? 'tri-state-checkbox--style-disabled' : '' }\\\" role=\\\"checkbox\\\" aria-disabled.to-view=\\\"disabled\\\" aria-checked.to-view=\\\"state !== CheckedState.UNCHECKED\\\" tabindex.to-view=\\\"!disabled ? '0' : null & attr\\\"> <safe-icon if.to-view=\\\"state !== CheckedState.UNCHECKED\\\" class=\\\"tri-state-checkbox__icon\\\" icon-name=\\\"System/Tabler/Check\\\"></safe-icon> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <text-editor if.to-view=\\\"showInlineTextEdit\\\" text.one-time=\\\"block.text\\\" title.one-time=\\\"block.title\\\" block-spacing-options.one-time=\\\"block.styleSpacingOptions\\\" autofocus.to-view=\\\"true\\\" context-identifier.to-view=\\\"model.contextIdentifier\\\" rich-text-changed.trigger=\\\"handleRichTextChanged($event)\\\" mode.to-view=\\\"textEditorMode\\\"></text-editor> <div ref=\\\"textEditControlElement\\\" class=\\\"uce-composable-block__text-edit-control ${ !hideEditBtn && showTextEdit && !showInlineTextEdit ? '' : 'popper-tooltip--hidden' }\\\"> <button-standard icon-name=\\\"Uce/Pen\\\" click.delegate=\\\"handleEditBlock()\\\" btn-size=\\\"icon\\\" tooltip-tk=\\\"pages.content-editor.tooltips.editText\\\" btn-color=\\\"secondary\\\"></button-standard> </div> <div if.to-view=\\\"showInlineTextEdit\\\" class=\\\"uce-composable-block__inline-edit-control\\\"> <button-standard icon-name=\\\"System/Check\\\" click.delegate=\\\"closeInlineTextEdit()\\\" btn-color=\\\"selected\\\" btn-size=\\\"tiny\\\"></button-standard> </div> <universal-block if.to-view=\\\"!showInlineTextEdit\\\" class=\\\"uce-composable-block__block ${ contentEditable ? 'uce-composable-block__block--editable' : '' }\\\" context-identifier.to-view=\\\"model.contextIdentifier\\\" block-id.to-view=\\\"model.blockId\\\" dnd-active.to-view=\\\"dndActive\\\" is-non-interactive-preview.to-view=\\\"isNonInteractivePreview\\\" click.trigger=\\\"handleEditBlock()\\\"></universal-block> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <template if.to-view=\\\"containerStructure\\\"></template> <div class=\\\"uce-composable-layout-container ${ contentLayoutMode != null ? `uce-composable-layout-container--layout-mode-${contentLayoutMode}` : '' } ${ showExtraContainerSpace && (layoutContainer.type === LayoutContainerType.Layout || dndActive) ? 'uce-composable-layout-container--extra-space' : '' } ${ (containerMode && layoutContainer.type !== LayoutContainerType.Layout) || (!dndActive && isEmptyCard) ? 'uce-composable-layout-container--disabled' : '' }\\\" mouseenter.trigger=\\\"handleHoverOverContainer($event, true)\\\" mouseleave.trigger=\\\"handleHoverOverContainer($event, false)\\\"> <div class=\\\"uce-composable-layout-container__content-wrapper ${ isHovered && layoutContainer.type === LayoutContainerType.Block && !isEmptyCard ? 'uce-composable-layout-container__content-wrapper--selectable-block' : '' } ${ selectedForInspector && layoutContainer.type === LayoutContainerType.Block ? 'uce-composable-layout-container__content-wrapper--selected-block' : '' } ${ layoutContainer.type === LayoutContainerType.Card && isHovered ? 'uce-composable-layout-container__content-wrapper--selectable-card' : '' } ${ selectedForInspector && layoutContainer.type === LayoutContainerType.Card ? 'uce-composable-layout-container__content-wrapper--selected-card' : '' } ${ containerMode && layoutContainer.type === LayoutContainerType.Layout ? 'uce-composable-layout-container__content-wrapper--selectable-container' : '' } ${ selectedForInspector && layoutContainer.type === LayoutContainerType.Layout ? 'uce-composable-layout-container__content-wrapper--selected-container' : '' } ${ dashedOutline && !dndActive && !isEmptyCard ? `uce-composable-layout-container__content-wrapper--dashed-outline uce-composable-layout-container__content-wrapper--dashed-outline-${layoutContainer.type === LayoutContainerType.Block ? 'block' : 'parent' }` : '' } ${ mouseOverResizer || resizingHighlight || (isHovered && containerMode && layoutContainer.type === LayoutContainerType.Layout) ? 'uce-composable-layout-container__content-wrapper--selectable-container-background' : '' }\\\"> <universal-layout-container if.to-view=\\\"layoutContainer.type !== LayoutContainerType.Block\\\" class=\\\"${ showExtraContainerSpace && dndActive && layoutContainer.type === LayoutContainerType.Card ? 'uce-composable-layout-container__card-spacing' : '' }\\\" context-identifier.to-view=\\\"contextIdentifier\\\" layout-container-id.to-view=\\\"layoutContainerId\\\" layout-container-view-model.to-view=\\\"viewModel\\\" block-view-model.to-view=\\\"blockViewModel\\\" is-non-interactive-preview.to-view=\\\"isNonInteractivePreview\\\" grey-out.to-view=\\\"containerMode\\\" child-sizes.from-view=\\\"childSizes\\\"></universal-layout-container> <template if.to-view=\\\"layoutContainer.type === LayoutContainerType.Block\\\"> <draggable class=\\\"uce-composable-layout-container__draggable\\\" drag-dom-element.to-view=\\\"draggedBlockElement\\\" payload.to-view=\\\"{\\n                             source: DndSubContext.Content,\\n                             existingPayloadId: layoutContainer.id,\\n                             existingPayloadOrder: layoutContainer.order,\\n                             existingPayloadParentId: layoutContainer.parentLayoutContainerId,\\n                             existingPayloadType: currentElementType,\\n                             excludedTargetSubContexts: dndExcludedTargetSubContexts,\\n                           }\\\" dnd-active.to-view=\\\"dndActive\\\" drag-allowed.to-view=\\\"allowDnd && !isIas && !isSingleBlockPage && !isEmptyCard\\\" context.to-view=\\\"dndContext\\\"> <content-editor-dragged-block ref=\\\"draggedBlockElement\\\" icon-name=\\\"System/Tabler/Plus\\\"></content-editor-dragged-block> <universal-layout-container class=\\\"${ inspectorMode !== InspectorMode.Inactive ? 'uce-composable-layout-container__content-inspector-mode' : '' }\\\" click.delegate=\\\"handleContainerClicked()\\\" context-identifier.to-view=\\\"contextIdentifier\\\" layout-container-id.to-view=\\\"layoutContainerId\\\" layout-container-view-model.to-view=\\\"viewModel\\\" block-view-model.to-view=\\\"blockViewModel\\\" mouse-over.to-view=\\\"isHovered && editBlockId !== layoutContainer.blockId\\\" is-non-interactive-preview.to-view=\\\"true\\\"></universal-layout-container> </draggable> <template if.to-view=\\\"!containerStructure.isPartOfCard || (containerStructure.isOnlyChildOfCard && !hideInnerDropzones)\\\"> <div if.to-view=\\\"showInnerCardinalDroptargets && dndActive && !isIas && !isSingleBlockPage\\\" class=\\\"uce-composable-layout-container__droptargets\\\"> <div class=\\\"uce-composable-layout-container__droptarget uce-composable-layout-container__droptarget--vertical-first ${ innerDropzoneTargeted === ContentEditingInsertModeCardinal.Top ? 'uce-composable-layout-container__droptarget--targeted' : '' }\\\"></div> <div class=\\\"uce-composable-layout-container__droptarget uce-composable-layout-container__droptarget--vertical-last ${ innerDropzoneTargeted === ContentEditingInsertModeCardinal.Bottom ? 'uce-composable-layout-container__droptarget--targeted' : '' }\\\"></div> <div class=\\\"uce-composable-layout-container__droptarget uce-composable-layout-container__droptarget--horizontal-first ${ innerDropzoneTargeted === ContentEditingInsertModeCardinal.Left ? 'uce-composable-layout-container__droptarget--targeted' : '' }\\\"></div> <div class=\\\"uce-composable-layout-container__droptarget uce-composable-layout-container__droptarget--horizontal-last ${ innerDropzoneTargeted === ContentEditingInsertModeCardinal.Right ? 'uce-composable-layout-container__droptarget--targeted' : '' }\\\"></div> </div> <drop-zone if.to-view=\\\"dndActive && !isIas && !isSingleBlockPage\\\" class=\\\"uce-composable-layout-container__dropzone ${ dndActive ? 'uce-composable-layout-container__dropzone--front' : ''}\\\" config.to-view=\\\"innerDropzoneConfig\\\" context.to-view=\\\"dndContext\\\" sub-dropzone-calc-mode.to-view=\\\"SubDropzoneCalcMode.Cardinal\\\" dnd-active.to-view=\\\"dndActive\\\"> </drop-zone> </template> </template> <div if.to-view=\\\"showResizers\\\" class=\\\"uce-composable-layout-container__children-container\\\" style.to-view=\\\"layoutStyles\\\"> <div repeat.for=\\\"child of orderedChildInfos\\\" class=\\\"uce-composable-layout-container__child-container\\\"> <layout-container-resizer if.to-view=\\\"!$first\\\" handle-mousedown.trigger=\\\"startResizing($index)\\\" apply-clicked.trigger=\\\"applyPreviousResizingState($index)\\\" can-apply.to-view=\\\"previousResizingStateAvailable\\\" edit-clicked.trigger=\\\"changeItemSizeViaDialog($index)\\\" mouseover.trigger=\\\"mouseOverResizer = true\\\" mouseout.trigger=\\\"mouseOverResizer = false\\\" direction.to-view=\\\"layoutContainer.layout.direction\\\" show-handle.to-view=\\\"resizingChildIndex === $index\\\" is-disabled.to-view=\\\"(resizingChildIndex !== -1) && (resizingChildIndex !== $index)\\\"></layout-container-resizer> <div if.to-view=\\\"mouseOverResizer\\\" class=\\\"uce-composable-layout-container__child-resizers-size\\\">${getChildLayoutContainerItemSize(child.id)}%</div> </div> </div> <div class=\\\"uce-composable-layout-container__children-container\\\" style.to-view=\\\"layoutStyles\\\"> <div repeat.for=\\\"child of orderedChildInfos\\\" class=\\\"uce-composable-layout-container__child-container\\\"> <content-editor-container-options show.to-view=\\\"child.id === showContainerOptionsForChildId\\\" class=\\\"uce-composable-layout-container__options-menu uce-composable-layout-container__options-menu--default\\\" container-mode.to-view=\\\"containerMode\\\" context-identifier.to-view=\\\"contextIdentifier\\\" layout-container-id.to-view=\\\"child.id\\\" mouseenter.trigger=\\\"handleHoverOverOptions($event, true, child.id)\\\" mouseleave.trigger=\\\"handleHoverOverOptions($event, false, child.id)\\\"></content-editor-container-options> </div> </div> <div if.to-view=\\\"layoutContainer.type === LayoutContainerType.Layout && dndActive && !isCardWithSingleChild\\\"> <layout-container-inside-dropzone-with-target dnd-active.to-view=\\\"dndActive\\\" dnd-context.to-view=\\\"dndContext\\\" direction.to-view=\\\"orthoDirection\\\" dropzone-config.to-view=\\\"orthoDropzoneConfigs[0]\\\" override-target-display.to-view=\\\"overrideFirstOrthoDropzoneState\\\" css=\\\"--dropzone-with-target-width: ${orthoDropzoneWidth}px;\\n                                                          --dropzone-with-target-padding: 0px;\\\"> </layout-container-inside-dropzone-with-target> <layout-container-inside-dropzone-with-target dnd-active.to-view=\\\"dndActive\\\" dnd-context.to-view=\\\"dndContext\\\" direction.to-view=\\\"orthoDirection\\\" dropzone-config.to-view=\\\"orthoDropzoneConfigs[1]\\\" override-target-display.to-view=\\\"overrideLastOrthoDropzoneState\\\" css=\\\"--dropzone-with-target-width: ${orthoDropzoneWidth}px;\\n                                                          --dropzone-with-target-padding: 0px;\\\"> </layout-container-inside-dropzone-with-target> </div> <div if.to-view=\\\"dndActive && layoutContainer.type !== LayoutContainerType.Block && !hideSequentialDropzones && !isCardWithSingleChild\\\" class=\\\"uce-composable-layout-container__children-container uce-composable-layout-container__droptargets ${ layoutContainer.type === LayoutContainerType.Card ? 'uce-composable-layout-container__card-spacing' : '' }\\\" style.to-view=\\\"layoutStyles\\\"> <div repeat.for=\\\"child of orderedChildInfos\\\" class=\\\"uce-composable-layout-container__child-container uce-composable-layout-container__test\\\"> <layout-container-inside-dropzone-with-target if.to-view=\\\"!sequentialDropzonesDisabled[$index]\\\" dnd-active.to-view=\\\"dndActive\\\" dnd-context.to-view=\\\"dndContext\\\" direction.to-view=\\\"layoutContainer.layout.direction\\\" dropzone-config.to-view=\\\"sequentialDropzoneConfigs[$index]\\\" override-target-display.to-view=\\\"overrideSequentialDropzonesStates\\\" css=\\\"--dropzone-with-target-width: ${sequentialDropzoneWidth}px;\\n                                                            --dropzone-with-target-padding: ${orthoDropzoneWidth}px;\\\"></layout-container-inside-dropzone-with-target> <layout-container-inside-dropzone-with-target if.to-view=\\\"$last && !sequentialDropzonesDisabled[$index + 1]\\\" dnd-active.to-view=\\\"dndActive\\\" dnd-context.to-view=\\\"dndContext\\\" direction.to-view=\\\"layoutContainer.layout.direction\\\" dropzone-config.to-view=\\\"sequentialDropzoneConfigs[$index + 1]\\\" override-target-display.to-view=\\\"overrideLastSequentialDropzoneState\\\" css=\\\"--dropzone-with-target-width: ${sequentialDropzoneWidth}px;\\n                                                            --dropzone-with-target-padding: ${orthoDropzoneWidth}px;\\\"></layout-container-inside-dropzone-with-target> </div> </div> <template if.to-view=\\\"layoutContainer.type === LayoutContainerType.Card && dndActive && !hideOuterDropzones\\\"> <layout-container-outside-dropzone-with-target class=\\\"uce-composable-layout-container__outer-dropzone uce-composable-layout-container__outer-dropzone--top\\\" dnd-active.to-view=\\\"dndActive\\\" dnd-context.to-view=\\\"dndContext\\\" dropzone-config.to-view=\\\"{\\n                                                                                 identifier: {\\n                                                                                   superId: layoutContainerId,\\n                                                                                   subId: 1,\\n                                                                                 },\\n                                                                                 insertModeSelector: ContentEditingInsertModeSelector.Cardinal,\\n                                                                                 insertModeCardinal: ContentEditingInsertModeCardinal.Top,\\n                                                                                 cardinalInto: false,\\n                                                                               }\\\" override-target-display.to-view=\\\"overrideOuterDropzoneStates\\\"></layout-container-outside-dropzone-with-target> <layout-container-outside-dropzone-with-target class=\\\"uce-composable-layout-container__outer-dropzone uce-composable-layout-container__outer-dropzone--right\\\" dnd-active.to-view=\\\"dndActive\\\" dnd-context.to-view=\\\"dndContext\\\" dropzone-config.to-view=\\\"{\\n                                                                                 identifier: {\\n                                                                                   superId: layoutContainerId,\\n                                                                                   subId: 2,\\n                                                                                 },\\n                                                                                 insertModeSelector: ContentEditingInsertModeSelector.Cardinal,\\n                                                                                 insertModeCardinal: ContentEditingInsertModeCardinal.Right,\\n                                                                                 cardinalInto: false,\\n                                                                               }\\\" override-target-display.to-view=\\\"overrideOuterDropzoneStates\\\"></layout-container-outside-dropzone-with-target> <layout-container-outside-dropzone-with-target class=\\\"uce-composable-layout-container__outer-dropzone uce-composable-layout-container__outer-dropzone--bottom\\\" dnd-active.to-view=\\\"dndActive\\\" dnd-context.to-view=\\\"dndContext\\\" dropzone-config.to-view=\\\"{\\n                                                                                 identifier: {\\n                                                                                   superId: layoutContainerId,\\n                                                                                   subId: 3,\\n                                                                                 },\\n                                                                                 insertModeSelector: ContentEditingInsertModeSelector.Cardinal,\\n                                                                                 insertModeCardinal: ContentEditingInsertModeCardinal.Bottom,\\n                                                                                 cardinalInto: false,\\n                                                                               }\\\" override-target-display.to-view=\\\"overrideBottomOuterDropzoneState\\\"></layout-container-outside-dropzone-with-target> <layout-container-outside-dropzone-with-target class=\\\"uce-composable-layout-container__outer-dropzone uce-composable-layout-container__outer-dropzone--left\\\" dnd-active.to-view=\\\"dndActive\\\" dnd-context.to-view=\\\"dndContext\\\" dropzone-config.to-view=\\\"{\\n                                                                                 identifier: {\\n                                                                                   superId: layoutContainerId,\\n                                                                                   subId: 4,\\n                                                                                 },\\n                                                                                 insertModeSelector: ContentEditingInsertModeSelector.Cardinal,\\n                                                                                 insertModeCardinal: ContentEditingInsertModeCardinal.Left,\\n                                                                                 cardinalInto: false,\\n                                                                               }\\\" override-target-display.to-view=\\\"overrideOuterDropzoneStates\\\"></layout-container-outside-dropzone-with-target> </template> </div> <content-editor-container-options show.to-view=\\\"isHovered\\n                                                     && layoutContainer.parentLayoutContainerId === null\\n                                                     && ((!containerMode && layoutContainer.type === LayoutContainerType.Block)\\n                                                       || (containerMode && layoutContainer.type === LayoutContainerType.Layout))\\n                                                     && !dndActive && !isInEditMode && !isEmptyCard\\\" class=\\\"uce-composable-layout-container__options-menu uce-composable-layout-container__options-menu--default\\\" container-mode.to-view=\\\"containerMode\\\" context-identifier.to-view=\\\"contextIdentifier\\\" layout-container-id.to-view=\\\"layoutContainer.id\\\" mouseenter.trigger=\\\"handleHoverOverOptions($event, true, layoutContainerId)\\\" mouseleave.trigger=\\\"handleHoverOverOptions($event, false, layoutContainerId)\\\"></content-editor-container-options> <content-editor-container-options show.to-view=\\\"isHovered && layoutContainer.type === LayoutContainerType.Card\\n                                                     && !dndActive && !containerMode && !resizing && !mouseOverResizer\\\" class=\\\"uce-composable-layout-container__options-menu uce-composable-layout-container__options-menu--card\\\" container-mode.to-view=\\\"containerMode\\\" context-identifier.to-view=\\\"contextIdentifier\\\" layout-container-id.to-view=\\\"layoutContainer.id\\\" selected.to-view=\\\"selectedForInspector\\\" dnd-payload.to-view=\\\"{\\n                                                            source: DndSubContext.Content,\\n                                                            existingPayloadId: layoutContainer.id,\\n                                                            existingPayloadOrder: layoutContainer.order,\\n                                                            existingPayloadParentId: layoutContainer.parentLayoutContainerId,\\n                                                            existingPayloadType: NonBlockElementType.Card,\\n                                                            excludedTargetSubContexts: dndExcludedTargetSubContexts,\\n                                                          }\\\" dnd-allowed.to-view=\\\"!isIas && !isSingleBlockPage\\\" dnd-active.to-view=\\\"dndActive\\\" dnd-context.to-view=\\\"dndContext\\\"></content-editor-container-options> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <course-learn-page-header context-identifier.to-view=\\\"contextIdentifier\\\" class=\\\"px-6\\\" page-id.to-view=\\\"pageId\\\" show-progress.to-view=\\\"false\\\"> <inline-edit-field view-model.ref=\\\"titleEditField\\\" slot=\\\"pageTitle\\\" value.to-view=\\\"page.title\\\" mode=\\\"click\\\" show-edit-border.to-view=\\\"false\\\" max-length.to-view=\\\"60\\\" min-length.to-view=\\\"1\\\" validation-failed-event.trigger=\\\"onTitleValidationFailed($event)\\\" save-event.trigger=\\\"onSaveTitle($event)\\\"></inline-edit-field> </course-learn-page-header> </template>\";\n// Exports\nexport default code;","import { bindable } from 'aurelia-framework';\n\nexport enum CheckedState {\n  CHECKED = 'checked',\n  UNCHECKED = 'unchecked',\n  INTERMEDIATE = 'intermediate',\n}\n\nexport class TriStateCheckbox {\n  @bindable() public state: CheckedState = CheckedState.UNCHECKED;\n  @bindable() public disabled: boolean = false;\n\n  private CheckedState = CheckedState;\n}","import offset from '@popperjs/core/lib/modifiers/offset';\nimport { createPopper, Instance } from '@popperjs/core/lib/popper-lite';\nimport { autoinject, computedFrom, observable, PLATFORM, useView } from 'aurelia-framework';\nimport { IComposablePresentationBlockModel } from 'common/aurelia-components/content-editor/composable-block/composable-block';\nimport { RichTextChangedEvent } from 'common/aurelia-components/text-editor/text-editor';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { UniversalBlock } from 'common/dto/content-editor/content.editor.interface';\nimport { BlockType } from 'common/dto/course/content/course.types';\nimport * as ContentContextMutations from 'common/store/mutations/content.context.mutations';\nimport { blockByIdSelectorCreator } from 'common/store/selectors/content.context.selectors';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { FunctionUtils } from 'common/utils/FunctionUtils';\nimport { ContentEditorApiService } from '../../../services/api/ContentEditorApiService';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\nimport * as ContentEditorMutations from '../../../store/content.editor.mutations';\nimport { IState, UceSidebarContent } from '../../../store/state';\nimport { ContentEditorMode } from '../../pages/content-editor/content-editor';\n\n\n@autoinject()\n@useView(PLATFORM.moduleName('resources/elements/uce-composable-block/uce-composable-block.html'))\nexport class UceComposableBlock {\n  private model!: IComposablePresentationBlockModel;\n  private domElement: HTMLElement;\n\n  public contextIdentifier: string | null = null;\n  public blockId: number | null = null;\n  public layoutContainerId: number | null = null;\n  private block: UniversalBlock | null = null;\n  private mode: ContentEditorMode = ContentEditorMode.COURSE;\n  private contentEditable = false;\n  private isNonInteractivePreview = true;\n\n  @observable() private dndActive = false;\n  private hideEditBtn = false;\n  private editBlockId: number | null = null;\n  private showTextEdit = false;\n\n  private textEditControlPopper: Instance | null = null;\n  private textEditControlElement: HTMLElement | null = null;\n\n  constructor(\n    element: Element,\n    private storeService: StoreService<IState>,\n    private contentEditorApi: ContentEditorApiService,\n    private customDialogService: CustomDialogService\n  ) {\n    this.domElement = element as HTMLElement;\n    this.domElement.classList.add('uce-composable-block');\n  }\n\n  protected activate(model: IComposablePresentationBlockModel): void {\n    this.model = model;\n    this.contextIdentifier = model?.contextIdentifier ?? null;\n    this.blockId = model?.blockId ?? null;\n    this.layoutContainerId = model?.layoutContainerId ?? null;\n  }\n\n  protected attached(): void {\n    this.subscribeToState();\n\n    assertNotNullOrUndefined(this.textEditControlElement, 'textEditControlElement cannot be null or undefined');\n    this.textEditControlPopper = createPopper(this.domElement, this.textEditControlElement, {\n      placement: 'top-start',\n      strategy: 'fixed',\n      modifiers: [\n        offset,\n        {\n          name: 'offset',\n          options: {\n            offset: [0, 2],\n          },\n        },\n      ],\n    });\n  }\n\n  protected detached(): void {\n    this.textEditControlPopper?.destroy();\n    this.storeService.disposeAllSubscriptions(this);\n  }\n\n  private subscribeToState(): void {\n    this.storeService.disposeAllSubscriptions(this);\n\n    const { contextIdentifier, blockId } = this;\n    if(contextIdentifier == null || blockId == null) return;\n\n    this.storeService.subscribeMemoized(\n      this,\n      blockByIdSelectorCreator,\n      block => {\n        this.block = block;\n      },\n      { contextIdentifier, blockId }\n    );\n\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.contentEditor.editBlockId,\n      state => state.contentEditor.mode,\n    ], (_state, editBlockId, mode) => {\n      this.editBlockId = editBlockId;\n      this.mode = mode;\n    });\n\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.contentEditor.sidebarRight,\n      state => state.contentEditor.inspector.currentLayoutContainerId,\n    ], (_state, sidebarRight, currentLayoutContainerIdInInspector) => {\n      /**\n       * editing is only allowed for:\n       * * LT, RFG, QUESTION, HOT_SPOT, MP_FLIPPING_CARD, MP_RISI\n       * * Text blocks. and with these specific circumstances\n       * ** if inspector is not opened\n       * ** if inspector is opened and the layoutContainer of the block is currently selected\n       */\n      this.contentEditable = this.block?.type === BlockType.MP_RFG\n        || this.block?.type === BlockType.MP_FLIPPING_CARD\n        || this.block?.type === BlockType.MP_HOT_SPOT\n        || this.block?.type === BlockType.MP_INTERACTIVE_TEXT\n        || this.block?.type === BlockType.MP_RISI\n        || this.block?.type === BlockType.QUESTION\n        || (this.block?.type === BlockType.TEXT\n          && (!sidebarRight.open\n            || sidebarRight.content !== UceSidebarContent.Inspector\n            || (sidebarRight.content === UceSidebarContent.Inspector\n              && this.layoutContainerId === currentLayoutContainerIdInInspector)));\n    });\n\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.contentEditor?.containerHoveredIds,\n    ], (_state, containerHoveredIds) => {\n      this.showTextEdit = containerHoveredIds != null && containerHoveredIds.length > 0\n        && containerHoveredIds[containerHoveredIds.length - 1] === this.layoutContainerId\n        && (this.block?.type === BlockType.TEXT || this.block?.type === BlockType.MP_INTERACTIVE_TEXT);\n      if(this.showTextEdit) {\n        this.textEditControlPopper?.forceUpdate();\n      }\n    });\n\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.contentEditor.dragAndDrop.active\n    ], (_state, dndActive) => {\n      this.dndActive = dndActive;\n    });\n  }\n\n  // works for TEXT, LT and RFG\n  private async handleEditBlock(): Promise<void> {\n    assertNotNullOrUndefined(this.block, 'block cannot be null or undefined');\n    assertNotNullOrUndefined(this.contextIdentifier, 'contextIdentifier cannot be null or undefined');\n\n    if(this.block.type === BlockType.TEXT || this.block.type === BlockType.MP_INTERACTIVE_TEXT) {\n      await this.storeService\n        .pipe(ContentEditorMutations.updateEditBlockId, this.block.id)\n        .pipe(ContentEditorMutations.resetContainerHoverState)\n        .dispatch();\n      return;\n    }\n    await this.storeService.dispatch(ContentEditorMutations.updateEditBlockId, null);\n    const updateBlockDto = await this.customDialogService.showContentEditorBlockEditorDialog({\n      contextIdentifier: this.contextIdentifier,\n      blockId: this.block.id,\n      block: this.block,\n    });\n\n    if(updateBlockDto == null) return;\n\n    const updatedBlock = await this.contentEditorApi.updateBlock<UniversalBlock>(this.block.id, {\n      ...updateBlockDto\n    });\n    await this.storeService.dispatch(ContentContextMutations.updateBlock, this.contextIdentifier, updatedBlock);\n  }\n\n  private async dndActiveChanged(): Promise<void> {\n    if(this.dndActive) {\n      this.hideEditBtn = true;\n    } else {\n      /**\n       * 250ms because showExtraContainerSpace animation takes 200ms to restore containers to\n       * original sizing. Popper should be displayed again only after this animation finished\n       */\n      await FunctionUtils.timeout(250);\n      this.textEditControlPopper?.update();\n      this.hideEditBtn = false;\n    }\n  }\n\n  @computedFrom('block', 'block.type', 'editBlockId', 'blockId')\n  private get showInlineTextEdit(): boolean {\n    return this.block != null\n      && (this.block.type === BlockType.TEXT || this.block.type === BlockType.MP_INTERACTIVE_TEXT)\n      && this.editBlockId === this.blockId;\n  }\n\n  private async handleRichTextChanged(event: RichTextChangedEvent): Promise<void> {\n    event.stopPropagation();\n    assertNotNullOrUndefined(this.block, '');\n    assertNotNullOrUndefined(this.blockId, '');\n    assertNotNullOrUndefined(this.contextIdentifier, '');\n\n    const updatedBlock = await this.contentEditorApi.updateBlock<UniversalBlock>(this.blockId, {\n      // There is no way to set a block title in UCE for rich-text blocks.\n      // Explicitly set this to an empty string in case the saved block was a legacy block\n      title: '',\n      text: JSON.stringify(event.detail.value),\n    });\n\n    await this.storeService.dispatch(ContentContextMutations.updateBlock, this.contextIdentifier, updatedBlock);\n  }\n\n  @computedFrom('mode')\n  private get textEditorMode(): string {\n    return this.mode === ContentEditorMode.COURSE ? 'content' : 'slide';\n  }\n\n  @computedFrom('mode')\n  private get showInlineTextEditorToolbar(): boolean {\n    return this.mode === ContentEditorMode.COURSE;\n  }\n\n  private closeInlineTextEdit(): void {\n    this.storeService\n      .pipe(ContentEditorMutations.updateEditBlockId, null)\n      .pipe(ContentEditorMutations.resetContainerHoverState)\n      .dispatch();\n  }\n}\n","import { autoinject, computedFrom, observable, PLATFORM, useView } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { ILayoutContainerModel } from 'common/aurelia-components/content-editor/composable-layout-container/composable-layout-container';\nimport { LayoutStyles } from 'common/aurelia-components/content-editor/universal-layout-container/universal-layout-container';\nimport { selectState } from 'common/aurelia-decorators/select-state';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { SubscriptionManager, SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\nimport { ContentEditingInsertModeCardinal, ContentEditingInsertModeSelector } from 'common/constants/content.editing.constants';\nimport { CONTENT_EDITOR_DROPZONE_MIN_WIDTH_PX, CONTENT_EDITOR_FRACTIONS } from 'common/constants/content.editor.constants';\nimport { IContainerStructureData } from 'common/dto/content-editor/content.editor.interface';\nimport { ContentElementType, NonBlockElementType } from 'common/dto/content-editor/content.editor.types';\nimport { BlockType } from 'common/dto/course/content/course.types';\nimport {\n  ILayoutContainerChildInfo,\n  ILayoutContainerDto,\n  LayoutContainerDirection,\n  LayoutContainerType\n} from 'common/dto/course/layout.container.interface';\nimport { ICreateUniversalBlockDto } from 'common/dto/course/management/course.management.interface';\nimport { ContentLayoutMode } from 'common/enum/content.layout.mode.enum';\nimport * as ContentContextMutations from 'common/store/mutations/content.context.mutations';\nimport {\n  blockByIdSelectorCreator,\n  contentLayoutModeSelectorCreator,\n  isPresentationSelectorCreator\n} from 'common/store/selectors/content.context.selectors';\nimport { isIasSelectorCreator, isSingleBlockPageSelectorCreator } from 'common/store/selectors/course.context.selectors';\nimport {\n  layoutContainerByIdSelectorCreator,\n  layoutContainerChildInfoOrderedSelectorCreator\n} from 'common/store/selectors/presentation.context.selectors';\nimport { ContainerResizeState, PreviousResizingState } from 'common/store/store.interface';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { FunctionUtils } from 'common/utils/FunctionUtils';\nimport { MathUtils } from 'common/utils/MathUtils';\nimport throttle from 'lodash/throttle';\nimport { ContentEditorApiService } from '../../../services/api/ContentEditorApiService';\nimport { ContentEditorService } from '../../../services/ContentEditorService';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\nimport {\n  ALL_DND_IDS,\n  DndActivityEventData,\n  DndContext,\n  DndDropEventData,\n  DndDropzoneIdentifier,\n  DndInsertModeSequential,\n  DndManager,\n  DndManagerService,\n  DndPayloadUniversal,\n  DndSequentialDropzonePosition,\n  DndSubContext,\n  IDndDropzoneConfig\n} from '../../../services/DndManagerService';\nimport * as ClipboardMutations from '../../../store/clipboard.mutations';\nimport * as ContentEditorMutations from '../../../store/content.editor.mutations';\nimport {\n  containerStructureSelectorCreator,\n  isContainerHoveredSelectorCreator,\n  isEmptyCardSelectorCreator,\n  showContainerOptionsForChildIdSelectorCreator\n} from '../../../store/content.selectors';\nimport { InspectorMode, IState } from '../../../store/state';\nimport { BlockUtils } from '../../../utils/BlockUtils';\nimport { SubDropzoneCalcMode } from '../drag-and-drop/drop-zone';\nimport { RichTextEditorToolbar } from '../rich-text-editor/rich-text-editor-toolbar/rich-text-editor-toolbar';\nimport { UceComposableBlock } from '../uce-composable-block/uce-composable-block';\nimport { DndOverrideTargetDisplay, DND_LOWER_WHITESPACE_ID } from './../../../services/DndManagerService';\n\nconst NOT_ALLOWED_IN_CARD: ContentElementType[] = [\n  BlockType.EMPTY_CARD,\n  BlockType.FILE,\n  BlockType.MP_FLIPPING_CARD,\n  BlockType.MP_HOT_SPOT,\n  BlockType.MP_INTERACTIVE_TEXT,\n  BlockType.MP_QUESTION,\n  BlockType.MP_RFG,\n  BlockType.MP_RISI,\n  BlockType.MP_SCORM,\n  BlockType.MP_SEQUENCE_START,\n  BlockType.MP_TILES,\n  BlockType.QUESTION,\n  NonBlockElementType.Card,\n];\n\n/**\n * Value in Milliseconds. If a new enter event occurs within the\n * specified duration the hover state stays \"hovered\" without a break.\n */\nconst HOVER_END_DELAY_MS = 50;\n\n@autoinject()\n@useView(PLATFORM.moduleName('resources/elements/uce-composable-layout-container/uce-composable-layout-container.html'))\nexport class UceComposableLayoutContainer {\n  @observable() public contextIdentifier!: string;\n  @observable() public layoutContainerId!: number;\n  @observable() public editBlockId: number | null = null;\n\n  public showDroptargets = false;\n  public showExtraContainerSpace = false;\n  public dndActive = false;\n  public dndContext = DndContext.ContentEditorLayout;\n  @observable() private dndAllowed = false;\n  @observable() private dndActiveState = false;\n  @observable() private lowerWhitespaceTargeted = false;\n\n  @selectState(UceComposableLayoutContainer, contentLayoutModeSelectorCreator, ['contextIdentifier', 'layoutContainerId']) private contentLayoutMode?: ContentLayoutMode | null;\n  @selectState(UceComposableLayoutContainer, isIasSelectorCreator, ['contextIdentifier']) private isIas: boolean = false;\n  @selectState(UceComposableLayoutContainer, isSingleBlockPageSelectorCreator, ['contextIdentifier']) private isSingleBlockPage: boolean = false;\n  @selectState(UceComposableLayoutContainer, isEmptyCardSelectorCreator, ['contextIdentifier', 'layoutContainerId']) private isEmptyCard: boolean = false;\n  @selectState(UceComposableLayoutContainer, isPresentationSelectorCreator, ['contextIdentifier']) private isPresentation?: boolean;\n  @selectState(UceComposableLayoutContainer, containerStructureSelectorCreator, ['layoutContainerId']) private containerStructure?: IContainerStructureData | null;\n  @selectState(UceComposableLayoutContainer, isContainerHoveredSelectorCreator, ['layoutContainerId']) private isHovered: boolean = false;\n  @selectState(\n    UceComposableLayoutContainer,\n    showContainerOptionsForChildIdSelectorCreator,\n    ['contextIdentifier', 'layoutContainerId'],\n  ) private showContainerOptionsForChildId?: number | null;\n\n  @observable() private layoutContainer: ILayoutContainerDto | null = null;\n  @observable() orderedChildInfos: Array<ILayoutContainerChildInfo> = [];\n  private childSizes: Array<number> = [];\n\n  private viewModel = UceComposableLayoutContainer;\n  private blockViewModel = UceComposableBlock;\n\n  private orthoDirection = LayoutContainerDirection.Horizontal;\n  private resizing = false;\n  private oldBlockId: number | null = null;\n  private currentElementType: ContentElementType | undefined;\n\n  private InspectorMode = InspectorMode;\n  private inspectorMode = InspectorMode.Inactive;\n  private mouseOver = false;\n  private element: HTMLElement;\n\n  private initialSizePercent = 0;\n  private subscriptions: Array<{ dispose: () => void }> = [];\n  private oneFractionPx = 0;\n  private containerStartPosPx = 0;\n  private containerEndPosPx = 0;\n  /**\n   * size regarding configured direction of layoutContainer\n   */\n  private sizePx = 0;\n  /**\n   * size orthogonal to configured direction\n   */\n  private orthoSizePx = 0;\n  private resizingChildIndex = -1;\n  private snappingEpsilonPercent = 1;\n  private snappingEpsilonPx = 0;\n  private startOffsetPx = 0;\n  private endOffsetPx = 0;\n  private dashedOutline = false;\n  private selectedForInspector = false;\n\n  private dndManager: DndManager<ContentElementType> | null = null;\n  private showInnerCardinalDroptargets = false;\n  private hideSequentialDropzones = false;\n  private hideOuterDropzones = false;\n  private hideInnerDropzones = false;\n  private isCardWithSingleChild = false;\n  private innerDropzoneTargeted: ContentEditingInsertModeCardinal = ContentEditingInsertModeCardinal.None;\n  private orthoDropzoneConfigs: Array<IDndDropzoneConfig> = [];\n  private sequentialDropzoneConfigs: Array<IDndDropzoneConfig> = [];\n  private sequentialDropzonesDisabled: Array<boolean> = [];\n  private sequentialDropzoneWidth = 0; // dropzone width for zones within sequential list of children\n  private orthoDropzoneWidth = 0; // dropzone width for zones orthogonal to list of children\n  private overrideSequentialDropzonesStates = DndOverrideTargetDisplay.NoOverride;\n  private overrideFirstOrthoDropzoneState = DndOverrideTargetDisplay.NoOverride;\n  private overrideLastSequentialDropzoneState = DndOverrideTargetDisplay.NoOverride;\n  private overrideLastOrthoDropzoneState = DndOverrideTargetDisplay.NoOverride;\n  private overrideOuterDropzoneStates = DndOverrideTargetDisplay.NoOverride;\n  private overrideBottomOuterDropzoneState = DndOverrideTargetDisplay.NoOverride;\n  private DndSequentialDropzonePosition = DndSequentialDropzonePosition;\n  private ContentEditingInsertModeCardinal = ContentEditingInsertModeCardinal;\n  private ContentEditingInsertModeSelector = ContentEditingInsertModeSelector;\n  private DndSubContext = DndSubContext;\n  private NonBlockElementType = NonBlockElementType;\n  private LayoutContainerDirection = LayoutContainerDirection;\n  private SubDropzoneCalcMode = SubDropzoneCalcMode;\n  private dndExcludedTargetSubContexts: Array<DndSubContext> = [];\n  private dndPayload: DndPayloadUniversal<ContentElementType> = null;\n  private draggedBlockElement: HTMLElement | null = null;\n  private draggedContainerElement: HTMLElement | null = null;\n  private innerDropzoneConfig: IDndDropzoneConfig = {\n    identifier: {\n      superId: 0,\n      subId: 0,\n    },\n    insertModeSelector: ContentEditingInsertModeSelector.Cardinal,\n  };\n  private subscriptionContextSpecial = `_special_${Math.random().toString(36).substring(2, 21)}`;\n  private subscriptionContextDefault = `_default_${Math.random().toString(36).substring(2, 21)}`;\n  private subscriptionContextBlock = `_block_${Math.random().toString(36).substring(2, 21)}`;\n  private subscriptionManager: SubscriptionManager;\n  private isNonInteractivePreview = true;\n  private LayoutContainerType = LayoutContainerType;\n  private mouseOverResizer = false;\n  private resizingHighlight = false;\n  private previousResizingStateAvailable = false;\n\n  constructor(\n    private storeService: StoreService<IState>,\n    private dndManagerService: DndManagerService,\n    private customDialogService: CustomDialogService,\n    private contentEditorApi: ContentEditorApiService,\n    private contentEditorService: ContentEditorService,\n    private i18n: I18N,\n    element: Element,\n    subscriptionManagerService: SubscriptionManagerService,\n  ) {\n    this.element = element as HTMLElement;\n    this.subscriptionManager = subscriptionManagerService.createSubscriptionManager();\n  }\n\n  protected activate(model?: ILayoutContainerModel): void {\n    assertNotNullOrUndefined(model?.contextIdentifier, 'contextIdentifier cannot be null or undefined');\n    assertNotNullOrUndefined(model?.layoutContainerId, 'layoutContainerId cannot be null or undefined');\n\n    this.contextIdentifier = model.contextIdentifier;\n    this.layoutContainerId = model.layoutContainerId;\n    this.isNonInteractivePreview = model.isNonInteractivePreview;\n    this.dndManager = this.dndManagerService.getDndManager<ContentElementType>(this.dndContext);\n  }\n\n  protected attached(): void {\n    this.subscribeToState();\n    this.subscribeToBlockState();\n    this.element.classList.add('uce-composable-layout-container-element');\n  }\n\n  protected detached(): void {\n    this.storeService.disposeAllSubscriptions(this);\n    this.dndUnsubscribe();\n  }\n\n  private orderedChildInfosChanged(): void {\n    if(this.layoutContainer == null) return;\n    this.isCardWithSingleChild = this.layoutContainer.type === LayoutContainerType.Card\n      && this.orderedChildInfos.length === 1;\n  }\n\n  private contentLayoutModeChanged(): void {\n    if(this.contentLayoutMode != null) {\n      this.element.classList.add(`uce-composable-layout-container-element--layout-mode-${this.contentLayoutMode}`);\n    } else {\n      this.element.classList.remove('uce-composable-layout-container-element--layout-mode-intrinsic');\n      this.element.classList.remove('uce-composable-layout-container-element--layout-mode-extrinsic');\n    }\n  }\n\n  private contextIdentifierChanged(): void {\n    this.subscribeToState();\n  }\n\n  private layoutContainerIdChanged(): void {\n    this.subscribeToState();\n  }\n\n  private layoutContainerChanged(): void {\n    if(this.layoutContainer != null) {\n      this.subscribeToSpecialDndState();\n      this.dndSubscribe();\n    }\n\n    if(this.oldBlockId === this.layoutContainer?.blockId) return;\n    this.oldBlockId = this.layoutContainer?.blockId ?? null;\n    this.subscribeToBlockState();\n  }\n\n  private dndActiveStateChanged(): void {\n    if(!this.dndActiveState) {\n      this.resetDndTargetOverrideStates();\n      this.hideSequentialDropzones = false;\n      this.hideOuterDropzones = false;\n    }\n    this.recalcDndActive();\n  }\n\n  private dndAllowedChanged(): void {\n    this.recalcDndActive();\n  }\n\n  /**\n   * reaction to dnd targetting whitespace below content on pages\n   */\n  private lowerWhitespaceTargetedChanged(): void {\n    // in case this root container is a block-container, target dropzone is cardinal.bottom!\n    switch(this.layoutContainer?.type) {\n      case LayoutContainerType.Block:\n        this.showInnerCardinalDroptargets = this.lowerWhitespaceTargeted;\n        this.innerDropzoneTargeted = this.lowerWhitespaceTargeted\n          ? ContentEditingInsertModeCardinal.Bottom\n          : ContentEditingInsertModeCardinal.None;\n        break;\n      case LayoutContainerType.Card:\n        this.overrideOuterDropzoneStates = this.getDndShowTargetOverride();\n        this.overrideBottomOuterDropzoneState = this.getDndForceTargetedOverride();\n        break;\n      case LayoutContainerType.Layout:\n        // in case this root container is a pure layout-container with a horizontal layout\n        if(this.layoutContainer?.layout.direction === LayoutContainerDirection.Horizontal) {\n          // the target dropzone is the orthoSequential zone at position \"last\"\n          this.overrideLastOrthoDropzoneState = this.getDndForceTargetedOverride();\n          // for consistency force-show first ortho and all sequential dropzone targets\n          this.overrideFirstOrthoDropzoneState = this.getDndShowTargetOverride();\n          this.overrideLastSequentialDropzoneState = this.getDndShowTargetOverride();\n          this.overrideSequentialDropzonesStates = this.getDndShowTargetOverride();\n        } else {\n          // in case this root container is a pure layout-container with a vertical layout\n          // the target dropzone is the sequential zone at position \"last\"\n          this.overrideLastSequentialDropzoneState = this.getDndForceTargetedOverride();\n          // for consistency force-show all non-last sequential and both ortho dropzone targets\n          this.overrideSequentialDropzonesStates = this.getDndShowTargetOverride();\n          this.overrideLastOrthoDropzoneState = this.getDndShowTargetOverride();\n          this.overrideFirstOrthoDropzoneState = this.getDndShowTargetOverride();\n        }\n        break;\n    }\n  }\n\n  private getDndShowTargetOverride(): DndOverrideTargetDisplay {\n    return this.lowerWhitespaceTargeted\n      ? DndOverrideTargetDisplay.ForceShow\n      : DndOverrideTargetDisplay.NoOverride;\n  }\n\n  private getDndForceTargetedOverride(): DndOverrideTargetDisplay {\n    return this.lowerWhitespaceTargeted\n      ? DndOverrideTargetDisplay.ForceTargeted\n      : DndOverrideTargetDisplay.NoOverride;\n  }\n\n  private recalcDndActive(): void {\n    this.dndActive = this.dndActiveState != null && this.dndActiveState === true && this.dndAllowed;\n    if(this.dndActive) {\n      this.storeService.dispatch(ContentEditorMutations.updateEditBlockId, null);\n    }\n  }\n\n  private subscribeToState(): void {\n    const { contextIdentifier, layoutContainerId } = this;\n    if(!this.element.isConnected) return;\n    this.storeService.disposeSubscriptionsForContext(this, this.subscriptionContextDefault);\n\n    this.storeService.subscribeMemoizedWithContext(\n      this,\n      this.subscriptionContextDefault,\n      layoutContainerByIdSelectorCreator,\n      layoutContainer => {\n        this.layoutContainer = layoutContainer;\n        this.updateDropzoneConfigs();\n      },\n      { contextIdentifier, layoutContainerId },\n    );\n\n    this.storeService.subscribeMemoizedWithContext(\n      this,\n      this.subscriptionContextDefault,\n      layoutContainerChildInfoOrderedSelectorCreator,\n      orderedChildInfos => {\n        this.orderedChildInfos = orderedChildInfos;\n        this.updateDropzoneConfigs();\n      },\n      { contextIdentifier, layoutContainerId },\n    );\n\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.contentEditor.dragAndDrop.active,\n      state => state.contentEditor.dragAndDrop.showDroptargets,\n    ], (_state, active, showDroptargets) => {\n      this.dndActiveState = active;\n      this.showDroptargets = showDroptargets;\n    }, false, this.subscriptionContextDefault);\n\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.contentEditor.editBlockId,\n      state => state.contentEditor.isResizing,\n      state => state.contentEditor.containerStyles,\n      state => state.contentEditor.resizing,\n      state => !!state.contentEditor.previousResizingState,\n    ], (_state, editBlockId, isResizing, containerStyles, resizing, previousResizingStateAvailable) => {\n      this.editBlockId = editBlockId;\n      this.resizing = isResizing;\n      this.resizingHighlight = resizing[this.layoutContainerId] != null;\n      this.showExtraContainerSpace = containerStyles.showExtraContainerSpace;\n      this.dashedOutline = containerStyles.dashedLayoutContainerIds.includes(this.layoutContainerId);\n      this.previousResizingStateAvailable = previousResizingStateAvailable;\n    }, false, this.subscriptionContextDefault);\n\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.contentEditor.inspector.currentLayoutContainerId,\n      state => state.contentEditor.inspector.mode,\n    ], (_state, currentLayoutContainerIdInInspector, inspectorMode) => {\n      // without ternary this could result in null === null -> wrongfully setting selected\n      this.selectedForInspector = currentLayoutContainerIdInInspector === null\n        ? false : this.layoutContainer?.id === currentLayoutContainerIdInInspector;\n      this.inspectorMode = inspectorMode;\n    }, false, this.subscriptionContextDefault);\n  }\n\n  private subscribeToSpecialDndState(): void {\n    if(!this.element.isConnected) return;\n    this.storeService.disposeSubscriptionsForContext(this, this.subscriptionContextSpecial);\n    // only root container is interested in lowerWhitespaceTargeted dnd state:\n    if(this.layoutContainer != null && this.layoutContainer?.parentLayoutContainerId == null) {\n      this.storeService.subscribeToDetailedChanges(this, [\n        state => state.contentEditor.dragAndDrop.lowerWhitespaceTargeted,\n      ], (_state, lowerWhitespaceTargeted) => {\n        this.lowerWhitespaceTargeted = lowerWhitespaceTargeted;\n      }, false, this.subscriptionContextSpecial);\n    }\n  }\n\n  private subscribeToBlockState(): void {\n    if(!this.layoutContainer?.blockId || !this.element.isConnected) return;\n    this.storeService.disposeSubscriptionsForContext(this, this.subscriptionContextBlock);\n    this.storeService.subscribeMemoizedWithContext(\n      this,\n      this.subscriptionContextBlock,\n      blockByIdSelectorCreator,\n      block => {\n        this.currentElementType = block?.type;\n        if(block?.type === BlockType.SPACER) {\n          this.dndExcludedTargetSubContexts.push(DndSubContext.Clipboard);\n        } else {\n          this.dndExcludedTargetSubContexts = [];\n        }\n      },\n      { contextIdentifier: this.contextIdentifier, blockId: this.layoutContainer.blockId },\n    );\n  }\n\n  private dndSubscribe(): void {\n    this.dndUnsubscribe();\n    const { layoutContainerId } = this;\n    if(layoutContainerId == null || this.dndManager == null) return;\n\n    const containerIdentifier: DndDropzoneIdentifier = {\n      superId: layoutContainerId,\n      subId: ALL_DND_IDS,\n    };\n    const dndLowerWhitespaceIdentifier: DndDropzoneIdentifier = {\n      superId: DND_LOWER_WHITESPACE_ID,\n      subId: DND_LOWER_WHITESPACE_ID,\n    };\n    this.dndManager.subscribeDrop(this.subscriptionContextDefault, this.dndOnDropHandler.bind(this), [containerIdentifier]);\n    this.dndManager.subscribeToDragActivity(this.subscriptionContextDefault, this.dndDragActivityHandler.bind(this), [containerIdentifier]);\n    this.dndManager.subscribePayloadChanged(this.subscriptionContextDefault, this.dndPayloadChangedHandler.bind(this));\n\n    // only root layout container is interested in lower-white-space drop events\n    if(this.layoutContainer != null && this.layoutContainer?.parentLayoutContainerId == null) {\n      this.dndManager.subscribeDrop(\n        this.subscriptionContextDefault,\n        this.dndOnDropInLowerWhitespaceHandler.bind(this),\n        [dndLowerWhitespaceIdentifier]\n      );\n    }\n  }\n\n  private dndUnsubscribe(): void {\n    this.dndManager?.disposeSubscriptions(this.subscriptionContextDefault);\n  }\n\n  private dndPayloadChangedHandler(payload: DndPayloadUniversal<ContentElementType>): void {\n    this.dndPayload = payload;\n    this.dndAllowed = this.dndPayload != null && this.dndPayload?.source !== DndSubContext.Template;\n    if(this.dndPayload == null) this.showInnerCardinalDroptargets = false;\n\n    // hide sequential dropzones only for cards for cases:\n    this.hideSequentialDropzones = this.dndPayload != null\n      && this.layoutContainer?.type === LayoutContainerType.Card\n      && (this.dndPayload.existingPayloadId === this.layoutContainer.id // no drop inside itself\n        || (this.dndPayload.existingPayloadType != null\n          && NOT_ALLOWED_IN_CARD.includes(this.dndPayload.existingPayloadType)) // multiple types are not allowed in card\n        || (this.dndPayload.createNewType != null\n          && NOT_ALLOWED_IN_CARD.includes(this.dndPayload.createNewType)));\n    if(this.containerStructure) {\n      this.hideInnerDropzones = this.dndPayload != null\n        && this.dndPayload.existingPayloadType === NonBlockElementType.Card\n        && this.containerStructure?.isOnlyChildOfCard;\n    }\n    this.hideOuterDropzones = this.dndPayload != null && this.dndPayload.existingPayloadId === this.layoutContainer?.id;\n\n    // disable dropzones next to payload if required\n    if(this.layoutContainer != null && this.dndPayload != null && this.dndPayload.existingPayloadOrder !== undefined\n      && this.dndPayload.source === DndSubContext.Content && this.dndPayload.existingPayloadParentId === this.layoutContainer.id\n      && this.sequentialDropzonesDisabled.length > this.dndPayload.existingPayloadOrder) {\n      this.sequentialDropzonesDisabled[this.dndPayload.existingPayloadOrder] = true;\n      this.sequentialDropzonesDisabled[this.dndPayload.existingPayloadOrder + 1] = true;\n    } else {\n      for(let i = 0; i < this.sequentialDropzonesDisabled.length; i++) this.sequentialDropzonesDisabled[i] = false;\n    }\n  }\n\n  private dndDragActivityHandler(dndInfo: DndActivityEventData<IDndDropzoneConfig>): void {\n    if(this.layoutContainer == null || this.dndPayload == null) return;\n    // in uce-composable-layout-container we only care about inner-cardinal-DragActivity;\n    // inner-sequential and outer-cardinal-DragActivity is handled in according layout-container-*-dropzone-with-target components\n    if(!('insertModeCardinal' in dndInfo.dropTarget) || dndInfo.dropTarget.cardinalInto === false) return;\n    // no targetting oneself:\n    if(dndInfo.dropTarget.identifier.superId === this.dndPayload.existingPayloadId) {\n      this.showInnerCardinalDroptargets = false;\n      return;\n    }\n    if(dndInfo.enterEvent) {\n      this.showInnerCardinalDroptargets = true;\n      this.innerDropzoneTargeted = dndInfo.dropTarget.insertModeCardinal ?? ContentEditingInsertModeCardinal.None;\n    } else {\n      if(dndInfo.dropTarget.insertModeCardinal === ContentEditingInsertModeCardinal.None) this.showInnerCardinalDroptargets = false;\n      this.innerDropzoneTargeted = ContentEditingInsertModeCardinal.None;\n    }\n  }\n\n  private dndOnDropInLowerWhitespaceHandler(dropData: DndDropEventData<ContentElementType>): void {\n    if(this.layoutContainer == null || dropData.dndPayload == null || dropData.dndPayload.source == null) {\n      this.stopDnd();\n      return;\n    }\n    const payload = dropData.dndPayload;\n\n    // in case this root container is an element container\n    if(this.layoutContainer.type !== LayoutContainerType.Layout) {\n      if(payload.source === DndSubContext.New) {\n        const cardinalInto = this.layoutContainer.type === LayoutContainerType.Block;\n        this.insertElementCardinal(LayoutContainerDirection.Vertical, 'last', payload.createNewType, cardinalInto);\n      }\n      if(payload.existingPayloadId != null && payload.source === DndSubContext.Clipboard)\n        this.moveElementAndInsertCardinal(\n          payload.source, payload?.existingPayloadId, LayoutContainerDirection.Vertical,\n          'last', dropData.dropTarget.cardinalInto ?? true,\n        );\n    } else {\n      // in case this root container is a pure layout-container with a horizontal layout -> insert orthogonal last\n      if(this.layoutContainer.layout.direction === LayoutContainerDirection.Horizontal) {\n        if(payload.source === DndSubContext.New) {\n          this.insertElementAt(1, true, payload.createNewType);\n        } else if(payload.existingPayloadId != null && payload.source != null)\n          this.moveElementAndInsertAt(payload.source, payload?.existingPayloadId, true, 1);\n      } else {\n        // in case this root container is a pure layout-container with a vertical layout -> insert sequential last\n        if(payload.source === DndSubContext.New) {\n          this.insertElementAt(this.orderedChildInfos.length, false, payload.createNewType);\n        } else if(payload.existingPayloadId != null && payload.source != null)\n          this.moveElementAndInsertAt(payload.source, payload.existingPayloadId, false, this.orderedChildInfos.length);\n      }\n    }\n    this.stopDnd();\n  }\n\n  private dndOnDropHandler(dropData: DndDropEventData<ContentElementType>): void {\n    /**\n     * tell content-editor to deactivate dnd. this must happen before any action in here\n     * to avoid getting stuck in dnd mode by some return case. also dnd wouldn't be reset\n     * safely in time before state changes propagate to view. then the new view wouldn't have\n     * it's dropzone configs caluclated in time for the immediate display due to dnd still being active\n     */\n    this.stopDnd();\n    if(this.layoutContainer == null || dropData.dndPayload == null || dropData.dndPayload.source == null) return;\n    const payload = dropData.dndPayload;\n    const dropInfo = dropData.dropTarget;\n    // no dropping on oneself\n    if(dropInfo.identifier.superId === payload.existingPayloadId) return;\n    if(dropInfo.insertModeSelector === ContentEditingInsertModeSelector.Sequential) {\n      // avoid dropping next to payloads original location\n      if(payload != null && payload.existingPayloadOrder !== undefined\n        && dropInfo.identifier.superId === payload?.existingPayloadParentId\n        && (dropInfo.sequentialOrder === payload.existingPayloadOrder\n          || dropInfo.sequentialOrder === payload.existingPayloadOrder + 1)) return;\n      // decide to insert a new block or an existing container sequentially\n      if(payload.source === DndSubContext.New) {\n        this.insertElementAt(dropInfo.identifier.subId, false, payload?.createNewType);\n      } else {\n        if(payload == null\n          || payload.existingPayloadId === undefined\n          || dropInfo.sequentialOrder === undefined) return;\n        this.moveElementAndInsertAt(payload.source!, payload?.existingPayloadId, false, dropInfo.sequentialOrder);\n      }\n    } else if(dropInfo.insertModeSelector === ContentEditingInsertModeSelector.OrthoSequential) {\n      if(payload.source === DndSubContext.New) {\n        this.insertElementAt(dropInfo.identifier.subId, true, payload?.createNewType);\n      } else {\n        if(payload == null\n          || payload.existingPayloadId === undefined\n          || dropInfo.sequentialOrder === undefined) return;\n        this.moveElementAndInsertAt(payload.source!, payload?.existingPayloadId, true, dropInfo.sequentialOrder);\n      }\n    } else if(dropInfo.insertModeSelector === ContentEditingInsertModeSelector.Cardinal) {\n      const direction: LayoutContainerDirection = (dropInfo.insertModeCardinal === ContentEditingInsertModeCardinal.Left\n        || dropInfo.insertModeCardinal === ContentEditingInsertModeCardinal.Right)\n        ? LayoutContainerDirection.Horizontal : LayoutContainerDirection.Vertical;\n      const position = (dropInfo.insertModeCardinal === ContentEditingInsertModeCardinal.Left\n        || dropInfo.insertModeCardinal === ContentEditingInsertModeCardinal.Top)\n        ? 'first' : 'last';\n\n      // inspector specific code: reset selected layout container if dropping inside selected container:\n      if(this.inspectorMode !== InspectorMode.Inactive && this.selectedForInspector) {\n        this.storeService.dispatch(ContentEditorMutations.updateInspector, null);\n      }\n\n      if(payload.source === DndSubContext.New) {\n        this.insertElementCardinal(direction, position, payload.createNewType, dropInfo.cardinalInto ?? true);\n      } else {\n        if(payload == null\n          || payload.existingPayloadId === undefined) return;\n        this.moveElementAndInsertCardinal(payload.source!, payload.existingPayloadId, direction, position, dropInfo.cardinalInto ?? true);\n      }\n    }\n  }\n\n  private stopDnd(): void {\n    if(this.inspectorMode !== InspectorMode.Container) this.storeService\n      .dispatch(ContentEditorMutations.updateContainerStylesState, { showExtraContainerSpace: false });\n    this.storeService\n      .pipe(ContentEditorMutations.updateDragAndDropState, { active: false })\n      .pipe(ContentEditorMutations.resetContainerHoverState)\n      .dispatch();\n  }\n\n  private resetDndTargetOverrideStates(): void {\n    this.overrideSequentialDropzonesStates = DndOverrideTargetDisplay.NoOverride;\n    this.overrideFirstOrthoDropzoneState = DndOverrideTargetDisplay.NoOverride;\n    this.overrideLastSequentialDropzoneState = DndOverrideTargetDisplay.NoOverride;\n    this.overrideLastOrthoDropzoneState = DndOverrideTargetDisplay.NoOverride;\n  }\n\n  private updateDropzoneConfigs(): void {\n    if(this.layoutContainer == null || this.innerDropzoneConfig == null) return;\n    if(this.orderedChildInfos.length > 1) {\n      this.sequentialDropzoneConfigs = [];\n      this.sequentialDropzonesDisabled = [];\n      this.orthoDropzoneConfigs = [];\n      this.updateDomRect();\n      this.sequentialDropzoneWidth = Math.max(this.sizePx * 0.1 / (this.orderedChildInfos.length * 2), CONTENT_EDITOR_DROPZONE_MIN_WIDTH_PX);\n      this.orthoDropzoneWidth = Math.max(this.orthoSizePx * 0.05, CONTENT_EDITOR_DROPZONE_MIN_WIDTH_PX);\n      // configure dropzones orthogonal to children-list\n      this.orthoDropzoneConfigs.push({\n        identifier: {\n          superId: this.layoutContainerId,\n          subId: 0,\n        },\n        insertModeSelector: ContentEditingInsertModeSelector.OrthoSequential,\n        sequentialOrder: 0,\n        sequentialPosition: DndSequentialDropzonePosition.First,\n      }, {\n        identifier: {\n          superId: this.layoutContainerId,\n          subId: 1,\n        },\n        insertModeSelector: ContentEditingInsertModeSelector.OrthoSequential,\n        sequentialOrder: 1,\n        sequentialPosition: DndSequentialDropzonePosition.Last,\n      });\n      // configure dropzones before, inbetween and after children-list\n      this.orderedChildInfos.forEach((_child, index) => {\n        if(this.layoutContainer != null) {\n          this.sequentialDropzoneConfigs.push({\n            identifier: {\n              superId: this.layoutContainerId,\n              subId: index,\n            },\n            insertModeSelector: ContentEditingInsertModeSelector.Sequential,\n            insertModeSequential: DndInsertModeSequential.Before,\n            sequentialOrder: index,\n            sequentialPosition: index === 0\n              ? DndSequentialDropzonePosition.First\n              : DndSequentialDropzonePosition.Inbetween,\n          });\n          this.sequentialDropzonesDisabled.push(false);\n        }\n      });\n      // add last zone separately:\n      this.sequentialDropzoneConfigs.push({\n        identifier: {\n          superId: this.layoutContainerId,\n          subId: this.orderedChildInfos.length,\n        },\n        insertModeSelector: ContentEditingInsertModeSelector.Sequential,\n        insertModeSequential: DndInsertModeSequential.After,\n        sequentialOrder: this.orderedChildInfos.length,\n        sequentialPosition: DndSequentialDropzonePosition.Last,\n      });\n      this.sequentialDropzonesDisabled.push(false);\n    }\n    this.innerDropzoneConfig.identifier = {\n      superId: this.layoutContainerId,\n      subId: ALL_DND_IDS,\n    };\n    this.innerDropzoneConfig.cardinalInto = true;\n  }\n\n  @computedFrom('editBlockId', 'blockId')\n  protected get isInEditMode(): boolean {\n    return this.blockId !== null && this.editBlockId === this.blockId;\n  }\n\n  @computedFrom('orderedChildInfos.length')\n  protected get isBlockContainer(): boolean {\n    return this.orderedChildInfos.length === 0;\n  }\n\n  @computedFrom('layoutContainer.blockId')\n  protected get blockId(): number | null {\n    return this.layoutContainer?.blockId ?? null;\n  }\n\n  @computedFrom('inspectorMode')\n  protected get containerMode(): boolean {\n    return this.inspectorMode === InspectorMode.Container;\n  }\n\n  @computedFrom('editBlockId', 'blockId')\n  protected get allowDnd(): boolean {\n    return this.editBlockId !== this.blockId;\n  }\n\n  @computedFrom('layoutContainer.blockId', 'layoutContainer.layout.direction', 'childSizes')\n  private get layoutStyles(): LayoutStyles | null {\n    if(this.layoutContainer == null) return null;\n    const { blockId, layout: { direction } } = this.layoutContainer;\n    const horizontal = direction === LayoutContainerDirection.Horizontal;\n\n    if(blockId != null || this.orderedChildInfos.length !== this.childSizes.length) return null;\n\n    const gridValue = this.childSizes.map(size => {\n      return `${size}px`;\n    }).join(' ');\n\n    return {\n      'grid-template-columns': horizontal ? gridValue : '1fr',\n      'grid-template-rows': horizontal ? '1fr' : gridValue,\n    };\n  }\n\n  @computedFrom('layoutContainer.blockId', 'layoutContainer.layout.direction', 'dndActive', 'isPresentation')\n  private get showResizers(): boolean {\n    return this.layoutContainer != null\n      // is parent of other containers\n      && this.layoutContainer?.blockId == null\n      && !this.dndActive\n      // exclude vertical parent containers in course (at the moment)\n      && !(this.layoutContainer.layout.direction === LayoutContainerDirection.Vertical && !this.isPresentation);\n  }\n\n  private startResizing(index: number): void {\n    if(this.layoutContainer == null) return;\n    // prepare values one time for cyclic use in resize mouse-event callback\n    this.resizingChildIndex = index;\n    const child1Id = this.orderedChildInfos[this.resizingChildIndex - 1].id;\n    const child2Id = this.orderedChildInfos[this.resizingChildIndex].id;\n\n    this.storeService.dispatch(ContentEditorMutations.startResizing, this.contextIdentifier, this.layoutContainerId, child1Id, child2Id);\n    this.updateDomRect();\n    this.oneFractionPx = this.sizePx / CONTENT_EDITOR_FRACTIONS;\n    this.snappingEpsilonPx = Math.round(this.sizePx / 100 * this.snappingEpsilonPercent);\n    this.initialSizePercent = this.orderedChildInfos[this.resizingChildIndex - 1]?.itemSize;\n    this.startOffsetPx = 0;\n    if(index > 1) {\n      for(let i = 0; i < index - 1; i++) {\n        this.startOffsetPx += this.orderedChildInfos[i].itemSize * (this.sizePx / 100);\n      }\n    }\n    this.endOffsetPx = 0;\n    if(index < this.orderedChildInfos.length - 1) {\n      for(let i = index + 1; i < this.orderedChildInfos.length; i++) {\n        this.endOffsetPx += this.orderedChildInfos[i].itemSize * (this.sizePx / 100);\n      }\n    }\n\n    const resizeCallback = throttle(this.resize.bind(this), 50);\n    const commitResizeCallback = this.commitResizing.bind(this);\n    window.addEventListener('mousemove', resizeCallback);\n    window.addEventListener('mouseup', commitResizeCallback);\n    this.subscriptions.push(\n      { dispose: () => { window.removeEventListener('mousemove', resizeCallback); } },\n      { dispose: () => { window.removeEventListener('mouseup', commitResizeCallback); } },\n    );\n  }\n\n  private async applyPreviousResizingState(index: number): Promise<void> {\n    const { contentEditor: { previousResizingState } } = await this.storeService.getState();\n    this.resizingChildIndex = index;\n    const child1 = this.orderedChildInfos[this.resizingChildIndex - 1];\n    const child2 = this.orderedChildInfos[this.resizingChildIndex];\n    if(this.layoutContainer == null || child1 == null || child2 == null || !previousResizingState) {\n      this.stopResizing();\n      return;\n    }\n    const newSizeChild1 = (child1.itemSize + child2.itemSize) * previousResizingState.child1Percentage / (previousResizingState.child1Percentage + previousResizingState.child2Percentage);\n    const sizeChangePercent = -(child1.itemSize - newSizeChild1);\n\n    if(sizeChangePercent !== 0) {\n      await this.storeService\n        .pipe(ContentEditorMutations.startResizing, this.contextIdentifier, this.layoutContainerId, child1.id, child2.id)\n        .pipe(ContentEditorMutations.setResizeChangePercent, this.contextIdentifier, this.layoutContainerId, sizeChangePercent)\n        .dispatch();\n      await this.commitResizing();\n    }\n    this.stopResizing();\n  }\n\n  private async changeItemSizeViaDialog(index: number): Promise<void> {\n    this.resizingChildIndex = index;\n    const child1 = this.orderedChildInfos[this.resizingChildIndex - 1];\n    const child2 = this.orderedChildInfos[this.resizingChildIndex];\n    if(this.layoutContainer == null || child1 == null || child2 == null) return;\n    const minPercent = Math.round((100 / CONTENT_EDITOR_FRACTIONS) / 2);\n    const maxPercent = child1.itemSize + child2.itemSize - minPercent;\n    const sizeChangePercent = await this.customDialogService.showChangeItemSizeDialog({\n      childOnePercentage: child1.itemSize,\n      childTwoPercentage: child2.itemSize,\n      min: minPercent,\n      max: maxPercent\n    });\n    if(!sizeChangePercent) {\n      this.stopResizing();\n      return;\n    }\n\n    if(sizeChangePercent !== 0) {\n      await this.storeService\n        .pipe(ContentEditorMutations.startResizing, this.contextIdentifier, this.layoutContainerId, child1.id, child2.id)\n        .pipe(ContentEditorMutations.setResizeChangePercent, this.contextIdentifier, this.layoutContainerId, sizeChangePercent)\n        .dispatch();\n      await this.commitResizing();\n    }\n    this.stopResizing();\n  }\n\n  private resize(e: MouseEvent): void {\n    if(this.layoutContainer == null) return;\n    const mousePosPx = (this.layoutContainer.layout.direction === LayoutContainerDirection.Horizontal ? e.clientX : e.clientY) - this.containerStartPosPx;\n    const minSize = this.startOffsetPx + (this.oneFractionPx / 2) + this.snappingEpsilonPx;\n    const maxSize = this.containerEndPosPx - this.endOffsetPx - (this.oneFractionPx / 2) - this.snappingEpsilonPx;\n    let tempSizePx = 0;\n\n    // decide the actual new size by checking possible states in this order: 1. min size, 2. max size,\n    // 3. snap to fraction-grid if mousPos is within grid + epsilon, 4. snap to fraction-grid if mousPos is within grid - epsilon, 5. free range\n    if(mousePosPx < minSize) {\n      tempSizePx = (this.oneFractionPx / 2);\n    } else if(mousePosPx + this.containerStartPosPx > maxSize) {\n      tempSizePx = this.containerEndPosPx - this.endOffsetPx - (this.oneFractionPx / 2) - this.containerStartPosPx - this.startOffsetPx;\n    } else {\n      const rest = mousePosPx % this.oneFractionPx;\n      if(rest < this.snappingEpsilonPx) {\n        tempSizePx = mousePosPx - rest - this.startOffsetPx;\n      } else if(rest > this.oneFractionPx - this.snappingEpsilonPx) {\n        tempSizePx = mousePosPx - rest - this.startOffsetPx + this.oneFractionPx;\n      } else {\n        tempSizePx = mousePosPx - this.startOffsetPx;\n      }\n    }\n\n    const tempSizePercent = tempSizePx * (100 / this.sizePx);\n    const sizeChangePercent = tempSizePercent - this.initialSizePercent;\n\n    if(sizeChangePercent !== 0) {\n      this.storeService.dispatch(ContentEditorMutations.setResizeChangePercent, this.contextIdentifier, this.layoutContainerId, MathUtils.roundPercentForItemSize(sizeChangePercent));\n    }\n  }\n\n  private getChildLayoutContainerItemSize(childLayoutContainerId: number): number {\n    return this.orderedChildInfos.find(cI => cI.id === childLayoutContainerId)?.itemSize ?? 0;\n  }\n\n  private stopResizing(): void {\n    this.resizingChildIndex = -1;\n    this.subscriptions.forEach(sub => sub.dispose());\n    this.subscriptions.length = 0;\n  }\n\n  private async commitResizing(): Promise<void> {\n    this.stopResizing();\n\n    const { contentEditor: { resizing } } = await this.storeService.getState();\n    const resizeState = resizing[this.layoutContainerId];\n    if(resizeState == null) return;\n\n    try {\n      const sizeChangePercent = MathUtils.roundPercentForItemSize(resizeState.sizeChangePercent);\n      await this.contentEditorApi.resizeLayoutContainers({\n        container1Id: resizeState.child1Id,\n        container2Id: resizeState.child2Id,\n        sizeChangePercent,\n      });\n      await this.storeService.dispatch(ContentEditorMutations.commitResizeState, this.contextIdentifier, this.layoutContainerId);\n      await this.saveResizingState(resizeState);\n    } catch(err) {\n      await this.storeService.dispatch(ContentEditorMutations.resetResizing, this.layoutContainerId);\n      throw err;\n    }\n  }\n\n  private async saveResizingState(resizeState: ContainerResizeState): Promise<void> {\n    const previousResizingState: PreviousResizingState = {\n      child1Percentage: this.getChildLayoutContainerItemSize(resizeState.child1Id),\n      child2Percentage: this.getChildLayoutContainerItemSize(resizeState.child2Id),\n    };\n    await this.storeService.dispatch(ContentEditorMutations.setPreviousResizingState, this.contextIdentifier, previousResizingState);\n  }\n\n  private updateDomRect(): void {\n    if(this.layoutContainer == null) return;\n\n    const rect = this.element.getBoundingClientRect();\n    const { direction } = this.layoutContainer.layout;\n\n    this.containerStartPosPx = direction === LayoutContainerDirection.Horizontal ? rect.left : rect.top;\n    this.containerEndPosPx = direction === LayoutContainerDirection.Horizontal ? rect.right : rect.bottom;\n    const orthoStartPosPx = direction === LayoutContainerDirection.Horizontal ? rect.top : rect.left;\n    const orthoEndPosPx = direction === LayoutContainerDirection.Horizontal ? rect.bottom : rect.right;\n\n    this.sizePx = this.containerEndPosPx - this.containerStartPosPx;\n    this.orthoSizePx = orthoEndPosPx - orthoStartPosPx;\n    this.orthoDirection = direction === LayoutContainerDirection.Horizontal\n      ? LayoutContainerDirection.Vertical : LayoutContainerDirection.Horizontal;\n  }\n\n  private async handleHoverOverContainer(\n    event: MouseEvent,\n    hovered: boolean,\n  ): Promise<void> {\n    if(this.resizing) return;\n    if(!hovered) await FunctionUtils.timeout(HOVER_END_DELAY_MS);\n    this.storeService.dispatch(ContentEditorMutations.updateContainerHoverState, this.layoutContainerId, hovered);\n    event.stopPropagation();\n  }\n\n  private async handleHoverOverOptions(\n    event: MouseEvent,\n    hovered: boolean,\n    containerId: number,\n  ): Promise<void> {\n    if(this.resizing) return;\n    if(!hovered) await FunctionUtils.timeout(HOVER_END_DELAY_MS);\n    this.storeService.dispatch(ContentEditorMutations.updateContainerOptionsHoverState, containerId, hovered);\n    event.stopPropagation();\n  }\n\n  private handleContainerClicked(): void {\n    if(this.inspectorMode !== InspectorMode.Inactive) {\n      this.storeService.dispatch(\n        ContentEditorMutations.updateInspector,\n        this.layoutContainerId,\n      );\n    }\n  }\n\n  private async insertElementCardinal(\n    direction: LayoutContainerDirection,\n    position: 'last' | 'first',\n    elementType?: ContentElementType,\n    insertInto?: boolean,\n  ): Promise<void> {\n    const createBlockDto = await this.selectBlockForType(elementType);\n    if(createBlockDto == null) return;\n\n    const changes = await this.contentEditorApi.insertElementCardinal(\n      this.layoutContainerId,\n      { direction, position, ...createBlockDto, insertInto: insertInto ?? true },\n    );\n    await this.storeService\n      .pipe(ContentContextMutations.applyLayoutChanges, this.contextIdentifier, changes)\n      .pipe(ContentEditorMutations.updateContainerStructure, this.contextIdentifier)\n      .pipe(ContentEditorMutations.resetContainerHoverState)\n      .dispatch();\n\n    if(elementType === NonBlockElementType.AiText) RichTextEditorToolbar.showAiTray();\n    await this.contentEditorService.focusNewTextBlock(changes);\n  }\n\n  private async insertElementAt(\n    index: number,\n    insertOrthogonal?: boolean,\n    elementType?: ContentElementType\n  ): Promise<void> {\n    const createBlockDto = await this.selectBlockForType(elementType);\n    if(createBlockDto == null) return;\n    const orthogonal = insertOrthogonal ?? false;\n\n    const changes = await this.contentEditorApi.insertElementAt(\n      this.layoutContainerId,\n      { index, orthogonal, ...createBlockDto },\n    );\n    await this.storeService\n      .pipe(ContentContextMutations.applyLayoutChanges, this.contextIdentifier, changes)\n      .pipe(ContentEditorMutations.updateContainerStructure, this.contextIdentifier)\n      .pipe(ContentEditorMutations.resetContainerHoverState)\n      .dispatch();\n\n    if(elementType === NonBlockElementType.AiText) RichTextEditorToolbar.showAiTray();\n    await this.contentEditorService.focusNewTextBlock(changes);\n  }\n\n  private async moveElementAndInsertCardinal(\n    source: DndSubContext,\n    idToMove: number,\n    direction: LayoutContainerDirection,\n    position: 'first' | 'last',\n    insertInto: boolean,\n  ): Promise<void> {\n    if(source === DndSubContext.Clipboard) {\n      let cardinalDirection = ContentEditingInsertModeCardinal.None;\n      if(direction === LayoutContainerDirection.Horizontal) {\n        cardinalDirection = position === 'first'\n          ? ContentEditingInsertModeCardinal.Left\n          : ContentEditingInsertModeCardinal.Right;\n      } else {\n        cardinalDirection = position === 'first'\n          ? ContentEditingInsertModeCardinal.Top\n          : ContentEditingInsertModeCardinal.Bottom;\n      }\n      const changes = await this.contentEditorApi.moveElementFromClipboard(idToMove, {\n        targetLayoutContainerId: this.layoutContainerId,\n        insertMode: ContentEditingInsertModeSelector.Cardinal,\n        insertModeCardinalDirection: cardinalDirection,\n        insertInto,\n      });\n      await this.storeService\n        .pipe(ContentContextMutations.applyLayoutChanges, this.contextIdentifier, changes.targetLayoutChanges)\n        .pipe(\n          ClipboardMutations.applyRemoveChanges,\n          changes.clipboardLayoutContainerChanges,\n          changes.clipboardCardContentChanges,\n          changes.clipboardRemovedBlockId,\n        ).pipe(ContentEditorMutations.updateContainerStructure, this.contextIdentifier)\n        .pipe(ContentEditorMutations.resetContainerHoverState)\n        .dispatch();\n    } else {\n      const changes = await this.contentEditorApi.moveElementAndInsertCardinal(idToMove, {\n        containerToInsertCardinalToId: this.layoutContainerId,\n        direction,\n        position,\n        insertInto,\n      });\n      await this.storeService\n        .pipe(ContentContextMutations.applyLayoutChanges, this.contextIdentifier, changes)\n        .pipe(ContentEditorMutations.updateContainerStructure, this.contextIdentifier)\n        .pipe(ContentEditorMutations.resetContainerHoverState)\n        .dispatch();\n    }\n  }\n\n  private async moveElementAndInsertAt(\n    source: DndSubContext,\n    idToMove: number,\n    insertDirectionOrthogonal: boolean,\n    insertAtIndex: number,\n  ): Promise<void> {\n    if(source === DndSubContext.Clipboard) {\n      const insertMode = insertDirectionOrthogonal\n        ? ContentEditingInsertModeSelector.OrthoSequential\n        : ContentEditingInsertModeSelector.Sequential;\n      const changes = await this.contentEditorApi.moveElementFromClipboard(idToMove, {\n        targetLayoutContainerId: this.layoutContainerId,\n        insertMode,\n        insertAtIndex,\n      });\n      await this.storeService\n        .pipe(ContentContextMutations.applyLayoutChanges, this.contextIdentifier, changes.targetLayoutChanges)\n        .pipe(\n          ClipboardMutations.applyRemoveChanges,\n          changes.clipboardLayoutContainerChanges,\n          changes.clipboardCardContentChanges,\n          changes.clipboardRemovedBlockId,\n        ).pipe(ContentEditorMutations.updateContainerStructure, this.contextIdentifier)\n        .pipe(ContentEditorMutations.resetContainerHoverState)\n        .dispatch();\n    } else {\n      const changes = await this.contentEditorApi.moveElementAndInsertAt(idToMove, {\n        containerToInsertAtId: this.layoutContainerId,\n        insertDirectionOrthogonal,\n        insertAtIndex,\n      });\n      await this.storeService\n        .pipe(ContentContextMutations.applyLayoutChanges, this.contextIdentifier, changes)\n        .pipe(ContentEditorMutations.updateContainerStructure, this.contextIdentifier)\n        .pipe(ContentEditorMutations.resetContainerHoverState)\n        .dispatch();\n    }\n  }\n\n  private async selectBlockForType(elementType: ContentElementType | undefined): Promise<ICreateUniversalBlockDto | null> {\n    if(elementType == null) return null;\n\n    if(elementType === BlockType.TEXT) {\n      return BlockUtils.convertToCreateUniversalBlock({ type: elementType, text: '' });\n    }\n    if(elementType === NonBlockElementType.AiText) {\n      return BlockUtils.convertToCreateUniversalBlock({ type: BlockType.TEXT, text: '' });\n    }\n\n    if(elementType === BlockType.SPACER) {\n      return {\n        title: '',\n        text: null,\n        type: BlockType.SPACER,\n        internalNote: null,\n      };\n    }\n    if(elementType === NonBlockElementType.Card) {\n      return BlockUtils.convertToCreateUniversalBlock({\n        type: BlockType.EMPTY_CARD,\n        text: this.i18n.tr('pages.content-editor.cardTextBlockPlaceholder'),\n      });\n    }\n\n    const block = await this.customDialogService.showContentEditorBlockEditorDialog({\n      contextIdentifier: this.contextIdentifier,\n      blockId: null,\n      block: elementType === NonBlockElementType.AiQuiz\n        ? { type: BlockType.QUESTION, nonBlockElementType: elementType, }\n        : { type: elementType },\n    });\n\n    return block ? BlockUtils.convertToCreateUniversalBlock(block) : null;\n  }\n}\n","import { FrameworkConfiguration, PLATFORM } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('resources/elements/uce-course-learn-page-header/uce-course-learn-page-header'));\n}\n","import { autoinject } from 'aurelia-dependency-injection';\nimport { PLATFORM } from 'aurelia-pal';\nimport { useView } from 'aurelia-templating';\nimport { ICourseLearnPageHeaderModel } from 'common/aurelia-components/course-learn-page-header/composable-course-learn-page-header';\nimport { selectState } from 'common/aurelia-decorators/select-state';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { CONTENT_EDITOR_COURSE_CONTEXT } from 'common/constants/content.editor.constants';\nimport { ICoursePageDto } from 'common/dto/course/content/page.interface';\nimport { pageByIdSelectorCreator } from 'common/store/selectors/course.context.selectors';\nimport { ICommonState } from 'common/store/store.interface';\nimport { ToastService } from 'services/ToastService';\nimport { InlineEditField, InlineEditSaveEvent, InlineEditValidationFailedEvent } from '../inline-edit-field/inline-edit-field';\nimport * as CourseContextMutations from 'common/store/mutations/course.context.mutations';\nimport { ContentEditorApiService } from 'services/api/ContentEditorApiService';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\n\n@useView(PLATFORM.moduleName('./uce-course-learn-page-header.html'))\n@autoinject()\nexport class UceCourseLearnPageHeader {\n  public pageId!: number;\n  public contextIdentifier = CONTENT_EDITOR_COURSE_CONTEXT;\n\n  private titleEditField?: InlineEditField;\n\n  @selectState(UceCourseLearnPageHeader, pageByIdSelectorCreator, ['contextIdentifier', 'pageId']) private page?: ICoursePageDto | null;\n  private domElement: HTMLElement;\n\n  constructor(\n    element: Element,\n    private toastService: ToastService,\n    private contentEditorApi: ContentEditorApiService,\n    private storeService: StoreService<ICommonState>,\n  ) {\n    this.domElement = element as HTMLElement;\n  }\n\n  protected activate(model: ICourseLearnPageHeaderModel): void {\n    this.pageId = model.pageId;\n  }\n\n  protected attached(): void {\n    this.domElement.classList.add('uce-course-learn-page-header');\n  }\n\n  private async onSaveTitle(event: InlineEditSaveEvent): Promise<void> {\n    assertNotNullOrUndefined(this.pageId, 'pageId cannot be null or undefined');\n    const newTitle = event.detail.value || null;\n\n    if(newTitle == null) {\n      this.toastService.error('pages.content-editor.savePageTitle');\n      this.titleEditField?.cancelEditing();\n      return;\n    }\n\n    try {\n      const updatedPage = await this.contentEditorApi.updatePage(this.pageId, { title: newTitle });\n      await this.storeService.dispatch(CourseContextMutations.updatePage, this.contextIdentifier, updatedPage);\n    } catch(e) {\n      this.toastService.error('pages.content-editor.savePageTitle');\n      this.titleEditField?.cancelEditing();\n    }\n  }\n\n  private onTitleValidationFailed(event: InlineEditValidationFailedEvent): void {\n    if(event.detail.value == null) {\n      this.toastService.error('pages.content-editor.savePageTitle');\n      this.titleEditField?.cancelEditing();\n    }\n  }\n}\n"],"names":[],"sourceRoot":""}