@touchpoll/tp-survey 0.0.48 → 0.0.50

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.
@@ -199,21 +199,28 @@ const answerSSValidator = () => (control) => {
199
199
  //ошибок нет, всё корректно
200
200
  return null;
201
201
  };
202
- const answerMSValidator = (visibleAlternativeCount, minCount = 1, maxCount = 0) => (control) => {
203
- //visibleAlternativeCount - количество альтернатив на экране, если 0, то смысла показывать вопрос нет
202
+ const answerMSValidator = (visibleAlternativeList, minCount = 1, maxCount = 0) => (control) => {
203
+ //visibleAlternativeList - альтернативы на экране, если их 0, то смысла показывать вопрос нет
204
204
  //minCount - Минимальное количество ответов, которое может выбрать респондент, по умолчанию 1.
205
205
  //maxCount - Максимальное количество ответов, которые может выбрать респондент. Если указано 0, количество не ограничено. По умолчанию 0
206
- if (visibleAlternativeCount === 0) {
206
+ if (visibleAlternativeList.length === 0) {
207
207
  return null;
208
208
  }
209
209
  //ответ не массив, такого быть не может, это ошибка
210
210
  if (!Array.isArray(control.value)) {
211
211
  return { answerMsAnswerType: true };
212
212
  }
213
+ //Проблема минимального количества ответов - если доступных на экране альтернатив меньше, чем настройка "минимальное количество ответов", то это нужно учитывать.
214
+ //Поэтому вычисляем минимально возможное количество ответов, которое может выбрать респондент и если оно меньше значения из настроек, возьмем его.
215
+ let minPossibleCount = minCount;
216
+ if (control.value.length > 0) {
217
+ const currentAlternativeGroup = visibleAlternativeList.find(alternative => alternative.Value === control.value[0])?.GroupNo ?? 1;
218
+ minPossibleCount = Math.min(visibleAlternativeList.filter(alternative => alternative.GroupNo === currentAlternativeGroup).length, minCount);
219
+ }
213
220
  //количество ответов
214
221
  const count = control.value.length;
215
222
  //проверяем minCount
216
- if (count < minCount) {
223
+ if (count < minPossibleCount) {
217
224
  return { answerMsMinCount: true };
218
225
  }
219
226
  //проверяем maxCount
@@ -546,7 +553,6 @@ class AlternativesContainerDirective {
546
553
  const deltaHorizontal = (containerWidthFull - width * columnCount - horizontalDistance * (columnCount - 1)) / 2 - defaultHorizontalPadding;
547
554
  let rowNum = -1;
548
555
  let colNum = 0;
549
- console.log(containerHeightFull, height * rowCount, verticalDistance, (rowCount - 1));
550
556
  alternatives.forEach((alt, index) => {
551
557
  let left = 0;
552
558
  let top = 0;
@@ -954,7 +960,7 @@ class AnswerOLComponent extends AnswerMasterComponent {
954
960
  useExisting: forwardRef(() => AnswerOLComponent),
955
961
  multi: true
956
962
  },
957
- ], usesInheritance: true, ngImport: i0, template: "<div class=\"container-main\">\r\n @if (telephoneInput()) {\r\n <mat-form-field appearance=\"outline\">\r\n <input\r\n type=\"text\"\r\n inputmode=\"numeric\"\r\n matInput\r\n [formControl]=\"control\" tpSurveyFocusAndSelect>\r\n <span matTextPrefix>+380 &nbsp;</span>\r\n </mat-form-field>\r\n @if(canSkip()) {\r\n <button mat-button (click)=\"skipClick()\">\u041F\u0440\u043E\u043F\u0443\u0441\u0442\u0438\u0442\u0438</button>\r\n }\r\n\r\n } @else {\r\n <mat-form-field appearance=\"outline\" class=\"input-text\">\r\n <textarea rows=\"10\" matInput [formControl]=\"control\" tpSurveyFocusAndSelect></textarea>\r\n </mat-form-field>\r\n\r\n<!-- <mat-form-field class=\"container-controls\" appearance=\"outline\">-->\r\n<!-- <textarea rows=\"10\" autofocus matInput [(ngModel)]=\"answer.AnswerValue\" (ngModelChange)=\"answerChange()\" appFocusAndSelect></textarea>-->\r\n<!-- </mat-form-field>-->\r\n }\r\n\r\n<!-- <mat-form-field appearance=\"outline\" class=\"input-od-number\">-->\r\n<!-- <input [formControl]=\"control\" tpSurveyFocusAndSelect matInput type=\"number\">-->\r\n<!-- </mat-form-field>-->\r\n</div>\r\n", styles: [":host{width:100%}.container-main{display:flex;width:100%;justify-content:center;align-items:center;flex-flow:column;gap:2em;padding:0 2em;box-sizing:border-box}.input-text{width:100%}\n"], dependencies: [{ kind: "directive", type: FocusAndSelectDirective, selector: "[tpSurveyFocusAndSelect]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }] }); }
963
+ ], usesInheritance: true, ngImport: i0, template: "<div class=\"container-main\">\r\n @if (telephoneInput()) {\r\n <mat-form-field appearance=\"outline\">\r\n <input\r\n type=\"text\"\r\n inputmode=\"numeric\"\r\n matInput\r\n [formControl]=\"control\" tpSurveyFocusAndSelect>\r\n <span matTextPrefix>+380 &nbsp;</span>\r\n </mat-form-field>\r\n @if(canSkip()) {\r\n <button mat-button (click)=\"skipClick()\">\u041F\u0440\u043E\u043F\u0443\u0441\u0442\u0438\u0442\u0438</button>\r\n }\r\n\r\n } @else {\r\n <mat-form-field appearance=\"outline\" class=\"input-text\">\r\n <textarea rows=\"10\" matInput [formControl]=\"control\" tpSurveyFocusAndSelect></textarea>\r\n </mat-form-field>\r\n }\r\n</div>\r\n", styles: [":host{width:100%}.container-main{display:flex;width:100%;justify-content:center;align-items:center;flex-flow:column;gap:2em;padding:0 2em;box-sizing:border-box}.input-text{width:100%}\n"], dependencies: [{ kind: "directive", type: FocusAndSelectDirective, selector: "[tpSurveyFocusAndSelect]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }] }); }
958
964
  }
959
965
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AnswerOLComponent, decorators: [{
960
966
  type: Component,
@@ -972,7 +978,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
972
978
  useExisting: forwardRef(() => AnswerOLComponent),
973
979
  multi: true
974
980
  },
975
- ], template: "<div class=\"container-main\">\r\n @if (telephoneInput()) {\r\n <mat-form-field appearance=\"outline\">\r\n <input\r\n type=\"text\"\r\n inputmode=\"numeric\"\r\n matInput\r\n [formControl]=\"control\" tpSurveyFocusAndSelect>\r\n <span matTextPrefix>+380 &nbsp;</span>\r\n </mat-form-field>\r\n @if(canSkip()) {\r\n <button mat-button (click)=\"skipClick()\">\u041F\u0440\u043E\u043F\u0443\u0441\u0442\u0438\u0442\u0438</button>\r\n }\r\n\r\n } @else {\r\n <mat-form-field appearance=\"outline\" class=\"input-text\">\r\n <textarea rows=\"10\" matInput [formControl]=\"control\" tpSurveyFocusAndSelect></textarea>\r\n </mat-form-field>\r\n\r\n<!-- <mat-form-field class=\"container-controls\" appearance=\"outline\">-->\r\n<!-- <textarea rows=\"10\" autofocus matInput [(ngModel)]=\"answer.AnswerValue\" (ngModelChange)=\"answerChange()\" appFocusAndSelect></textarea>-->\r\n<!-- </mat-form-field>-->\r\n }\r\n\r\n<!-- <mat-form-field appearance=\"outline\" class=\"input-od-number\">-->\r\n<!-- <input [formControl]=\"control\" tpSurveyFocusAndSelect matInput type=\"number\">-->\r\n<!-- </mat-form-field>-->\r\n</div>\r\n", styles: [":host{width:100%}.container-main{display:flex;width:100%;justify-content:center;align-items:center;flex-flow:column;gap:2em;padding:0 2em;box-sizing:border-box}.input-text{width:100%}\n"] }]
981
+ ], template: "<div class=\"container-main\">\r\n @if (telephoneInput()) {\r\n <mat-form-field appearance=\"outline\">\r\n <input\r\n type=\"text\"\r\n inputmode=\"numeric\"\r\n matInput\r\n [formControl]=\"control\" tpSurveyFocusAndSelect>\r\n <span matTextPrefix>+380 &nbsp;</span>\r\n </mat-form-field>\r\n @if(canSkip()) {\r\n <button mat-button (click)=\"skipClick()\">\u041F\u0440\u043E\u043F\u0443\u0441\u0442\u0438\u0442\u0438</button>\r\n }\r\n\r\n } @else {\r\n <mat-form-field appearance=\"outline\" class=\"input-text\">\r\n <textarea rows=\"10\" matInput [formControl]=\"control\" tpSurveyFocusAndSelect></textarea>\r\n </mat-form-field>\r\n }\r\n</div>\r\n", styles: [":host{width:100%}.container-main{display:flex;width:100%;justify-content:center;align-items:center;flex-flow:column;gap:2em;padding:0 2em;box-sizing:border-box}.input-text{width:100%}\n"] }]
976
982
  }] });
977
983
 
978
984
  class AsFormArrayPipe {
@@ -1298,7 +1304,7 @@ class ContainerAnswerComponent {
1298
1304
  break;
1299
1305
  }
1300
1306
  case QuestionsType.eqMS: {
1301
- this.answerForm.controls.answer.addValidators(answerMSValidator(this.visibleAlternativeList().length, this.question().AlternativeMinAnswersCount, this.question().AlternativeMaxAnswersCount));
1307
+ this.answerForm.controls.answer.addValidators(answerMSValidator(this.visibleAlternativeList(), this.question().AlternativeMinAnswersCount, this.question().AlternativeMaxAnswersCount));
1302
1308
  break;
1303
1309
  }
1304
1310
  case QuestionsType.eqOD: {
@@ -1813,8 +1819,8 @@ class TpSurveyCoreService {
1813
1819
  if (!currentQuestion) {
1814
1820
  return;
1815
1821
  }
1816
- //если ответ на текущий вопрос не закончен, выходим
1817
- if (!this._interview.questionIsComplete(currentQuestion.QuestionGuid)) {
1822
+ //если ответ на текущий вопрос не закончен И опция пропуска вопроса не активна, выходим
1823
+ if (!this._interview.questionIsComplete(currentQuestion.QuestionGuid) && !currentQuestion.CanSkip) {
1818
1824
  return;
1819
1825
  }
1820
1826
  //если указан PostScript, выполним его
@@ -2475,7 +2481,9 @@ class SurveyPlayComponent {
2475
2481
  * кнопка далее нужно проверять при показе вопроса и при изменении ответа. При показе она может быть доступна сразу(например info).
2476
2482
  * Кнопка доступна если ответ корректно заполнен(questionIsComplete) и это не eqEND вопрос
2477
2483
  * */
2478
- this.nextButtonAvailable = toSignal(merge(this.#core.on(SurveyEvents.seQuestionAnswersChange).pipe(map(data => data.question)), this.#core.on(SurveyEvents.seQuestionShow).pipe(map(data => data))).pipe(map(question => this.#core.questionIsComplete(question.QuestionGuid) && question.QuestionType !== QuestionsType.eqEND && question.QuestionType !== QuestionsType.eqLANG), delay(1)), { initialValue: false });
2484
+ this.nextButtonAvailable = toSignal(merge(this.#core.on(SurveyEvents.seQuestionAnswersChange).pipe(map(data => data.question)), this.#core.on(SurveyEvents.seQuestionShow).pipe(map(data => data))).pipe(
2485
+ //вопрос должен быть не eqEND и не eqLANG(для них кнопки далее быть не должно) + вопрос должен быть заполнен или его можно пропустить(указано в настройках)
2486
+ map(question => !([QuestionsType.eqEND, QuestionsType.eqLANG].includes(question.QuestionType)) && (this.#core.questionIsComplete(question.QuestionGuid) || question.CanSkip)), delay(1)), { initialValue: false });
2479
2487
  //кнопку Назад можно показывать если в настройках указали ShowBtnBack и это не eqEND вопрос
2480
2488
  this.backButtonAvailable = toSignal(this.#core.on(SurveyEvents.seQuestionShow).pipe(filter(question => !!question), map((question) => question.QuestionNum > 1 && question.ShowBtnBack && question.QuestionType !== QuestionsType.eqEND && question.QuestionType !== QuestionsType.eqLANG), delay(1)));
2481
2489
  this.#core.on(SurveyEvents.seSurveyEnd).pipe(takeUntilDestroyed(this.#destroyRef)).subscribe({