herum-shared 0.1.34 → 0.1.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { EventEmitter, ViewChild, Output, Input, Component, Pipe, HostListener, Inject, forwardRef, ViewChildren, Optional, Self, Injectable, Directive, ViewEncapsulation, HostBinding, NgModule } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
- import { formatDate, DOCUMENT, CommonModule, DatePipe } from '@angular/common';
5
- import { Subject, BehaviorSubject, forkJoin, EMPTY } from 'rxjs';
6
- import { takeUntil, debounceTime, tap, shareReplay, map, switchMap, catchError } from 'rxjs/operators';
7
- import { keyboardAsciiCodes, regexExpressions, svgsStrings, system, defaultGrade, defaultPlaceholder as defaultPlaceholder$1, types, formStatuses, startEndDateError, minDateError, formatError, timestampError, timePattern, dayInMilliSeconds, dateRangeTimeRangePlaceHolder, dateRangeTimeRangeWithoutSecondsPlaceHolder, dateRangePlaceHolder, dateTimePlaceHolder, dateTimeWithoutSecondsPlaceHolder, datePlaceHolder, timePlaceHolder, timeWithoutSecondsPlaceHolder, generalKeys, uploadsManagerKeys, skipToastHeader, assignmentMetadata, attributes, defaultAuthorizationObject, resourceIdPlaceholder, getPublishAuthorization, getMongoMethodsDisplayedNamesMap, resourcesFilesSuffixes, calendarActiveColorCssVariable, calendarHoverColorCssVariable, calendarLibrarySelector, calendarLibraryBodyCellSelector, timerActiveColorCssVariable, timerHoverColorCssVariable, timerItemSizeColorCssVariable, anySubFileTypeWildCard, maleAvatarPath, femaleAvatarPath, signUpFormKeys, filesSuffixes, tableRowHeights, dialogsDescriptions, dialogsTitles, getToastsTemplates, toastStatuses, toastContext, toastStates, uploadStatuses } from 'herum-shared/constants';
4
+ import { formatDate, CommonModule, DatePipe } from '@angular/common';
5
+ import { Subject, BehaviorSubject, EMPTY, forkJoin } from 'rxjs';
6
+ import { takeUntil, debounceTime, tap, catchError, switchMap, shareReplay } from 'rxjs/operators';
7
+ import { keyboardAsciiCodes, regexExpressions, svgsStrings, system, defaultGrade, defaultPlaceholder as defaultPlaceholder$1, types, formStatuses, startEndDateError, minDateError, formatError, timestampError, timePattern, dayInMilliSeconds, dateRangeTimeRangePlaceHolder, dateRangeTimeRangeWithoutSecondsPlaceHolder, dateRangePlaceHolder, dateTimePlaceHolder, dateTimeWithoutSecondsPlaceHolder, datePlaceHolder, timePlaceHolder, timeWithoutSecondsPlaceHolder, calendarActiveColorCssVariable, calendarHoverColorCssVariable, calendarLibrarySelector, calendarLibraryBodyCellSelector, timerActiveColorCssVariable, timerHoverColorCssVariable, timerItemSizeColorCssVariable, resourcesFilesSuffixes, anySubFileTypeWildCard, maleAvatarPath, femaleAvatarPath, signUpFormKeys, filesSuffixes, tableRowHeights, dialogsDescriptions, dialogsTitles, getToastsTemplates, toastStatuses, toastContext, toastStates, uploadsManagerKeys, uploadStatuses } from 'herum-shared/constants';
8
8
  import * as i1$2 from 'herum-shared/services';
9
9
  import * as i2 from '@angular/cdk/bidi';
10
10
  import * as i1$1 from '@angular/platform-browser';
@@ -25,14 +25,14 @@ import { HERUM_SHARED_CONFIG_TOKEN } from 'herum-shared/environment';
25
25
  import * as i4 from 'herum-shared/directives';
26
26
  import { DirectivesModule as DirectivesModule$1 } from 'herum-shared/directives';
27
27
  import * as i1$4 from 'herum-shared/herum-types';
28
- import { QuizHeaderState, microResourceAuthorizationType, ResourceState, TimeUnit, Gender, StepStatus, TableActions } from 'herum-shared/herum-types';
29
- import { isTruncatedTitleElement, convertToDate, updateFullYear, getDropdownAnimationStates, toHash, buildPath, setHeaders, remainJustWantedValueInDictionary, getVersionPathParameter, getAssignmentStateDisplayName, replaceInterpolateKeysWithObjectProperties, convertHeightToPixels } from 'herum-shared/utils';
28
+ import { QuizHeaderState, ResourceState, TimeUnit, Gender, StepStatus, TableActions } from 'herum-shared/herum-types';
29
+ import { isTruncatedTitleElement, convertToDate, updateFullYear, getDropdownAnimationStates, getAssignmentStateDisplayName, replaceInterpolateKeysWithObjectProperties, convertHeightToPixels, buildPath } from 'herum-shared/utils';
30
+ import * as i2$2 from 'herum-shared/atoms';
31
+ import { HerumCheckboxComponent as HerumCheckboxComponent$1, AtomsModule as AtomsModule$1 } from 'herum-shared/atoms';
30
32
  import * as i1$8 from '@angular/cdk/clipboard';
31
33
  import { ClipboardModule } from '@angular/cdk/clipboard';
32
34
  import * as i4$1 from 'herum-shared/pipes';
33
35
  import { PipesModule as PipesModule$1 } from 'herum-shared/pipes';
34
- import * as i2$2 from 'herum-shared/atoms';
35
- import { AtomsModule as AtomsModule$1 } from 'herum-shared/atoms';
36
36
  import { openClose as openClose$1 } from 'herum-shared/animations';
37
37
  import * as i2$3 from '@angular/material/menu';
38
38
  import { MatMenuModule } from '@angular/material/menu';
@@ -42,22 +42,18 @@ import { DateRange, MatDatepickerModule } from '@angular/material/datepicker';
42
42
  import * as i1$7 from '@angular/material/core';
43
43
  import { MatNativeDateModule, MAT_DATE_LOCALE } from '@angular/material/core';
44
44
  import { v4 } from 'uuid';
45
- import { SYSTEM_AUDIO_VISUAL_CONFIGURATION, SYSTEM_TRACK_TEXT_CHANGES_SERVICE } from 'herum-shared/tokens';
45
+ import { SYSTEM_AUDIO_VISUAL_CONFIGURATION } from 'herum-shared/tokens';
46
46
  import * as i1$5 from '@angular/common/http';
47
- import { HttpHeaders } from '@angular/common/http';
48
- import { StorageService } from 'herum-shared/static-services';
49
- import { selfIsTeacherExample, closedListExample, permissionsTemplatesExample } from 'herum-shared/objectsExample';
50
- import * as i2$4 from '@angular/router';
51
- import { cloneDeep } from 'lodash';
52
47
  import * as i1$6 from '@angular/material/dialog';
53
48
  import { MAT_DIALOG_DATA } from '@angular/material/dialog';
54
- import * as i2$5 from 'herum-shared/molecules';
49
+ import * as i2$4 from 'herum-shared/molecules';
55
50
  import { MoleculesModule as MoleculesModule$1 } from 'herum-shared/molecules';
56
51
  import * as i3$1 from 'ag-grid-angular';
57
52
  import { AgGridModule } from 'ag-grid-angular';
58
53
  import { __decorate } from 'tslib';
59
54
  import { TableRowHeight } from 'herum-shared/decorators';
60
55
  import { trigger, state, style, transition, animate } from '@angular/animations';
56
+ import { StorageService } from 'herum-shared/static-services';
61
57
  import { ErrorMessageDialogComponent as ErrorMessageDialogComponent$1 } from 'herum-shared/errors';
62
58
 
63
59
  const max = 3;
@@ -1494,7 +1490,7 @@ class QuizMultiAnswerQuestionComponent {
1494
1490
  this.destroySubject$.complete();
1495
1491
  }
1496
1492
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QuizMultiAnswerQuestionComponent, deps: [{ token: i1$3.FormBuilder }, { token: HERUM_SHARED_CONFIG_TOKEN }], target: i0.ɵɵFactoryTarget.Component });
1497
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: QuizMultiAnswerQuestionComponent, isStandalone: false, selector: "quiz-multi-answer-question", inputs: { question: "question", quizData: "quizData", userAnswers: "userAnswers", isCheckingMode: "isCheckingMode", areAnswersRevealed: "areAnswersRevealed", areAnswersBlocked: "areAnswersBlocked", correctAnswerCount: "correctAnswerCount" }, outputs: { onAnswersChange: "onAnswersChange", onValidationChange: "onValidationChange" }, viewQueries: [{ propertyName: "checkboxes", predicate: HerumCheckboxComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"main-container\">\r\n <p class=\"correct-answer-count\">\u05D9\u05E9 \u05DC\u05E1\u05DE\u05DF {{ correctAnswerCount }} \u05EA\u05E9\u05D5\u05D1\u05D5\u05EA</p>\r\n\r\n <form *ngIf=\"question.answers\" [formGroup]=\"answersForm\" class=\"answers-container\">\r\n <div class=\"answer-item\" *ngFor=\"let answer of question.answers;let i=index\">\r\n <div class=\"answer-container\" [ngClass]=\"{'revealed-answers':(areAnswersRevealed || isCheckingMode)}\"\r\n [attr.type]=\"(areAnswersRevealed || isCheckingMode) ? answerTypeAttributes[i] : ''\"\r\n [attr.includes-additional-option-text]=\"(additionalOptionsText && additionalOptionsText[i]) ? 'true' : 'false'\">\r\n <herum-checkbox [isBlocked]=\"isBlocked\" [formControlName]=\"controlNamePrefix + i\"\r\n [id]=\"controlNamePrefix + i\">\r\n </herum-checkbox>\r\n\r\n <p class=\"answer-text cursor-pointer\" [ngClass]=\"{'cursor-pointer':!isBlocked}\"\r\n (click)=\"_onAnswerClicked(i)\">{{ answer.content }}</p>\r\n </div>\r\n\r\n <span *ngIf=\"answer.note && (areAnswersRevealed || isCheckingMode)\" class=\"answer-note\">\r\n {{ answer.note }}\r\n </span>\r\n </div>\r\n </form>\r\n</div>", styles: [".answer-text{line-height:1;font-size:14px;font-weight:700}.correct-answer-count{margin-block-end:0;font-size:14px}.answers-container,.main-container{display:flex;flex-direction:column;gap:8px;width:100%}.answer-container{display:flex;align-items:center;gap:8px}.answer-container,.answer-note{flex:1}\n", ".quiz-container{display:flex;flex-direction:column;gap:16px}.quiz-container p,.quiz-container b{font-size:16px;margin-bottom:.25rem}.quiz-container .quiz-title{font-weight:700}.quiz-container .error-message{color:var(--error-color);font-weight:700}.quiz-container .answer-item{display:flex;flex-direction:row;gap:8px}.answers-container{display:flex;flex-direction:column;gap:16px}.answers-container .answer-item{display:flex;flex-direction:row;gap:8px}.answers-container .answer-note{background-color:var(--light-text-color);border-radius:var(border-radius);font-size:14px}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: HerumCheckboxComponent, selector: "herum-checkbox", inputs: ["type", "isChecked", "isBlocked"], outputs: ["checkedEmitter"] }] });
1493
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: QuizMultiAnswerQuestionComponent, isStandalone: false, selector: "quiz-multi-answer-question", inputs: { question: "question", quizData: "quizData", userAnswers: "userAnswers", isCheckingMode: "isCheckingMode", areAnswersRevealed: "areAnswersRevealed", areAnswersBlocked: "areAnswersBlocked", correctAnswerCount: "correctAnswerCount" }, outputs: { onAnswersChange: "onAnswersChange", onValidationChange: "onValidationChange" }, viewQueries: [{ propertyName: "checkboxes", predicate: HerumCheckboxComponent$1, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"main-container\">\r\n <p class=\"correct-answer-count\">\u05D9\u05E9 \u05DC\u05E1\u05DE\u05DF {{ correctAnswerCount }} \u05EA\u05E9\u05D5\u05D1\u05D5\u05EA</p>\r\n\r\n <form *ngIf=\"question.answers\" [formGroup]=\"answersForm\" class=\"answers-container\">\r\n <div class=\"answer-item\" *ngFor=\"let answer of question.answers;let i=index\">\r\n <div class=\"answer-container\" [ngClass]=\"{'revealed-answers':(areAnswersRevealed || isCheckingMode)}\"\r\n [attr.type]=\"(areAnswersRevealed || isCheckingMode) ? answerTypeAttributes[i] : ''\"\r\n [attr.includes-additional-option-text]=\"(additionalOptionsText && additionalOptionsText[i]) ? 'true' : 'false'\">\r\n <herum-checkbox [isBlocked]=\"isBlocked\" [formControlName]=\"controlNamePrefix + i\"\r\n [id]=\"controlNamePrefix + i\">\r\n </herum-checkbox>\r\n\r\n <p class=\"answer-text cursor-pointer\" [ngClass]=\"{'cursor-pointer':!isBlocked}\"\r\n (click)=\"_onAnswerClicked(i)\">{{ answer.content }}</p>\r\n </div>\r\n\r\n <span *ngIf=\"answer.note && (areAnswersRevealed || isCheckingMode)\" class=\"answer-note\">\r\n {{ answer.note }}\r\n </span>\r\n </div>\r\n </form>\r\n</div>", styles: [".answer-text{line-height:1;font-size:14px;font-weight:700}.correct-answer-count{margin-block-end:0;font-size:14px}.answers-container,.main-container{display:flex;flex-direction:column;gap:8px;width:100%}.answer-container{display:flex;align-items:center;gap:8px}.answer-container,.answer-note{flex:1}\n", ".quiz-container{display:flex;flex-direction:column;gap:16px}.quiz-container p,.quiz-container b{font-size:16px;margin-bottom:.25rem}.quiz-container .quiz-title{font-weight:700}.quiz-container .error-message{color:var(--error-color);font-weight:700}.quiz-container .answer-item{display:flex;flex-direction:row;gap:8px}.answers-container{display:flex;flex-direction:column;gap:16px}.answers-container .answer-item{display:flex;flex-direction:row;gap:8px}.answers-container .answer-note{background-color:var(--light-text-color);border-radius:var(border-radius);font-size:14px}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: HerumCheckboxComponent, selector: "herum-checkbox", inputs: ["type", "isChecked", "isBlocked"], outputs: ["checkedEmitter"] }] });
1498
1494
  }
1499
1495
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QuizMultiAnswerQuestionComponent, decorators: [{
1500
1496
  type: Component,
@@ -1522,7 +1518,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
1522
1518
  type: Output
1523
1519
  }], checkboxes: [{
1524
1520
  type: ViewChildren,
1525
- args: [HerumCheckboxComponent]
1521
+ args: [HerumCheckboxComponent$1]
1526
1522
  }] } });
1527
1523
 
1528
1524
  class QuizLoaderComponent {
@@ -1735,28 +1731,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
1735
1731
  type: Input
1736
1732
  }] } });
1737
1733
 
1738
- class HerumFormControl extends FormControl {
1739
- errorMessages = {};
1740
- currentErrorMessage = '';
1741
- destroySubject$ = new Subject();
1742
- /**
1743
- @comment The component that creates this class should have destroySubject$ so you can listen to its ngOnDestroy life cycle hook so you can unsubscribe statusChangesSubscription
1744
- */
1745
- constructor(formState, validatorOrOpts, asyncValidator, errorMessages, componentReference) {
1746
- super(formState, validatorOrOpts, asyncValidator);
1747
- if (errorMessages)
1748
- this.errorMessages = errorMessages;
1749
- this.statusChanges.pipe(takeUntil(this.destroySubject$)).subscribe(() => this.setCurrentErrorMessage());
1750
- componentReference.destroySubject$.pipe(takeUntil(this.destroySubject$)).subscribe(() => {
1751
- this.destroySubject$.next(null);
1752
- this.destroySubject$.complete();
1753
- });
1754
- }
1755
- setCurrentErrorMessage() {
1756
- this.currentErrorMessage = this.errors ? this.errorMessages[Object.keys(this.errors)[0]] : null;
1757
- }
1758
- }
1759
-
1760
1734
  const emptyNumberInputValue = '0';
1761
1735
  const numericTextType = 'numeric-text';
1762
1736
  class HerumInputFieldComponent {
@@ -1822,14 +1796,14 @@ class HerumInputFieldComponent {
1822
1796
  })).subscribe();
1823
1797
  }
1824
1798
  setInputsByFormControl() {
1825
- console.log(this.ngControl);
1826
1799
  if (!this.ngControl)
1827
1800
  return;
1828
1801
  if (this.ngControl instanceof FormControlName)
1829
1802
  this.formControlName = this.ngControl.name?.toString() || '';
1830
1803
  this.ngControl.control.statusChanges.pipe(takeUntil(this.destroySubject$)).subscribe(status => {
1831
- if (this.ngControl.control instanceof HerumFormControl)
1832
- this.errorMsg = this.ngControl.control.currentErrorMessage;
1804
+ const controlWithErrorMessage = this.ngControl.control;
1805
+ if (!!controlWithErrorMessage.currentErrorMessage)
1806
+ this.errorMsg = controlWithErrorMessage.currentErrorMessage;
1833
1807
  const controlStatus = this.ngControl.control.status;
1834
1808
  this.isValid = controlStatus === formStatuses.valid;
1835
1809
  this.isLoading = controlStatus === formStatuses.pending;
@@ -3359,1196 +3333,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
3359
3333
  args: [SYSTEM_AUDIO_VISUAL_CONFIGURATION]
3360
3334
  }] }] });
3361
3335
 
3362
- const NestedConditionSigniture = "filters";
3363
- const defaultPagingDataFormat = "pageInfo { hasNextPage, hasPreviousPage, startCursor, endCursor }";
3364
- const offsetPagingDataFormat = "pageInfo { hasNextPage, hasPreviousPage }";
3365
- const DefaultQueryName = "DefaultQueryName";
3366
- class GraphQLService {
3367
- httpClient;
3368
- environmentConfig;
3369
- constructor(httpClient, environmentConfig) {
3370
- this.httpClient = httpClient;
3371
- this.environmentConfig = environmentConfig;
3372
- }
3373
- executeQuery(gqlQuery, isListQuery = true, isOffsetPagination = false) {
3374
- let variablesObjectForBody;
3375
- let variablesStringForQuerySignature;
3376
- if (gqlQuery.variables) {
3377
- variablesObjectForBody = this.generateVariablesObjectForBody(gqlQuery.variables);
3378
- variablesStringForQuerySignature = this.generateVariablesStringForQuerySigniture(gqlQuery.variables, gqlQuery.queryName);
3379
- }
3380
- const query = this.generateQuery(gqlQuery.resolverName, gqlQuery.formatExample, gqlQuery.filters, gqlQuery.paging?.first, gqlQuery.paging?.after, gqlQuery.offsetPaging, gqlQuery.variables?.length > 0 ? variablesStringForQuerySignature : '', gqlQuery.order, gqlQuery.conditionPaths, gqlQuery.orderPaths, gqlQuery.offsetPagingPaths, isListQuery, isOffsetPagination).replace(regexExpressions.curlyBraces, '');
3381
- return this.httpClient.post(this.environmentConfig?.graphQLConfiguration?.serverBasePath, { query: query, variables: variablesObjectForBody }, { headers: gqlQuery.headers })
3382
- .pipe(shareReplay(1), map(res => {
3383
- return res.data ? res.data[gqlQuery.resolverName] : null;
3384
- }));
3385
- }
3386
- getFreeTextCondition(freeText, orConditionKeys) {
3387
- let filters = {
3388
- and: []
3389
- };
3390
- freeText.split(" ").forEach(substring => {
3391
- let orIteration = [];
3392
- orConditionKeys.forEach(orConditionKey => {
3393
- orIteration.push({
3394
- [orConditionKey]: { contains: substring }
3395
- });
3396
- });
3397
- filters.and.push({ or: orIteration });
3398
- });
3399
- return filters;
3400
- }
3401
- generateFilterStringDynamically(ids, key, type) {
3402
- let filters = [];
3403
- let variables = [];
3404
- ids.forEach((id, index) => {
3405
- let newFilter = {};
3406
- newFilter[key] = {
3407
- eq: '$' + key + index
3408
- };
3409
- filters.push(newFilter);
3410
- variables.push({
3411
- name: key + index,
3412
- value: id,
3413
- type
3414
- });
3415
- });
3416
- return { filters, variables };
3417
- }
3418
- convertToResolverNameFormat(mongoCollectionName) {
3419
- return mongoCollectionName.charAt(0).toLowerCase() + mongoCollectionName.slice(1);
3420
- }
3421
- generateQuery(resolverName, formatExample, condition, first, after, offsetPaging, variablesStringForQuerySigniture, order, conditionPaths, orderPaths, offsetPagingPaths, isListQuery, isOffsetPagination) {
3422
- const conditionString = this.generateConditionString(condition);
3423
- const returnFormat = this.getKeysString(formatExample, conditionPaths, orderPaths, offsetPagingPaths);
3424
- let orderString = order ? `order:${this.generateOrderString(order)},` : '';
3425
- let pagingString = '';
3426
- if (isListQuery) {
3427
- pagingString = isOffsetPagination
3428
- ? (offsetPaging?.skip > -1 || offsetPaging?.take > -1 ? this.generateOffsetPagingString(offsetPaging) : '')
3429
- : (first || after ? this.generatePagingString(first, after) : '');
3430
- }
3431
- if (after)
3432
- pagingString += ',';
3433
- const resolverParameters = (orderString + pagingString + conditionString) == '' ? '' : '(' + orderString + pagingString + conditionString + ')';
3434
- if (pagingString != '')
3435
- pagingString += ',';
3436
- const elementsName = isOffsetPagination ? 'items' : 'nodes';
3437
- const query = `query ${variablesStringForQuerySigniture ? variablesStringForQuerySigniture : ''} {
3438
- ${resolverName + resolverParameters} { ${isListQuery ? (isOffsetPagination ? offsetPagingDataFormat : defaultPagingDataFormat) + `,totalCount , ${elementsName} {` : ''} ${returnFormat} } ${isListQuery ? '}' : ''} }`;
3439
- return query;
3440
- }
3441
- generateConditionString(condition, isRecursiveCall = false) {
3442
- let conditionString = "";
3443
- if (!condition || (!condition.and || condition.and?.length == 0) && (!condition.or || condition.or?.length == 0))
3444
- return conditionString;
3445
- if (condition) {
3446
- conditionString = isRecursiveCall ? "" : "where: {";
3447
- if (condition?.and) {
3448
- let andString = "";
3449
- condition.and.forEach(filter => {
3450
- (Object.keys(filter)[0] == 'or' || Object.keys(filter)[0] == 'and') ?
3451
- andString += `{${this.generateConditionString(filter, true)}},` :
3452
- andString += `{${this.getKeysString(filter, null, null, null, null, true)}},`;
3453
- });
3454
- andString = andString.slice(0, -1);
3455
- conditionString += `and: [${andString}]`;
3456
- conditionString += condition.or ? ',' : '';
3457
- }
3458
- if (condition?.or) {
3459
- let orString = "";
3460
- condition.or.forEach(filter => orString += `{${this.getKeysString(filter, null, null, null, null, true)}},`);
3461
- condition.or.forEach(filter => {
3462
- (Object.keys(filter)[0] == 'or' || Object.keys(filter)[0] == 'and') ?
3463
- orString += `{${this.generateConditionString(filter, true)}},` :
3464
- orString += `{${this.getKeysString(filter, null, null, null, null, true)}},`;
3465
- });
3466
- orString = orString.slice(0, -1);
3467
- conditionString += `or: [${orString} ]`;
3468
- }
3469
- conditionString += isRecursiveCall ? "" : "}";
3470
- }
3471
- return conditionString;
3472
- }
3473
- generatePagingString(first, after) {
3474
- let result = '';
3475
- result += first ? `first:${first},` : '';
3476
- result += after ? ` after:"${after}"` : '';
3477
- return result;
3478
- }
3479
- generateOffsetPagingString(offsetPaging) {
3480
- const { skip, take } = offsetPaging;
3481
- let result = '';
3482
- result += skip > -1 ? `skip:${skip},` : '';
3483
- result += take > -1 ? ` take:${take}, ` : '';
3484
- return result;
3485
- }
3486
- getKeysString(obj, conditionPaths, orderPaths, offsetPagingPaths, parentKey = null, isConditionString = false) {
3487
- let result = '';
3488
- for (const key in obj) {
3489
- result += `${key}`;
3490
- if (((conditionPaths && conditionPaths[key]) || (orderPaths && orderPaths[key])) && !isConditionString) {
3491
- result += '(';
3492
- if (conditionPaths && conditionPaths[key])
3493
- result += this.generateConditionString(conditionPaths[key]);
3494
- if (orderPaths && orderPaths[key])
3495
- result += this.getKeysString(orderPaths[key], null, null, null, null, true);
3496
- if (offsetPagingPaths && offsetPagingPaths[key])
3497
- result += (offsetPagingPaths[key].skip > -1 || offsetPagingPaths[key].take > -1) ? `,${this.generateOffsetPagingString(offsetPagingPaths[key])}` : '';
3498
- result += `)`;
3499
- }
3500
- if (offsetPagingPaths && offsetPagingPaths[key])
3501
- result += '{items';
3502
- if (obj[key]?.length > 0 && !isConditionString && obj[key] !== null && typeof obj[key] !== 'string') {
3503
- result += isConditionString ? `: { ${this.getKeysString(obj[key], conditionPaths, orderPaths, offsetPagingPaths, key, isConditionString)} }` :
3504
- ` { ${this.getKeysString(obj[key][0], conditionPaths, orderPaths, key, isConditionString)} }`;
3505
- }
3506
- else if (typeof obj[key] === 'object' && obj[key] !== null && typeof obj[key] !== 'string')
3507
- result += isConditionString ? `: { ${this.getKeysString(obj[key], conditionPaths, orderPaths, offsetPagingPaths, key, isConditionString)} }` :
3508
- ` { ${this.getKeysString(obj[key], conditionPaths, orderPaths, offsetPagingPaths, parentKey + '.' + key, isConditionString)} }`;
3509
- else if (typeof obj[key] === 'string' && obj[key] !== null && isConditionString)
3510
- result += (obj[key][0] == '$' || obj[key].includes('ASC') || obj[key].includes('DESC')) ? `: ${obj[key]}` : `: "${obj[key]}"`;
3511
- else if (typeof obj[key] === 'number' && obj[key] !== null && isConditionString)
3512
- result += `: ${JSON.stringify(obj[key])}`;
3513
- else if (typeof obj[key] === 'boolean' && obj[key] !== null && isConditionString)
3514
- result += `: ${obj[key]}`;
3515
- if (offsetPagingPaths && offsetPagingPaths[key])
3516
- result += '}';
3517
- result += ', ';
3518
- }
3519
- return result.slice(0, -2);
3520
- }
3521
- generateVariablesObjectForBody(variables) {
3522
- return variables.reduce((acc, obj) => {
3523
- acc[obj.name] = obj.value;
3524
- return acc;
3525
- }, {});
3526
- }
3527
- generateVariablesStringForQuerySigniture(variables, queryName) {
3528
- if (!queryName)
3529
- queryName = DefaultQueryName;
3530
- let result = (queryName ? queryName : DefaultQueryName) + '(';
3531
- variables.forEach(variable => {
3532
- result += "$" + variable.name + ":" + variable.type + ",";
3533
- });
3534
- result = result.slice(0, -1) + ")";
3535
- return result;
3536
- }
3537
- generateOrderString(order) {
3538
- let orderString = '{';
3539
- Object.keys(order).forEach((key, index, keys) => {
3540
- orderString += typeof order[key] === 'object' ?
3541
- `${key}:${this.generateOrderString(order[key])}` :
3542
- `${key}:${order[key]}`;
3543
- if (index < keys.length - 1)
3544
- orderString += ',';
3545
- });
3546
- return orderString + '}';
3547
- }
3548
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: GraphQLService, deps: [{ token: i1$5.HttpClient }, { token: HERUM_SHARED_CONFIG_TOKEN }], target: i0.ɵɵFactoryTarget.Injectable });
3549
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: GraphQLService, providedIn: 'root' });
3550
- }
3551
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: GraphQLService, decorators: [{
3552
- type: Injectable,
3553
- args: [{
3554
- providedIn: 'root'
3555
- }]
3556
- }], ctorParameters: () => [{ type: i1$5.HttpClient }, { type: undefined, decorators: [{
3557
- type: Inject,
3558
- args: [HERUM_SHARED_CONFIG_TOKEN]
3559
- }] }] });
3560
-
3561
- const AuthStorageKey = 'AUTH_SESSION_ID';
3562
- const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
3563
- class AuthService {
3564
- http;
3565
- router;
3566
- gql;
3567
- environmentConfig;
3568
- sessionId$ = new BehaviorSubject('');
3569
- isTeacher$ = new Subject();
3570
- constructor(http, router, gql, environmentConfig) {
3571
- this.http = http;
3572
- this.router = router;
3573
- this.gql = gql;
3574
- this.environmentConfig = environmentConfig;
3575
- let sessionId = StorageService.getItem(AuthStorageKey);
3576
- if (!sessionId)
3577
- return;
3578
- this.sessionId$.next(sessionId);
3579
- }
3580
- tryLogin(signInFormData) {
3581
- const personalId = signInFormData.personalId;
3582
- let loginFormat = {
3583
- identifier: personalId,
3584
- hash: toHash(this.generateStringForAuthenticationHash(personalId, signInFormData.militaryId))
3585
- };
3586
- return this.http.post(this.environmentConfig?.environment?.siteServerPath + this.environmentConfig?.authenticationPaths?.tryLogin, loginFormat)
3587
- .pipe(map((authenticationResponse) => this.handleNewSessionId(authenticationResponse)));
3588
- }
3589
- getUserIdentificationQuestions(personalId) {
3590
- return this.http.get(this.environmentConfig?.environment?.siteServerPath + `/Authentication/SecurityQuestions/${personalId}`);
3591
- }
3592
- signUp(signUpData) {
3593
- return this.http.post(this.environmentConfig?.environment?.siteServerPath + this.environmentConfig?.authenticationPaths?.signUp, signUpData)
3594
- .pipe(map((authenticationResponse) => this.handleNewSessionId(authenticationResponse)));
3595
- }
3596
- logout() {
3597
- this.clearSession();
3598
- this.router.navigate(['/login']);
3599
- }
3600
- clearSession() {
3601
- StorageService.deleteAll();
3602
- this.sessionId$.next('');
3603
- }
3604
- isValidSessionId(sessionId) {
3605
- let jSessionId = JSON.stringify(sessionId ?? '');
3606
- return this.http.post(this.environmentConfig?.environment?.siteServerPath + this.environmentConfig?.authenticationPaths?.isValidSessionId, jSessionId, { headers: headers });
3607
- }
3608
- isTeacher() {
3609
- let userQuery = {
3610
- resolverName: 'self',
3611
- formatExample: selfIsTeacherExample,
3612
- conditionPaths: { collegeStudyingLessons: { and: [{ lesson: { isDeleted: { eq: false } } }] } }
3613
- };
3614
- return this.gql.executeQuery(userQuery, false).pipe(map(user => {
3615
- const isTeacher = !(!user.collegeTeacherAssignments || user.collegeTeacherAssignments.length == 0) ||
3616
- !(!user.collegeTeachingLessons || user.collegeTeachingLessons.length == 0) ||
3617
- !(!user.collegeCheckingLessons || user.collegeCheckingLessons.length == 0) || user.isAdmin == true;
3618
- this.isTeacher$.next(isTeacher);
3619
- return isTeacher;
3620
- }));
3621
- }
3622
- setIdentificationQuestions(password, questions) {
3623
- return this.http.post(this.environmentConfig?.environment?.siteServerPath + '/Authentication/UpdateLoginData', {
3624
- password,
3625
- securityQuestions: questions.map(question => ({ ...question, answer: toHash(question.answer) }))
3626
- });
3627
- }
3628
- resetPassword(securityQuestions, personalId, newPassword) {
3629
- return this.http.post(this.environmentConfig?.environment?.siteServerPath + '/Authentication/ResetPassword', {
3630
- personalId: personalId,
3631
- answers: securityQuestions.map(question => ({ questionId: question._id, answer: toHash(question.answer) })),
3632
- newPassword: newPassword
3633
- });
3634
- }
3635
- securityCheck(securityQuestions, personalId) {
3636
- return this.http.post(this.environmentConfig?.environment?.siteServerPath + '/Authentication/SecurityCheck', {
3637
- personalId: personalId,
3638
- answers: securityQuestions.map(question => ({ questionId: question._id, answer: toHash(question.answer) }))
3639
- });
3640
- }
3641
- handleNewSessionId(authenticationResponse) {
3642
- if (authenticationResponse.sessionId?.length > 0)
3643
- this.updateSessionId(authenticationResponse.sessionId);
3644
- return authenticationResponse;
3645
- }
3646
- updateSessionId(newValue) {
3647
- this.sessionId$.next(newValue);
3648
- StorageService.setItem(AuthStorageKey, newValue);
3649
- }
3650
- generateStringForAuthenticationHash(personalId, militaryId) {
3651
- return personalId + militaryId;
3652
- }
3653
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AuthService, deps: [{ token: i1$5.HttpClient }, { token: i2$4.Router }, { token: GraphQLService }, { token: HERUM_SHARED_CONFIG_TOKEN }], target: i0.ɵɵFactoryTarget.Injectable });
3654
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AuthService, providedIn: 'root' });
3655
- }
3656
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AuthService, decorators: [{
3657
- type: Injectable,
3658
- args: [{
3659
- providedIn: 'root'
3660
- }]
3661
- }], ctorParameters: () => [{ type: i1$5.HttpClient }, { type: i2$4.Router }, { type: GraphQLService }, { type: undefined, decorators: [{
3662
- type: Inject,
3663
- args: [HERUM_SHARED_CONFIG_TOKEN]
3664
- }] }] });
3665
-
3666
- class CommonGraphqlRequestsService {
3667
- gql;
3668
- environmentConfig;
3669
- constructor(gql, environmentConfig) {
3670
- this.gql = gql;
3671
- this.environmentConfig = environmentConfig;
3672
- }
3673
- getGroupsByIds(ids, formatExample) {
3674
- let filterQuery = this.gql.generateFilterStringDynamically(ids, 'id', 'String');
3675
- let query = {
3676
- resolverName: this.gql.convertToResolverNameFormat(this.environmentConfig?.mongoUpdates?.Collections?.Groups),
3677
- formatExample: formatExample,
3678
- filters: {
3679
- or: filterQuery.filters
3680
- },
3681
- variables: filterQuery.variables
3682
- };
3683
- return this.gql.executeQuery(query).pipe(map(gqlGroups => gqlGroups?.nodes));
3684
- }
3685
- getClosedLists(names) {
3686
- let query = {
3687
- resolverName: this.gql.convertToResolverNameFormat(this.environmentConfig?.mongoUpdates?.Collections?.ClosedLists),
3688
- formatExample: closedListExample,
3689
- filters: { and: [{ isDeleted: { eq: false } }] },
3690
- variables: []
3691
- };
3692
- names?.forEach((name, i) => {
3693
- if (query.filters.or)
3694
- query.filters.or.push({
3695
- name: {
3696
- eq: '$name' + i
3697
- },
3698
- });
3699
- else
3700
- query.filters.or = [{
3701
- name: {
3702
- eq: '$name' + i
3703
- },
3704
- }];
3705
- query.variables.push({
3706
- name: 'name' + i,
3707
- value: name,
3708
- type: 'String'
3709
- });
3710
- });
3711
- return this.gql.executeQuery(query).pipe(map(gqlResult => gqlResult.nodes));
3712
- }
3713
- getUsersByIds(usersIds, formatExample) {
3714
- let filterQuery = this.gql.generateFilterStringDynamically(usersIds, generalKeys.id, 'String');
3715
- let query = {
3716
- resolverName: this.gql.convertToResolverNameFormat(this.environmentConfig?.mongoUpdates?.Collections?.Users),
3717
- formatExample,
3718
- filters: {
3719
- or: filterQuery.filters
3720
- },
3721
- variables: filterQuery.variables
3722
- };
3723
- return this.gql.executeQuery(query).pipe(map(gqlResponse => gqlResponse?.nodes));
3724
- }
3725
- getPermissionsTemplates() {
3726
- let query = {
3727
- resolverName: 'permissionsTemplates',
3728
- formatExample: permissionsTemplatesExample,
3729
- };
3730
- return this.gql.executeQuery(query).pipe(map(gqlResponse => gqlResponse.nodes));
3731
- }
3732
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: CommonGraphqlRequestsService, deps: [{ token: GraphQLService }, { token: HERUM_SHARED_CONFIG_TOKEN }], target: i0.ɵɵFactoryTarget.Injectable });
3733
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: CommonGraphqlRequestsService, providedIn: 'root' });
3734
- }
3735
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: CommonGraphqlRequestsService, decorators: [{
3736
- type: Injectable,
3737
- args: [{
3738
- providedIn: 'root'
3739
- }]
3740
- }], ctorParameters: () => [{ type: GraphQLService }, { type: undefined, decorators: [{
3741
- type: Inject,
3742
- args: [HERUM_SHARED_CONFIG_TOKEN]
3743
- }] }] });
3744
-
3745
- const innerUniqListItemKey = '_id';
3746
- const emptyValueFlagForCreationUniqListItem = 'null';
3747
- class DbActionsInnerIdManagerService {
3748
- determineIfInnerIdIsNeeded(value) {
3749
- if (!Array.isArray(value))
3750
- return;
3751
- if (value[0][innerUniqListItemKey])
3752
- value[0].id = value[0][innerUniqListItemKey] == emptyValueFlagForCreationUniqListItem ? null : value[0][innerUniqListItemKey];
3753
- }
3754
- deleteInnerIdFieldIfExist(itemToAttach, itemValue) {
3755
- if (itemValue.hasOwnProperty(innerUniqListItemKey)) {
3756
- itemToAttach[Object.keys(itemToAttach)[0]][generalKeys.id] =
3757
- itemToAttach[Object.keys(itemToAttach)[0]][innerUniqListItemKey] == emptyValueFlagForCreationUniqListItem ?
3758
- null :
3759
- itemToAttach[Object.keys(itemToAttach)[0]][innerUniqListItemKey];
3760
- delete itemToAttach[Object.keys(itemToAttach)[0]][innerUniqListItemKey];
3761
- }
3762
- }
3763
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DbActionsInnerIdManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3764
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DbActionsInnerIdManagerService, providedIn: 'root' });
3765
- }
3766
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DbActionsInnerIdManagerService, decorators: [{
3767
- type: Injectable,
3768
- args: [{
3769
- providedIn: 'root'
3770
- }]
3771
- }] });
3772
-
3773
- const ATTACH = "Attach";
3774
- class DbActionRequestsService {
3775
- http;
3776
- dbActionsInnerIdManagerService;
3777
- environmentConfig;
3778
- constructor(http, dbActionsInnerIdManagerService, environmentConfig) {
3779
- this.http = http;
3780
- this.dbActionsInnerIdManagerService = dbActionsInnerIdManagerService;
3781
- this.environmentConfig = environmentConfig;
3782
- }
3783
- getFileRequest(request, file) {
3784
- const formData = new FormData();
3785
- formData.append(generalKeys.newFileRequest, JSON.stringify(request));
3786
- formData.append(generalKeys.file, file);
3787
- return formData;
3788
- }
3789
- addOrUpdateAndAttachBulkWithFile(mongoCollectionName, fields, file, ids, uploadsManagerTitle, skipToast) {
3790
- let headers = this.setAddOrUpdateAndAttachBulkWithFileHeaders([uploadsManagerTitle, skipToast]);
3791
- return this.getMongoCollectionModelInfo(mongoCollectionName).pipe(switchMap((modelInfo) => {
3792
- if (fields.files)
3793
- delete fields.files;
3794
- const splittedFields = this.splitFieldByType(fields, modelInfo);
3795
- const request = {
3796
- DbBasicActionRequest: {
3797
- data: splittedFields.keysToUpdate,
3798
- ids
3799
- },
3800
- DbAttachmentActionRequests: this.getFormattedAttachments(ids, splittedFields.keysToAttach, splittedFields.keysToAttachInDifferentModel, modelInfo)
3801
- };
3802
- return this.http.put(buildPath([
3803
- this.environmentConfig?.environment?.siteServerPath,
3804
- mongoCollectionName,
3805
- this.environmentConfig?.mongoUpdates?.Methods?.AddOrUpdate,
3806
- this.environmentConfig?.mongoUpdates?.Submethods?.AndAttach,
3807
- this.environmentConfig?.mongoUpdates?.Options?.Bulk,
3808
- this.environmentConfig?.mongoUpdates?.Options?.SetFile
3809
- ]), this.getFileRequest(request, file), { responseType: 'text', reportProgress: !!file, headers });
3810
- }));
3811
- }
3812
- setAddOrUpdateAndAttachBulkWithFileHeaders(headerToSet) {
3813
- let headers = null;
3814
- const [uploadsManagerTitle, skipToast] = headerToSet;
3815
- if (uploadsManagerTitle)
3816
- headers = setHeaders(new HttpHeaders(), [{ key: uploadsManagerKeys.uploadsManagerTitleHeader, value: uploadsManagerTitle }], true);
3817
- if (skipToast)
3818
- headers = skipToastHeader;
3819
- return headers;
3820
- }
3821
- AndAttachBulk(mongoCollectionName, fields, ids, method, attachmentsToUpdate) {
3822
- if (ids.every(id => !id))
3823
- ids = undefined;
3824
- return this.getMongoCollectionModelInfo(mongoCollectionName).pipe(switchMap((modelInfo) => {
3825
- const splittedFields = this.splitFieldByType(fields, modelInfo);
3826
- const request = {
3827
- DbBasicActionRequest: {
3828
- data: Object.assign(splittedFields.keysToUpdate, attachmentsToUpdate),
3829
- ids
3830
- },
3831
- DbAttachmentActionRequests: this.getFormattedAttachments(ids, splittedFields.keysToAttach, splittedFields.keysToAttachInDifferentModel, modelInfo)
3832
- };
3833
- if (method == 'create')
3834
- delete request.DbBasicActionRequest.ids;
3835
- return this.http.request(method == 'create' ? 'post' : 'put', buildPath([
3836
- this.environmentConfig?.environment?.siteServerPath,
3837
- mongoCollectionName,
3838
- method == 'addOrUpdate' ? this.environmentConfig?.mongoUpdates?.Methods?.AddOrUpdate : this.environmentConfig?.mongoUpdates?.Methods?.Create,
3839
- this.environmentConfig?.mongoUpdates?.Submethods?.AndAttach,
3840
- this.environmentConfig?.mongoUpdates?.Options?.Bulk
3841
- ]), { body: request });
3842
- }));
3843
- }
3844
- basicBulk(mongoCollectionName, fields, ids, requestType, skipToast) {
3845
- return this.getMongoCollectionModelInfo(mongoCollectionName).pipe(switchMap((modelInfo) => {
3846
- const updatedFields = remainJustWantedValueInDictionary(generalKeys.id, fields);
3847
- const splitedFields = this.splitFieldByType(fields, modelInfo);
3848
- const requests = Object.entries(updatedFields).map(([field, value]) => {
3849
- const fieldModelInfo = splitedFields.keysToAttachInDifferentModel[field];
3850
- return fieldModelInfo?.sourceField ?
3851
- this.buildMirrorSourceCollectionRequestsData(value, fieldModelInfo.sourceField, fieldModelInfo.innerPreviewModelName, ids[0], requestType, fieldModelInfo.attachedToType)
3852
- : this.buildSourceCollectionRequestsData(ids, { [field]: value }, requestType, mongoCollectionName);
3853
- });
3854
- let headers = null;
3855
- if (skipToast)
3856
- headers = skipToastHeader;
3857
- return this.http.post(buildPath([
3858
- this.environmentConfig?.environment?.siteServerPath,
3859
- mongoCollectionName,
3860
- this.environmentConfig?.mongoUpdates?.Methods?.Basic,
3861
- this.environmentConfig?.mongoUpdates?.Options?.Bulk,
3862
- ]), { requests }, { headers });
3863
- }));
3864
- }
3865
- buildSourceCollectionRequestsData(mongoSourceCollectionIds, data, requestType, mongoSourceCollectionName) {
3866
- return {
3867
- ids: mongoSourceCollectionIds,
3868
- data,
3869
- requestType,
3870
- actOnType: mongoSourceCollectionName
3871
- };
3872
- }
3873
- buildMirrorSourceCollectionRequestsData(fieldValue, sourceField, innerPreviewModelName, mongoSourceCollectionId, requestType, attachedToType) {
3874
- return {
3875
- ids: this.arrayOfIdObjectsToIdsArray(fieldValue),
3876
- data: this.buildBasicBulkObjectData(sourceField, innerPreviewModelName, mongoSourceCollectionId),
3877
- requestType,
3878
- actOnType: attachedToType
3879
- };
3880
- }
3881
- arrayOfIdObjectsToIdsArray(array) {
3882
- return array.map(object => object.id);
3883
- }
3884
- buildBasicBulkObjectData(sourceField, innerPreviewModelName, mongoSourceCollectionId) {
3885
- const value = innerPreviewModelName ? { [innerPreviewModelName]: { id: mongoSourceCollectionId } } : { id: mongoSourceCollectionId };
3886
- return { [sourceField]: [value] };
3887
- }
3888
- deleteMongoDocument(mongoCollectionName, ids) {
3889
- return this.http.post(buildPath([
3890
- this.environmentConfig?.environment?.siteServerPath,
3891
- mongoCollectionName,
3892
- this.environmentConfig?.mongoUpdates?.Methods?.Delete,
3893
- ]), ids);
3894
- }
3895
- deletePreviewItemsFromList(mongoCollectionName, fields, ids) {
3896
- const request = {
3897
- ids,
3898
- data: fields
3899
- };
3900
- return this.http.put(buildPath([
3901
- this.environmentConfig?.environment?.siteServerPath,
3902
- mongoCollectionName,
3903
- this.environmentConfig?.mongoUpdates?.Methods?.ListItemDeletion
3904
- ]), request);
3905
- }
3906
- getFormattedAttachments(ids, objectsToAttach, keysToAttachInDifferentModel, modelInfo) {
3907
- let result = [];
3908
- Object.keys(objectsToAttach).forEach(keyToAttach => {
3909
- let attachments = {};
3910
- if (Array.isArray(objectsToAttach[keyToAttach]))
3911
- objectsToAttach[keyToAttach].forEach((itemToAttach) => {
3912
- const itemKey = Object.keys(itemToAttach)[0];
3913
- const itemValue = itemToAttach[itemKey];
3914
- this.dbActionsInnerIdManagerService.deleteInnerIdFieldIfExist(itemToAttach, itemValue);
3915
- if (itemValue.hasOwnProperty(generalKeys.id) && itemValue[generalKeys.id] !== null)
3916
- delete itemToAttach[Object.keys(itemToAttach)[0]][generalKeys.id];
3917
- Object.assign(attachments, itemToAttach);
3918
- });
3919
- else
3920
- attachments[objectsToAttach[keyToAttach]] = {};
3921
- objectsToAttach[keyToAttach].forEach((objectToAttach, index) => {
3922
- if (objectsToAttach[keyToAttach] && Object.keys(objectsToAttach[keyToAttach][index]) && attachments[Object.keys(objectsToAttach[keyToAttach][index])[0]])
3923
- Object.keys(attachments[Object.keys(objectsToAttach[keyToAttach][index])[0]]).forEach(keyOfObjectToAttachData => {
3924
- if (modelInfo[keyToAttach].innerPreviewModelName == keyOfObjectToAttachData || !modelInfo[keyToAttach].innerProperties.hasOwnProperty(keyOfObjectToAttachData))
3925
- delete attachments[Object.keys(objectsToAttach[keyToAttach][index])[0]][keyOfObjectToAttachData];
3926
- });
3927
- });
3928
- result.push({
3929
- field: keyToAttach.charAt(0).toUpperCase() + keyToAttach.slice(1),
3930
- attachments,
3931
- ids
3932
- });
3933
- });
3934
- Object.keys(keysToAttachInDifferentModel).forEach(field => {
3935
- const extensionValue = Object.values(DbActionsInconsistencyMap[field].extension)[0];
3936
- const updatedExtensionInfo = { [ids[0]]: extensionValue };
3937
- let request = {
3938
- field: keysToAttachInDifferentModel[field].sourceField,
3939
- attachments: updatedExtensionInfo,
3940
- ids: keysToAttachInDifferentModel[field].values.map(value => value.id),
3941
- attachedToType: keysToAttachInDifferentModel[field].attachedToType
3942
- };
3943
- result.push(request);
3944
- });
3945
- return result;
3946
- }
3947
- splitFieldByType(fields, modelInfo) {
3948
- return Object.entries(fields).reduce((acc, [key, value]) => {
3949
- if (modelInfo[key] && (modelInfo[key].attachedToType == null || modelInfo[key].sourceField == null || modelInfo[key].sourceField == undefined)) {
3950
- const group = modelInfo[key].propertyUpdateType === ATTACH ? 'keysToAttach' : 'keysToUpdate';
3951
- if (value !== null && value !== undefined && (!Array.isArray(value) || value.length > 0)) {
3952
- acc[group] = {
3953
- ...acc[group], [key]: modelInfo[key].propertyUpdateType === ATTACH ?
3954
- value?.map(value => {
3955
- return { [value.id + '']: value };
3956
- }) :
3957
- value
3958
- };
3959
- this.dbActionsInnerIdManagerService.determineIfInnerIdIsNeeded(value);
3960
- }
3961
- }
3962
- else {
3963
- if (modelInfo[DbActionsInconsistencyMap[key]?.backendNaming])
3964
- acc.keysToAttachInDifferentModel = {
3965
- ...acc.keysToAttachInDifferentModel, [key]: {
3966
- attachedToType: modelInfo[DbActionsInconsistencyMap[key].backendNaming]?.attachedToType,
3967
- sourceField: modelInfo[DbActionsInconsistencyMap[key].backendNaming]?.sourceField,
3968
- innerPreviewModelName: modelInfo[DbActionsInconsistencyMap[key].backendNaming]?.innerPreviewModelName,
3969
- values: fields[key]
3970
- }
3971
- };
3972
- else
3973
- acc.keysToAttachInDifferentModel = {
3974
- ...acc.keysToAttachInDifferentModel, [key]: {
3975
- attachedToType: modelInfo[key]?.attachedToType,
3976
- sourceField: modelInfo[key]?.sourceField,
3977
- innerPreviewModelName: modelInfo[key]?.innerPreviewModelName,
3978
- values: fields[key]
3979
- }
3980
- };
3981
- }
3982
- return acc;
3983
- }, { keysToAttach: {}, keysToUpdate: {}, keysToAttachInDifferentModel: {} });
3984
- }
3985
- getMongoCollectionModelInfo(mongoCollectionName) {
3986
- return this.http.get(buildPath([
3987
- this.environmentConfig?.environment?.siteServerPath,
3988
- mongoCollectionName,
3989
- this.environmentConfig?.mongoUpdates?.Methods?.ModelInfo
3990
- ]));
3991
- }
3992
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DbActionRequestsService, deps: [{ token: i1$5.HttpClient }, { token: DbActionsInnerIdManagerService }, { token: HERUM_SHARED_CONFIG_TOKEN }], target: i0.ɵɵFactoryTarget.Injectable });
3993
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DbActionRequestsService, providedIn: 'root' });
3994
- }
3995
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DbActionRequestsService, decorators: [{
3996
- type: Injectable,
3997
- args: [{
3998
- providedIn: 'root'
3999
- }]
4000
- }], ctorParameters: () => [{ type: i1$5.HttpClient }, { type: DbActionsInnerIdManagerService }, { type: undefined, decorators: [{
4001
- type: Inject,
4002
- args: [HERUM_SHARED_CONFIG_TOKEN]
4003
- }] }] });
4004
- const DbActionsInconsistencyMap = {
4005
- groups: {
4006
- backendNaming: "members",
4007
- extension: {
4008
- "NEW_VALUE": {}
4009
- },
4010
- },
4011
- groupsPermissions: {
4012
- backendNaming: "permittedGroups",
4013
- extension: {
4014
- "NEW_VALUE": {
4015
- "permission": {
4016
- "update": true
4017
- }
4018
- }
4019
- },
4020
- },
4021
- groupsViewPermissions: {
4022
- backendNaming: "permittedGroups",
4023
- extension: {
4024
- "NEW_VALUE": {
4025
- "permission": {
4026
- "update": false
4027
- }
4028
- }
4029
- }
4030
- },
4031
- assignments: {
4032
- backendNaming: "assignments",
4033
- extension: {
4034
- "NEW_VALUE": {
4035
- "id": null,
4036
- assignmentMetadata
4037
- }
4038
- }
4039
- },
4040
- "collegeTeacherAssignments": {
4041
- backendNaming: "collegeTeacherAssignments",
4042
- extension: {
4043
- "NEW_VALUE": {
4044
- "id": null
4045
- }
4046
- }
4047
- },
4048
- "collegeStudentAssignments": {
4049
- backendNaming: "collegeStudentAssignments",
4050
- extension: {
4051
- "NEW_VALUE": {
4052
- "id": null
4053
- }
4054
- }
4055
- }
4056
- };
4057
-
4058
- class GlobalKeyboardListenerService {
4059
- environmentConfig;
4060
- globalKeyboardEvents$ = new Subject();
4061
- connection;
4062
- constructor(environmentConfig) {
4063
- this.environmentConfig = environmentConfig;
4064
- this.initGlobalSocket();
4065
- }
4066
- initGlobalSocket() {
4067
- if (this.connection)
4068
- return;
4069
- this.connection = new WebSocket(this.environmentConfig?.environment?.keyboardEventsLocalSocketPath);
4070
- this.connection.onmessage = (webSocketMessage) => {
4071
- const event = JSON.parse(webSocketMessage.data);
4072
- if (event.state == 'UP')
4073
- this.globalKeyboardEvents$.next(event);
4074
- };
4075
- }
4076
- get globalKeysToChromeKeysNames() {
4077
- return {
4078
- 'NUMPAD 0': 'Insert',
4079
- 'NUMPAD 1': 'End',
4080
- 'NUMPAD 2': 'ArrowDown',
4081
- 'NUMPAD 3': 'PageDown',
4082
- 'NUMPAD 4': 'ArrowLeft',
4083
- 'NUMPAD 5': 'Clear',
4084
- 'NUMPAD 6': 'ArrowRight',
4085
- 'NUMPAD 7': 'Home',
4086
- 'NUMPAD 8': '',
4087
- 'NUMPAD 9': 'PageUp',
4088
- };
4089
- }
4090
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: GlobalKeyboardListenerService, deps: [{ token: HERUM_SHARED_CONFIG_TOKEN }], target: i0.ɵɵFactoryTarget.Injectable });
4091
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: GlobalKeyboardListenerService, providedIn: 'root' });
4092
- }
4093
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: GlobalKeyboardListenerService, decorators: [{
4094
- type: Injectable,
4095
- args: [{
4096
- providedIn: 'root'
4097
- }]
4098
- }], ctorParameters: () => [{ type: undefined, decorators: [{
4099
- type: Inject,
4100
- args: [HERUM_SHARED_CONFIG_TOKEN]
4101
- }] }] });
4102
-
4103
- class KeyPressService {
4104
- shouldPreventMacroKeyPress(event, macroKeysPress) {
4105
- const eventTarget = event.target;
4106
- const targetMacroKeys = eventTarget.getAttribute(attributes.preventMacroKeysPressEvent)?.split(",").map(Number);
4107
- const targetHasPreventMacroKeyPress = targetMacroKeys?.some(targetMacroKey => macroKeysPress.includes(targetMacroKey));
4108
- return targetHasPreventMacroKeyPress || eventTarget.hasAttribute(attributes.contenteditable);
4109
- }
4110
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: KeyPressService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4111
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: KeyPressService, providedIn: 'root' });
4112
- }
4113
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: KeyPressService, decorators: [{
4114
- type: Injectable,
4115
- args: [{
4116
- providedIn: 'root'
4117
- }]
4118
- }] });
4119
-
4120
- class LoaderManagerService {
4121
- loadersIds = [];
4122
- loadingDescription = '';
4123
- addLoader(loaderId, description) {
4124
- this.loadersIds.push(loaderId);
4125
- this.loadingDescription = description;
4126
- }
4127
- changeDescription(description) {
4128
- this.loadingDescription = description;
4129
- }
4130
- clear() {
4131
- this.loadersIds = [];
4132
- this.loadingDescription = '';
4133
- }
4134
- removeLoaderId(loaderIdToRemove) {
4135
- let indexToRemove = this.loadersIds.findIndex(loaderId => loaderId == loaderIdToRemove);
4136
- if (indexToRemove != -1)
4137
- this.loadersIds.splice(indexToRemove, 1);
4138
- }
4139
- get isFullScreenLoading() {
4140
- return this.loadersIds.length > 0;
4141
- }
4142
- ;
4143
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: LoaderManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4144
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: LoaderManagerService, providedIn: 'root' });
4145
- }
4146
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: LoaderManagerService, decorators: [{
4147
- type: Injectable,
4148
- args: [{
4149
- providedIn: 'root'
4150
- }]
4151
- }] });
4152
-
4153
- const freeTextAnswerField = 'FreeTextAnswer';
4154
- const gradeField = 'Grade';
4155
- const answerNotesField = 'AnswerNotes[]';
4156
- const UserQuestionsDataPath = 'QuizData.UserQuestionsData';
4157
- class MicroResourcesService {
4158
- http;
4159
- environmentConfig;
4160
- constructor(http, environmentConfig) {
4161
- this.http = http;
4162
- this.environmentConfig = environmentConfig;
4163
- }
4164
- getAssignmentUpdateTimings(selectedResource, openingTime, closingTime) {
4165
- return [{
4166
- propertyPath: this.buildQuestionPropertyPath(selectedResource.quiz.questions[0]?.id, freeTextAnswerField),
4167
- collectionItemType: '',
4168
- openingTime,
4169
- closingTime,
4170
- authorizationType: microResourceAuthorizationType.update
4171
- },
4172
- {
4173
- propertyPath: this.buildQuestionPropertyPath(selectedResource.quiz.questions[1]?.id, freeTextAnswerField),
4174
- collectionItemType: '',
4175
- openingTime,
4176
- closingTime,
4177
- authorizationType: microResourceAuthorizationType.update
4178
- }];
4179
- }
4180
- getPublishGradeTimings(selectedResource, openingTime = new Date(2999, 1, 1), closingTime) {
4181
- return [{
4182
- authorizationType: microResourceAuthorizationType.view,
4183
- closingTime: closingTime,
4184
- collectionItemType: "",
4185
- openingTime: openingTime,
4186
- propertyPath: this.buildQuestionPropertyPath(selectedResource.quiz.questions[0].id, gradeField)
4187
- }, {
4188
- authorizationType: microResourceAuthorizationType.view,
4189
- closingTime: closingTime,
4190
- collectionItemType: "",
4191
- openingTime: openingTime,
4192
- propertyPath: this.buildQuestionPropertyPath(selectedResource.quiz.questions[1].id, gradeField)
4193
- }, {
4194
- authorizationType: microResourceAuthorizationType.view,
4195
- closingTime: closingTime,
4196
- collectionItemType: "",
4197
- openingTime: openingTime,
4198
- propertyPath: this.buildQuestionPropertyPath(selectedResource.quiz.questions[0].id, answerNotesField)
4199
- }, {
4200
- authorizationType: microResourceAuthorizationType.view,
4201
- closingTime: closingTime,
4202
- collectionItemType: "",
4203
- openingTime: openingTime,
4204
- propertyPath: this.buildQuestionPropertyPath(selectedResource.quiz.questions[1].id, answerNotesField)
4205
- }, {
4206
- authorizationType: microResourceAuthorizationType.view,
4207
- closingTime: closingTime,
4208
- collectionItemType: "",
4209
- openingTime: openingTime,
4210
- propertyPath: `Grade`
4211
- }];
4212
- }
4213
- updateUserMicroResourceAuthorizationLocally(currentLesson, studentId, microResourceAuthorizations, selectedResource) {
4214
- currentLesson.students.find(student => student.student.id == studentId)
4215
- .resourceSubscriptions.find(resourceSubscription => resourceSubscription.resourcePreview.id == selectedResource.id)
4216
- .microResourceAuthorizations = microResourceAuthorizations;
4217
- }
4218
- updateUserMicroResourceVisibility(microResource, resource, lesson, user) {
4219
- let propertyPath;
4220
- propertyPath = this.resolvePropertyPath(microResource.propertyPath, resource.quiz.questions);
4221
- resource.microResourceAuthorizations = resource.microResourceAuthorizations.filter(microResourceAuthorization => microResourceAuthorization.propertyPath != "" &&
4222
- microResourceAuthorization.propertyPath != propertyPath);
4223
- resource.microResourceAuthorizations.push({
4224
- propertyPath: propertyPath,
4225
- collectionItemType: microResource.collectionItemType,
4226
- openingTime: microResource.openingTime,
4227
- closingTime: microResource.closingTime,
4228
- authorizationType: microResourceAuthorizationType.view
4229
- });
4230
- return this.updateUserMicroResourceAuthorization(user.student.id, lesson, resource, resource.microResourceAuthorizations);
4231
- }
4232
- updateUserMicroResourceAuthorization(studentId, lesson, resource, authorizations) {
4233
- return this.http.post(this.environmentConfig?.environment?.siteServerPath + '/Activity/UpdateAuthorizations', {
4234
- userIds: [studentId],
4235
- lessonId: lesson.id,
4236
- resourceId: resource.id,
4237
- authorizations
4238
- }).pipe(tap(() => {
4239
- this.updateUserMicroResourceAuthorizationLocally(lesson, studentId, authorizations, resource);
4240
- }));
4241
- }
4242
- resolvePropertyPath(path, questions) {
4243
- return typeof path === 'function' ? path(questions) : path;
4244
- }
4245
- isTimePass(date) {
4246
- if (!date)
4247
- return false;
4248
- return new Date(date).getTime() < new Date().getTime();
4249
- }
4250
- isAuthenticated(microResource) {
4251
- return this.isTimePass(microResource.openingTime) && !this.isTimePass(microResource.closingTime);
4252
- }
4253
- isQuestionAssignment(resourceSubscription, questionType) {
4254
- const question = resourceSubscription?.quizData?.userQuestionsData.find(userQuestionData => userQuestionData.questionType === questionType);
4255
- if (!question)
4256
- return false;
4257
- return !!resourceSubscription.microResourceAuthorizations?.find(microResourceAuthorization => microResourceAuthorization.propertyPath === this.buildQuestionPropertyPath(question.id, freeTextAnswerField));
4258
- }
4259
- isQuestionPendingForCheck(resourceSubscription, questionData) {
4260
- const microResourceAuthorizations = resourceSubscription.microResourceAuthorizations;
4261
- const questionId = questionData.id;
4262
- const questionClosingTime = microResourceAuthorizations?.find(microResourceAuthorization => microResourceAuthorization.propertyPath === this.buildQuestionPropertyPath(questionId, freeTextAnswerField) && microResourceAuthorization.authorizationType === microResourceAuthorizationType.update)?.closingTime;
4263
- const gradePublishOpeningTime = microResourceAuthorizations?.find(microResourceAuthorization => microResourceAuthorization.propertyPath === this.buildQuestionPropertyPath(questionId, gradeField))?.openingTime;
4264
- let isQuestionPendingForCheck = false;
4265
- if (questionClosingTime && questionData.grade === defaultGrade) {
4266
- isQuestionPendingForCheck = gradePublishOpeningTime ?
4267
- new Date(questionClosingTime).getTime() < new Date().getTime() && new Date().getTime() < new Date(gradePublishOpeningTime).getTime() :
4268
- new Date(questionClosingTime).getTime() < new Date().getTime();
4269
- }
4270
- return isQuestionPendingForCheck;
4271
- }
4272
- buildQuestionPropertyPath(id, field) {
4273
- return `${UserQuestionsDataPath}[${id}].${field}`;
4274
- }
4275
- hasFillAuthorizationClosingTimePassed(innerAuthorizations, resource) {
4276
- const fillAuthorizationPropertyPath = defaultAuthorizationObject.fill().propertyPath.replace(resourceIdPlaceholder, resource.id);
4277
- const fillAuthorization = innerAuthorizations?.find(auth => auth.propertyPath == fillAuthorizationPropertyPath && auth.authorizationType == microResourceAuthorizationType.fill);
4278
- return this.isTimePass(fillAuthorization?.closingTime);
4279
- }
4280
- isPublishGradeAuthenticated(innerAuthorizations, resource) {
4281
- const publishGradeInnerAuthorizations = this.getAuthorization(innerAuthorizations, defaultAuthorizationObject.resourceGrade(), microResourceAuthorizationType.view, resource);
4282
- return publishGradeInnerAuthorizations ? this.isAuthenticated(publishGradeInnerAuthorizations) : false;
4283
- }
4284
- getAuthorization(innerAuthorizations, defaultAuthorizationObject, microResourceAuthorizationType, resource) {
4285
- const fillAuthorizationPropertyPath = defaultAuthorizationObject.propertyPath.replace(resourceIdPlaceholder, resource.id);
4286
- return innerAuthorizations.find((innerAuthorization) => innerAuthorization.propertyPath === fillAuthorizationPropertyPath && innerAuthorization.authorizationType === microResourceAuthorizationType);
4287
- }
4288
- createMultiResourceDefaultAuthorizations(students, pageId, resourcesIds, defaultAuthorizations, authorizations) {
4289
- const updates = [];
4290
- let microAuthorizations = [];
4291
- if (authorizations)
4292
- microAuthorizations = authorizations;
4293
- else {
4294
- resourcesIds.forEach(resourceId => {
4295
- let defaultAuthorizationsCopy = cloneDeep(defaultAuthorizations);
4296
- defaultAuthorizationsCopy.forEach(authorization => authorization.propertyPath = authorization.propertyPath.replace(resourceIdPlaceholder, resourceId));
4297
- microAuthorizations.push(...defaultAuthorizationsCopy);
4298
- });
4299
- }
4300
- const parsedAuthorizations = microAuthorizations.map((authorization) => ({
4301
- propertyPath: authorization.propertyPath,
4302
- closingTime: authorization.closingTime,
4303
- openingTime: authorization.openingTime,
4304
- authorizationType: authorization.authorizationType,
4305
- lastUpDateTime: new Date(),
4306
- collectionItemType: authorization.collectionItemType
4307
- }));
4308
- students.forEach(student => {
4309
- updates.push({
4310
- userIds: [student.user?.id],
4311
- hadrachaPageId: pageId,
4312
- authorizations: [...(student.innerAuthorizations || []), ...parsedAuthorizations]
4313
- });
4314
- });
4315
- return forkJoin(updates.map(request => {
4316
- return this.http.post(this.environmentConfig?.environment?.siteServerPath + this.environmentConfig?.resourcePaths?.resourceUpdateAuthorizations, request);
4317
- }));
4318
- }
4319
- copyResourceStudentsAuthorizations(students, pageId, authSourceResourceId, authTargetResourceId, useDefaultGradePermissions) {
4320
- const updates = [];
4321
- students.forEach(student => {
4322
- let sourceResourceAuthorizations = student.innerAuthorizations.filter(innerAuthorization => innerAuthorization.propertyPath.includes(authSourceResourceId));
4323
- sourceResourceAuthorizations = cloneDeep(sourceResourceAuthorizations);
4324
- let targetResourceAuthorizations = sourceResourceAuthorizations.map(authorization => ({
4325
- ...authorization,
4326
- lastUpDateTime: new Date(),
4327
- propertyPath: authorization.propertyPath.replace(authSourceResourceId, authTargetResourceId)
4328
- }));
4329
- if (useDefaultGradePermissions) {
4330
- let defaultGradePermissions = cloneDeep(getPublishAuthorization());
4331
- defaultGradePermissions.forEach(authorization => authorization.propertyPath = authorization.propertyPath.replace(resourceIdPlaceholder, authTargetResourceId));
4332
- targetResourceAuthorizations = targetResourceAuthorizations.filter(authorization => !defaultGradePermissions.some(defaultGradePermission => defaultGradePermission.propertyPath == authorization.propertyPath));
4333
- targetResourceAuthorizations = [...targetResourceAuthorizations, ...defaultGradePermissions];
4334
- }
4335
- updates.push({
4336
- userIds: [student.user?.id],
4337
- hadrachaPageId: pageId,
4338
- authorizations: [...(student.innerAuthorizations || []), ...(targetResourceAuthorizations || [])]
4339
- });
4340
- });
4341
- return forkJoin(updates.map(request => this.http.post(this.environmentConfig?.environment?.siteServerPath + this.environmentConfig?.resourcePaths?.resourceUpdateAuthorizations, request)));
4342
- }
4343
- removeResourceAuthorizations(page, resourcesIdsToRemove) {
4344
- const updates = [];
4345
- resourcesIdsToRemove.forEach(resourceIdToRemove => {
4346
- page.students.forEach(student => {
4347
- let resourceAuthorizationsToKeep = student.innerAuthorizations.filter(innerAuthorization => innerAuthorization.propertyPath.includes(resourceIdToRemove));
4348
- updates.push({
4349
- userIds: [student.user?.id],
4350
- hadrachaPageId: page.id,
4351
- authorizations: resourceAuthorizationsToKeep
4352
- });
4353
- });
4354
- });
4355
- return forkJoin(updates.map(request => this.http.post(this.environmentConfig?.environment?.siteServerPath + this.environmentConfig?.resourcePaths?.resourceUpdateAuthorizations, request)));
4356
- }
4357
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: MicroResourcesService, deps: [{ token: i1$5.HttpClient }, { token: HERUM_SHARED_CONFIG_TOKEN }], target: i0.ɵɵFactoryTarget.Injectable });
4358
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: MicroResourcesService, providedIn: 'root' });
4359
- }
4360
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: MicroResourcesService, decorators: [{
4361
- type: Injectable,
4362
- args: [{
4363
- providedIn: 'root'
4364
- }]
4365
- }], ctorParameters: () => [{ type: i1$5.HttpClient }, { type: undefined, decorators: [{
4366
- type: Inject,
4367
- args: [HERUM_SHARED_CONFIG_TOKEN]
4368
- }] }] });
4369
-
4370
- class UtilsService {
4371
- environmentConfig;
4372
- constructor(environmentConfig) {
4373
- this.environmentConfig = environmentConfig;
4374
- }
4375
- getDisplayedNameForMongoMethodByUserActivity(urlRequest) {
4376
- let mongoMethodDisplayedName;
4377
- const mongoMethodsDisplayedNamesMap = getMongoMethodsDisplayedNamesMap(this.environmentConfig?.mongoUpdates, this.environmentConfig?.authenticationPaths);
4378
- Object.entries(mongoMethodsDisplayedNamesMap).forEach(([mongoMethod, displayedName]) => {
4379
- const urlParts = urlRequest?.split('/');
4380
- const matchedMethod = urlParts?.find(urlPart => urlPart === mongoMethod);
4381
- if (matchedMethod)
4382
- mongoMethodDisplayedName = displayedName;
4383
- });
4384
- return mongoMethodDisplayedName;
4385
- }
4386
- getUrlFromFileData(fileData) {
4387
- if (!fileData?.key || !fileData?.bucket)
4388
- return;
4389
- const fileDataKeyWithoutTrailingSlash = fileData.key.endsWith('/') ? fileData.key.slice(0, -1) : fileData.key;
4390
- return buildPath([this.environmentConfig?.environment?.s3ServerPath + fileData.bucket, fileDataKeyWithoutTrailingSlash]);
4391
- }
4392
- fetchFiles(fileId, resourceType, bucket) {
4393
- if (!fileId)
4394
- return Promise.reject();
4395
- const bucketPath = bucket ? bucket : this.environmentConfig?.buckets[resourceType];
4396
- if (fileId && fileId[0] != '/' && bucketPath[bucketPath.length - 1] != '/')
4397
- fileId = "/" + fileId;
4398
- const path = this.environmentConfig?.environment?.s3ServerPath + bucketPath + fileId;
4399
- return fetch(path);
4400
- }
4401
- async initAudioFile(fileId, bucketName, signal) {
4402
- const audioBucketName = bucketName ? (bucketName + "/") : this.environmentConfig?.buckets.Audio;
4403
- return fetch(this.environmentConfig?.environment?.s3ServerPath + audioBucketName + fileId, { signal: signal })
4404
- .then(async (response) => {
4405
- const arrayBuffer = await response.arrayBuffer();
4406
- if (arrayBuffer.byteLength === 0) {
4407
- const blob = await response.blob();
4408
- const reader = new FileReader();
4409
- reader.onload = () => {
4410
- const arrayBuffer = reader.result;
4411
- const file = new File([arrayBuffer], fileId, {
4412
- type: 'audio/mp3',
4413
- });
4414
- return file;
4415
- };
4416
- reader.readAsArrayBuffer(blob);
4417
- }
4418
- else {
4419
- const file = new File([arrayBuffer], fileId, {
4420
- type: 'audio/mpeg',
4421
- });
4422
- return file;
4423
- }
4424
- });
4425
- }
4426
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: UtilsService, deps: [{ token: HERUM_SHARED_CONFIG_TOKEN }], target: i0.ɵɵFactoryTarget.Injectable });
4427
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: UtilsService, providedIn: 'root' });
4428
- }
4429
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: UtilsService, decorators: [{
4430
- type: Injectable,
4431
- args: [{
4432
- providedIn: 'root'
4433
- }]
4434
- }], ctorParameters: () => [{ type: undefined, decorators: [{
4435
- type: Inject,
4436
- args: [HERUM_SHARED_CONFIG_TOKEN]
4437
- }] }] });
4438
-
4439
- class ResourceDataBuilderService {
4440
- utilsService;
4441
- constructor(utilsService) {
4442
- this.utilsService = utilsService;
4443
- }
4444
- buildFilePath(resource) {
4445
- return this.utilsService.getUrlFromFileData(resource.resourceFile) + this.getVersionPathParameter(resource);
4446
- }
4447
- buildDirectoryPath(resource) {
4448
- return this.utilsService.getUrlFromFileData(resource.resourceFile) + resourcesFilesSuffixes[resource.resourceType] + this.getVersionPathParameter(resource);
4449
- }
4450
- getVersionPathParameter(resource) {
4451
- return getVersionPathParameter(new Date(resource.lastUpdateTime));
4452
- }
4453
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ResourceDataBuilderService, deps: [{ token: UtilsService }], target: i0.ɵɵFactoryTarget.Injectable });
4454
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ResourceDataBuilderService, providedIn: 'root' });
4455
- }
4456
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ResourceDataBuilderService, decorators: [{
4457
- type: Injectable,
4458
- args: [{
4459
- providedIn: 'root'
4460
- }]
4461
- }], ctorParameters: () => [{ type: UtilsService }] });
4462
-
4463
- class SystemStylingService {
4464
- document;
4465
- rendererFactory;
4466
- renderer = null;
4467
- constructor(document, rendererFactory) {
4468
- this.document = document;
4469
- this.rendererFactory = rendererFactory;
4470
- this.renderer = this.rendererFactory.createRenderer(null, null);
4471
- }
4472
- setHerumStyling() {
4473
- this.renderer.removeClass(document.body, "college-colors");
4474
- this.renderer.removeClass(document.body, "hadracha-colors");
4475
- this.renderer.addClass(document.body, "herum-colors");
4476
- this.setFavicon("/assets/college/pagesIcons/EchoIcon.svg");
4477
- }
4478
- setCollegeStyling() {
4479
- this.setCssVariable("--main-header-height", "0vh");
4480
- this.renderer.removeClass(document.body, "hadracha-colors");
4481
- this.renderer.removeClass(document.body, "herum-colors");
4482
- this.renderer.addClass(document.body, "college-colors");
4483
- this.setFavicon("/assets/college/pagesIcons/EchoIcon.svg");
4484
- }
4485
- setHadrachaStyling() {
4486
- this.renderer.removeClass(document.body, "college-colors");
4487
- this.renderer.removeClass(document.body, "herum-colors");
4488
- this.renderer.addClass(document.body, "hadracha-colors");
4489
- this.setFavicon("/assets/hadracha/general/hadracha-favicon.svg");
4490
- }
4491
- setCssVariable(name, value) {
4492
- document.documentElement.style.setProperty(name, value);
4493
- }
4494
- setFavicon(path) {
4495
- const link = this.document.querySelector("link[rel*='icon']");
4496
- link.type = 'image/x-icon';
4497
- link.rel = 'icon';
4498
- link.href = path;
4499
- this.document.head.appendChild(link);
4500
- }
4501
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SystemStylingService, deps: [{ token: DOCUMENT }, { token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable });
4502
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SystemStylingService, providedIn: 'root' });
4503
- }
4504
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SystemStylingService, decorators: [{
4505
- type: Injectable,
4506
- args: [{
4507
- providedIn: 'root'
4508
- }]
4509
- }], ctorParameters: () => [{ type: Document, decorators: [{
4510
- type: Inject,
4511
- args: [DOCUMENT]
4512
- }] }, { type: i0.RendererFactory2 }] });
4513
- function systemStylingFactory(systemName, systemStylingService) {
4514
- return () => {
4515
- switch (systemName) {
4516
- case system.college:
4517
- systemStylingService.setCollegeStyling();
4518
- break;
4519
- case system.herum:
4520
- systemStylingService.setHerumStyling();
4521
- break;
4522
- case system.hadracha:
4523
- systemStylingService.setHadrachaStyling();
4524
- break;
4525
- default:
4526
- throw new Error(`Unsupported system:${systemName}`);
4527
- }
4528
- };
4529
- }
4530
-
4531
- class TrackTextChangesService {
4532
- systemContextTrackTextChangesService;
4533
- constructor(systemContextTrackTextChangesService) {
4534
- this.systemContextTrackTextChangesService = systemContextTrackTextChangesService;
4535
- }
4536
- getStyle() {
4537
- return this.systemContextTrackTextChangesService.getStyle();
4538
- }
4539
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: TrackTextChangesService, deps: [{ token: SYSTEM_TRACK_TEXT_CHANGES_SERVICE }], target: i0.ɵɵFactoryTarget.Injectable });
4540
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: TrackTextChangesService, providedIn: 'root' });
4541
- }
4542
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: TrackTextChangesService, decorators: [{
4543
- type: Injectable,
4544
- args: [{
4545
- providedIn: 'root'
4546
- }]
4547
- }], ctorParameters: () => [{ type: i1$4.ISystemTrackTextChangesService, decorators: [{
4548
- type: Inject,
4549
- args: [SYSTEM_TRACK_TEXT_CHANGES_SERVICE]
4550
- }] }] });
4551
-
4552
3336
  const unwantedSelectors = ["div", null];
4553
3337
  class UserActionDirective {
4554
3338
  el;
@@ -5018,13 +3802,13 @@ class AudioPlayerComponent {
5018
3802
  this.pauseAudio();
5019
3803
  this.removeAudioElementEventListeners();
5020
3804
  }
5021
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AudioPlayerComponent, deps: [{ token: AudioVisualizationService }, { token: GlobalKeyboardListenerService }, { token: KeyPressService }, { token: UtilsService }, { token: SYSTEM_AUDIO_VISUAL_CONFIGURATION }], target: i0.ɵɵFactoryTarget.Component });
3805
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AudioPlayerComponent, deps: [{ token: AudioVisualizationService }, { token: i1$2.GlobalKeyboardListenerService }, { token: i1$2.KeyPressService }, { token: i1$2.UtilsService }, { token: SYSTEM_AUDIO_VISUAL_CONFIGURATION }], target: i0.ɵɵFactoryTarget.Component });
5022
3806
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: AudioPlayerComponent, isStandalone: false, selector: "herum-audio-player", inputs: { showVolumeSliders: "showVolumeSliders", isPreview: "isPreview", getTimeUpdate: "getTimeUpdate", playbackSpeed: "playbackSpeed", isBlock: "isBlock", currentTime: "currentTime", isAudioPlaying: "isAudioPlaying", width: "width", id: "id", audioFile: "audioFile", mediaSettings: "mediaSettings", bucketName: "bucketName" }, outputs: { periodicCurrentTime: "periodicCurrentTime", isLoadingChange: "isLoadingChange", timingUpdateByRequest: "timingUpdateByRequest", mediaSettingsUpdate: "mediaSettingsUpdate" }, host: { listeners: { "window:resize": "onWindowResize()", "document:keyup": "handleKeyboardEvent($event)" } }, viewQueries: [{ propertyName: "audioCanvas", first: true, predicate: ["audioCanvas"], descendants: true }, { propertyName: "slider", first: true, predicate: ["slider"], descendants: true, static: true }, { propertyName: "audioContainer", first: true, predicate: ["audioContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"audio-container\" #audioContainer>\r\n <p class=\"current-time\" *ngIf=\"!errorMessage\">{{ currentTimeLabel }}</p>\r\n\r\n <p *ngIf=\"errorMessage\" class=\"m-0 d-flex gap-2 align-items-center\">\r\n <img src=\"/assets/college/learningArea/error.svg\">\r\n {{ errorMessage }}\r\n </p>\r\n\r\n <div class=\"audio-loader-container\" [userAction]=\"'currentTime: ' + currentTime\">\r\n <canvas [class.transparent]=\"isLoading\" #audioCanvas (click)=\"_onCanvasClick($event)\"> </canvas>\r\n </div>\r\n\r\n <div class=\"audio-controls\">\r\n <div *ngIf=\"showVolumeSliders\" class=\"volume-container\">\r\n <div class=\"right slider-container\">\r\n <label>R</label>\r\n <audio-slider color=\"#3B2DBE\" [id]=\"'right'\" userAction\r\n (sliderChange)=\"rightVolume=$event/100; _updateVolume()\">\r\n </audio-slider>\r\n </div>\r\n\r\n <div class=\"left slider-container\">\r\n <label>L</label>\r\n <audio-slider color=\"#2D7ABE\" [id]=\"'left'\" userAction\r\n (sliderChange)=\"leftVolume=$event/100; _updateVolume()\">\r\n </audio-slider>\r\n </div>\r\n </div>\r\n\r\n <button class=\"control-button\" [userAction]=\"'currentTime: ' + currentTime\" (click)=\"_skipForward(15)\" userAction>\r\n <img src=\"assets/shared/audio-images/next15.svg\" alt=\"Fast Forward\" />\r\n </button>\r\n\r\n <button class=\"control-button play-button\" [userAction]=\"isAudioPlaying ? 'play' : 'pause'\"\r\n (click)=\"_onTogglePlay()\">\r\n <ng-container *ngIf=\"!isLoading\">\r\n <img *ngIf=\"!isBlock\"\r\n [src]=\"isAudioPlaying ? 'assets/shared/audio-images/pause.svg' : 'assets/shared/audio-images/play.svg'\"\r\n alt=\"Play/Pause\" />\r\n <img *ngIf=\"isBlock\"\r\n [src]=\"isAudioPlaying ? 'assets/shared/audio-images/gray-pause.svg' : 'assets/shared/audio-images/gray-play.svg'\"\r\n alt=\"Play/Pause\" />\r\n </ng-container>\r\n <herum-spinner *ngIf=\"isLoading\"></herum-spinner>\r\n </button>\r\n\r\n <button class=\"control-button\" (click)=\"_skipBackward(15)\" [userAction]=\"'currentTime: ' + currentTime\">\r\n <img src=\"assets/shared/audio-images/previous15.svg\" alt=\"Rewind\" />\r\n </button>\r\n\r\n <div class=\"speed-control\">\r\n <herum-video-select class=\"video-speed-select\" userAction [options]=\"speedOptions\"\r\n [currentVideoSpeed]=\"playbackSpeed\" (selectedOptionEmitter)=\"_updatePlaybackSpeed($event)\">\r\n </herum-video-select>\r\n </div>\r\n </div>\r\n</div>", styles: [":root{--background-color: #f2f2f2;background-color:var(--background-color)}*{box-sizing:border-box}.audio-container{text-align:center;flex:1}.time-control{margin:20px}canvas{width:100%;height:116px;border-radius:8px;margin-top:4px;opacity:1}.transparent{opacity:0!important}.audio-loader-container{position:relative;display:flex;align-items:center;justify-content:center}.audio-loader-container .d-flex{position:absolute;z-index:2}.audio-controls{padding:12px;display:flex;align-items:center;justify-content:center;gap:10px;background-color:var(--background-color);height:calc(100% - 160px)}.control-button{width:40px;height:40px;display:flex;align-items:center;justify-content:center;background:#f9f9f9;border:none;border-radius:12px;cursor:pointer;transition:background .3s ease;fill:#fff;filter:drop-shadow(0px 0px 6px rgba(0,0,0,.16))}.control-button img{width:20px;height:20px}.control-button:hover{background:#f0f0f0}.play-button{width:50px;height:50px;border:none;border-radius:50%}.play-button img{width:25px;height:25px}.speed-control{display:flex;align-items:center;justify-content:center;background:#f9f9f9;border:none;border-radius:5px;padding:5px 10px;fill:#fff;filter:drop-shadow(0px 0px 6px rgba(0,0,0,.16))}.current-time{font-weight:400;font-size:14px;text-align:left;margin:0;padding-left:12px}.speed-control select{border:none;background:transparent;font-size:14px;outline:none;cursor:pointer}.volume-sliders{display:flex;align-items:center;justify-content:center;gap:20px;margin-top:10px}.volume-container{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px}.slider-container{display:flex;flex-direction:row-reverse;align-items:center;justify-content:center;gap:10px}.slider-container label{margin:0;background:#d18a8a;border-radius:50%;width:18px;height:18px;display:flex;align-items:center;justify-content:center;color:#fff}.left label{background-color:#2d7abe}.right label{background-color:#3b2dbe}audio-slider{width:90px}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: UserActionDirective, selector: "[userAction]", inputs: ["userAction"] }, { kind: "component", type: HerumSpinnerComponent, selector: "herum-spinner", inputs: ["size", "borderColor", "borderWidth", "borderTopColor", "shape"] }, { kind: "component", type: HerumVideoSelectComponent, selector: "herum-video-select", inputs: ["currentVideoSpeed", "options"], outputs: ["selectedOptionEmitter"] }, { kind: "component", type: AudioSliderComponent, selector: "audio-slider", inputs: ["sliderValue", "maxValue", "color", "id"], outputs: ["sliderChange"] }] });
5023
3807
  }
5024
3808
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AudioPlayerComponent, decorators: [{
5025
3809
  type: Component,
5026
3810
  args: [{ standalone: false, selector: 'herum-audio-player', template: "<div class=\"audio-container\" #audioContainer>\r\n <p class=\"current-time\" *ngIf=\"!errorMessage\">{{ currentTimeLabel }}</p>\r\n\r\n <p *ngIf=\"errorMessage\" class=\"m-0 d-flex gap-2 align-items-center\">\r\n <img src=\"/assets/college/learningArea/error.svg\">\r\n {{ errorMessage }}\r\n </p>\r\n\r\n <div class=\"audio-loader-container\" [userAction]=\"'currentTime: ' + currentTime\">\r\n <canvas [class.transparent]=\"isLoading\" #audioCanvas (click)=\"_onCanvasClick($event)\"> </canvas>\r\n </div>\r\n\r\n <div class=\"audio-controls\">\r\n <div *ngIf=\"showVolumeSliders\" class=\"volume-container\">\r\n <div class=\"right slider-container\">\r\n <label>R</label>\r\n <audio-slider color=\"#3B2DBE\" [id]=\"'right'\" userAction\r\n (sliderChange)=\"rightVolume=$event/100; _updateVolume()\">\r\n </audio-slider>\r\n </div>\r\n\r\n <div class=\"left slider-container\">\r\n <label>L</label>\r\n <audio-slider color=\"#2D7ABE\" [id]=\"'left'\" userAction\r\n (sliderChange)=\"leftVolume=$event/100; _updateVolume()\">\r\n </audio-slider>\r\n </div>\r\n </div>\r\n\r\n <button class=\"control-button\" [userAction]=\"'currentTime: ' + currentTime\" (click)=\"_skipForward(15)\" userAction>\r\n <img src=\"assets/shared/audio-images/next15.svg\" alt=\"Fast Forward\" />\r\n </button>\r\n\r\n <button class=\"control-button play-button\" [userAction]=\"isAudioPlaying ? 'play' : 'pause'\"\r\n (click)=\"_onTogglePlay()\">\r\n <ng-container *ngIf=\"!isLoading\">\r\n <img *ngIf=\"!isBlock\"\r\n [src]=\"isAudioPlaying ? 'assets/shared/audio-images/pause.svg' : 'assets/shared/audio-images/play.svg'\"\r\n alt=\"Play/Pause\" />\r\n <img *ngIf=\"isBlock\"\r\n [src]=\"isAudioPlaying ? 'assets/shared/audio-images/gray-pause.svg' : 'assets/shared/audio-images/gray-play.svg'\"\r\n alt=\"Play/Pause\" />\r\n </ng-container>\r\n <herum-spinner *ngIf=\"isLoading\"></herum-spinner>\r\n </button>\r\n\r\n <button class=\"control-button\" (click)=\"_skipBackward(15)\" [userAction]=\"'currentTime: ' + currentTime\">\r\n <img src=\"assets/shared/audio-images/previous15.svg\" alt=\"Rewind\" />\r\n </button>\r\n\r\n <div class=\"speed-control\">\r\n <herum-video-select class=\"video-speed-select\" userAction [options]=\"speedOptions\"\r\n [currentVideoSpeed]=\"playbackSpeed\" (selectedOptionEmitter)=\"_updatePlaybackSpeed($event)\">\r\n </herum-video-select>\r\n </div>\r\n </div>\r\n</div>", styles: [":root{--background-color: #f2f2f2;background-color:var(--background-color)}*{box-sizing:border-box}.audio-container{text-align:center;flex:1}.time-control{margin:20px}canvas{width:100%;height:116px;border-radius:8px;margin-top:4px;opacity:1}.transparent{opacity:0!important}.audio-loader-container{position:relative;display:flex;align-items:center;justify-content:center}.audio-loader-container .d-flex{position:absolute;z-index:2}.audio-controls{padding:12px;display:flex;align-items:center;justify-content:center;gap:10px;background-color:var(--background-color);height:calc(100% - 160px)}.control-button{width:40px;height:40px;display:flex;align-items:center;justify-content:center;background:#f9f9f9;border:none;border-radius:12px;cursor:pointer;transition:background .3s ease;fill:#fff;filter:drop-shadow(0px 0px 6px rgba(0,0,0,.16))}.control-button img{width:20px;height:20px}.control-button:hover{background:#f0f0f0}.play-button{width:50px;height:50px;border:none;border-radius:50%}.play-button img{width:25px;height:25px}.speed-control{display:flex;align-items:center;justify-content:center;background:#f9f9f9;border:none;border-radius:5px;padding:5px 10px;fill:#fff;filter:drop-shadow(0px 0px 6px rgba(0,0,0,.16))}.current-time{font-weight:400;font-size:14px;text-align:left;margin:0;padding-left:12px}.speed-control select{border:none;background:transparent;font-size:14px;outline:none;cursor:pointer}.volume-sliders{display:flex;align-items:center;justify-content:center;gap:20px;margin-top:10px}.volume-container{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px}.slider-container{display:flex;flex-direction:row-reverse;align-items:center;justify-content:center;gap:10px}.slider-container label{margin:0;background:#d18a8a;border-radius:50%;width:18px;height:18px;display:flex;align-items:center;justify-content:center;color:#fff}.left label{background-color:#2d7abe}.right label{background-color:#3b2dbe}audio-slider{width:90px}\n"] }]
5027
- }], ctorParameters: () => [{ type: AudioVisualizationService }, { type: GlobalKeyboardListenerService }, { type: KeyPressService }, { type: UtilsService }, { type: i1$4.AudioVisualConfiguration, decorators: [{
3811
+ }], ctorParameters: () => [{ type: AudioVisualizationService }, { type: i1$2.GlobalKeyboardListenerService }, { type: i1$2.KeyPressService }, { type: i1$2.UtilsService }, { type: i1$4.AudioVisualConfiguration, decorators: [{
5028
3812
  type: Inject,
5029
3813
  args: [SYSTEM_AUDIO_VISUAL_CONFIGURATION]
5030
3814
  }] }], propDecorators: { showVolumeSliders: [{
@@ -6062,31 +4846,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
6062
4846
  args: ['editor']
6063
4847
  }] } });
6064
4848
 
6065
- class AnswerNotesToTextChangesPipe {
6066
- transform(answerNotes) {
6067
- return answerNotes?.map(answerNote => ({
6068
- type: answerNote.type,
6069
- creatingUser: answerNote.creatingUser,
6070
- id: answerNote.id,
6071
- note: answerNote.note,
6072
- timeStamp: answerNote.timeStamp,
6073
- startOffset: answerNote.startIndex,
6074
- endOffset: answerNote.endIndex,
6075
- commentText: answerNote.commentText
6076
- }))
6077
- .sort((a, b) => new Date(a.startOffset).getTime() - new Date(b.startOffset).getTime());
6078
- }
6079
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AnswerNotesToTextChangesPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
6080
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.17", ngImport: i0, type: AnswerNotesToTextChangesPipe, isStandalone: false, name: "answerNotesToTextChanges" });
6081
- }
6082
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AnswerNotesToTextChangesPipe, decorators: [{
6083
- type: Pipe,
6084
- args: [{
6085
- standalone: false,
6086
- name: 'answerNotesToTextChanges'
6087
- }]
6088
- }] });
6089
-
6090
4849
  class QuizOpenAnswerQuestionComponent {
6091
4850
  answerNotesToTextChangesPipe;
6092
4851
  previewMode = false;
@@ -6122,13 +4881,13 @@ class QuizOpenAnswerQuestionComponent {
6122
4881
  this.destroySubject$.next(null);
6123
4882
  this.destroySubject$.complete();
6124
4883
  }
6125
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QuizOpenAnswerQuestionComponent, deps: [{ token: AnswerNotesToTextChangesPipe }], target: i0.ɵɵFactoryTarget.Component });
4884
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QuizOpenAnswerQuestionComponent, deps: [{ token: i4$1.AnswerNotesToTextChangesPipe }], target: i0.ɵɵFactoryTarget.Component });
6126
4885
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: QuizOpenAnswerQuestionComponent, isStandalone: false, selector: "quiz-open-answer-question", inputs: { previewMode: "previewMode", question: "question", userQuestion: "userQuestion", areAnswersRevealed: "areAnswersRevealed", areAnswersBlocked: "areAnswersBlocked", isCheckingMode: "isCheckingMode", selectedTextChange: "selectedTextChange" }, outputs: { freeTextCorrectAnswerChange: "freeTextCorrectAnswerChange", notesChange: "notesChange" }, usesOnChanges: true, ngImport: i0, template: "<span class=\"answer-title\">{{ isCheckingMode ? '\u05EA\u05E9\u05D5\u05D1\u05EA \u05D4\u05D7\u05E0\u05D9\u05DA' : '\u05DB\u05EA\u05D5\u05D1 \u05EA\u05E9\u05D5\u05D1\u05EA\u05DA' }}\r\n <span *ngIf=\"!isCheckingMode && question?.charactersLimit > 0\">\r\n (\u05E2\u05D3 {{ question?.charactersLimit }} \u05EA\u05D5\u05D5\u05D9\u05DD)\r\n </span>\r\n</span>\r\n\r\n<herum-text-area *ngIf=\"!areAnswersRevealed && !isCheckingMode\" [disabled]=\"previewMode || areAnswersBlocked\"\r\n [maxLength]=\"question?.charactersLimit\" [formControl]=\"freeTextCorrectAnswerControl\" heightMode=\"max\">\r\n</herum-text-area>\r\n\r\n<track-text-changes *ngIf=\"isCheckingMode || areAnswersRevealed\"\r\n [isReadOnly]=\"areAnswersRevealed && !isCheckingMode || !isCheckingMode\" [fontSize]=\"14\"\r\n [selectedChange]=\"selectedTextChange\" [showComments]=\"false\" [baseContent]=\"freeTextCorrectAnswerControl.value\"\r\n [changes]=\"notes\" (changesEmitter)=\"_notesChange($event)\">\r\n</track-text-changes>", styles: [".answer-title{font-size:14px;margin-block-end:8px}herum-text-area,track-text-changes{height:100%;width:100%}::ng-deep track-text-changes .editor-container{padding:0}::ng-deep track-text-changes .text-editor{min-height:180px;height:100%;width:100%}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: HerumTextAreaComponent, selector: "herum-text-area", inputs: ["placeholder", "disabled", "formControlName", "isValid", "isLoading", "errorMsg", "showErrorMsgGap", "id", "preventMacroKeysPressEvent", "heightMode", "fontSize", "inputValue", "maxLength"], outputs: ["inputValueEmitter"] }, { kind: "component", type: TrackTextChangesComponent, selector: "track-text-changes", inputs: ["changes", "selectedChange", "currentUser", "baseContent", "isReadOnly", "fontSize", "showComments"], outputs: ["changesEmitter"] }] });
6127
4886
  }
6128
4887
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QuizOpenAnswerQuestionComponent, decorators: [{
6129
4888
  type: Component,
6130
4889
  args: [{ standalone: false, selector: 'quiz-open-answer-question', template: "<span class=\"answer-title\">{{ isCheckingMode ? '\u05EA\u05E9\u05D5\u05D1\u05EA \u05D4\u05D7\u05E0\u05D9\u05DA' : '\u05DB\u05EA\u05D5\u05D1 \u05EA\u05E9\u05D5\u05D1\u05EA\u05DA' }}\r\n <span *ngIf=\"!isCheckingMode && question?.charactersLimit > 0\">\r\n (\u05E2\u05D3 {{ question?.charactersLimit }} \u05EA\u05D5\u05D5\u05D9\u05DD)\r\n </span>\r\n</span>\r\n\r\n<herum-text-area *ngIf=\"!areAnswersRevealed && !isCheckingMode\" [disabled]=\"previewMode || areAnswersBlocked\"\r\n [maxLength]=\"question?.charactersLimit\" [formControl]=\"freeTextCorrectAnswerControl\" heightMode=\"max\">\r\n</herum-text-area>\r\n\r\n<track-text-changes *ngIf=\"isCheckingMode || areAnswersRevealed\"\r\n [isReadOnly]=\"areAnswersRevealed && !isCheckingMode || !isCheckingMode\" [fontSize]=\"14\"\r\n [selectedChange]=\"selectedTextChange\" [showComments]=\"false\" [baseContent]=\"freeTextCorrectAnswerControl.value\"\r\n [changes]=\"notes\" (changesEmitter)=\"_notesChange($event)\">\r\n</track-text-changes>", styles: [".answer-title{font-size:14px;margin-block-end:8px}herum-text-area,track-text-changes{height:100%;width:100%}::ng-deep track-text-changes .editor-container{padding:0}::ng-deep track-text-changes .text-editor{min-height:180px;height:100%;width:100%}\n"] }]
6131
- }], ctorParameters: () => [{ type: AnswerNotesToTextChangesPipe }], propDecorators: { previewMode: [{
4890
+ }], ctorParameters: () => [{ type: i4$1.AnswerNotesToTextChangesPipe }], propDecorators: { previewMode: [{
6132
4891
  type: Input
6133
4892
  }], question: [{
6134
4893
  type: Input
@@ -6340,7 +5099,7 @@ class HerumFilesViewerDialogComponent {
6340
5099
  this.dialogRef.close(this.fileData);
6341
5100
  }
6342
5101
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: HerumFilesViewerDialogComponent, deps: [{ token: i1$6.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
6343
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: HerumFilesViewerDialogComponent, isStandalone: false, selector: "herum-files-viewer-dialog", ngImport: i0, template: "<herum-files-viewer [fileData]=\"fileData\" (downloadFile)=\"_downloadFile()\">\r\n</herum-files-viewer>", styles: ["::ng-deep .mat-mdc-dialog-container{padding:0!important;display:block}:host{height:100%;width:100%;display:flex}\n"], dependencies: [{ kind: "component", type: i2$5.HerumFilesViewerComponent, selector: "herum-files-viewer", inputs: ["fileData", "showDeleteFileButton"], outputs: ["downloadFile", "deleteFile"] }] });
5102
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: HerumFilesViewerDialogComponent, isStandalone: false, selector: "herum-files-viewer-dialog", ngImport: i0, template: "<herum-files-viewer [fileData]=\"fileData\" (downloadFile)=\"_downloadFile()\">\r\n</herum-files-viewer>", styles: ["::ng-deep .mat-mdc-dialog-container{padding:0!important;display:block}:host{height:100%;width:100%;display:flex}\n"], dependencies: [{ kind: "component", type: i2$4.HerumFilesViewerComponent, selector: "herum-files-viewer", inputs: ["fileData", "showDeleteFileButton"], outputs: ["downloadFile", "deleteFile"] }] });
6344
5103
  }
6345
5104
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: HerumFilesViewerDialogComponent, decorators: [{
6346
5105
  type: Component,
@@ -8469,6 +7228,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
8469
7228
  }]
8470
7229
  }] });
8471
7230
 
7231
+ class AnswerNotesToTextChangesPipe {
7232
+ transform(answerNotes) {
7233
+ return answerNotes?.map(answerNote => ({
7234
+ type: answerNote.type,
7235
+ creatingUser: answerNote.creatingUser,
7236
+ id: answerNote.id,
7237
+ note: answerNote.note,
7238
+ timeStamp: answerNote.timeStamp,
7239
+ startOffset: answerNote.startIndex,
7240
+ endOffset: answerNote.endIndex,
7241
+ commentText: answerNote.commentText
7242
+ }))
7243
+ .sort((a, b) => new Date(a.startOffset).getTime() - new Date(b.startOffset).getTime());
7244
+ }
7245
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AnswerNotesToTextChangesPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
7246
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.17", ngImport: i0, type: AnswerNotesToTextChangesPipe, isStandalone: false, name: "answerNotesToTextChanges" });
7247
+ }
7248
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AnswerNotesToTextChangesPipe, decorators: [{
7249
+ type: Pipe,
7250
+ args: [{
7251
+ standalone: false,
7252
+ name: 'answerNotesToTextChanges'
7253
+ }]
7254
+ }] });
7255
+
8472
7256
  class StringArrayToSignUpFieldArrayPipe {
8473
7257
  transform(fields) {
8474
7258
  if (!Array.isArray(fields))
@@ -10861,6 +9645,28 @@ const openClose = trigger('openClose', [
10861
9645
  ])
10862
9646
  ]);
10863
9647
 
9648
+ class HerumFormControl extends FormControl {
9649
+ errorMessages = {};
9650
+ currentErrorMessage = '';
9651
+ destroySubject$ = new Subject();
9652
+ /**
9653
+ @comment The component that creates this class should have destroySubject$ so you can listen to its ngOnDestroy life cycle hook so you can unsubscribe statusChangesSubscription
9654
+ */
9655
+ constructor(formState, validatorOrOpts, asyncValidator, errorMessages, componentReference) {
9656
+ super(formState, validatorOrOpts, asyncValidator);
9657
+ if (errorMessages)
9658
+ this.errorMessages = errorMessages;
9659
+ this.statusChanges.pipe(takeUntil(this.destroySubject$)).subscribe(() => this.setCurrentErrorMessage());
9660
+ componentReference.destroySubject$.pipe(takeUntil(this.destroySubject$)).subscribe(() => {
9661
+ this.destroySubject$.next(null);
9662
+ this.destroySubject$.complete();
9663
+ });
9664
+ }
9665
+ setCurrentErrorMessage() {
9666
+ this.currentErrorMessage = this.errors ? this.errorMessages[Object.keys(this.errors)[0]] : null;
9667
+ }
9668
+ }
9669
+
10864
9670
  const suffixStorageKey = 'FETCHED_MESSAGE_HAS_SHOWN';
10865
9671
  class FetchedMessageService {
10866
9672
  http;