From 963562621ddf0e8d24a29a8481c5e6da1b040708 Mon Sep 17 00:00:00 2001 From: Mihajlo Medjedovic Date: Mon, 18 Mar 2024 17:32:29 +0100 Subject: [PATCH] feat: numeric values in hot dropdown aligned right --- .../edit-record/edit-record.component.html | 4 +- client/src/app/editor/editor.component.ts | 67 ++++++++++++------- .../app/shared/dc-validator/dc-validator.ts | 10 ++- .../editors/numericAutocomplete.ts | 27 ++++++++ client/src/environments/_eula.ts | 2 +- client/src/styles.scss | 5 ++ 6 files changed, 87 insertions(+), 28 deletions(-) create mode 100644 client/src/app/shared/dc-validator/editors/numericAutocomplete.ts diff --git a/client/src/app/editor/components/edit-record/edit-record.component.html b/client/src/app/editor/components/edit-record/edit-record.component.html index c678fcf..73c5f84 100644 --- a/client/src/app/editor/components/edit-record/edit-record.component.html +++ b/client/src/app/editor/components/edit-record/edit-record.component.html @@ -112,7 +112,7 @@
0) { hot.setCellMeta(entry.row, entry.col, 'renderer', 'autocomplete') - hot.setCellMeta(entry.row, entry.col, 'editor', 'autocomplete') + hot.setCellMeta(entry.row, entry.col, 'editor', 'autocomplete.custom') hot.setCellMeta(entry.row, entry.col, 'strict', entry.strict) hot.setCellMeta(entry.row, entry.col, 'filter', false) this.currentEditRecordValidator?.updateRule(entry.col, { renderer: 'autocomplete', - editor: 'autocomplete', + editor: 'autocomplete.custom', strict: entry.strict, filter: false }) @@ -2057,13 +2057,13 @@ export class EditorComponent implements OnInit, AfterViewInit { } hot.setCellMeta(row, cellCol, 'renderer', 'autocomplete') - hot.setCellMeta(row, cellCol, 'editor', 'autocomplete') + hot.setCellMeta(row, cellCol, 'editor', 'autocomplete.custom') hot.setCellMeta(row, cellCol, 'strict', cellValidationEntry.strict) hot.setCellMeta(row, cellCol, 'filter', false) this.currentEditRecordValidator?.updateRule(cellCol, { renderer: 'autocomplete', - editor: 'autocomplete', + editor: 'autocomplete.custom', strict: cellValidationEntry.strict, filter: false }) @@ -2706,13 +2706,13 @@ export class EditorComponent implements OnInit, AfterViewInit { const strict = this.cellValidationSource[validationSourceIndex].strict hot.setCellMeta(row, column, 'renderer', 'autocomplete') - hot.setCellMeta(row, column, 'editor', 'autocomplete') + hot.setCellMeta(row, column, 'editor', 'autocomplete.custom') hot.setCellMeta(row, column, 'strict', strict) hot.setCellMeta(row, column, 'filter', false) this.currentEditRecordValidator?.updateRule(column, { renderer: 'autocomplete', - editor: 'autocomplete', + editor: 'autocomplete.custom', strict: strict, filter: false }) @@ -2946,6 +2946,37 @@ export class EditorComponent implements OnInit, AfterViewInit { ) } + /** + * Function checks if selected hot cell is solo cell selected + * and if it is, set the `filter` property based on filter param. + * + * @param filter + */ + private setCellFilter(filter: boolean) { + const hotSelected = this.hotInstance.getSelected() + const selection = hotSelected ? hotSelected[0] : hotSelected + + // When we open a dropdown we want filter disabled so value in cell + // don't filter out items, since we want to see them all. + // But when we start typing we want to be able to start filtering values + // again + if (selection) { + const startRow = selection[0] + const endRow = selection[2] + const startCell = selection[1] + const endCell = selection[3] + + if (startRow === endRow && startCell === endCell) { + const cellMeta = this.hotInstance.getCellMeta(startRow, startCell) + + // If filter is not already set at the value in the param, set it + if (cellMeta && cellMeta.filter === !filter) { + this.hotInstance.setCellMeta(startRow, startCell, 'filter', filter) + } + } + } + } + async ngOnInit() { this.licenceService.hot_license_key.subscribe( (hot_license_key: string | undefined) => { @@ -3301,28 +3332,16 @@ export class EditorComponent implements OnInit, AfterViewInit { } ) - hot.addHook('beforeKeyDown', (e: any) => { - const hotSelected = this.hotInstance.getSelected() - const selection = hotSelected ? hotSelected[0] : hotSelected - + hot.addHook('afterBeginEditing', () => { // When we open a dropdown we want filter disabled so value in cell // don't filter out items, since we want to see them all. + this.setCellFilter(false) + }) + + hot.addHook('beforeKeyDown', () => { // When we start typing, we are enabling the filter since we want to find // values faster. - if (selection) { - const startRow = selection[0] - const endRow = selection[2] - const startCell = selection[1] - const endCell = selection[3] - - if (startRow === endRow && startCell === endCell) { - const cellMeta = this.hotInstance.getCellMeta(startRow, startCell) - - if (cellMeta && cellMeta.filter === false) { - this.hotInstance.setCellMeta(startRow, startCell, 'filter', true) - } - } - } + this.setCellFilter(true) }) hot.addHook('afterChange', (source: any, change: any) => { diff --git a/client/src/app/shared/dc-validator/dc-validator.ts b/client/src/app/shared/dc-validator/dc-validator.ts index 75bc25e..af1674f 100644 --- a/client/src/app/shared/dc-validator/dc-validator.ts +++ b/client/src/app/shared/dc-validator/dc-validator.ts @@ -20,6 +20,7 @@ import { parseColType } from './utils/parseColType' import { dqValidate } from './validations/dq-validation' import { specialMissingNumericValidator } from './validations/hot-custom-validators' import { applyNumericFormats } from './utils/applyNumericFormats' +import { CustomAutocompleteEditor } from './editors/numericAutocomplete' export class DcValidator { private rules: DcValidation[] = [] @@ -38,6 +39,8 @@ export class DcValidator { dqData: DQData[], hotInstance?: Handsontable ) { + this.registerCustomEditors() + this.sasparams = sasparams this.hotInstance = hotInstance this.rules = parseColType(sasparams.COLTYPE) @@ -51,6 +54,10 @@ export class DcValidator { this.setupValidations() } + registerCustomEditors() { + Handsontable.editors.registerEditor('autocomplete.custom', CustomAutocompleteEditor) + } + getRules(): DcValidation[] { return this.rules } @@ -262,6 +269,7 @@ export class DcValidator { if (source.length > 0) { this.rules[i].source = source this.rules[i].type = 'autocomplete' + this.rules[i].editor = 'autocomplete.custom' this.rules[i].filter = false } @@ -315,7 +323,7 @@ export class DcValidator { // Because of dynamic cell validation, that will change the type of cell to dropdown // `rules[i].colType` could be different type (eg. numeric). So we check if current cell is dropdown, to call HOT native dropdown validator - if (this.editor === 'autocomplete') { + if (this.editor === 'autocomplete' || this.editor === 'autocomplete.custom') { self .getHandsontableValidator('autocomplete') .call(this, value, (valid: boolean) => { diff --git a/client/src/app/shared/dc-validator/editors/numericAutocomplete.ts b/client/src/app/shared/dc-validator/editors/numericAutocomplete.ts new file mode 100644 index 0000000..c248dca --- /dev/null +++ b/client/src/app/shared/dc-validator/editors/numericAutocomplete.ts @@ -0,0 +1,27 @@ +import Handsontable from "handsontable"; +import Core from "handsontable/core"; + +export class CustomAutocompleteEditor extends Handsontable.editors.AutocompleteEditor { + constructor(instance: Core) { + super(instance); + } + + createElements() { + super.createElements(); + } + + // Listbox open + open(event?: Event | undefined): void { + super.open(event) + + if (this.isCellNumeric()) { + this.htContainer.classList.add('numericListbox') + } else { + this.htContainer.classList.remove('numericListbox') + } + } + + isCellNumeric() { + return this.cellProperties?.className?.includes('htNumeric') + } +} \ No newline at end of file diff --git a/client/src/environments/_eula.ts b/client/src/environments/_eula.ts index 684dea6..3d7cba2 100644 --- a/client/src/environments/_eula.ts +++ b/client/src/environments/_eula.ts @@ -18,4 +18,4 @@ In any case, you must not make any such use of this software as to develop softw UNLESS EXPRESSLY AGREED OTHERWISE, 4GL APPS PROVIDES THIS SOFTWARE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, AND IN NO EVENT AND UNDER NO LEGAL THEORY, SHALL 4GL APPS BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER ARISING FROM USE OR INABILITY TO USE THIS SOFTWARE. -` +` \ No newline at end of file diff --git a/client/src/styles.scss b/client/src/styles.scss index ef72978..396e38c 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -713,6 +713,11 @@ clr-icon.is-info { border: 1px solid red !important; color: #ffffff !important; } + +.handsontable .numericListbox { + text-align: right; +} + .margin-top-20 { margin-top: 20px; }