diff --git a/docs/release-notes-editor.txt b/docs/release-notes-editor.txt index 6a8d41bc9fb18f2987e7a24cf2a34f71d104c24e..0226e5131caaca30a2d0ec3fa0077094b9062e90 100644 --- a/docs/release-notes-editor.txt +++ b/docs/release-notes-editor.txt @@ -13,6 +13,9 @@ Editor - Ermöglicht die Darstellung eines optionalen Tastatursymbols bei Eingabefeldern und -bereichen - Erlaubt Validierungen ohne Warnmeldungen Warnmeldungen können nun ohne Zeichenketten abgespeichert werden. +- Ermöglicht die Definition eigener Zeichen für die Eingabehilfe + Durch Auswahl der Option "Eigene Zeichen" öffnet sich ein Textfeld, + in das die gewünschten Zeichen als ein Wort eingegeben werden. 1.34.0 - Implement GeoGebra applet element diff --git a/docs/release-notes-player.txt b/docs/release-notes-player.txt index e83b58e06e2af03afe771f9c23c72f1e8639b099..2f2819f6c54a3ffea5ced4dfe8a0888ff8720dfe 100644 --- a/docs/release-notes-player.txt +++ b/docs/release-notes-player.txt @@ -10,6 +10,8 @@ Player werden nach erster Benutzung der Elemente ausgeblendet - Verbessert die Performanz von GeoGebra-Elementen - Zeigt Validierungsfehler ohne angegebene Warnmeldungen nur mit rotem Rahmen an +- Die Eingabehilfe "Eigene Zeichen" nutzt weitestgehend das Layout + der Eingabehilfe "Französische Sonderzeichen" 1.27.0 - Add new input assistance presets ('Space' and 'Comma'). diff --git a/docs/unit_definition_changelog.txt b/docs/unit_definition_changelog.txt index 17f3a3777f3be9d733530f345ed58b1968a78735..c7320369c99cf85f82983feee558e47a54fa486e 100644 --- a/docs/unit_definition_changelog.txt +++ b/docs/unit_definition_changelog.txt @@ -52,3 +52,5 @@ iqb-aspect-definition@1.0.0 +expectedCharactersCount: number; +hasKeyboardIcon: boolean; - TextFieldElement: +hasKeyboardIcon: boolean; +- TextFieldElement/TextFieldSimpleElement/SpellCorrectElement/TextAreaElement: InputAssistancePreset +'custom' + +inputAssistanceCustomKeys: string; diff --git a/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/text-field-simple.ts b/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/text-field-simple.ts index a24b51a7f101c961bb1935be4e6d898a2b778a0d..7d5ff006917452646e320931ccd5d17cf1488f14 100644 --- a/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/text-field-simple.ts +++ b/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/text-field-simple.ts @@ -15,6 +15,7 @@ export class TextFieldSimpleElement extends InputElement { pattern: string | null = null; patternWarnMessage: string = 'Eingabe entspricht nicht der Vorgabe'; inputAssistancePreset: InputAssistancePreset = null; + inputAssistanceCustomKeys: string = ''; inputAssistancePosition: 'floating' | 'right' = 'floating'; restrictedToInputAssistanceChars: boolean = true; hasArrowKeys: boolean = false; @@ -34,6 +35,9 @@ export class TextFieldSimpleElement extends InputElement { if (element.pattern) this.pattern = element.pattern; if (element.patternWarnMessage !== undefined) this.patternWarnMessage = element.patternWarnMessage; if (element.inputAssistancePreset) this.inputAssistancePreset = element.inputAssistancePreset; + if (element.inputAssistanceCustomKeys !== undefined) { + this.inputAssistanceCustomKeys = element.inputAssistanceCustomKeys; + } if (element.inputAssistancePosition) this.inputAssistancePosition = element.inputAssistancePosition; if (element.restrictedToInputAssistanceChars !== undefined) { this.restrictedToInputAssistanceChars = element.restrictedToInputAssistanceChars; diff --git a/projects/common/models/elements/element.ts b/projects/common/models/elements/element.ts index d883aca9b32c924be7bf4e99f65f55b71261ed73..35f1959522ff1be7a1baccf02504ec6712a2f794 100644 --- a/projects/common/models/elements/element.ts +++ b/projects/common/models/elements/element.ts @@ -13,7 +13,7 @@ TextLabel | TextLabel[] | ClozeDocument | LikertRowElement[] | Hotspot[] | PositionProperties | PlayerProperties | BasicStyles; export type InputAssistancePreset = null | 'french' | 'numbers' | 'numbersAndOperators' | 'numbersAndBasicOperators' -| 'comparisonOperators' | 'squareDashDot' | 'placeValue' | 'space' | 'comma'; +| 'comparisonOperators' | 'squareDashDot' | 'placeValue' | 'space' | 'comma' | 'custom'; export abstract class UIElement { [index: string]: unknown; diff --git a/projects/common/models/elements/input-elements/spell-correct.ts b/projects/common/models/elements/input-elements/spell-correct.ts index 9f687bb99bd5f201b247d4d5eb0d3da01ef0f556..e635cb99552b002d1b97706598acb955e351c7ba 100644 --- a/projects/common/models/elements/input-elements/spell-correct.ts +++ b/projects/common/models/elements/input-elements/spell-correct.ts @@ -11,6 +11,7 @@ import { SpellCorrectComponent } from 'common/components/input-elements/spell-co export class SpellCorrectElement extends InputElement implements PositionedUIElement { inputAssistancePreset: InputAssistancePreset = null; + inputAssistanceCustomKeys: string = ''; inputAssistancePosition: 'floating' | 'right' = 'floating'; restrictedToInputAssistanceChars: boolean = true; hasArrowKeys: boolean = false; @@ -22,6 +23,9 @@ export class SpellCorrectElement extends InputElement implements PositionedUIEle constructor(element: Partial<SpellCorrectElement>) { super({ width: 230, height: 80, ...element }); if (element.inputAssistancePreset) this.inputAssistancePreset = element.inputAssistancePreset; + if (element.inputAssistanceCustomKeys !== undefined) { + this.inputAssistanceCustomKeys = element.inputAssistanceCustomKeys; + } if (element.inputAssistancePosition) this.inputAssistancePosition = element.inputAssistancePosition; if (element.restrictedToInputAssistanceChars !== undefined) { this.restrictedToInputAssistanceChars = element.restrictedToInputAssistanceChars; diff --git a/projects/common/models/elements/input-elements/text-area.ts b/projects/common/models/elements/input-elements/text-area.ts index c29c0f3826bb2282a1bebcde46dbcd2cd6a42bb0..dc74f4198d35d1d5a7a2eb74a8921df6986c5a25 100644 --- a/projects/common/models/elements/input-elements/text-area.ts +++ b/projects/common/models/elements/input-elements/text-area.ts @@ -16,6 +16,7 @@ export class TextAreaElement extends InputElement implements PositionedUIElement rowCount: number = 3; expectedCharactersCount: number = 300; inputAssistancePreset: InputAssistancePreset = null; + inputAssistanceCustomKeys: string = ''; inputAssistancePosition: 'floating' | 'right' = 'floating'; hasArrowKeys: boolean = false; hasReturnKey: boolean = false; @@ -36,6 +37,9 @@ export class TextAreaElement extends InputElement implements PositionedUIElement if (element.hasDynamicRowCount) this.hasDynamicRowCount = element.hasDynamicRowCount; if (element.expectedCharactersCount) this.expectedCharactersCount = element.expectedCharactersCount; if (element.inputAssistancePreset) this.inputAssistancePreset = element.inputAssistancePreset; + if (element.inputAssistanceCustomKeys !== undefined) { + this.inputAssistanceCustomKeys = element.inputAssistanceCustomKeys; + } if (element.inputAssistancePosition) this.inputAssistancePosition = element.inputAssistancePosition; if (element.restrictedToInputAssistanceChars !== undefined) { this.restrictedToInputAssistanceChars = element.restrictedToInputAssistanceChars; diff --git a/projects/common/models/elements/input-elements/text-field.ts b/projects/common/models/elements/input-elements/text-field.ts index c6e1750c0ad147fc210e6e911254533eb4bed103..e9ed44c084a4547915d98ce25a0bb4d5f6fe4fff 100644 --- a/projects/common/models/elements/input-elements/text-field.ts +++ b/projects/common/models/elements/input-elements/text-field.ts @@ -15,6 +15,7 @@ export class TextFieldElement extends InputElement implements PositionedUIElemen pattern: string | null = null; patternWarnMessage: string = 'Eingabe entspricht nicht der Vorgabe'; inputAssistancePreset: InputAssistancePreset = null; + inputAssistanceCustomKeys: string = ''; inputAssistancePosition: 'floating' | 'right' = 'floating'; restrictedToInputAssistanceChars: boolean = true; hasArrowKeys: boolean = false; @@ -37,6 +38,9 @@ export class TextFieldElement extends InputElement implements PositionedUIElemen if (element.pattern !== undefined) this.pattern = element.pattern; if (element.patternWarnMessage !== undefined) this.patternWarnMessage = element.patternWarnMessage; if (element.inputAssistancePreset) this.inputAssistancePreset = element.inputAssistancePreset; + if (element.inputAssistanceCustomKeys !== undefined) { + this.inputAssistanceCustomKeys = element.inputAssistanceCustomKeys; + } if (element.inputAssistancePosition) this.inputAssistancePosition = element.inputAssistancePosition; if (element.restrictedToInputAssistanceChars !== undefined) { this.restrictedToInputAssistanceChars = element.restrictedToInputAssistanceChars; diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-field-element-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-field-element-properties.component.ts index 28cdb0a99b28116ae2c1789467f617ac0e6aee5c..018a2616332f5272aa45834adb2bba8272200566 100644 --- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-field-element-properties.component.ts +++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-field-element-properties.component.ts @@ -102,12 +102,21 @@ import { CombinedProperties } from 'editor/src/app/components/properties-panel/e <mat-select [value]="combinedProperties.inputAssistancePreset" (selectionChange)="updateModel.emit({ property: 'inputAssistancePreset', value: $event.value })"> <mat-option *ngFor="let option of [null, 'french', 'numbers', 'numbersAndOperators', 'numbersAndBasicOperators', - 'comparisonOperators', 'squareDashDot', 'placeValue', 'space', 'comma']" + 'comparisonOperators', 'squareDashDot', 'placeValue', 'space', 'comma', 'custom']" [value]="option"> {{ option === null ? ('propertiesPanel.none' | translate) : ('propertiesPanel.' + option | translate) }} </mat-option> </mat-select> </mat-form-field> + + <mat-form-field *ngIf="combinedProperties.inputAssistancePreset === 'custom'" + class="wide-form-field" appearance="fill"> + <mat-label>{{'propertiesPanel.inputAssistanceCustomKeys' | translate }}</mat-label> + <input matInput type="text" + [value]="$any(combinedProperties.inputAssistanceCustomKeys)" + (input)="updateModel.emit({ property: 'inputAssistanceCustomKeys', value: $any($event.target).value })"> + </mat-form-field> + <mat-form-field *ngIf="combinedProperties.inputAssistancePreset !== null && combinedProperties.inputAssistancePosition !== undefined" appearance="fill"> diff --git a/projects/editor/src/assets/i18n/de.json b/projects/editor/src/assets/i18n/de.json index bd37edc0cac3e00edcbdac946a27ef0963a5ef83..387202ddf1298480438dd64787bfb3823b857018 100644 --- a/projects/editor/src/assets/i18n/de.json +++ b/projects/editor/src/assets/i18n/de.json @@ -133,6 +133,8 @@ "squareDashDot": "Quadrat Strich Punkt", "placeValue": "Stellenwert", "comparisonOperators": "Vergleichsoperatoren", + "custom": "Eigene Zeichen", + "inputAssistanceCustomKeys": "Zeichenkette", "inputAssistancePosition": "Eingabehilfeposition", "floating": "schwebend", "showSoftwareKeyboard": "Tastatur einblenden", diff --git a/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.css b/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.css index ae36ce96808fa2a683f40f959df72114b235eda8..9953287e4888ace49df40e91ec935f0656081cc9 100644 --- a/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.css +++ b/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.css @@ -3,6 +3,10 @@ margin: auto; } +.floating-row-container { + max-width: 354px; +} + .grid-layout { justify-content: center; margin-top: 15px; diff --git a/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.html b/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.html index ac09adb3659d3fe99ffc65d25bcab5a9d0011e68..3698e6a63920d3b256624e9f4a18f959c98e8459 100644 --- a/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.html +++ b/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.html @@ -1,4 +1,5 @@ -<div [class.fixed-row-container]="position === 'right' && preset === 'french'"> +<div [class.fixed-row-container]="position === 'right' && ( preset === 'french' || preset === 'custom' )" + [class.floating-row-container]="position === 'floating'"> <div *ngFor="let row of rows; let last = last"> <ng-container *ngFor="let key of row; let index = index; let lastRowKey = last"> <aspect-keypad-key diff --git a/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.ts b/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.ts index c9e9f569c8a941f42b1602e189829904926a6b0e..87f3fb53ba12676520636c24fb8a2c660c4067a1 100644 --- a/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.ts +++ b/projects/player/modules/key-input/components/keypad-layout/keypad-layout.component.ts @@ -3,7 +3,7 @@ import { } from '@angular/core'; import { InputAssistancePreset } from 'common/models/elements/element'; import { KeyInputRestrictionDirective } from '../../directives/key-input-restriction.directive'; -import { KeyLayout } from '../../configs/key-layout'; +import { KeyInputLayout } from '../../configs/key-layout'; @Component({ selector: 'aspect-keypad-layout', @@ -12,6 +12,7 @@ import { KeyLayout } from '../../configs/key-layout'; }) export class KeypadLayoutComponent extends KeyInputRestrictionDirective implements OnInit { @Input() preset!: InputAssistancePreset; + @Input() layout!: KeyInputLayout; @Input() position!: 'floating' | 'right'; @Output() keyClicked = new EventEmitter<string>(); @@ -21,8 +22,8 @@ export class KeypadLayoutComponent extends KeyInputRestrictionDirective implemen shift: boolean = false; ngOnInit(): void { - this.rows = KeyLayout.get(this.preset).default; - this.additionalRows = KeyLayout.get(this.preset).additional; + this.rows = this.layout.default; + this.additionalRows = this.layout.additional; this.allowedKeys = [ ...this.rows.flat().filter(key => key.length === 1), ...this.additionalRows.flat().filter(key => key.length === 1) @@ -45,6 +46,6 @@ export class KeypadLayoutComponent extends KeyInputRestrictionDirective implemen toggleShift(): void { this.shift = !this.shift; - this.rows = this.shift ? KeyLayout.get(this.preset).shift : KeyLayout.get(this.preset).default; + this.rows = this.shift ? this.layout.shift : this.layout.default; } } diff --git a/projects/player/modules/key-input/components/keypad/keypad.component.html b/projects/player/modules/key-input/components/keypad/keypad.component.html index c8bb4b239a78f9156a332fe5159eaadb9044ea6f..17febc138b5e4deb91089d292161bd3ffc40236d 100644 --- a/projects/player/modules/key-input/components/keypad/keypad.component.html +++ b/projects/player/modules/key-input/components/keypad/keypad.component.html @@ -10,6 +10,7 @@ <aspect-keypad-layout [inputElement]="inputElement" [preset]="preset" + [layout]="layout" [position]="position" [restrictToAllowedKeys]="restrictToAllowedKeys" [hasArrowKeys]="hasArrowKeys" diff --git a/projects/player/modules/key-input/components/keypad/keypad.component.ts b/projects/player/modules/key-input/components/keypad/keypad.component.ts index c9d62b232b5c7f024a07fcf0148729bc581293ad..09b7677efeffb48c27e425b9cc80d1055c10eb8a 100644 --- a/projects/player/modules/key-input/components/keypad/keypad.component.ts +++ b/projects/player/modules/key-input/components/keypad/keypad.component.ts @@ -1,15 +1,17 @@ import { - Component, EventEmitter, Input, Output + Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { InputAssistancePreset } from 'common/models/elements/element'; +import { KeyInputLayout, KeyLayout } from 'player/modules/key-input/configs/key-layout'; @Component({ selector: 'aspect-keypad', templateUrl: './keypad.component.html', styleUrls: ['./keypad.component.css'] }) -export class KeypadComponent { +export class KeypadComponent implements OnInit { @Input() preset!: InputAssistancePreset; + @Input() customKeys!: string; @Input() position!: 'floating' | 'right'; @Input() inputElement!: HTMLTextAreaElement | HTMLInputElement; @Input() positionOffset!: number; @@ -21,6 +23,11 @@ export class KeypadComponent { @Output() keyClicked = new EventEmitter<string>(); arrows: string[] = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; + layout: KeyInputLayout = { default: [], shift: [], additional: [] }; + + ngOnInit(): void { + this.layout = KeyLayout.get(this.preset, this.customKeys); + } evaluateClickedKeyValue(key: string): void { if (this.arrows.includes(key)) { diff --git a/projects/player/modules/key-input/configs/key-layout.ts b/projects/player/modules/key-input/configs/key-layout.ts index b26e660b9efb73c7b25640c8cfadfce4b71acec5..06430e0fb43b6569d970820c1f28a6319d6cdda4 100644 --- a/projects/player/modules/key-input/configs/key-layout.ts +++ b/projects/player/modules/key-input/configs/key-layout.ts @@ -1,11 +1,13 @@ import { InputAssistancePreset } from 'common/models/elements/element'; +export interface KeyInputLayout { + default: string[][], + shift: string[][], + additional: string[][] +} + export class KeyLayout { - static get = (preset: InputAssistancePreset | 'keyboard'): { - default: string[][], - shift: string[][], - additional: string[][] - } => { + static get = (preset: InputAssistancePreset | 'keyboard', customKeys: string = ''): KeyInputLayout => { switch (preset) { case 'french': { return { @@ -112,7 +114,7 @@ export class KeyLayout { additional: [[]] }; } - default: { // keyboard + case 'keyboard': { return { default: [ ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'ß', 'Backspace'], @@ -131,6 +133,15 @@ export class KeyLayout { additional: [[]] }; } + default: { // custom + return { + default: [ + customKeys.split('') + ], + shift: [[]], + additional: [[]] + }; + } } }; } diff --git a/projects/player/src/app/components/floating-keypad/floating-keypad.component.html b/projects/player/src/app/components/floating-keypad/floating-keypad.component.html index a41123ccd32dbefdca522fab645f4433942840f0..842e27cfa39a86dd3066979d8a2800ce634ae286 100644 --- a/projects/player/src/app/components/floating-keypad/floating-keypad.component.html +++ b/projects/player/src/app/components/floating-keypad/floating-keypad.component.html @@ -9,6 +9,7 @@ [inputElement]="keypadService.inputElement" [position]="keypadService.position" [preset]="keypadService.preset" + [customKeys]="keypadService.elementComponent.elementModel.inputAssistanceCustomKeys" [restrictToAllowedKeys]="keypadService.elementComponent.elementModel.restrictedToInputAssistanceChars" [hasArrowKeys]="keypadService.elementComponent.elementModel.hasArrowKeys" [hasReturnKey]="!!keypadService.elementComponent.elementModel.hasReturnKey" diff --git a/projects/player/src/app/components/layouts/player-layout/player-layout.component.html b/projects/player/src/app/components/layouts/player-layout/player-layout.component.html index 3ec577af701f4713c99bf91736685f661459c6bf..8473b75daf41315bb3581762f7d70fc7b706d975 100644 --- a/projects/player/src/app/components/layouts/player-layout/player-layout.component.html +++ b/projects/player/src/app/components/layouts/player-layout/player-layout.component.html @@ -12,6 +12,7 @@ [inputElement]="keypadService.inputElement" [position]="keypadService.position" [preset]="keypadService.preset" + [customKeys]="keypadService.elementComponent.elementModel.inputAssistanceCustomKeys" [restrictToAllowedKeys]="keypadService.elementComponent.elementModel.restrictedToInputAssistanceChars" [hasArrowKeys]="keypadService.elementComponent.elementModel.hasArrowKeys" [hasReturnKey]="!!keypadService.elementComponent.elementModel.hasReturnKey" diff --git a/projects/player/src/app/services/keypad.service.ts b/projects/player/src/app/services/keypad.service.ts index af0af2b98e7b93928ae94399fda7de033c05bf2c..f9f529e4c922931ceb1c800f44e21fa8f2450299 100644 --- a/projects/player/src/app/services/keypad.service.ts +++ b/projects/player/src/app/services/keypad.service.ts @@ -1,12 +1,12 @@ import { Injectable } from '@angular/core'; import { TextFieldComponent } from 'common/components/input-elements/text-field.component'; import { TextAreaComponent } from 'common/components/input-elements/text-area.component'; -import { InputService } from '../classes/input-service'; import { SpellCorrectComponent } from 'common/components/input-elements/spell-correct.component'; import { TextFieldSimpleComponent } from 'common/components/compound-elements/cloze/cloze-child-elements/text-field-simple.component'; import { InputAssistancePreset } from 'common/models/elements/element'; +import { InputService } from '../classes/input-service'; @Injectable({ providedIn: 'root'