module EditableNumber ( NumberElem , set , formatNumber ) where import Control.Monad.Eff (Eff) import Data.Int (round, toNumber, pow) as Int import Data.Maybe (Maybe(..)) import Data.String (Pattern(..), Replacement(..)) import Data.String (replace) as String import DOM (DOM) import DOM.HTML (window) as DOM import DOM.HTML.Types (htmlDocumentToDocument) as DOM import DOM.HTML.Window (document) as DOM import DOM.Node.Document (createElement, createTextNode) as DOM import DOM.Node.Element (setClassName, setAttribute) as DOM import DOM.Node.Node (textContent) as DOM import DOM.Node.Types (Element, Node) import DOM.Node.Types (elementToNode, textToNode) as DOM import Math (round) as Math import Prelude import Dom (replaceElement, appendNodes) as Dom import Parser (TextWithNumber) import Parser (textWithNumber) as Parser type NumberElem = { elem :: Element , number :: Number } set :: forall e. { tag :: String, node :: Node } -> Eff (dom :: DOM | e) (Maybe NumberElem) set { tag, node } = do content <- DOM.textContent node case Parser.textWithNumber content of Just twn -> do textWithNumber <- textWithNumberElem tag twn Dom.replaceElement node (DOM.elementToNode textWithNumber) pure (Just { elem: textWithNumber, number: twn.number }) Nothing -> pure Nothing textWithNumberElem :: forall e. String -> TextWithNumber -> Eff (dom :: DOM | e) Element textWithNumberElem tag { begin, number, end } = do document <- DOM.htmlDocumentToDocument <$> (DOM.window >>= DOM.document) elem <- DOM.createElement tag document beginNode <- DOM.textToNode <$> DOM.createTextNode begin document numberNode <- numberElem number endNode <- DOM.textToNode <$> DOM.createTextNode end document Dom.appendNodes (DOM.elementToNode elem) [ beginNode, DOM.elementToNode numberNode, endNode ] pure elem numberElem :: forall e. Number -> Eff (dom :: DOM | e) Element numberElem number = do document <- DOM.htmlDocumentToDocument <$> (DOM.window >>= DOM.document) container <- DOM.createElement "input" document DOM.setClassName "number" container DOM.setAttribute "value" (formatNumber number) container pure container formatNumber :: Number -> String formatNumber number = if Math.round number == number then show (Int.round number) else String.replace (Pattern ".") (Replacement ",") (show (roundAt 1 number)) roundAt :: Int -> Number -> Number roundAt at n = let exp = Int.toNumber (Int.pow 10 at) in Math.round (n * exp) / exp