type parseInsideTextResult = { before : string; number : float; after : string } let execRegex (regex : Js.Re.t) (str : string) : string option Js.Array.t = match Js.Re.exec_ regex str with | Some result -> Js.Array.map Js.toOption (Js.Re.captures result) | None -> [||] let parseInsideText (str : string) : parseInsideTextResult option = match execRegex [%re "/^([^\\d]*)(\\d+)((\\.|,)(\\d+))?(.*)/"] str with | [| _; Some before; Some intPart; _; _; decPart; Some after |] -> Some { before; number = Js.Float.fromString ( intPart ^ Belt.Option.mapWithDefault decPart "" (fun str -> "." ^ str) ); after; } | _ -> None type parseResult = { number : float; remaining : string } let parse (str : string) : parseResult option = match parseInsideText str with | Some parseResult -> if parseResult.before == "" then Some { number = parseResult.number; remaining = parseResult.after } else None | _ -> None type numberElement = { element : Dom.element; numberInput : Dom.element } let prettyPrint (number : float) : string = let strNumber = Js.Float.toString number in match Js.String.split "." strNumber with | [| intPart; decPart |] -> intPart ^ "," ^ Js.String.slice ~from:0 ~to_:2 decPart | _ -> strNumber let createElement (tag : string) (content : parseInsideTextResult) : numberElement = let numberInput = DomUtils.h "input" [| ("class", "g-Number"); ("value", prettyPrint content.number) |] [| DomUtils.TextChild "" |] in { element = DomUtils.h tag [||] [| DomUtils.TextChild content.before; DomUtils.ElemChild numberInput; DomUtils.TextChild content.after; |]; numberInput; }