herum-shared 0.1.34 → 0.1.36

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 {
@@ -1822,12 +1818,15 @@ class HerumInputFieldComponent {
1822
1818
  })).subscribe();
1823
1819
  }
1824
1820
  setInputsByFormControl() {
1825
- console.log(this.ngControl);
1826
1821
  if (!this.ngControl)
1827
1822
  return;
1828
1823
  if (this.ngControl instanceof FormControlName)
1829
1824
  this.formControlName = this.ngControl.name?.toString() || '';
1830
1825
  this.ngControl.control.statusChanges.pipe(takeUntil(this.destroySubject$)).subscribe(status => {
1826
+ console.log(Reflect.getPrototypeOf(this.ngControl.control));
1827
+ console.log(Reflect.getPrototypeOf(this.ngControl.control) === HerumFormControl.prototype);
1828
+ console.log(Reflect.getPrototypeOf(this.ngControl.control) === HerumFormControl);
1829
+ console.log(this.ngControl.control.constructor.name === HerumFormControl.prototype.constructor.name);
1831
1830
  if (this.ngControl.control instanceof HerumFormControl)
1832
1831
  this.errorMsg = this.ngControl.control.currentErrorMessage;
1833
1832
  const controlStatus = this.ngControl.control.status;
@@ -3359,1196 +3358,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
3359
3358
  args: [SYSTEM_AUDIO_VISUAL_CONFIGURATION]
3360
3359
  }] }] });
3361
3360
 
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
3361
  const unwantedSelectors = ["div", null];
4553
3362
  class UserActionDirective {
4554
3363
  el;
@@ -5018,13 +3827,13 @@ class AudioPlayerComponent {
5018
3827
  this.pauseAudio();
5019
3828
  this.removeAudioElementEventListeners();
5020
3829
  }
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 });
3830
+ 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
3831
  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
3832
  }
5024
3833
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AudioPlayerComponent, decorators: [{
5025
3834
  type: Component,
5026
3835
  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: [{
3836
+ }], ctorParameters: () => [{ type: AudioVisualizationService }, { type: i1$2.GlobalKeyboardListenerService }, { type: i1$2.KeyPressService }, { type: i1$2.UtilsService }, { type: i1$4.AudioVisualConfiguration, decorators: [{
5028
3837
  type: Inject,
5029
3838
  args: [SYSTEM_AUDIO_VISUAL_CONFIGURATION]
5030
3839
  }] }], propDecorators: { showVolumeSliders: [{
@@ -6062,31 +4871,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
6062
4871
  args: ['editor']
6063
4872
  }] } });
6064
4873
 
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
4874
  class QuizOpenAnswerQuestionComponent {
6091
4875
  answerNotesToTextChangesPipe;
6092
4876
  previewMode = false;
@@ -6122,13 +4906,13 @@ class QuizOpenAnswerQuestionComponent {
6122
4906
  this.destroySubject$.next(null);
6123
4907
  this.destroySubject$.complete();
6124
4908
  }
6125
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QuizOpenAnswerQuestionComponent, deps: [{ token: AnswerNotesToTextChangesPipe }], target: i0.ɵɵFactoryTarget.Component });
4909
+ 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
4910
  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
4911
  }
6128
4912
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: QuizOpenAnswerQuestionComponent, decorators: [{
6129
4913
  type: Component,
6130
4914
  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: [{
4915
+ }], ctorParameters: () => [{ type: i4$1.AnswerNotesToTextChangesPipe }], propDecorators: { previewMode: [{
6132
4916
  type: Input
6133
4917
  }], question: [{
6134
4918
  type: Input
@@ -6340,7 +5124,7 @@ class HerumFilesViewerDialogComponent {
6340
5124
  this.dialogRef.close(this.fileData);
6341
5125
  }
6342
5126
  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"] }] });
5127
+ 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
5128
  }
6345
5129
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: HerumFilesViewerDialogComponent, decorators: [{
6346
5130
  type: Component,
@@ -8469,6 +7253,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
8469
7253
  }]
8470
7254
  }] });
8471
7255
 
7256
+ class AnswerNotesToTextChangesPipe {
7257
+ transform(answerNotes) {
7258
+ return answerNotes?.map(answerNote => ({
7259
+ type: answerNote.type,
7260
+ creatingUser: answerNote.creatingUser,
7261
+ id: answerNote.id,
7262
+ note: answerNote.note,
7263
+ timeStamp: answerNote.timeStamp,
7264
+ startOffset: answerNote.startIndex,
7265
+ endOffset: answerNote.endIndex,
7266
+ commentText: answerNote.commentText
7267
+ }))
7268
+ .sort((a, b) => new Date(a.startOffset).getTime() - new Date(b.startOffset).getTime());
7269
+ }
7270
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AnswerNotesToTextChangesPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
7271
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.17", ngImport: i0, type: AnswerNotesToTextChangesPipe, isStandalone: false, name: "answerNotesToTextChanges" });
7272
+ }
7273
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AnswerNotesToTextChangesPipe, decorators: [{
7274
+ type: Pipe,
7275
+ args: [{
7276
+ standalone: false,
7277
+ name: 'answerNotesToTextChanges'
7278
+ }]
7279
+ }] });
7280
+
8472
7281
  class StringArrayToSignUpFieldArrayPipe {
8473
7282
  transform(fields) {
8474
7283
  if (!Array.isArray(fields))