{"version":3,"file":"app-ef7d455c.f584a1446b2fc034d810.bundle.js","mappings":"AAKA","sources":["webpack://lernplattform-admin-frontend/./src/store/actions.ts","webpack://lernplattform-admin-frontend/./src/store/clipboard.mutations.ts","webpack://lernplattform-admin-frontend/./src/store/clipboard.selectors.ts","webpack://lernplattform-admin-frontend/./src/store/configure.ts","webpack://lernplattform-admin-frontend/./src/store/content.editor.mutations.ts","webpack://lernplattform-admin-frontend/./src/store/content.selectors.ts","webpack://lernplattform-admin-frontend/./src/store/distinar.selectors.ts","webpack://lernplattform-admin-frontend/./src/store/lecturer.distinar.mutations.ts","webpack://lernplattform-admin-frontend/./src/store/state.ts","webpack://lernplattform-admin-frontend/./src/store/template.mutations.ts","webpack://lernplattform-admin-frontend/./src/store/template.selectors.ts","webpack://lernplattform-admin-frontend/./src/utils/AppUtils.ts","webpack://lernplattform-admin-frontend/./src/utils/BlockUtils.ts","webpack://lernplattform-admin-frontend/./src/utils/FilterUtils.ts","webpack://lernplattform-admin-frontend/./src/utils/HtmlUtils.ts","webpack://lernplattform-admin-frontend/./src/utils/MediaShareUtils.ts","webpack://lernplattform-admin-frontend/./src/utils/ValidationUtils.ts"],"sourcesContent":["import { IRoleAssignment, IWhoamiData } from 'common/dto/auth/auth.interface';\nimport { IQuizTemplateWithQuestionCountDto } from 'common/dto/course/quiz/template/quiz.template.interface';\nimport { ColumnSortDirection } from 'common/dto/filter/filter.enum';\nimport { ISettingsDto } from 'common/dto/setting/setting.interface';\nimport { ITenantDto, ITenantDtoLecturer } from 'common/dto/tenant/management/tenant.management.interface';\nimport { RoleName } from 'common/enum/role.enums';\nimport { cloneDeep, merge } from 'lodash';\nimport { IGlobalFilterStatus, IHistoryInstruction, IQuickDistinarData, IQuickQuizData, IState, ITableFilterStatus, initialState, initialTableState } from './state';\n\nconst cloneState = (state: IState): IState => cloneDeep(state);\n\nexport function applyPartialState(state: IState, partialState: Partial<IState>): IState {\n  return merge({}, state, partialState);\n}\n\nexport const loginAction = (state: IState): IState => {\n  return {\n    ...state,\n    isLoggedIn: true,\n  };\n};\n\nexport const setCsrfTokenAction = (state: IState, csrfToken: string): IState => {\n  return {\n    ...state,\n    csrfToken,\n  };\n};\n\n// Aurelia really wants this parameter defined ...\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport const resetState = (state: IState): IState => {\n  const newState = cloneState(initialState);\n  // we have to keep the initializing state else `distinarInitializing` would be potentially `true`\n  // even if we already are initialized\n  newState.distinarInitializing = state.distinarInitializing;\n  return newState;\n};\n\nexport const logoutAction = (state: IState): IState => {\n  return resetState(state);\n};\n\nexport const setPersonalInfoAction = (state: IState, data: IWhoamiData<string>): IState => {\n  return {\n    ...state,\n    currentRole: cloneDeep(data.currentRole) || null,\n    user: {\n      ...state.user,\n      id: data.id,\n      firstname: data.firstname || '',\n      isLecturer: data.currentRole?.role === RoleName.Lecturer,\n      isOperator: data.currentRole?.role === RoleName.Operator,\n      isPowerUser: data.currentRole?.role === RoleName.PowerUser,\n      isProvider: data.currentRole?.role === RoleName.Provider,\n      lastname: data.lastname || '',\n      schoolName: data.schoolName || '',\n      titlePrefix: data.titlePrefix || '',\n      titleSuffix: data.titleSuffix || '',\n    },\n  };\n};\n\nexport const setSettingsAction = (state: IState, settings: ISettingsDto): IState => {\n  return {\n    ...state,\n    settings\n  };\n};\n\nexport const setRolesAction = (state: IState, data: IRoleAssignment<string>[]): IState => {\n  return {\n    ...state,\n    roles: data,\n  };\n};\n\nexport const setLanguageAction = (state: IState, language: string): IState => {\n  return {\n    ...state,\n    language,\n  };\n};\n\nexport const setCurrentTenantAction = (state: IState, tenant: ITenantDto<string> | ITenantDtoLecturer | null): IState => {\n  return {\n    ...state,\n    currentTenant: tenant,\n  };\n};\n\nexport const setRowsPerTablePageAction = (state: IState, data: number): IState => {\n  return {\n    ...state,\n    tables: {\n      ...state.tables,\n      rowsPerPage: data,\n    },\n  };\n};\n\nexport const setExtendTableSizeAction = (state: IState, extended: boolean): IState => {\n  return {\n    ...state,\n    tables: {\n      ...state.tables,\n      extended,\n    },\n  };\n};\n\nexport const clearNavigationHistory = (state: IState): IState => {\n  return {\n    ...state,\n    navigationHistory: {\n      ...state.navigationHistory,\n      previousInstructions: [],\n      currentInstruction: null,\n    },\n  };\n};\n\n/**\n * appends a new instruction to `previousInstructions`\n */\nexport const addInstructionToNavigationHistory = (state: IState, historyInstruction: IHistoryInstruction): IState => {\n  return {\n    ...state,\n    navigationHistory: {\n      ...state.navigationHistory,\n      previousInstructions: [\n        ...state.navigationHistory.previousInstructions,\n        historyInstruction,\n      ],\n    },\n  };\n};\n\n/**\n * sets `currentInstruction` and reverts the history to the first entry of `previousInstructions` where `historyInstruction.config.name === currentInstruction.config.name` if it exists\n */\nexport const setCurrentNavigationInstruction = (state: IState, currentInstruction: IHistoryInstruction): IState => {\n  const revertIndex = state.navigationHistory.previousInstructions.findIndex(instruction => instruction.config.name === currentInstruction.config.name);\n\n  return {\n    ...state,\n    navigationHistory: {\n      ...state.navigationHistory,\n      currentInstruction,\n      previousInstructions: revertIndex === -1\n        ? state.navigationHistory.previousInstructions\n        : state.navigationHistory.previousInstructions.slice(0, revertIndex),\n    }\n  };\n};\n\nexport const setupGlobalFilter = (state: IState, globalFilterId: string, tableId: string | null): IState => {\n  const globalFilterStatus = {\n    ...state.globalFilters[globalFilterId] ?? { filters: {}, active: false },\n    tableId,\n  };\n\n  return {\n    ...state,\n    globalFilters: {\n      [globalFilterId]: globalFilterStatus,\n    },\n  };\n};\n\nexport const setGlobalFilterStatusValue = (state: IState, globalFilterId: string, fieldName: string, value: string): IState => {\n  const filters: Partial<Record<string, string>> = {\n    ...state.globalFilters[globalFilterId]?.filters ?? {}\n  };\n  if(value === '') delete filters[fieldName];\n  else filters[fieldName] = value;\n\n  const globalFilterStatus = {\n    ...state.globalFilters[globalFilterId] ?? { active: false, tableId: null },\n    filters,\n  };\n\n  return {\n    ...state,\n    globalFilters: {\n      ...state.globalFilters,\n      [globalFilterId]: globalFilterStatus,\n    },\n  };\n};\n\nexport const toggleGlobalFilterActive = (state: IState, globalFilterId: string): IState | false => {\n  if(state.globalFilters[globalFilterId] == null) return false;\n\n  const globalFilterStatus = {\n    ...state.globalFilters[globalFilterId],\n    active: !state.globalFilters[globalFilterId]?.active,\n  } as IGlobalFilterStatus;\n\n  return {\n    ...state,\n    globalFilters: {\n      [globalFilterId]: globalFilterStatus,\n    },\n  };\n};\n\nexport const setTableFilterStatusValue = (state: IState, tableId: string, columnId: string, value: string): IState => {\n  const filters: Partial<Record<string, string>> = { ...state.tables.filterStatus[tableId]?.filters ?? {} };\n  if(value === '') delete filters[columnId];\n  else filters[columnId] = value;\n\n  return updateTableFilterStatus(state, tableId, { filters });\n};\n\nexport const setTableFilterStatusOffset = (state: IState, tableId: string, offset: number): IState => {\n  return updateTableFilterStatus(state, tableId, {\n    offset,\n  });\n};\n\nexport const setSelectedGalleryCourseId = (state: IState, courseId: number | null): IState => {\n  return {\n    ...state,\n    gallery: {\n      ...state.gallery,\n      selectedCourseId: courseId\n    },\n  };\n};\n\nexport const setTableFilterStatusSort = (state: IState, tableId: string, columnId: string, direction: ColumnSortDirection): IState => {\n  return updateTableFilterStatus(state, tableId, {\n    sortColumnId: columnId,\n    sortDirection: direction,\n  });\n};\n\nexport const clearTableFilter = (state: IState, tableId: string): IState => {\n  const globalFilterId = Object.entries(state.globalFilters)\n    .find(([, filterStatus]) => filterStatus?.tableId === tableId)?.[0];\n\n  const globalFilters = {\n    ...state.globalFilters,\n    ...(globalFilterId != null\n      ? { [globalFilterId]: { ...state.globalFilters[globalFilterId], filters: {} } as IGlobalFilterStatus }\n      : {}\n    )\n  };\n\n  return {\n    ...state,\n    tables: {\n      ...state.tables,\n      filterStatus: {\n        ...state.tables.filterStatus,\n        [tableId]: {\n          ...state.tables.filterStatus[tableId],\n          filters: {},\n        },\n      },\n    },\n    globalFilters,\n  };\n};\n\nexport const clearAllTableStates = (state: IState): IState => {\n  return {\n    ...state,\n    tables: initialTableState\n  };\n};\n\nexport const setQuizTemplates = (state: IState, quizTemplates: IQuizTemplateWithQuestionCountDto[]): IState => {\n  return {\n    ...state,\n    quizTemplates\n  };\n};\n\nexport const setQuickQuizData = (state: IState, quickQuizData: IQuickQuizData | null): IState => {\n  return {\n    ...state,\n    quickQuizData\n  };\n};\n\nexport const setQuickDistinarData = (state: IState, quickDistinarData: IQuickDistinarData | null): IState => {\n  return {\n    ...state,\n    quickDistinarData\n  };\n};\n\nexport const setPendingTeacherRegistrationsCount = (state: IState, pendingTeacherRegistrationsCount: number): IState => {\n  return {\n    ...state,\n    pendingTeacherRegistrationsCount\n  };\n};\n\nexport const clearTableSort = (state: IState, tableId: string): IState => {\n  const newFilterStatus = { ...state.tables.filterStatus };\n  const data = newFilterStatus[tableId];\n\n  if(!data) return state;\n\n  const newData = { ...data };\n  delete newData.offset;\n  delete newData.sortColumnId;\n  delete newData.sortDirection;\n  newFilterStatus[tableId] = newData;\n\n  return {\n    ...state,\n    tables: {\n      ...state.tables,\n      filterStatus: newFilterStatus,\n    }\n  };\n};\n\nfunction updateTableFilterStatus(state: IState, tableId: string, update: Partial<ITableFilterStatus>): IState {\n  return {\n    ...state,\n    tables: {\n      ...state.tables,\n      filterStatus: {\n        ...state.tables.filterStatus,\n        [tableId]: {\n          ...state.tables.filterStatus[tableId],\n          filters: state.tables.filterStatus[tableId]?.filters ?? {},\n          ...update,\n        },\n      },\n    }\n  };\n}\n","import {\n  IChanges,\n  IClipboardContentResponseDto,\n  ILayoutChanges,\n  IOrderById,\n  UniversalBlock,\n  UniversalLayoutContainer,\n} from 'common/dto/content-editor/content.editor.interface';\nimport { AdminStateMutationUtils } from 'services/AdminStateMutationUtils';\nimport { IState } from './state';\n\nexport function setContent<T extends IState>(\n  state: T,\n  clipboardContent: IClipboardContentResponseDto<UniversalLayoutContainer, UniversalBlock>,\n): T {\n  return AdminStateMutationUtils.updateClipboardPerformanceData({\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      clipboard: clipboardContent.clipboardContent,\n      clipboardCardContent: clipboardContent.clipboardCardContent,\n    }\n  });\n}\n\nexport function addItem<T extends IState>(\n  state: T,\n  newLayoutContainer: UniversalLayoutContainer,\n  newCardContent: ILayoutChanges<UniversalLayoutContainer, UniversalBlock>,\n  newBlock?: UniversalBlock,\n): T {\n  return AdminStateMutationUtils.updateClipboardPerformanceData({\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      clipboard: {\n        ...state.contentEditor.clipboard,\n        layoutContainers: [\n          ...state.contentEditor.clipboard.layoutContainers,\n          newLayoutContainer,\n        ],\n        blocks: newBlock == null ? state.contentEditor.clipboard.blocks : [\n          ...state.contentEditor.clipboard.blocks,\n          newBlock,\n        ],\n      },\n      clipboardCardContent: {\n        ...state.contentEditor.clipboardCardContent,\n        layoutContainers: [\n          ...state.contentEditor.clipboardCardContent.layoutContainers,\n          ...newCardContent.layoutContainerChanges.added,\n        ],\n        blocks: [\n          ...state.contentEditor.clipboardCardContent.blocks,\n          ...newCardContent.blockChanges.added,\n        ],\n      },\n    },\n  });\n}\n\nexport function applyRemoveChanges<T extends IState>(\n  state: T,\n  layoutContainerChanges: IChanges<IOrderById>,\n  cardContentChanges: ILayoutChanges<UniversalLayoutContainer, UniversalBlock>,\n  removeBlockId?: number | null,\n): T {\n  const blocksUpdated = state.contentEditor.clipboard.blocks.filter(block => block.id !== removeBlockId);\n  const layoutContainersUpdated: UniversalLayoutContainer[] = state.contentEditor.clipboard.layoutContainers\n    .filter(container => !layoutContainerChanges.removedIds.includes(container.id)) ?? [];\n\n  for(const layoutContainer of layoutContainersUpdated) {\n    const updatedIndex = layoutContainerChanges.updated.findIndex(updated => updated.id === layoutContainer.id);\n    if(updatedIndex !== -1) {\n      layoutContainer.order = layoutContainerChanges.updated[updatedIndex].order;\n    }\n  }\n\n  const cardContentBlocks = state.contentEditor.clipboardCardContent.blocks\n    .filter(block => !cardContentChanges.blockChanges.removedIds.includes(block.id));\n  const cardContentContainers = state.contentEditor.clipboardCardContent.layoutContainers\n    .filter(container => !cardContentChanges.layoutContainerChanges.removedIds.includes(container.id));\n\n  return AdminStateMutationUtils.updateClipboardPerformanceData({\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      clipboard: {\n        ...state.contentEditor.clipboard,\n        layoutContainers: layoutContainersUpdated,\n        blocks: blocksUpdated,\n      },\n      clipboardCardContent: {\n        ...state.contentEditor.clipboardCardContent,\n        layoutContainers: cardContentContainers,\n        blocks: cardContentBlocks,\n      },\n    },\n  });\n}\n","import { UniversalBlock, UniversalLayoutContainer } 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 { LayoutContainerType } from 'common/dto/course/layout.container.interface';\nimport { createSelectorCreator } from 'common/store/selectors/selectors';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { IState } from './state';\n\nexport interface IClipboardContentElementLayoutContainer {\n  layoutContainerId: number;\n  blockId: number | null;\n  elementType: ContentElementType;\n  orderWithinType: number;\n}\ninterface IClipboardContentFlow {\n  clipboardContent?: Array<IClipboardContentElementLayoutContainer>;\n  sortedClipboardLayoutContainers?: Array<UniversalLayoutContainer>;\n  orderByType?: Record<ContentElementType, number>;\n}\n\nexport const clipboardContentSelectorCreator = createSelectorCreator<IState, IClipboardContentFlow, Array<IClipboardContentElementLayoutContainer>>([\n  ({ state }) => ({\n    sortedClipboardLayoutContainers: ArrayUtils\n      .immutableSort(state.contentEditor.clipboard.layoutContainers, (a, b) => a.order - b.order),\n  }),\n  ({ state, sortedClipboardLayoutContainers }) => {\n    if(sortedClipboardLayoutContainers == null) return { };\n\n    const currentOrderByType: Record<string, number | undefined> = { };\n    // checking != null should not be required to ensure proper content of clipboard. but it\n    // helps to keep IClipboardContentElementLayoutContainer cleaner (no | null or | undefined)\n    return {\n      clipboardContent: sortedClipboardLayoutContainers\n        .reduce<Array<IClipboardContentElementLayoutContainer>>((accumulatedClipboardElements, layoutContainer) => {\n          const blockId = state.contentEditor.clipboard.blockIdByLayoutContainerId[layoutContainer.id] ?? null;\n          let elementType: ContentElementType | null = null;\n          switch(layoutContainer.type) {\n            case LayoutContainerType.Block:\n              elementType = (blockId != null ? state.contentEditor.clipboard.blockTypeById[blockId] ?? null : null) as BlockType | null;\n              break;\n            case LayoutContainerType.Card:\n              elementType = NonBlockElementType.Card;\n              break;\n          }\n\n          if(elementType != null) {\n            const currentOrder = currentOrderByType[elementType];\n            let newOrder: number;\n            if(currentOrder == null) {\n              newOrder = currentOrderByType[elementType] = 1;\n            } else {\n              newOrder = currentOrderByType[elementType] = currentOrder + 1;\n            }\n\n            return [\n              ...accumulatedClipboardElements,\n              {\n                layoutContainerId: layoutContainer.id,\n                blockId,\n                elementType,\n                orderWithinType: newOrder,\n              },\n            ];\n          }\n\n          return [...accumulatedClipboardElements];\n        }, []),\n    };\n  },\n], result => result?.clipboardContent ?? []);\n\ninterface ILayoutContainerByIdFlow {\n  layoutContainerId: number;\n  layoutContainer?: UniversalLayoutContainer;\n}\n\nexport const cardLayoutContainerByIdSelectorCreator = createSelectorCreator<IState, ILayoutContainerByIdFlow, UniversalLayoutContainer | null>([\n  ({ state, layoutContainerId }) => ({\n    layoutContainer: state.contentEditor.clipboard.layoutContainers.find(container => container.id === layoutContainerId),\n  }),\n], result => result.layoutContainer ?? null);\n\nexport const layoutContainerByIdSelectorCreator = createSelectorCreator<IState, ILayoutContainerByIdFlow, UniversalLayoutContainer | null>([\n  ({ state, layoutContainerId }) => ({\n    layoutContainer: state.contentEditor.clipboardCardContent.layoutContainers.find(container => container.id === layoutContainerId),\n  }),\n], result => result.layoutContainer ?? null);\n\ninterface IBlockByIdFlow {\n  blockId: number;\n  block?: UniversalBlock;\n}\n\nexport const blockByIdSelectorCreator = createSelectorCreator<IState, IBlockByIdFlow, UniversalBlock | null>([\n  ({ state, blockId }) => ({\n    block: state.contentEditor.clipboardCardContent.blocks.find(block => block.id === blockId),\n  }),\n], result => result.block ?? null);\n\ninterface ILayoutContainerChildIdsOrderedFlow {\n  layoutContainerId: number;\n  childIdsOrdered?: Array<number>;\n}\n\nexport const layoutContainerChildIdsOrderedSelectorCreator = createSelectorCreator<IState, ILayoutContainerChildIdsOrderedFlow, Array<number>>([\n  ({ state, layoutContainerId }) => ({\n    childIdsOrdered: ArrayUtils.immutableSort(\n      state.contentEditor.clipboardCardContent.layoutContainers.filter(container => container.parentLayoutContainerId === layoutContainerId),\n      (a, b) => a.order - b.order\n    ).map(container => container.id),\n  }),\n], result => result.childIdsOrdered ?? []);\n\ninterface ILayoutContainerItemSizeOrderedFlow {\n  layoutContainerId: number;\n  childrenOrdered?: UniversalLayoutContainer[];\n  itemSizes?: number[];\n}\n\nexport const layoutContainerItemSizeOrderedSelectorCreator = createSelectorCreator<IState, ILayoutContainerItemSizeOrderedFlow, number[]>([\n  ({ state, layoutContainerId }) => ({\n    childrenOrdered: ArrayUtils.immutableSort(\n      state.contentEditor.clipboardCardContent.layoutContainers.filter(container => container.parentLayoutContainerId === layoutContainerId),\n      (a, b) => a.order - b.order\n    ),\n  }),\n  ({ childrenOrdered }) => ({\n    itemSizes: childrenOrdered?.map(container => container.layout.itemSize),\n  }),\n], result => result.itemSizes ?? []);\n","import { __awaiter } from \"tslib\";\nimport { PLATFORM } from 'aurelia-framework';\nimport { MiddlewarePlacement, rehydrateFromLocalStorage } from 'aurelia-store';\nimport { Config } from 'common/fe-config/config';\nimport { registerCommonStoreActions } from 'common/store/configure';\nimport { createContentPerformanceDataMiddleware } from 'common/store/middlewares/content-performance-data.middleware';\nimport { StoreStorageMiddleware } from 'common/store/middlewares/store-storage.middleware';\nimport { createUpdateRateMiddleware } from 'common/store/middlewares/update-rate.middleware';\nimport { first } from 'rxjs/operators';\nimport * as allActions from './actions';\nimport * as ClipboardMutations from './clipboard.mutations';\nimport * as ContentEditorMutations from './content.editor.mutations';\nimport * as LecturerDistinarMutations from './lecturer.distinar.mutations';\nimport * as TemplateMutations from './template.mutations';\nconst LOCAL_STORAGE_STORE_KEY = 'lera-data';\nexport function configureStore(store, dataStorageService, customDialogService, enableWritingToIndexedDb) {\n    return __awaiter(this, void 0, void 0, function* () {\n        store.registerMiddleware(createContentPerformanceDataMiddleware(), MiddlewarePlacement.After);\n        if (Config().debug) {\n            store.registerMiddleware(createUpdateRateMiddleware(), MiddlewarePlacement.After);\n        }\n        for (const action of Object.values(allActions)) {\n            if (typeof action === 'function') {\n                store.registerAction(action.name, action);\n            }\n        }\n        store.registerAction('LECTURER:closeDistinarSideMenu', LecturerDistinarMutations.closeDistinarSideMenu);\n        store.registerAction('LECTURER:endLectureAction', LecturerDistinarMutations.endLectureAction);\n        store.registerAction('LECTURER:resetActiveLecture', LecturerDistinarMutations.resetActiveLecture);\n        store.registerAction('LECTURER:setDistinarSideMenuSection', LecturerDistinarMutations.setDistinarSideMenuSection);\n        store.registerAction('LECTURER:startLectureAction', LecturerDistinarMutations.startLectureAction);\n        store.registerAction('LECTURER:updateDistinarPresentationResumeData', LecturerDistinarMutations.updateDistinarPresentationResumeData);\n        store.registerAction('LECTURER:setConferenceStopping', LecturerDistinarMutations.setConferenceStopping);\n        store.registerAction('CONTENT_EDITOR:closeSidebarRight', ContentEditorMutations.closeSidebarRight);\n        store.registerAction('CONTENT_EDITOR:commitResizeState', ContentEditorMutations.commitResizeState);\n        store.registerAction('CONTENT_EDITOR:openSidebarRight', ContentEditorMutations.openSidebarRight);\n        store.registerAction('CONTENT_EDITOR:resetContainerHoverState', ContentEditorMutations.resetContainerHoverState);\n        store.registerAction('CONTENT_EDITOR:resetResizing', ContentEditorMutations.resetResizing);\n        store.registerAction('CONTENT_EDITOR:setPreviousResizingState', ContentEditorMutations.setPreviousResizingState);\n        store.registerAction('CONTENT_EDITOR:setResizeChangePercent', ContentEditorMutations.setResizeChangePercent);\n        store.registerAction('CONTENT_EDITOR:setSidebarRight', ContentEditorMutations.setSidebarRight);\n        store.registerAction('CONTENT_EDITOR:startResizing', ContentEditorMutations.startResizing);\n        store.registerAction('CONTENT_EDITOR:updateContainerHoverState', ContentEditorMutations.updateContainerHoverState);\n        store.registerAction('CONTENT_EDITOR:updateContainerOptionsHoverState', ContentEditorMutations.updateContainerOptionsHoverState);\n        store.registerAction('CONTENT_EDITOR:updateContainerStructure', ContentEditorMutations.updateContainerStructure);\n        store.registerAction('CONTENT_EDITOR:updateContainerStylesState', ContentEditorMutations.updateContainerStylesState);\n        store.registerAction('CONTENT_EDITOR:updateContentEditorMode', ContentEditorMutations.updateContentEditorMode);\n        store.registerAction('CONTENT_EDITOR:updateDragAndDropState', ContentEditorMutations.updateDragAndDropState);\n        store.registerAction('CONTENT_EDITOR:updateEditBlockId', ContentEditorMutations.updateEditBlockId);\n        store.registerAction('CONTENT_EDITOR:updateThemeColors', ContentEditorMutations.updateThemeColors);\n        store.registerAction('CONTENT_EDITOR:updateIsPresentationShared', ContentEditorMutations.updateIsPresentationShared);\n        store.registerAction('CONTENT_EDITOR:updateInspector', ContentEditorMutations.updateInspector);\n        store.registerAction('CONTENT_EDITOR_CLIPBOARD:addItem', ClipboardMutations.addItem);\n        store.registerAction('CONTENT_EDITOR_CLIPBOARD:applyRemoveChanges', ClipboardMutations.applyRemoveChanges);\n        store.registerAction('CONTENT_EDITOR_CLIPBOARD:setContent', ClipboardMutations.setContent);\n        store.registerAction('CONTENT_EDITOR_TEMPLATE:addItem', TemplateMutations.addItem);\n        store.registerAction('CONTENT_EDITOR_TEMPLATE:applyRemoveChanges', TemplateMutations.applyRemoveChanges);\n        store.registerAction('CONTENT_EDITOR_TEMPLATE:setContent', TemplateMutations.setContent);\n        registerCommonStoreActions(store);\n        const storeStorageMiddleware = new StoreStorageMiddleware(dataStorageService, {\n            storageKeyPrefix: '$adminMainstate',\n            blockedPropertyNames: new Set([\n                'distinarInitializing',\n                'conferenceContext'\n            ]),\n            handleError: () => setTimeout(() => customDialogService.confirmAction({\n                titleTk: 'globals.warning',\n                confirmTk: 'dialogs.confirmation.confirm',\n                textTk: 'dialogs.dbConnectError.description',\n                onlyShowConfirmAction: true,\n            }), 1000),\n        });\n        const storedState = yield storeStorageMiddleware.loadStoredState();\n        if (Object.keys(storedState).length === 0 && enableWritingToIndexedDb) {\n            const legacyState = rehydrateFromLocalStorage({}, LOCAL_STORAGE_STORE_KEY);\n            PLATFORM.global.localStorage.removeItem(LOCAL_STORAGE_STORE_KEY);\n            const currentState = yield store.state.pipe(first()).toPromise();\n            storeStorageMiddleware.setInitialState(currentState);\n            storeStorageMiddleware.register(store);\n            yield store.dispatch(allActions.applyPartialState, legacyState);\n        }\n        else {\n            yield store.dispatch(allActions.applyPartialState, storedState);\n            const currentState = yield store.state.pipe(first()).toPromise();\n            storeStorageMiddleware.setInitialState(currentState);\n            if (enableWritingToIndexedDb)\n                storeStorageMiddleware.register(store);\n        }\n    });\n}\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlndXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3N0b3JlL2NvbmZpZ3VyZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSx5QkFBeUIsRUFBUyxNQUFNLGVBQWUsQ0FBQztBQUV0RixPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDakQsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDcEUsT0FBTyxFQUFFLHNDQUFzQyxFQUFFLE1BQU0sOERBQThELENBQUM7QUFDdEgsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sbURBQW1ELENBQUM7QUFDM0YsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0saURBQWlELENBQUM7QUFDN0YsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXZDLE9BQU8sS0FBSyxVQUFVLE1BQU0sV0FBVyxDQUFDO0FBQ3hDLE9BQU8sS0FBSyxrQkFBa0IsTUFBTSx1QkFBdUIsQ0FBQztBQUM1RCxPQUFPLEtBQUssc0JBQXNCLE1BQU0sNEJBQTRCLENBQUM7QUFDckUsT0FBTyxLQUFLLHlCQUF5QixNQUFNLCtCQUErQixDQUFDO0FBRTNFLE9BQU8sS0FBSyxpQkFBaUIsTUFBTSxzQkFBc0IsQ0FBQztBQUcxRCxNQUFNLHVCQUF1QixHQUFHLFdBQVcsQ0FBQztBQUU1QyxNQUFNLFVBQWdCLGNBQWMsQ0FBQyxLQUFvQixFQUFFLGtCQUFzQyxFQUFFLG1CQUF3QyxFQUFFLHdCQUFpQzs7UUFDNUssS0FBSyxDQUFDLGtCQUFrQixDQUFDLHNDQUFzQyxFQUFFLEVBQUUsbUJBQW1CLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFOUYsSUFBRyxNQUFNLEVBQUUsQ0FBQyxLQUFLLEVBQUU7WUFDakIsS0FBSyxDQUFD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","import { IContainerStructurePerformanceData } from 'common/dto/content-editor/content.editor.interface';\nimport { ICourseLayoutContainerDto, ILayoutContainerDto, IPresentationLayoutContainerDto, LayoutContainerType } from 'common/dto/course/layout.container.interface';\nimport { ContainerResizeState, PreviousResizingState } from 'common/store/store.interface';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { MathUtils } from 'common/utils/MathUtils';\nimport { StateMutationUtils } from 'common/utils/StateMutationUtils';\nimport { ContentEditorMode } from '../resources/pages/content-editor/content-editor';\nimport {\n  IContentEditorContainerHoverState,\n  IContentEditorContainerStylesState,\n  IContentEditorDndState,\n  InspectorMode,\n  IState,\n  UceSidebarContent\n} from './state';\n\nexport function startResizing<T extends IState>(\n  state: T,\n  presentationContext: string,\n  layoutContainerId: number,\n  child1Id: number,\n  child2Id: number,\n): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      isResizing: true,\n      resizing: {\n        ...state.contentEditor?.resizing,\n        [layoutContainerId]: {\n          ...state.contentEditor?.resizing[layoutContainerId],\n          child1Id,\n          child2Id,\n          sizeChangePercent: 0,\n        },\n      },\n    },\n  };\n}\n\nexport function setResizeChangePercent<T extends IState>(\n  state: T,\n  presentationContext: string,\n  layoutContainerId: number,\n  sizeChangePercent: number,\n): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      resizing: {\n        ...state.contentEditor?.resizing,\n        [layoutContainerId]: {\n          ...state.contentEditor?.resizing[layoutContainerId],\n          sizeChangePercent,\n        },\n      },\n    },\n  };\n}\n\nexport function setPreviousResizingState<T extends IState>(\n  state: T,\n  presentationContext: string,\n  previousResizingState: PreviousResizingState\n): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      previousResizingState\n    },\n  };\n}\n\nexport function resetResizing<T extends IState>(state: T, layoutContainerId: number): T {\n  const resizing = { ...state.contentEditor.resizing };\n  delete resizing[layoutContainerId];\n\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      isResizing: false,\n      resizing,\n    },\n  };\n}\n\nexport function commitResizeState<T extends IState>(\n  state: T,\n  contextIdentifier: string,\n  layoutContainerId: number,\n): T {\n  const context = state.contentContexts[contextIdentifier] ?? null;\n  if(context == null) return { ...state };\n  const content = context.type === 'course'\n    ? state.courseContentById[context.state.courseId]\n    : state.presentationContentById[context.state.presentationId];\n  if(content == null) return { ...state };\n\n  // eslint-disable-next-line\n  const layoutContainers: Array<ILayoutContainerDto> = content.layoutContainers;\n  const { contentEditor } = state;\n  const resizeState = contentEditor?.resizing[layoutContainerId] ?? null;\n\n  if(contentEditor == null || resizeState == null) return { ...state };\n\n  const updateIndices = ArrayUtils.findIndices(layoutContainers, container => container.id === resizeState.child1Id\n    || container.id === resizeState.child2Id);\n\n  const resizingState = { ...contentEditor.resizing };\n  delete resizingState[layoutContainerId];\n\n  if(context.type === 'course') {\n    return {\n      ...StateMutationUtils.updateCourseContent(state, context.state.courseId, () => ({\n        layoutContainers: StateMutationUtils.updateItemsInArray(\n          content.layoutContainers as Array<ICourseLayoutContainerDto>,\n          updateIndices,\n          item => ({\n            layout: {\n              ...item.layout,\n              itemSize: calculateItemSize(item, resizeState)\n            },\n          }),\n        ),\n      })),\n      contentEditor: {\n        ...contentEditor,\n        isResizing: false,\n        resizing: resizingState,\n      },\n    };\n  }\n\n  return {\n    ...StateMutationUtils.updatePresentationContent(state, context.state.presentationId, () => ({\n      layoutContainers: StateMutationUtils.updateItemsInArray(\n        content.layoutContainers as Array<IPresentationLayoutContainerDto>,\n        updateIndices,\n        item => ({\n          layout: {\n            ...item.layout,\n            itemSize: calculateItemSize(item, resizeState)\n          },\n        }),\n      ),\n    })),\n    contentEditor: {\n      ...contentEditor,\n      isResizing: false,\n      resizing: resizingState,\n    },\n  };\n}\n\nexport function updateThemeColors<T extends IState>(state: T, themeColors: Array<string>): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      themeColors,\n    },\n  };\n}\n\nexport function updateIsPresentationShared<T extends IState>(state: T, isPresentationShared: boolean): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      isPresentationShared,\n    },\n  };\n}\n\n// updateContainerStylesState\nexport function updateContainerStylesState<T extends IState>(state: T, editorState: Partial<IContentEditorContainerStylesState>): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      containerStyles: {\n        ...state.contentEditor.containerStyles,\n        ...editorState,\n      },\n    },\n  };\n}\n\nexport function updateDragAndDropState<T extends IState>(state: T, dndState: Partial<IContentEditorDndState>): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      dragAndDrop: {\n        ...state.contentEditor.dragAndDrop,\n        ...dndState,\n      },\n    },\n  };\n}\n\nexport function updateContentEditorMode<T extends IState>(state: T, mode: ContentEditorMode): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      mode,\n    },\n  };\n}\n\nexport function updateEditBlockId<T extends IState>(state: T, editBlockId: number | null): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      editBlockId,\n    },\n  };\n}\n\nexport function resetContainerHoverState<T extends IState>(state: T): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      containerHoverStateById: {},\n      containerHoveredIds: [],\n      containerStyles: {\n        ...state.contentEditor.containerStyles,\n        dashedLayoutContainerIds: [],\n      }\n    }\n  };\n}\n\nexport function updateContainerHoverState<T extends IState>(\n  state: T,\n  layoutContainerId: number,\n  newIsHovered: boolean,\n): T {\n  /**\n   * Null checks in this algo are mostly used to allow dynamic initialization of values.\n   * this allows the record to be cleaned out regularly and keeps the state free of useless entries.\n   */\n\n  /**\n   * Hover-falling-edge events are delayed to allow a flicker free transition between hovering over\n   * a container and its options menu. If two hover-rising-edge events occur before a delayed hover-falling-edge\n   * event is processed, the hover-falling-edge would overwrite the actual correct hover-true state.\n   * To solve this problem a hover*count exists. A hover state is only false if the count is 0.\n   */\n  let hoverOverContainerCount = state.contentEditor.containerHoverStateById[layoutContainerId]?.hoverOverContainerCount ?? 0;\n  const hoverOverOptionsCount = state.contentEditor.containerHoverStateById[layoutContainerId]?.hoverOverOptionsCount ?? 0;\n\n  if(newIsHovered) {\n    hoverOverContainerCount += 1;\n  } else if(!newIsHovered && hoverOverContainerCount > 0) {\n    hoverOverContainerCount -= 1;\n  }\n\n  const hoverOverContainer = hoverOverContainerCount > 0;\n  const hoverOverOptions = state.contentEditor.containerHoverStateById[layoutContainerId]?.hoverOverOptions ?? false;\n  const hoverOverResult = hoverOverContainer || hoverOverOptions;\n\n  // remember last container hovered in list for container mode and correct spacer display on slides\n  const hoveredContainerIds = calculateHoveredIds(\n    state.contentEditor.containerHoverStateById,\n    hoverOverResult,\n    layoutContainerId,\n    state.contentEditor.containerHoveredIds,\n  );\n\n  const dashedLayoutContainerIds = calculateDashedLayoutContainerIds(\n    hoveredContainerIds,\n    state.contentEditor.containerStructure,\n    state.contentEditor.inspector.mode,\n  );\n\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      containerHoverStateById: {\n        ...state.contentEditor.containerHoverStateById,\n        [layoutContainerId]: {\n          ...state.contentEditor.containerHoverStateById[layoutContainerId],\n          hoverOverContainer,\n          hoverOverContainerCount,\n          hoverOverOptions,\n          hoverOverOptionsCount,\n          hoverOverResult,\n        },\n      },\n      containerHoveredIds: hoveredContainerIds,\n      containerStyles: {\n        ...state.contentEditor.containerStyles,\n        dashedLayoutContainerIds,\n      }\n    }\n  };\n}\n\nexport function updateContainerOptionsHoverState<T extends IState>(\n  state: T,\n  layoutContainerId: number,\n  newIsHovered: boolean,\n): T {\n  /**\n   * Null checks in this algo are mostly used to allow dynamic initialization of values.\n   * this allows the record to be cleaned out regularly and keeps the state free of useless entries.\n   */\n\n  /**\n   * Hover-falling-edge events are delayed to allow a flicker free transition between hovering over\n   * a container and its options menu. If two hover-rising-edge events occur before a delayed hover-falling-edge\n   * event is processed, the hover-falling-edge would overwrite the actual correct hover-true state.\n   * To solve this problem a hover*count exists. A hover state is only false if the count is 0.\n   */\n  let hoverOverOptionsCount = state.contentEditor.containerHoverStateById[layoutContainerId]?.hoverOverOptionsCount ?? 0;\n  const hoverOverContainerCount = state.contentEditor.containerHoverStateById[layoutContainerId]?.hoverOverContainerCount ?? 0;\n\n  if(newIsHovered) {\n    hoverOverOptionsCount += 1;\n  } else if(!newIsHovered && hoverOverOptionsCount > 0) {\n    hoverOverOptionsCount -= 1;\n  }\n\n  const hoverOverOptions = hoverOverOptionsCount > 0;\n  const hoverOverContainer = state.contentEditor.containerHoverStateById[layoutContainerId]?.hoverOverContainer ?? false;\n  const hoverOverResult = hoverOverContainer || hoverOverOptions;\n\n  // remember last container hovered in list for container mode and correct spacer display on slides\n  const hoveredContainerIds = calculateHoveredIds(\n    state.contentEditor.containerHoverStateById,\n    hoverOverResult,\n    layoutContainerId,\n    state.contentEditor.containerHoveredIds,\n  );\n\n  const dashedLayoutContainerIds = calculateDashedLayoutContainerIds(\n    hoveredContainerIds,\n    state.contentEditor.containerStructure,\n    state.contentEditor.inspector.mode,\n  );\n\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      containerHoverStateById: {\n        ...state.contentEditor.containerHoverStateById,\n        [layoutContainerId]: {\n          ...state.contentEditor.containerHoverStateById[layoutContainerId],\n          hoverOverContainer,\n          hoverOverContainerCount,\n          hoverOverOptions,\n          hoverOverOptionsCount,\n          hoverOverResult,\n        },\n      },\n      containerHoveredIds: hoveredContainerIds,\n      containerStyles: {\n        ...state.contentEditor.containerStyles,\n        dashedLayoutContainerIds,\n      }\n    }\n  };\n}\n\nfunction calculateItemSize(container: IPresentationLayoutContainerDto | ICourseLayoutContainerDto, resizeState: ContainerResizeState): number {\n  const percentageRaw = container.id === resizeState.child1Id\n    ? container.layout.itemSize + resizeState.sizeChangePercent\n    : container.layout.itemSize - resizeState.sizeChangePercent;\n  return MathUtils.roundPercentForItemSize(percentageRaw);\n}\n\nfunction calculateDashedLayoutContainerIds(\n  hoveredContainerIds: number[],\n  containerStructure: IContainerStructurePerformanceData,\n  inspectorMode: InspectorMode,\n): number[] {\n  let dashedLayoutContainerIds: number[] = [];\n  if(hoveredContainerIds.length > 0 && inspectorMode === InspectorMode.Container) {\n    const checkForContainerId = hoveredContainerIds[hoveredContainerIds.length - 1];\n    const containerData = containerStructure.structureDataByLayoutContainerId[checkForContainerId];\n\n    if(containerData != null && containerData.immediateChildrenIds != null) {\n      dashedLayoutContainerIds = [...containerData.immediateChildrenIds];\n      const typeOfCheckedContainer = containerStructure.layoutContainerTypeById[checkForContainerId];\n\n      if(typeOfCheckedContainer != null\n        && typeOfCheckedContainer === LayoutContainerType.Layout) {\n        dashedLayoutContainerIds.push(checkForContainerId);\n      }\n    }\n  }\n  return dashedLayoutContainerIds;\n}\n\nfunction calculateHoveredIds(\n  containerHoverStateById: { [containerId: number]: IContentEditorContainerHoverState },\n  newHoverOverResult: boolean,\n  layoutContainerId: number,\n  containerHoveredIds: number[],\n): number[] {\n  const oldHoverOverResult = containerHoverStateById[layoutContainerId] == null\n    || containerHoverStateById[layoutContainerId].hoverOverResult == null\n    ? false : containerHoverStateById[layoutContainerId].hoverOverResult;\n  let hoveredContainerIds = containerHoveredIds;\n  if(newHoverOverResult && !oldHoverOverResult) hoveredContainerIds = [\n    ...hoveredContainerIds,\n    layoutContainerId\n  ];\n\n  if(!newHoverOverResult && oldHoverOverResult) {\n    hoveredContainerIds = StateMutationUtils\n      .removeItemsInArray(\n        hoveredContainerIds,\n        id => id === layoutContainerId);\n  }\n  return hoveredContainerIds;\n}\n\n/**\n * open/close derived from current content:\n * requested sidebarContent === current content => close\n * requested sidebarContent !== current content => (keep) open\n */\nexport function setSidebarRight<T extends IState>(\n  state: T,\n  sidebarContent: UceSidebarContent,\n): T {\n  const isCurrentContent = sidebarContent === state.contentEditor.sidebarRight.content;\n  const newSidebarContent = isCurrentContent ? UceSidebarContent.None : sidebarContent;\n  /**\n   * Initially no usecase where setSidebarRight is called with content None when content is\n   * already None. Added \"|| content\" check just to ensure proper functionality if such a\n   * call might occur in future.\n   */\n  const newOpenState = isCurrentContent || newSidebarContent === UceSidebarContent.None ? false : true;\n\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor, sidebarRight: {\n        ...state.contentEditor.sidebarRight,\n        content: newSidebarContent,\n        open: newOpenState,\n      },\n    },\n  };\n}\n\nexport function closeSidebarRight<T extends IState>(state: T): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      sidebarRight: {\n        ...state.contentEditor.sidebarRight,\n        content: UceSidebarContent.None,\n        open: false,\n      },\n    },\n  };\n}\n\nexport function openSidebarRight<T extends IState>(\n  state: T,\n  sidebarContent: UceSidebarContent,\n): T {\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      sidebarRight: {\n        ...state.contentEditor.sidebarRight,\n        content: sidebarContent,\n        open: true,\n      },\n    },\n  };\n}\n\n/**\n * Call without any parameters: reset layoutContainerId to null and mode to inactive\n * Providing a layoutContainerId (even if it is null): If mode is NOT provided: keep current mode\n */\nexport function updateInspector<T extends IState>(\n  state: T,\n  layoutContainerId?: number | null,\n  newMode?: InspectorMode,\n): T {\n  let desiredMode = newMode ?? state.contentEditor.inspector.mode;\n  if(newMode == null && layoutContainerId === undefined) desiredMode = InspectorMode.Inactive;\n\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      inspector: {\n        ...state.contentEditor.inspector,\n        currentLayoutContainerId: layoutContainerId === undefined ? null : layoutContainerId,\n        mode: desiredMode,\n      },\n    },\n  };\n}\n\ninterface IContainerStructureContainer {\n  id: number;\n  parentLayoutContainerId: number | null;\n  type: LayoutContainerType;\n}\n\nexport function updateContainerStructure<TState extends IState>(\n  state: TState,\n  contextIdentifier: string\n): TState {\n  // get the layoutContainers of the current page (possibly iasSlide) or slide\n  const context = state.contentContexts[contextIdentifier] ?? null;\n  if(context == null) return state;\n  let currentContentContainers: ICourseLayoutContainerDto[] | IPresentationLayoutContainerDto[] | undefined;\n  if(context.type === 'course') {\n    const currentPageId = context.state.pageId;\n    const currentIasSlideId = context.state.iasSlideId;\n    currentContentContainers = state.courseContentById[context.state.courseId]?.layoutContainers\n      .filter(courseContainer => courseContainer.pageId === currentPageId\n        && (currentIasSlideId == null || courseContainer.slideId === currentIasSlideId));\n\n  } else {\n    const currentSlideId = context.state.slideId;\n    currentContentContainers = state.presentationContentById[context.state.presentationId]?.layoutContainers\n      .filter(presentationContainer => presentationContainer.slideId === currentSlideId);\n  }\n  if(currentContentContainers == null) return state;\n  const layoutContainers: IContainerStructureContainer[] = currentContentContainers\n    .map(currentContentContainer => ({\n      id: currentContentContainer.id,\n      parentLayoutContainerId: currentContentContainer.parentLayoutContainerId,\n      type: currentContentContainer.type,\n    }));\n\n  // extract structure from containers:\n  const containerStructure: IContainerStructurePerformanceData = {\n    structureDataByLayoutContainerId: {},\n    layoutContainerTypeById: {},\n  };\n  const parentContainerByContainerId = ArrayUtils.toRecord(\n    layoutContainers,\n    layoutContainer => layoutContainer.id,\n    layoutContainer => layoutContainers.find(container => container.id === layoutContainer.parentLayoutContainerId),\n  );\n  for(const currentContainer of layoutContainers) {\n    containerStructure.structureDataByLayoutContainerId[currentContainer.id] = {\n      ancestorIds: currentContainer.parentLayoutContainerId == null ? null : [],\n      immediateChildrenIds: null,\n      isPartOfCard: false,\n      isOnlyChildOfCard: false,\n    };\n\n    containerStructure.layoutContainerTypeById[currentContainer.id] = currentContainer.type;\n    // don't search for parents of root container\n    if(currentContainer.parentLayoutContainerId == null) continue;\n\n    // crawl to root:\n    let rootReached = false;\n    let currentId = currentContainer.id;\n    while(!rootReached) {\n      const currentParent = parentContainerByContainerId[currentId];\n      if(currentParent != null) {\n        containerStructure.structureDataByLayoutContainerId[currentContainer.id]\n          .ancestorIds?.push(currentParent.id);\n        if(currentParent.type === LayoutContainerType.Card)\n          containerStructure.structureDataByLayoutContainerId[currentContainer.id]\n            .isPartOfCard = true;\n        currentId = currentParent.id;\n      } else {\n        rootReached = true;\n      }\n    }\n  }\n\n  for(const currentContainer of layoutContainers) {\n    containerStructure.structureDataByLayoutContainerId[currentContainer.id]\n      .immediateChildrenIds = layoutContainers\n        .filter(container => container.parentLayoutContainerId === currentContainer.id)\n        .map(container => container.id);\n\n    if(currentContainer.type === LayoutContainerType.Card\n      && containerStructure.structureDataByLayoutContainerId[currentContainer.id].immediateChildrenIds != null\n      && containerStructure.structureDataByLayoutContainerId[currentContainer.id].immediateChildrenIds?.length === 1) {\n      const onlyChildId = containerStructure.structureDataByLayoutContainerId[currentContainer.id].immediateChildrenIds![0];\n      containerStructure.structureDataByLayoutContainerId[onlyChildId].isOnlyChildOfCard = true;\n    }\n  }\n\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      containerStructure,\n    }\n  };\n}\n","import { IContainerStructureData } from 'common/dto/content-editor/content.editor.interface';\nimport { BlockType } from 'common/dto/course/content/course.types';\nimport { LayoutContainerType } from 'common/dto/course/layout.container.interface';\nimport { createSelectorCreator } from 'common/store/selectors/selectors';\nimport { ContentContextState, IUniversalContentWithPerformanceData } from 'common/store/store.interface';\nimport { StateSelectorUtils } from 'common/utils/StateSelectorUtils';\nimport { InspectorMode, IState } from './state';\n\ninterface IContainerStructureFlow {\n  layoutContainerId: number;\n  containerStructure: IContainerStructureData;\n}\n\nexport const containerStructureSelectorCreator = createSelectorCreator<IState, IContainerStructureFlow, IContainerStructureData | null>([\n  ({ state, layoutContainerId }) => ({\n    containerStructure: state.contentEditor.containerStructure.structureDataByLayoutContainerId[layoutContainerId] ?? null,\n  }),\n], result => result.containerStructure);\n\ninterface IShowContainerOptionsForChildIdFlow {\n  contextIdentifier: string;\n  layoutContainerId: number;\n  contextState?: ContentContextState;\n  content?: IUniversalContentWithPerformanceData;\n  showContainerOptionsForChildId: number | null;\n}\n\nexport const showContainerOptionsForChildIdSelectorCreator = createSelectorCreator<IState, IShowContainerOptionsForChildIdFlow, number | null>([\n  ({ state, contextIdentifier }) => ({ contextState: state.contentContexts[contextIdentifier] }),\n  ({ state, contextState }) => {\n    if(contextState == null) return { content: undefined };\n    const content = contextState.type === 'course'\n      ? state.courseContentById[contextState.state.courseId]\n      : state.presentationContentById[contextState.state.presentationId];\n    return { content };\n  },\n  ({ state, content, layoutContainerId }) => {\n    // default return value is null\n    const showContainerOptionsForChildId: number | null = null;\n    const structure = state.contentEditor.containerStructure;\n\n    // reading too soon from structure info? -> cancel here:\n    if(structure.structureDataByLayoutContainerId[layoutContainerId] == null) {\n      return { showContainerOptionsForChildId };\n    }\n\n    /**\n     * don't show container options if one of these conditions applies:\n     * 1. drag and drop is active\n     * 2. resizing is active\n     * 3. container has no children\n     * 4. requesting layoutContainerId is a block container\n     */\n    const childrenIds = structure.structureDataByLayoutContainerId[layoutContainerId].immediateChildrenIds;\n    if(state.contentEditor.dragAndDrop.active\n      || state.contentEditor.isResizing\n      || childrenIds == null\n      || (structure.layoutContainerTypeById[layoutContainerId] != null\n        && structure.layoutContainerTypeById[layoutContainerId] === LayoutContainerType.Block)) {\n      return { showContainerOptionsForChildId };\n    }\n\n    // check all children if one needs to display an options menu:\n    for(const childId of childrenIds) {\n      // no further checks needed if container is not hovered over\n      if(state.contentEditor.containerHoverStateById[childId] == null\n        || state.contentEditor.containerHoverStateById[childId].hoverOverResult == null\n        || state.contentEditor.containerHoverStateById[childId].hoverOverResult === false) {\n        continue;\n      }\n\n      // don't show options for empty card or block currently editing\n      const block = StateSelectorUtils.selectBlockByLayoutContainerId(content, childId);\n      const emptyCard = block?.type === BlockType.EMPTY_CARD;\n      if(emptyCard || state.contentEditor.editBlockId === block?.id) {\n        continue;\n      }\n\n      // show options for according inspector mode\n      if((state.contentEditor.inspector.mode === InspectorMode.Container\n        && structure.layoutContainerTypeById[childId] === LayoutContainerType.Layout\n        && (state.contentEditor.containerHoveredIds.length > 0\n          && childId === state.contentEditor\n            .containerHoveredIds[state.contentEditor.containerHoveredIds.length - 1]))\n        || (state.contentEditor.inspector.mode !== InspectorMode.Container\n          && structure.layoutContainerTypeById[childId] === LayoutContainerType.Block)) {\n        return { showContainerOptionsForChildId: childId };\n      }\n    }\n    return { showContainerOptionsForChildId };\n  },\n], result => result.showContainerOptionsForChildId);\n\n\n\ninterface IIsEmptyCardFlow {\n  contextIdentifier: string;\n  layoutContainerId: number;\n  content?: IUniversalContentWithPerformanceData;\n  isEmptyCard?: boolean;\n}\n\nexport const isEmptyCardSelectorCreator = createSelectorCreator<IState, IIsEmptyCardFlow, boolean>([\n  ({ state, contextIdentifier }) => {\n    const context = state.contentContexts[contextIdentifier] ?? null;\n    if(context == null) return {};\n    return {\n      content: context.type === 'course'\n        ? state.courseContentById[context.state.courseId]\n        : state.presentationContentById[context.state.presentationId],\n    };\n  },\n  ({ content, layoutContainerId }) => {\n    const block = StateSelectorUtils.selectBlockByLayoutContainerId(content, layoutContainerId);\n    return { isEmptyCard: block?.type === BlockType.EMPTY_CARD };\n  },\n], result => result.isEmptyCard === true);\n\n\ninterface IIsContainerHoveredFlow {\n  layoutContainerId: number;\n  isHovered?: boolean;\n}\n\nexport const isContainerHoveredSelectorCreator = createSelectorCreator<IState, IIsContainerHoveredFlow, boolean>([\n  ({ state, layoutContainerId }) => {\n    if(state.contentEditor.isResizing) return { isHovered: false };\n\n    let isHovered = state.contentEditor.containerHoverStateById[layoutContainerId] == null\n      || state.contentEditor.containerHoverStateById[layoutContainerId].hoverOverResult == null\n      ? false : state.contentEditor.containerHoverStateById[layoutContainerId].hoverOverResult;\n\n    // in case of container mode only allow the last isHovered result to be displayed:\n    if(state.contentEditor.inspector.mode === InspectorMode.Container && isHovered\n      && state.contentEditor.containerHoveredIds.length > 0) {\n      isHovered = layoutContainerId === state.contentEditor\n        .containerHoveredIds[state.contentEditor.containerHoveredIds.length - 1];\n    }\n\n    return { isHovered };\n  },\n], result => result.isHovered === true);\n","import { IAttendeeDto } from 'common/dto/distinar/distinar.interface';\nimport { createSelectorCreator } from 'common/store/selectors/selectors';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { IDistinarPresentationResumeData, IResumePresentationInfo, IState } from './state';\n\ninterface IResumePresentationInfoFlow {\n  contextIdentifier: string;\n\n  distinarPresentationResumeData?: IDistinarPresentationResumeData | null;\n  presentationId?: number | null;\n  slideId?: number | null;\n  presentationTitle: string | null;\n  orderedSlideIds?: Array<number>;\n  resumePresentationInfo?: IResumePresentationInfo | null;\n}\n\nexport const resumePresentationInfoSelectorCreator = createSelectorCreator<IState, IResumePresentationInfoFlow, IResumePresentationInfo | null>([\n  ({ state }) => {\n    const { distinarPresentationResumeData } = state;\n    return { distinarPresentationResumeData };\n  },\n  ({ distinarPresentationResumeData }) => ({\n    presentationId: distinarPresentationResumeData?.presentationId ?? null,\n    slideId: distinarPresentationResumeData?.slideId ?? null,\n  }),\n  ({ state, presentationId }) => {\n    const presentation = presentationId != null ? state.presentationContentById[presentationId] : null;\n    const orderedSlideIds = presentation?.orderedSlideIds;\n    const presentationTitle = presentation?.title ?? null;\n    return { orderedSlideIds, presentationTitle };\n  },\n  ({ orderedSlideIds, presentationTitle, slideId }) => ({\n    resumePresentationInfo: orderedSlideIds != null ? {\n      totalSlides: orderedSlideIds.length ?? 1,\n      slideIndex: (orderedSlideIds.findIndex(id => id === slideId) ?? 0),\n      presentationTitle: presentationTitle ?? '',\n    } : null,\n  }),\n], ({ resumePresentationInfo }) => ({\n  slideIndex: resumePresentationInfo?.slideIndex ?? 1,\n  presentationTitle: resumePresentationInfo?.presentationTitle ?? '',\n  totalSlides: resumePresentationInfo?.totalSlides ?? 1\n}));\n\ninterface ISelectAttendeeIdsFlow {\n  participating: boolean;\n  filteredAttendees?: IAttendeeDto[];\n  sortedAttendees?: IAttendeeDto[];\n}\n\nexport const selectAttendeeIdsSortedByName = createSelectorCreator<IState, ISelectAttendeeIdsFlow, number[]>([\n  ({ state, participating }) => ({\n    filteredAttendees: state.distinar.attendees.filter(attendee => attendee.online === participating),\n  }),\n  ({ filteredAttendees }) => ({\n    sortedAttendees: filteredAttendees != null\n      ? getAttendeesSortedByName(filteredAttendees)\n      : []\n  }),\n], ({ sortedAttendees }) => sortedAttendees?.map(attendee => attendee.id) ?? []);\n\nexport const selectAttendeeById = (attendeeId: number) => (state: IState): IAttendeeDto | null =>\n  state.distinar.attendees.find(a => a.id === attendeeId) ?? null;\n\nconst getAttendeesSortedByName = (attendees: IAttendeeDto[]): IAttendeeDto[] => {\n  return ArrayUtils.immutableSort(attendees, (a, b) => {\n    const aName = `${a.lastname ?? 'z'}${a.firstname ?? 'z'}`.toLowerCase();\n    const bName = `${b.lastname ?? 'z'}${b.firstname ?? 'z'}`.toLowerCase();\n    if(aName < bName) return -1;\n    if(aName > bName) return 1;\n    return 0;\n  });\n};","import { ILectureStatusDto } from 'common/dto/distinar/distinar.interface';\nimport { IEventDto } from 'common/dto/tenant/event/tenant.event.interface';\nimport { LectureSideMenuSectionName } from '../resources/elements/lecture-side-menu/lecture-side-menu';\nimport { initialState, IState } from './state';\n\nexport function setConferenceStopping<T extends IState>(state: T, stopping: boolean): T {\n  return {\n    ...state,\n    distinarConferenceStopping: stopping,\n  };\n}\n\nexport function closeDistinarSideMenu<T extends IState>(state: T): T {\n  return {\n    ...state,\n    distinar: {\n      ...state.distinar,\n      sideMenu: {\n        ...state.distinar.sideMenu,\n        activeSideMenuSection: null,\n        open: false,\n      },\n    },\n  };\n}\n\n/**\n *\n * @param sectionName\n * @param autoToggleSideMenu - if set to `true` and the current `activeSideMenuSection` equals `sectionName` the side menu will transition to closed state.\n * If the side menu is currently closed, it will transition to opened state with the `activeSideMenuSection` set to `sectionName`\n */\nexport function setDistinarSideMenuSection<T extends IState>(state: T, sectionName: LectureSideMenuSectionName, autoToggleSideMenu = false): T {\n  let isOpen;\n\n  if(!autoToggleSideMenu) {\n    isOpen = state.distinar.sideMenu.open;\n  } else if((state.distinar.sideMenu.activeSideMenuSection === sectionName && state.distinar.sideMenu.open)\n    || sectionName == null) {\n    isOpen = false;\n  } else {\n    isOpen = true;\n  }\n\n  return {\n    ...state,\n    distinar: {\n      ...state.distinar,\n      sideMenu: {\n        ...state.distinar.sideMenu,\n        open: isOpen,\n        activeSideMenuSection: isOpen ? sectionName : null,\n      },\n    },\n  };\n}\n\nexport function endLectureAction<T extends IState>(state: T): T {\n  return {\n    ...state,\n    distinar: {\n      ...initialState.distinar\n    },\n    distinarPresentationResumeData: null,\n    quickQuizData: null,\n    quickDistinarData: null\n  };\n}\n\nexport function resetActiveLecture<T extends IState>(state: T): T {\n  return {\n    ...state,\n    distinar: {\n      ...state.distinar,\n      conference: {\n        ...state.distinar.conference,\n        hasActiveMeeting: initialState.distinar.conference.hasActiveMeeting,\n        meetingSessionStatusCode: initialState.distinar.conference.meetingSessionStatusCode,\n      },\n      // set all properties that need to be reset to the initialState value\n      activeLecture: initialState.distinar.activeLecture,\n      lectureStatus: initialState.distinar.lectureStatus,\n      attendees: initialState.distinar.attendees,\n    },\n  };\n}\n\nexport function startLectureAction<T extends IState>(state: T, lecture: IEventDto<string>, lectureStatus: ILectureStatusDto): T {\n  return {\n    ...state,\n    distinar: {\n      ...state.distinar,\n      activeLecture: lecture,\n      lectureStatus,\n    },\n  };\n}\n\nexport function updateDistinarPresentationResumeData<T extends IState>(state: T, slideId: number | null, presentationId: number | null): T {\n  const lectureId = state.distinarConnectionData?.id ?? null;\n  return {\n    ...state,\n    distinarPresentationResumeData: {\n      ...state.distinarPresentationResumeData,\n      slideId,\n      presentationId,\n      lectureId\n    }\n  };\n}\n","import { Config } from 'common/fe-config/config';\nimport { ContentEditorMode } from '../resources/pages/content-editor/content-editor';\nexport var InspectorMode;\n(function (InspectorMode) {\n    InspectorMode[\"Inactive\"] = \"inactive\";\n    InspectorMode[\"Element\"] = \"element\";\n    InspectorMode[\"Container\"] = \"container\";\n})(InspectorMode || (InspectorMode = {}));\nexport var UceSidebarContent;\n(function (UceSidebarContent) {\n    UceSidebarContent[\"None\"] = \"none\";\n    UceSidebarContent[\"Blocks\"] = \"blocks\";\n    UceSidebarContent[\"Templates\"] = \"templates\";\n    UceSidebarContent[\"Inspector\"] = \"inspector\";\n})(UceSidebarContent || (UceSidebarContent = {}));\nexport const initialTableState = {\n    rowsPerPage: 10,\n    extended: true,\n    filterStatus: {\n        'tenant-student-list': {\n            filters: Config().defaultTableFilter.enabled ? { status: 'active' } : {}\n        },\n    }\n};\nexport const initialState = {\n    cache: {\n        chatRoomIdWithUsersByChatRoomId: {},\n        chatRooms: [],\n        conversationsByChatRoomId: {},\n        courseIntersectionByUserId: {},\n        coursesByCourseId: {}\n    },\n    chat: {\n        unreadChatRooms: [],\n    },\n    isLoggedIn: false,\n    language: 'de',\n    user: {\n        id: null,\n        email: '',\n        firstname: '',\n        isLecturer: false,\n        isOperator: false,\n        isPowerUser: false,\n        isProvider: false,\n        lastname: '',\n        schoolName: '',\n        titlePrefix: '',\n        titleSuffix: '',\n    },\n    settings: null,\n    currentRole: null,\n    currentTenant: null,\n    roles: [],\n    csrfToken: null,\n    distinar: {\n        sideMenu: {\n            open: false,\n            activeSideMenuSection: null,\n        },\n        activeLecture: null,\n        lectureStatus: null,\n        attendees: [],\n        conference: {\n            chimeAttendeeId: null,\n            chimeExternalUserId: null,\n            hasActiveMeeting: false,\n            meetingSessionStatusCode: null,\n        },\n        conferenceConfiguration: {\n            streamAudio: false,\n            streamVideo: false,\n            shareScreen: false,\n            selectedDevices: {\n                audioInput: null,\n                audioOutput: null,\n                videoInput: null,\n            },\n        },\n        chatRoomLastRead: null,\n        chatRoomLastMessageReceived: null,\n    },\n    distinarPresentationResumeData: null,\n    distinarConferenceStopping: false,\n    distinarConnection: {\n        attempts: [],\n        connected: false,\n        connecting: false,\n        disconnecting: false,\n        disconnectReason: null,\n        failedConnecting: false,\n    },\n    distinarConnectionData: null,\n    distinarInitializing: true,\n    quickQuizData: null,\n    quickDistinarData: null,\n    tables: initialTableState,\n    gallery: {\n        selectedCourseId: null,\n    },\n    navigationHistory: {\n        previousInstructions: [],\n        currentInstruction: null,\n    },\n    conferenceContext: {\n        bindingContexts: {\n            contentShare: {\n                attendeeId: null,\n                hasTile: false,\n            },\n            lecturer: {\n                attendeeId: null,\n                hasTile: false,\n            },\n            local: {\n                attendeeId: null,\n                hasTile: false,\n            },\n            matrix: {\n                rotation: false,\n                itemCount: 1,\n                autoResize: true,\n                allAttendeeIds: [],\n                attendeeIds: [],\n            },\n        },\n        tiles: [],\n        boundTiles: {},\n        elementCountByChimeAttendeeId: {},\n        videoElements: {},\n        activeSpeakers: [],\n        activeSpeakerScores: {},\n        onScreenScores: {},\n        attendeeInfoByAttendeeId: {},\n        contentShareTileIdByAttendeeId: {},\n        isActiveSpeakerByAttendeeId: {},\n        videoTileIdByAttendeeId: {},\n        attendeeScores: {},\n        connectionIsGood: true,\n        hideMenus: false,\n    },\n    pendingTeacherRegistrationsCount: 0,\n    contentContexts: {},\n    courseContentById: {},\n    presentationContentById: {},\n    contentEditor: {\n        isPresentationShared: false,\n        themeColors: [],\n        mode: ContentEditorMode.PRESENTATION,\n        containerHoverStateById: {},\n        containerHoveredIds: [],\n        extrinsicScaleFactor: null,\n        editBlockId: null,\n        previousResizingState: null,\n        resizing: {},\n        isResizing: false,\n        containerStyles: {\n            showExtraContainerSpace: false,\n            dashedLayoutContainerIds: [],\n        },\n        dragAndDrop: {\n            active: false,\n            showDroptargets: false,\n            lowerWhitespaceTargeted: false,\n        },\n        clipboard: {\n            layoutContainers: [],\n            blocks: [],\n            blockIdByLayoutContainerId: {},\n            blockTypeById: {},\n            elementTypeByContainerId: {},\n        },\n        clipboardCardContent: {\n            layoutContainers: [],\n            blocks: [],\n        },\n        containerStructure: {\n            structureDataByLayoutContainerId: {},\n            layoutContainerTypeById: {},\n        },\n        templates: {\n            templateById: {},\n            layoutContainers: [],\n        },\n        sidebarRight: {\n            content: UceSidebarContent.None,\n            open: false,\n        },\n        inspector: {\n            currentLayoutContainerId: null,\n            mode: InspectorMode.Inactive,\n        },\n    },\n    fullscreenContainer: {\n        noSideMenu: false,\n    },\n    quizTemplates: [],\n    globalFilters: {},\n};\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc3RvcmUvc3RhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBaUJBLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUdqRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxrREFBa0QsQ0FBQztBQUVyRixNQUFNLENBQU4sSUFBWSxhQUlYO0FBSkQsV0FBWSxhQUFhO0lBQ3ZCLHNDQUFxQixDQUFBO0lBQ3JCLG9DQUFtQixDQUFBO0lBQ25CLHdDQUF1QixDQUFBO0FBQ3pCLENBQUMsRUFKVyxhQUFhLEtBQWIsYUFBYSxRQUl4QjtBQUVELE1BQU0sQ0FBTixJQUFZLGlCQUtYO0FBTEQsV0FBWSxpQkFBaUI7SUFDM0Isa0NBQWEsQ0FBQTtJQUNiLHNDQUFpQixDQUFBO0lBQ2pCLDRDQUF1QixDQUFBO0lBQ3ZCLDRDQUF1QixDQUFBO0FBQ3pCLENBQUMsRUFMVyxpQkFBaUIsS0FBakIsaUJBQWlCLFFBSzVCO0FBRUQsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQWdCO0lBQzVDLFdBQVcsRUFBRSxFQUFFO0lBQ2YsUUFBUSxFQUFFLElBQUk7SUFDZCxZQUFZLEVBQUU7UUFDWixxQkFBcUIsRUFBRTtZQUNyQixPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRTtTQUN6RTtLQUNGO0NBQ0YsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBVztJQUNsQyxLQUFLLEVBQUU7UUFDTCwrQkFBK0IsRUFBRSxFQUFFO1FBQ25DLFNBQVMsRUFBRSxFQUFFO1FBQ2IseUJBQXlCLEVBQUUsRUFBRTtRQUM3QiwwQkFBMEIsRUFBRSxFQUFFO1FBQzlCLGlCQUFpQixFQUFFLEVBQUU7S0FDdEI7SUFDRCxJQUFJLEVBQUU7UUFDSixl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","import {\n  IPageSlideTemplateDeleteResponseDto,\n  IPageSlideTemplateDto,\n  IPageSlideTemplatesWithContentDto,\n} from 'common/dto/content-editor/content.editor.interface';\nimport { ITemplateLayoutContainerDto } from 'common/dto/course/layout.container.interface';\nimport { cloneDeep } from 'lodash';\nimport { IState } from './state';\n\nexport function setContent<T extends IState>(\n  state: T,\n  templateContent: IPageSlideTemplatesWithContentDto<ITemplateLayoutContainerDto>,\n): T {\n  const templateById = templateContent.templates.reduce<{ [templateId: number]: IPageSlideTemplateDto }>((acc, template) => ({\n    ...acc,\n    [template.id]: template,\n  }), {});\n\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      templates: {\n        templateById,\n        layoutContainers: [...templateContent.layoutContainers],\n      }\n    }\n  };\n}\n\nexport function addItem<T extends IState>(\n  state: T,\n  newTemplateContent: IPageSlideTemplatesWithContentDto<ITemplateLayoutContainerDto>,\n): T {\n  if(newTemplateContent.templates[0] == null) return { ...state };\n\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      templates: {\n        ...state.contentEditor.templates,\n        templateById: {\n          ...state.contentEditor.templates.templateById,\n          [newTemplateContent.templates[0].id]: newTemplateContent.templates[0],\n        },\n        layoutContainers: [\n          ...state.contentEditor.templates.layoutContainers,\n          ...newTemplateContent.layoutContainers,\n        ],\n      },\n    },\n  };\n}\n\nexport function applyRemoveChanges<T extends IState>(\n  state: T,\n  removedInfos: IPageSlideTemplateDeleteResponseDto,\n): T {\n  const templateById = cloneDeep(state.contentEditor.templates.templateById);\n  delete templateById[removedInfos.deletedTemplateId];\n  const layoutContainers = (cloneDeep(state.contentEditor.templates.layoutContainers))\n    .filter(container => removedInfos.deletedLayoutContainerIds.findIndex(removedId => removedId === container.id) === -1);\n\n  return {\n    ...state,\n    contentEditor: {\n      ...state.contentEditor,\n      templates: {\n        templateById,\n        layoutContainers,\n      },\n    },\n  };\n}\n","import { IPageSlideTemplateDto } from 'common/dto/content-editor/content.editor.interface';\nimport { ILayoutContainerChildInfo, ITemplateLayoutContainerDto } from 'common/dto/course/layout.container.interface';\nimport { createSelectorCreator } from 'common/store/selectors/selectors';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { cloneDeep } from 'lodash';\nimport { IState } from './state';\n\n// Todo(Ian): optimize selector creator\nexport const publicTemplatesSelectorCreator = createSelectorCreator<\n  IState,\n  { templateIds: Array<number> },\n  Array<number>\n>([\n  ({ state }) => {\n    const allTemplates = cloneDeep(state.contentEditor.templates.templateById);\n    const templateIdsHelper: Array<number> =  [];\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    Object.keys(allTemplates).map(Number).forEach((key, index) => {\n      if(allTemplates[key] != null && !allTemplates[key]?.isUserTemplate) {\n        templateIdsHelper.push(allTemplates[key]?.id ?? -1);\n      }\n    });\n    const templateIds = templateIdsHelper.filter(id => id !== -1);\n\n    return { templateIds };\n  },\n], result => result.templateIds);\n\n\n// Todo(Ian): optimize selector creator\nexport const userOwnedTemplatesSelectorCreator = createSelectorCreator<\n  IState,\n  { templateIds: Array<number> },\n  Array<number>\n>([\n  ({ state }) => {\n    const allTemplates = cloneDeep(state.contentEditor.templates.templateById);\n    const templateIdsHelper: Array<number> = [];\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    Object.keys(allTemplates).map(Number).forEach((key, index) => {\n      if(allTemplates[key] != null && allTemplates[key]?.isUserTemplate) {\n        templateIdsHelper.push(allTemplates[key]?.id ?? -1);\n      }\n    });\n    const templateIds = templateIdsHelper.filter(id => id !== -1);\n\n    return { templateIds };\n  },\n], result => result.templateIds);\n\ninterface ITemplateByIdFlow {\n  templateId: number;\n  template?: IPageSlideTemplateDto;\n}\n\nexport const templateByIdSelectorCreator = createSelectorCreator<IState, ITemplateByIdFlow, IPageSlideTemplateDto | null>([\n  ({ state, templateId }) => ({\n    template: state.contentEditor.templates.templateById[templateId],\n  }),\n], result => result.template ?? null);\n\ninterface ILayoutContainerByIdFlow {\n  layoutContainerId: number;\n  layoutContainer?: ITemplateLayoutContainerDto;\n}\n\nexport const layoutContainerByIdSelectorCreator = createSelectorCreator<IState, ILayoutContainerByIdFlow, ITemplateLayoutContainerDto | null>([\n  ({ state, layoutContainerId }) => ({\n    layoutContainer: state.contentEditor.templates.layoutContainers.find(container => container.id === layoutContainerId),\n  }),\n], result => result.layoutContainer ?? null);\n\ninterface ILayoutContainerChildIdsOrderedFlow {\n  layoutContainerId: number;\n  childIdsOrdered?: Array<number>;\n}\n\nexport const layoutContainerChildIdsOrderedSelectorCreator = createSelectorCreator<IState, ILayoutContainerChildIdsOrderedFlow, Array<number>>([\n  ({ state, layoutContainerId }) => ({\n    childIdsOrdered: ArrayUtils.immutableSort(\n      state.contentEditor.templates.layoutContainers.filter(container => container.parentLayoutContainerId === layoutContainerId),\n      (a, b) => a.order - b.order\n    ).map(container => container.id),\n  }),\n], result => result.childIdsOrdered ?? []);\n\ninterface ILayoutContainerChildInfoOrderedFlow {\n  layoutContainerId: number;\n  childrenOrdered?: Array<ITemplateLayoutContainerDto>;\n  childInfos?: Array<ILayoutContainerChildInfo>;\n}\n\nexport const layoutContainerChildInfoOrderedSelectorCreator = createSelectorCreator<IState, ILayoutContainerChildInfoOrderedFlow, Array<ILayoutContainerChildInfo>>([\n  ({ state, layoutContainerId }) => ({\n    childrenOrdered: ArrayUtils.immutableSort(\n      state.contentEditor.templates.layoutContainers.filter(container => container.parentLayoutContainerId === layoutContainerId),\n      (a, b) => a.order - b.order\n    ),\n  }),\n  ({ childrenOrdered }) => ({\n    childInfos: childrenOrdered?.map<ILayoutContainerChildInfo>(container => ({\n      blockType: container.templateBlockType,\n      id: container.id,\n      itemSize: container.layout.itemSize,\n    })),\n  }),\n], result => result.childInfos ?? []);\n","import { imageNameToString as commonImageNameToString } from 'common/aurelia-components/images';\nimport { Config } from 'common/fe-config/config';\nimport { AppFlavour } from 'common/fe-config/config.interface';\nimport { StringUtils } from 'common/utils/StringUtils';\nimport { imageNameToString } from '../resources/images';\n\nexport class AppUtils {\n  public static getLogo(useAlternateVersion?: boolean): string {\n    switch(AppUtils.appFlavour) {\n      case AppFlavour.Lera:\n        return imageNameToString.LogoLera;\n      case AppFlavour.Risi:\n        return imageNameToString.LogoRisi;\n      case AppFlavour.Frp:\n        return useAlternateVersion ? commonImageNameToString.LogoFrpAlt : commonImageNameToString.LogoFrpText;\n      default:\n        return imageNameToString.LogoYarrive;\n    }\n  }\n\n  public static getHomeBanner(): string {\n    switch(AppUtils.appFlavour) {\n      case AppFlavour.Frp:\n        return imageNameToString.BannerFrp;\n      default:\n        return imageNameToString.BannerYarrive;\n    }\n  }\n\n  /**\n   * If an image is needed in a same-origin context, e.g. canvases.\n   * If the url starts with the configured UFE base url's origin, that origin is replaced with the AFE's origin.\n   * If not applicable, the original url is let through\n   */\n  public static transformUfeImageUrlToAfeUrlIfNeeded(imageUrl: string): string {\n    try {\n      const ufeOrigin = new URL(Config().ufe.baseUrl).origin;\n      if(!ufeOrigin) return imageUrl;\n      const siteOrigin = window.location.origin;\n      return imageUrl.replace(new RegExp(`^${StringUtils.escapeStringForRegex(ufeOrigin)}`), siteOrigin);\n    } catch(e) {\n      return imageUrl;\n    }\n\n  }\n\n  private static get appFlavour(): AppFlavour {\n    return Config().appFlavour;\n  }\n}\n","import { UniversalBlock } from 'common/dto/content-editor/content.editor.interface';\nimport { BlockType } from 'common/dto/course/content/course.types';\nimport { ICreateUniversalBlockDto } from 'common/dto/course/management/course.management.interface';\nimport { IContentEditorBlockEditorBlock } from './../resources/dialogs/content-editor-block-editor-dialog/content-editor-block-editor-dialog';\n\nexport class BlockUtils {\n  public static getIconClass(type: BlockType): string {\n    switch(type) {\n      case BlockType.TEXT: return 'fe-align-left';\n      case BlockType.PICTURE: return 'fe-image';\n      case BlockType.AUDIO: return 'fe-volume-2';\n      case BlockType.VIDEO: return 'fe-video';\n      case BlockType.YOUTUBE: return 'fe-video';\n      case BlockType.VIMEO: return 'fe-video';\n      case BlockType.FILE: return 'fe-file';\n      case BlockType.QUESTION: return 'fe-help-circle';\n      case BlockType.MP_INTERACTIVE_TEXT: return 'fe-check-circle';\n      case BlockType.MP_TILES: return 'fe-grid';\n      default: return 'fe-alert-triangle';\n    }\n  }\n\n  public static convertToCreateUniversalBlock(block: IContentEditorBlockEditorBlock): ICreateUniversalBlockDto {\n    return {\n      ...block,\n      title: block?.title ?? '',\n      text: block?.text ?? null,\n      internalNote: block?.internalNote ?? null,\n      correctAnswerInfoText: block?.correctAnswerInfoText ?? undefined,\n      correctAnswerInfoPictureId: block?.correctAnswerInfoPictureId ?? undefined,\n      correctAnswerInfoAudioId: block?.correctAnswerInfoAudioId ?? undefined,\n      incorrectAnswerInfoText: block?.incorrectAnswerInfoText ?? undefined,\n      incorrectAnswerInfoPictureId: block?.incorrectAnswerInfoPictureId ?? undefined,\n      incorrectAnswerInfoAudioId: block?.incorrectAnswerInfoAudioId ?? undefined,\n    };\n  }\n\n  public static convertToLocalBlock(block: IContentEditorBlockEditorBlock | UniversalBlock): IContentEditorBlockEditorBlock {\n    const blockText = block.type === BlockType.MP_TILES ? '' : null;\n    return {\n      ...block,\n      title: block?.title ?? '',\n      text: block?.text ? block.text : blockText,\n      questionIds: 'questionIds' in block ? block?.questionIds ?? [] : [],\n      tiles: block?.tiles ?? [],\n      videoUrl: [BlockType.YOUTUBE, BlockType.VIMEO].includes(block.type) ? block?.videoUrl ?? null : null,\n    };\n  }\n}\n","import { FilterOperationType } from 'common/dto/filter/filter.enum';\nimport { IFilterDto } from 'common/dto/filter/filter.interface';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\n\nexport class FilterUtils {\n\n  public static removeDuplicateFilterFields<T>(\n    currentFilter: IFilterDto<T>,\n    newField: { field: keyof T; type: FilterOperationType; value: any }\n  ): IFilterDto<T> {\n    currentFilter.filter = [\n      newField,\n      ...ArrayUtils.remove(\n        currentFilter.filter ?? [],\n        f => f.field === newField.field && f.type === newField.type\n      ) ?? []\n    ];\n    return currentFilter;\n  }\n\n  public static removeFilterForField<T>(\n    currentFilter: IFilterDto<T>,\n    field: keyof T\n  ): IFilterDto<T> {\n    currentFilter.filter = [\n      ...ArrayUtils.remove(\n        currentFilter.filter ?? [],\n        f => f.field === field\n      ) ?? []\n    ];\n    return currentFilter;\n  }\n}","export class HtmlUtils {\n  public static createAndAppendStyleTag(contents: string): HTMLStyleElement {\n    const styleTag = document.createElement('style');\n    styleTag.append(contents);\n    document.head.append(styleTag);\n    return styleTag;\n  }\n}","import { IMediaShareDetails } from 'common/dto/content/share/media.share.interface';\nimport { GalleryMediaType } from 'common/enum/gallery.enum';\n\nexport class MediaShareUtils {\n\n  public static isSupportedFileType(type: GalleryMediaType): boolean {\n    return [GalleryMediaType.Audio, GalleryMediaType.File, GalleryMediaType.Picture].includes(type);\n  }\n\n  public static hasActiveShares(shares: IMediaShareDetails[]): boolean {\n    if(shares.length === 0) return false;\n    if(shares.every(s => s.limitToCourseGroupIds && s.limitToCourseGroupIds.length === 0)) return false;\n    return true;\n  }\n}","import { MIN_PASSWORD_LENGTH, MIN_PASSWORD_STRENGTH_AFE } from 'common/constants/auth.constants';\nimport { ICourseGroupResponseDto, ICreateCourseGroupDto } from 'common/dto/course/course.group.interface';\nimport { LearnGoalUtils } from 'common/utils/LearnGoalUtils';\nimport Moment from 'moment';\nimport { DateService } from '../services/DateService';\nimport { LocalStudent } from '../services/StudentService';\n\nexport interface IErrorTk {\n  errorTk: string;\n  errorTkParams?: Record<string, string>;\n}\n\ntype DateToValidate = Date | string | undefined | null;\n\nexport class ValidationUtils {\n\n  public static isEndTimeBeforeStartTime(startTimeString: string, endTimeString: string): string | null {\n    const dateService = new DateService();\n    const todayString = new Date().toISOString();\n    const start = dateService.combineDateAndTime(todayString, startTimeString);\n    const end = dateService.combineDateAndTime(todayString, endTimeString);\n    return Moment(start).isAfter(end) ? 'utils.validation.endTimeBeforeStartTime' : null;\n  }\n\n  public static isEndDateBeforeStartDate(startDate: DateToValidate, endDate: DateToValidate, customTk?: string): string | null {\n    return Moment(startDate).isAfter(endDate) ? (customTk ?? 'utils.validation.endDateBeforeStartDate') : null;\n  }\n\n  public static isDateInPast(date: DateToValidate): string | null {\n    return !date || Moment(date).isBefore() ? 'utils.validation.dateInPastError' : null;\n  }\n\n  public static isDateValid(date: DateToValidate): string | null {\n    return !date || !Moment(date).isValid() ? 'utils.validation.dateInvalidError' : null;\n  }\n\n  /** date = null .. also returns null (meaning it is valid) */\n  public static isDateValidOrNull(date: DateToValidate): string | null {\n    if(!date) return null;\n    return !Moment(date).isValid() ? 'utils.validation.dateInvalidError' : null;\n  }\n\n  public static isExamDateValid(date: DateToValidate, minDaysToExam: number, maxDaysToExam: number | null): string | null {\n    if(!date) return null;\n    const isDateInPast = ValidationUtils.isDateInPast(date);\n    if(!isDateInPast) {\n      const daysToExam = LearnGoalUtils.getDaysTillExamDate(date);\n      if(maxDaysToExam && daysToExam > maxDaysToExam) {\n        return 'utils.validation.examDateTooManyDaysError';\n      }\n      return daysToExam < minDaysToExam ? 'utils.validation.examDateNotEnoughDaysError' : null;\n    }\n    return isDateInPast;\n  }\n\n  public static checkCourseGroupUniqueness(courseGroup: ICreateCourseGroupDto<string>, existingCourseGroups: ICourseGroupResponseDto<string>[]): string | null {\n    return existingCourseGroups.some(cG => {\n      return cG.course.id === courseGroup.courseId\n        && cG.name === courseGroup.name\n        && cG.from === courseGroup.from\n        && cG.to === courseGroup.to;\n    }) ? 'utils.validation.createCourseGroupDuplicateError' : null;\n  }\n\n  public static checkName(name: string | undefined): string | null {\n    return !name ? 'utils.validation.noNameError' : null;\n  }\n\n  /**\n   * @param checkedType used to provide proper error messages\n   * @param value value to check\n   * @param validationValues array of strings to compare value against to avoid duplicates\n   * @param maxLength (optional) check if max-length is exceeded\n   * @param allowEmpty activate check for empty strings\n   * @returns error as IErrorTk or null\n   */\n  public static checkForDuplicatesAndLength(\n    checkedType: 'Name' | 'Id',\n    value: string,\n    validationValues: Array<string>,\n    allowEmpty: boolean,\n    maxLength?: number,\n  ): IErrorTk | null {\n    let errorTk: IErrorTk | null = null;\n    // check isNotEmpty (if required)\n    if(!allowEmpty) {\n      errorTk = !value || value === '' ? { errorTk: `utils.validation.no${checkedType}Error` } : null;\n      if(errorTk != null) return errorTk;\n    }\n    // check for duplicates\n    if(validationValues != null && validationValues.length > 0) {\n      errorTk = validationValues.findIndex(validationValue => validationValue === value) !== -1 ? {\n        errorTk: `utils.validation.duplicate${checkedType}Error`,\n      } : null;\n      if(errorTk != null) return errorTk;\n    }\n    // check for max-length exceeded - if provided\n    errorTk = maxLength != null && value.length > maxLength ? {\n      errorTk: `utils.validation.tooLong${checkedType}Error`,\n      errorTkParams: { maxLength: `${maxLength}` }\n    } : null;\n    return errorTk;\n  }\n\n  public static checkEventTitle(title: string | undefined): string | null {\n    return !title ? 'utils.validation.noTitleError' : null;\n  }\n\n  public static checkEventLecturer(lecturerId?: number): string | null {\n    return !lecturerId ? 'utils.validation.noLecturerError' : null;\n  }\n\n  public static checkTitle(title: string | undefined, maxLength?: number): IErrorTk | null {\n    if(title && maxLength) return title.length > maxLength ? {\n      errorTk: 'utils.validation.tooLongTitleError',\n      errorTkParams: { maxLength: `${maxLength}` }\n    } : null;\n    return !title ? { errorTk: 'utils.validation.noTitleError' } : null;\n  }\n\n  public static checkText(text: string | undefined, maxLength?: number): IErrorTk | null {\n    if(text && maxLength) return text.length > maxLength ? {\n      errorTk: 'utils.validation.tooLongTextError',\n      errorTkParams: { maxLength: `${maxLength}` }\n    } : null;\n    return !text ? { errorTk: 'utils.validation.noTextError' } : null;\n  }\n\n  public static checkStartDate(startDateString: string | undefined | null, endDateString: string | undefined | null): string | null {\n    if(this.isDateValid(startDateString)) return 'utils.validation.noStartDate';\n    // if endDate is null, but startDate is not => start date is basically valid.\n    // invalid endDate must be checked separately\n    if(this.isDateValid(endDateString)) return null;\n    return Moment(startDateString).isAfter(endDateString) ? 'utils.validation.startDateAfterEndDate' : null;\n  }\n\n  public static checkEndDate(startDateString: string | undefined | null, endDateString: string | undefined | null): string | null {\n    if(this.isDateValid(endDateString)) return 'utils.validation.noEndDate';\n    // if startDate is null, but endDate is not => end date is basically valid.\n    // invalid startDate must be checked separately\n    if(this.isDateValid(startDateString)) return null;\n    return Moment(startDateString).isAfter(endDateString) ? 'utils.validation.endDateBeforeStartDate' : null;\n  }\n\n  public static checkAllCourseGroups(courseGroups: Array<ICourseGroupResponseDto<string> | null>): string | null {\n    if(!courseGroups.length) return 'utils.validation.noCourseGroupError';\n    return courseGroups.some(cG => cG == null) ? 'utils.validation.coursesWithoutCourseGroupsError' : null;\n  }\n\n  public static checkCourseGroupsAndUsers(courseGroups: ICourseGroupResponseDto<string>[], users: LocalStudent[]): string | null {\n    return !courseGroups.length && !users.length ? 'utils.validation.noUsersOrGroupsError' : null;\n  }\n\n  public static checkEventDescription(description: string | undefined): string | null {\n    return !description ? 'utils.validation.noDescriptionError' : null;\n  }\n\n  public static checkPasswordLength(password: string): IErrorTk | null {\n    const error: IErrorTk = {\n      errorTk: 'utils.validation.passwordTooShortError',\n      errorTkParams: { minLength: `${MIN_PASSWORD_LENGTH}` }\n    };\n    return password.length < MIN_PASSWORD_LENGTH ? error : null;\n  }\n\n  public static checkPasswordStrength(passwordStrength: number): IErrorTk | null {\n    const error: IErrorTk = {\n      errorTk: 'utils.validation.passwordTooWeakError'\n    };\n    return passwordStrength < MIN_PASSWORD_STRENGTH_AFE ? error : null;\n  }\n\n  public static checkPasswords(password: string, passwordRepeat: string, passwordStrength: number): IErrorTk | null {\n    const passwordTooShortError = this.checkPasswordLength(password);\n    if(passwordTooShortError) return passwordTooShortError;\n    const passwordTooWeakError = this.checkPasswordStrength(passwordStrength);\n    if(passwordTooWeakError) return passwordTooWeakError;\n\n    const error: IErrorTk = {\n      errorTk: 'utils.validation.passwordsNotEqualError'\n    };\n    return password !== passwordRepeat ? error : null;\n  }\n}\n"],"names":[],"sourceRoot":""}