import { ChangeWorker, ComponentModel, CURRENCY, structure, toNumber } from './cykLang' import { computed, onUnmounted, Ref, ref, watch } from 'vue'; // import { getDBManager, getVarValue, setVarValue } from '../services/cyklang'; import loglevel from 'loglevel'; import { ComponentModelParameter, componentModelParameter } from './cykReact'; import { useCykLang } from './cykLang'; import { PrimitiveData, Variable, variable2json } from '@cyklang/core'; const logger = loglevel.getLogger('InputComponent.vue'); logger.setLevel('debug'); export function useCykInput(props: { componentArg: ComponentModel | undefined }) { const { structure } = useCykLang(); const debug_label = props.componentArg?.objectData?.tag.attributes.LABEL || 'no label'; const model = ref() const isLoading = ref(true); const visible = componentModelParameter(props.componentArg, "visible", true) const cpLocked = new ComponentModelParameter(props.componentArg, "locked", false) const locked = cpLocked.model const label = componentModelParameter(props.componentArg, "label", structure.scope.xlate(props.componentArg?.objectData?.tag.attributes.LABEL)) const tooltip = componentModelParameter(props.componentArg, "tooltip", structure.scope.xlate(props.componentArg?.objectData?.tag.attributes.TOOLTIP)) const readOnly = ref(false) // onchange let changeWorker: ChangeWorker | undefined const onchangeFunction = props.componentArg?.objectData?.variables.getFunction('onchange'); if (onchangeFunction && props.componentArg?.objectData) { changeWorker = new ChangeWorker(onchangeFunction, props.componentArg?.objectData.scope) } const mask = ref() const fillMask = ref() const reverseFillMask = ref(false) const unmaskedValue = ref(true) /** * * @returns */ const doLoading = async () => { try { if (!props.componentArg || !props.componentArg.model) { logger.debug('props', props) throw 'props.componentArg.model undefined' } await props.componentArg.interpolateAttributes() const attMask = props.componentArg.attributes.MASK if (attMask && typeof attMask === 'string') { const parts = attMask.split(';') mask.value = parts[0] if (parts[1] && parts[1].trim() === '0') { unmaskedValue.value = false } else { unmaskedValue.value = true } if (parts[2] && parts[2].trim()) { fillMask.value = parts[2].trim() } // if (parts.length > 1) { // logger.debug('mask.parts', parts) // logger.debug(`mask.value = ${mask.value},unmaskedValue.value = ${unmaskedValue.value}, fillMask.value = ${fillMask.value}`) // } } if (props.componentArg.attributes.READONLY !== undefined || locked.value) { readOnly.value = true } else { readOnly.value = false } model.value = getDisplayModelValue(props.componentArg)?.toString(); } catch (err) { logger.error(err) } finally { isLoading.value = false; } } doLoading() /** * */ const listenModel = async () => { if (!gotFocus.value) { isLoading.value = true await doLoading() } } props.componentArg?.model?.addVariableListener(listenModel) const gotFocus = ref(false) const focus = (evt: Event) => { gotFocus.value = true model.value = getFocusModelValue(props.componentArg) // if (getVarValue(props.componentArg) && getVarValue(props.componentArg) !== null) { // model.value = String(getVarValue(props.componentArg)) // } // else { // model.value = '' // } } const blur = (evt: Event) => { gotFocus.value = false if (!props.componentArg?.model) return model.value = getDisplayModelValue(props.componentArg)?.toString(); logger.debug(`blur [${model.value}]`) } if ( props.componentArg !== undefined && props.componentArg.model !== undefined && props.componentArg.dirtyManager && props.componentArg.objectData?.tag.attributes['IGNORE-DIRTY'] === undefined && props.componentArg.attributes.READONLY === undefined ) { props.componentArg.dirtyManager.registerVariable( props.componentArg.model, props.componentArg.objectData?.tag.attributes.LABEL || 'no label' ); } watch(model, (after, before) => { if (!gotFocus.value) return logger.debug(`input.watch model [${model.value}]`) if (!props.componentArg?.model) throw 'input props.componentArg.model undefined' setModelValue(props.componentArg, after) props.componentArg.dirtyManager?.variableChanged(props.componentArg.model) changeWorker?.onchangeRequired() }) watch([locked], () => { isLoading.value = true doLoading() }) const slots = ref(new Map()); props.componentArg?.objectData?.tag.childs.forEach((child) => { if (child.name === 'TEMPLATE') { slots.value.set(child.attributes.NAME, child.getText()); } }); const rules: any[] = []; if (props.componentArg?.objectData?.tag.attributes.MANDATORY !== undefined) { rules.push( (val: any) => (val !== undefined && val !== null && String(val) !== '') || props.componentArg?.objectData?.tag.attributes.MANDATORY ); } onUnmounted(() => { props.componentArg?.objectData?.destroy() props.componentArg?.model?.removeVariableListener(listenModel) cpLocked.destroy() }); return { isLoading, visible, label, model, slots, rules, focus, blur, readOnly, tooltip, mask, fillMask, reverseFillMask, unmaskedValue }; } export const INPUT_ATTS = [ 'TYPE', 'COLOR', 'BG-COLOR', 'STACK-LABEL', 'HINT', 'DENSE', 'FILLED', 'OUTLINED', 'STANDOUT', 'BORDERLESS', 'ROUNDED', 'SQUARE', 'AUTOGROW', 'READONLY', 'DISABLE', ] /** * * @param dbColumn * @param variable * @returns */ function getDisplayModelValue(componentArg: ComponentModel): string { const dataTypeName = componentArg.model?.dataType.name; const att_type = componentArg.objectData?.tag.attributes.TYPE; const att_format = componentArg.objectData?.tag.attributes.FORMAT; const variable = componentArg.model; let result = "" if (!variable || !variable.data || variable.data === null) return result const data = variable.data if (data.type.isPrimitive()) { const value = (data as PrimitiveData).value result = String(value) if (att_type === undefined || String(att_type).trim() === '') { // attribute type undefined switch (dataTypeName) { case 'string': if (att_format === 'date') { if (value && value !== null) { result = structure.scope.formatDate(value as string) } // logger.debug('dbColumn', dbColumn, 'formatDate: ' + result) } else { result = structure.scope.xlate(value as string) } break; case 'number': const numericValue = toNumber(value); if (numericValue !== undefined) { if (att_format === 'money') { result = new Intl.NumberFormat(undefined, { style: "currency", currency: CURRENCY }).format(numericValue) // result = result.replace(/\s(\d)/g, '$1') // delete space separator for thousands } else if (att_format === 'number_fixed;2') { result = new Intl.NumberFormat(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2}).format(numericValue) } else { result = new Intl.NumberFormat(undefined).format(numericValue) } } else { result = '' } break; case 'datetime': if (value && value !== null) { result = structure.scope.formatDatetime(value as Date) } // logger.debug('dbColumn', dbColumn, 'formatDatetime: ' + result) break; case 'boolean': break; default: logger.debug(`getDisplayModelValue unsupported dataType: ${dataTypeName}`) } } else if (att_type === 'date') { // input type = date if (att_format === undefined || att_format === 'date' || att_format === 'month') { result = String(value) } else { throw ` type = date, format unsupported : ${att_format}` } } } else if (data.type.isObject()) { result = JSON.stringify(variable2json(variable)) } else { logger.debug('qColumnField unsupported dataType: ' + data.type.name) } return result } /** * * @param variable * @returns */ function getFocusModelValue( componentArg: ComponentModel | undefined ): string { if (!componentArg) return ''; const dataTypeName = componentArg.model?.dataType.name; const att_type = componentArg.objectData?.tag.attributes.TYPE; const att_format = componentArg.objectData?.tag.attributes.FORMAT; const variable = componentArg.model; if (!variable) return '' if (variable.data === undefined || variable.data === null) return '' let result: string; const pvalue = variable.getPrimitiveValue(); if (att_type === undefined || String(att_type).trim() === '') { // attribute type undefined if (dataTypeName === 'datetime') { if (pvalue instanceof Date) { logger.debug('result instanceof Date'); //logger.debug(variable.data); logger.debug(pvalue.toISOString()); result = pvalue.toISOString().slice(0, 10); } else { result = ''; } logger.debug('>> get date ' + result); } else if (dataTypeName === 'boolean') { result = (pvalue as boolean) === true ? '1' : '0'; } else if (dataTypeName === 'number') { result = String(pvalue); } else if (dataTypeName === 'string') { result = pvalue as string; } else { throw `model data type not supported : ${dataTypeName}` } } else if (att_type === 'date') { // input type = date if (att_format === undefined || att_format === 'date' || att_format === 'month') { result = pvalue as string } else { throw ` type = ${att_type} is unsupported` } return result; } /** * * @param variable * @param nval */ function setModelValue( componentArg: ComponentModel, nval: string | number | null | undefined ) { const dataTypeName = componentArg.model?.dataType.name; const att_type = componentArg.objectData?.tag.attributes.TYPE; const att_format = componentArg.objectData?.tag.attributes.FORMAT; const variable = componentArg.model; if (!variable) return; let ndata; if (att_type === 'date') { // input type = date if (dataTypeName === 'string') { if (att_format === undefined || att_format === 'date') { // format = date ndata = new PrimitiveData(structure.stringDataType, nval); } else if (att_format === 'month') { // format = month if (nval === null || nval === undefined) { ndata = structure.undefinedData; } else if (typeof (nval) == 'string') { let strin = nval as string if (strin.trim() === '') { ndata = structure.undefinedData; } else { strin = strin.substring(0, 7) + '-01' ndata = new PrimitiveData(structure.stringDataType, strin) } } else { throw ` with type = date, format = month, typeof(nval) unsupported : ${typeof (nval)}` } } else { throw ` with type = date, this format is not supported : ${att_format}` } } else { throw ` with type = date, this model datatype is not supported : ${att_type}` } } else { // default or other type if (dataTypeName === 'string') { const strin = String(nval); ndata = new PrimitiveData(structure.stringDataType, strin); } else if (dataTypeName === 'number') { const numericValue = toNumber(nval) if (numericValue) { ndata = new PrimitiveData(structure.numberDataType, numericValue) } else { ndata = undefined } } else if (dataTypeName === 'boolean') { const bool = Boolean(nval); ndata = new PrimitiveData( structure.booleanDataType, bool ); } else if (dataTypeName === 'datetime') { let dat; if (nval === null) { logger.debug('>> set date null'); dat = null; } else if (nval === undefined) { logger.debug('>> set date undefined'); dat = null; } else if (nval === '') { logger.debug('>> set date blank'); dat = null; } else { logger.debug('>> set date ' + nval); dat = new Date(String(nval)); } logger.debug('set date ' + dat); ndata = new PrimitiveData(structure.datetimeDataType, dat); } else { throw ` this model datatype is not supported : ${dataTypeName}` } } variable.setValue(ndata); }