Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$mol_number dot minus constraint #717

Merged
merged 16 commits into from
Nov 25, 2024
Merged
4 changes: 3 additions & 1 deletion number/number.view.tree
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ $mol_number $mol_view
value? +NaN
enabled true
sub /
<= String $mol_string
<= String $mol_format
allow \0123456789,.-
mask* <= mask* \
- \ we don't want native number controls in mobile devices
- \ https://stackoverflow.com/questions/3790935/can-i-hide-the-html5-number-input-s-spin-box
type <= type \tel
Expand Down
82 changes: 68 additions & 14 deletions number/number.view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace $.$$ {
export class $mol_number extends $.$mol_number {

value_limited( val? : number ) : number {
if (Number.isNaN( val )) return this.value(val)
if (Number.isNaN( val )) return this.value( val )
if ( val === undefined ) return this.value()

const min = this.value_min()
Expand All @@ -27,34 +27,88 @@ namespace $.$$ {
this.value_limited( ( this.value_limited() || 0 ) + this.precision_change() )
}

value_normalized(next?: string) {
const next_num = this.value_limited( next === undefined ? next : Number(next) )

if (Number.isNaN(next_num)) return ''
round(val: number) {
if (Number.isNaN(val)) return ''
if( val === 0 ) return '0'
if( !val ) return ''

const precision_view = this.precision_view()

if( next_num === 0 ) return '0'
if( !next_num ) return ''
if (! precision_view) return val.toFixed()

if( precision_view >= 1 ) {
return ( next_num / precision_view ).toFixed()
return ( val / precision_view ).toFixed()
} else {
const fixed_number = Math.log10( 1 / precision_view )
return next_num.toFixed( Math.ceil( fixed_number ) )
return val.toFixed( Math.ceil( fixed_number ) )
}
}

@ $mol_mem
override value_string( next? : string ) {
const current = this.value_normalized()
override value_string( next? : string ): string {
// Вытягиваем value
// Если кто-то поменяет из вне value, value_string надо обновить
const current = this.round( this.value_limited() )
if (next === undefined) return current

const minus = next.includes('-')
zerkalica marked this conversation as resolved.
Show resolved Hide resolved
// Запятые меняем на точки, удаляем не-цифры и не-точки и лишние ноли в начале целой части.
next = next.replace(/,/g, '.').replace(/[^\d\.]/g, '').replace(/^0{2,}/, '0')

// Второй минус не даем ввести.
// Если где-либо ввели минус, то ставим минус в начале, если его там нет
if ( minus ) next = '-' + next

let dot_pos = next.indexOf('.')

if (dot_pos !== -1) {
const prev = $mol_wire_probe(() => this.value_string()) ?? ''
const dot_pos_prev = prev.indexOf('.')
// Определяем где относительно предыдущей точки юзер поставил новую
if (dot_pos_prev === dot_pos) dot_pos = next.lastIndexOf('.')

// Из частей до и после новой точки старую точку удаляем, отбрасываем значения больше
const frac = next.slice(dot_pos + 1).replace(/\./g, '')

if ( next !== undefined) this.value_normalized( next )
// Если точка идет первой, перед ней пишем 0, что бы форматирование выглядело нормально в mask
next = (next.slice(0, dot_pos) || '0').replace(/\./g, '') + '.' + frac
}

// Оставляем старое значение в value есть сочетание, приводящие к NaN, например -.
if ( Number.isNaN(Number(next)) ) return next

return next ?? current
const precision = this.precision_view()
// Точку в конце поставить нельзя, если precision_view целое число > 0
zerkalica marked this conversation as resolved.
Show resolved Hide resolved
if ( next.endsWith('.') && precision - Math.floor(precision) === 0) return next
if ( next.endsWith('-') ) return next

// Если пустая строка - сетим NaN
// Применяем округления.
return this.round( this.value_limited(Number(next || Number.NaN)) )
}


format(num_str: string) {
zerkalica marked this conversation as resolved.
Show resolved Hide resolved
let result = ''

for (let i = num_str.length - 1; i >= 0; i--) {
result += '_'
if ((i % 3) === 0) result += ' '
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я бы предложил форматировать через подчёркивания, как в JS.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

подчеркивания используются в mol_format как плейсхолдер в маске:

while( mask[ from ] && mask[ from ] !== '_' ) {

разделитель не может быть подчеркиванием

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Возможно стоит добавить кастомизацию плейсхолдера.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

такая себе идея, будут несовместимые шаблоны, я пока отвинтил format, бажный он, быстро пофиксить не получилось

}
return result.trim()

}

override mask(val: string) {
const [_, main = '', frac = ''] = val.match(/(\-?\d+)(?:\.?(\d+))?/) ?? []

const prefix = this.format(main)
if (! frac) return prefix

const suffix = this.format(frac).split('').reverse().join('')

return prefix + '_' + suffix
}

@ $mol_mem
override dec_enabled() : boolean {
return this.enabled() && (
Expand Down
Loading