UNPKG

coffeescript-ui

Version:
290 lines (227 loc) 6.48 kB
### * coffeescript-ui - Coffeescript User Interface System (CUI) * Copyright (c) 2013 - 2016 Programmfabrik GmbH * MIT Licence * https://github.com/programmfabrik/coffeescript-ui, http://www.coffeescript-ui.org ### class CUI.NumberInput extends CUI.Input initOpts: -> super() @addOpts decimals: default: 0 check: "Integer" symbol: check: (v) -> CUI.util.isString(v) and v.length > 0 symbol_before: default: false check: Boolean store_as_integer: default: false check: Boolean decimalpoint: mandatory: true default: "." check: [",","."] separator: check: (v) -> CUI.util.isString(v) and v.length > 0 min: default: null check: (v) -> CUI.util.isNumber(v) max: default: null check: (v) -> CUI.util.isNumber(v) @removeOpt("checkInput") @removeOpt("getValueForDisplay") @removeOpt("getValueForInput") @removeOpt("correctValueForInput") @removeOpt("prevent_invalid_input") readOpts: -> super() @_checkInput = @__checkInput @_prevent_invalid_input = true @setMin(@_min) @setMax(@_max) setMin: (@__min) -> setMax: (@__max) -> formatValueForDisplay: (value=@getValue(), forInput = false) -> CUI.util.assert(typeof(value) == "number" or value == null, "NumberInput.formatValueForDisplay", "value needs to be Number or null", value: value, type: typeof(value)) if CUI.util.isEmpty(value) return "" if @_store_as_integer v = (value / Math.pow(10, @_decimals)).toFixed(@_decimals) else v = value+"" # decimal is a "." v0 = v.split(".") if v0.length > 1 number = v0[0] decimals = v0[1] else number = v0[0] decimals = "" if @_decimals > 0 while decimals.length < @_decimals decimals = decimals + "0" if forInput if @_decimals > 0 return number + @_decimalpoint + decimals else return number if @_decimals > 0 v1 = @__addSeparator(number)+@_decimalpoint+decimals else v1 = @__addSeparator(number) # console.debug "v: ", v, value, @__addSeparator(v), v1 @__addSymbol(v1) getValue: -> v = super() if @hasData() return v # value is as string in our input @getValueForStore(v) getValueForDisplay: -> @formatValueForDisplay(@getValue()) getValueForStore: (value) -> if not CUI.util.isString(value) value = value + "" number = parseFloat(value.replace(/,/,".")) if isNaN(number) return null if @_store_as_integer return parseInt((number * Math.pow(10, @_decimals)).toFixed(0)) return number getDefaultValue: -> null setValue: (v, flags = {}) -> @checkValue(v) super(v, flags) checkValue: (v) -> if v == null true else if @_decimals > 0 and CUI.util.isFloat(v) true else if CUI.util.isInteger(v) true else throw new Error("#{@__cls}.setValue(value): Value needs to be Number or null.") __addSymbol: (str) -> if CUI.util.isEmpty(@_symbol) return str if @_symbol_before @_symbol+" "+str else str+" "+@_symbol __addSeparator: (str) -> if CUI.util.isEmpty(@_separator) return str nn = [] for n,idx in str.split("").reverse() if idx%3 == 0 and idx > 0 nn.push(@_separator) nn.push(n) nn.reverse() nn.join("") correctValueForInput: (value) -> return value.replace(/[,\.]/g, @_decimalpoint) getValueForInput: -> @formatValueForDisplay(null, true) checkInput: (value) -> if value == null return true else return super(value) __checkInput: (value) -> if not @hasShadowFocus() v = value.replace(@_symbol, "") else v = value v = v.trim() if v == "" return true if @_separator re = new RegExp(RegExp.escape(@_separator), "g") v = v.replace(re, "") point_idx = v.lastIndexOf(@_decimalpoint) if point_idx == -1 number = v points = "" else if @_decimals == 0 return false number = v.substring(0, point_idx) points = v.substring(point_idx+1) # console.debug "v:", v, "number:", number, "points:", points, "decimalpoint", @_decimalpoint, "separator", @_separator if points.length > @_decimals return false if number.length > 0 and not number.match(/^((0|[1-9]+[0-9]*)|(-|-[1-9]|-[1-9][0-9]*))$/) # console.debug "number not matched", number return false if not CUI.util.isNull(@__min) if @__min >= 0 and number == "-" return false if number < @__min return false if not CUI.util.isNull(@__max) if number > @__max return false if not points.match(/^([0-9]*)$/) # console.debug "points not matched", points return false if points.length > @_decimals return false return true # v.replace(".", @_decimalpoint) @format: (v, opts={}) -> if CUI.util.isEmpty(v) v = null # automatically set decimals if CUI.util.isFloat(v) and not opts.hasOwnProperty("decimals") _v = v+"" opts.decimals = _v.length - _v.indexOf(".") - 1 ni = new CUI.NumberInput(opts) ni.start() if not ni.checkInput(v+"") null else ni.formatValueForDisplay(v) @parse: (string, decimals) -> if isNaN(string.replace(/[,\.]/g, "")) # Remove comma to check if the input is valid. return null if isNaN(decimals) decimals = 0 commaIndex = string.indexOf(",") dotIndex = string.indexOf(".") # Comma or dot not found, nothing to do. if commaIndex == -1 and dotIndex == -1 return parseInt(string) # In case both are found, we assume that the first one will be the thousand and the second one the decimal separator. if dotIndex > 0 and commaIndex > 0 if dotIndex > commaIndex thousandSeparatorRegex = /,/g else thousandSeparatorRegex = /\./g # When decimal defined, we can guess the decimal separator if the input has the correct amount of decimals. if not thousandSeparatorRegex and decimals > 0 decimal = string[string.length - 1 - decimals] if decimal == "," thousandSeparatorRegex = /\./g else if decimal == "." thousandSeparatorRegex = /,/g # When there is no decimals it is possible to check with a regexp whether the separator is a valid thousand separator. if not thousandSeparatorRegex and decimals == 0 if string.match(/^\d{1,3}([\.,]\d{3})+/)?[0] == string if dotIndex > 0 thousandSeparatorRegex = /\./g else thousandSeparatorRegex = /,/g if thousandSeparatorRegex string = string.replace(thousandSeparatorRegex, "") if decimals == 0 return parseInt(string) else string = string.replace(/,/, ".") return parseFloat(string)