github.com/simpleiot/simpleiot@v0.18.3/frontend/src/UI/Sanitize.elm (about)

     1  module UI.Sanitize exposing (date, float, hmParser, parseDate, parseHM, time)
     2  
     3  import Parser exposing ((|.), Parser)
     4  
     5  
     6  float : String -> String
     7  float input =
     8      Tuple.second <| floatHelper ( input, "" )
     9  
    10  
    11  floatHelper : ( String, String ) -> ( String, String )
    12  floatHelper state =
    13      let
    14          sIn =
    15              Tuple.first state
    16  
    17          sInList =
    18              String.toList sIn
    19      in
    20      case sInList of
    21          c :: rest ->
    22              let
    23                  sOut =
    24                      Tuple.second state
    25              in
    26              if (String.length sOut == 0 && c == '-') || Char.isDigit c || (c == '.' && not (String.contains "." sOut)) then
    27                  let
    28                      sOutList =
    29                          String.toList sOut
    30                  in
    31                  floatHelper ( String.fromList rest, String.fromList <| sOutList ++ [ c ] )
    32  
    33              else
    34                  state
    35  
    36          _ ->
    37              state
    38  
    39  
    40  {-| sanitizeTime looks for a valid time input in the form of hh:mm
    41  this function simply stops when it hits an invalid
    42  portion and returns the valid portion
    43  -}
    44  time : String -> String
    45  time t =
    46      Tuple.second <| timeHelper ( t, "" )
    47  
    48  
    49  {-| -- the first value in tuple is incoming string, and 2nd is output
    50  we chomp characters from the input and then process them to the output
    51  -}
    52  timeHelper : ( String, String ) -> ( String, String )
    53  timeHelper state =
    54      let
    55          sIn =
    56              Tuple.first state
    57  
    58          sInList =
    59              String.toList sIn
    60      in
    61      case sInList of
    62          c :: rest ->
    63              let
    64                  sOut =
    65                      Tuple.second state
    66  
    67                  sOutList =
    68                      String.toList sOut
    69  
    70                  checkDigit =
    71                      \ch chRest ->
    72                          if Char.isDigit ch then
    73                              timeHelper ( String.fromList chRest, String.fromList <| sOutList ++ [ ch ] )
    74  
    75                          else
    76                              ( "", sOut )
    77              in
    78              case List.length sOutList of
    79                  0 ->
    80                      checkDigit c rest
    81  
    82                  1 ->
    83                      if c == ':' then
    84                          -- add a leading digit and try again
    85                          timeHelper ( sIn, String.fromList <| '0' :: sOutList )
    86  
    87                      else if Char.isDigit c then
    88                          let
    89                              sOutNew =
    90                                  String.fromList <| sOutList ++ [ c ]
    91                          in
    92                          case String.toInt (String.slice 0 2 sOutNew) of
    93                              Just hr ->
    94                                  if hr > 23 then
    95                                      ( "", sOut )
    96  
    97                                  else
    98                                      timeHelper ( String.fromList rest, sOutNew )
    99  
   100                              Nothing ->
   101                                  ( "", sOut )
   102  
   103                      else
   104                          ( "", sOut )
   105  
   106                  2 ->
   107                      if c == ':' then
   108                          timeHelper ( String.fromList rest, String.fromList <| sOutList ++ [ c ] )
   109  
   110                      else
   111                          ( "", sOut )
   112  
   113                  3 ->
   114                      checkDigit c rest
   115  
   116                  4 ->
   117                      if Char.isDigit c then
   118                          let
   119                              sOutNew =
   120                                  String.fromList <| sOutList ++ [ c ]
   121                          in
   122                          case String.toInt (String.slice 3 5 sOutNew) of
   123                              Just hr ->
   124                                  if hr > 59 then
   125                                      ( "", sOut )
   126  
   127                                  else
   128                                      timeHelper ( String.fromList rest, sOutNew )
   129  
   130                              Nothing ->
   131                                  ( "", sOut )
   132  
   133                      else
   134                          ( "", sOut )
   135  
   136                  _ ->
   137                      ( "", sOut )
   138  
   139          _ ->
   140              -- we are done
   141              state
   142  
   143  
   144  parseHM : String -> Maybe String
   145  parseHM t =
   146      Parser.run hmParser t
   147          |> Result.toMaybe
   148  
   149  
   150  hmParser : Parser String
   151  hmParser =
   152      Parser.getChompedString <|
   153          Parser.succeed identity
   154              |. (Parser.oneOf [ Parser.backtrackable altIntParser, Parser.int ]
   155                      |> Parser.andThen
   156                          (\v ->
   157                              if v < 0 || v > 23 then
   158                                  Parser.problem "hour is out of range"
   159  
   160                              else
   161                                  Parser.succeed v
   162                          )
   163                 )
   164              |. Parser.symbol ":"
   165              |. ((Parser.oneOf [ altIntParser, Parser.int ]
   166                      |> Parser.andThen
   167                          (\v ->
   168                              if v < 0 || v > 59 then
   169                                  Parser.problem "minute is not in range"
   170  
   171                              else
   172                                  Parser.succeed v
   173                          )
   174                  )
   175                      |> Parser.getChompedString
   176                      |> Parser.andThen
   177                          (\s ->
   178                              if String.length s /= 2 then
   179                                  Parser.problem "minute must be 2 digits"
   180  
   181                              else
   182                                  Parser.succeed s
   183                          )
   184                 )
   185  
   186  
   187  parseDate : String -> Maybe String
   188  parseDate d =
   189      Parser.run dateParser d
   190          |> Result.toMaybe
   191  
   192  
   193  dateParser : Parser String
   194  dateParser =
   195      Parser.getChompedString <|
   196          Parser.succeed identity
   197              |. (Parser.oneOf [ Parser.backtrackable altIntParser, Parser.int ]
   198                      |> Parser.andThen
   199                          (\v ->
   200                              if v < 2023 || v > 2099 then
   201                                  Parser.problem "year is out of range"
   202  
   203                              else
   204                                  Parser.succeed v
   205                          )
   206                 )
   207              |. Parser.symbol "-"
   208              |. ((Parser.oneOf [ altIntParser, Parser.int ]
   209                      |> Parser.andThen
   210                          (\v ->
   211                              if v < 1 || v > 12 then
   212                                  Parser.problem "month is not in range"
   213  
   214                              else
   215                                  Parser.succeed v
   216                          )
   217                  )
   218                      |> Parser.getChompedString
   219                      |> Parser.andThen
   220                          (\s ->
   221                              if String.length s /= 2 then
   222                                  Parser.problem "month must be 2 digits"
   223  
   224                              else
   225                                  Parser.succeed s
   226                          )
   227                 )
   228              |. Parser.symbol "-"
   229              |. ((Parser.oneOf [ altIntParser, Parser.int ]
   230                      |> Parser.andThen
   231                          (\v ->
   232                              if v < 1 || v > 31 then
   233                                  Parser.problem "day is not in range"
   234  
   235                              else
   236                                  Parser.succeed v
   237                          )
   238                  )
   239                      |> Parser.getChompedString
   240                      |> Parser.andThen
   241                          (\s ->
   242                              if String.length s /= 2 then
   243                                  Parser.problem "day must be 2 digits"
   244  
   245                              else
   246                                  Parser.succeed s
   247                          )
   248                 )
   249  
   250  
   251  altIntParser : Parser Int
   252  altIntParser =
   253      Parser.symbol "0" |> Parser.andThen (\_ -> Parser.int)
   254  
   255  
   256  {-| date looks for a valid date input in the form of YYYY-MM-DD
   257  this function simply stops when it hits an invalid
   258  portion and returns the valid portion
   259  -}
   260  date : String -> String
   261  date d =
   262      Tuple.second <| dateHelper ( d, "" )
   263  
   264  
   265  {-| -- the first value in tuple is incoming string, and 2nd is output
   266  we chomp characters from the input and then process them to the output
   267  0123456789
   268  YYYY-MM-DD
   269  -}
   270  dateHelper : ( String, String ) -> ( String, String )
   271  dateHelper state =
   272      let
   273          sIn =
   274              Tuple.first state
   275  
   276          sInList =
   277              String.toList sIn
   278      in
   279      case sInList of
   280          c :: rest ->
   281              let
   282                  sOut =
   283                      Tuple.second state
   284  
   285                  sOutList =
   286                      String.toList sOut
   287  
   288                  checkDigit =
   289                      \ch chRest ->
   290                          if Char.isDigit ch then
   291                              dateHelper ( String.fromList chRest, String.fromList <| sOutList ++ [ ch ] )
   292  
   293                          else
   294                              ( "", sOut )
   295              in
   296              case List.length sOutList of
   297                  0 ->
   298                      if c /= '2' then
   299                          ( "", sOut )
   300  
   301                      else
   302                          checkDigit c rest
   303  
   304                  1 ->
   305                      if c /= '0' then
   306                          ( "", sOut )
   307  
   308                      else
   309                          checkDigit c rest
   310  
   311                  2 ->
   312                      checkDigit c rest
   313  
   314                  3 ->
   315                      checkDigit c rest
   316  
   317                  4 ->
   318                      if c == '-' then
   319                          dateHelper ( String.fromList rest, String.fromList <| sOutList ++ [ c ] )
   320  
   321                      else
   322                          ( "", sOut )
   323  
   324                  5 ->
   325                      checkDigit c rest
   326  
   327                  6 ->
   328                      if c == '-' then
   329                          dateHelper
   330                              ( sIn
   331                              , String.fromList <|
   332                                  List.take 5 sOutList
   333                                      ++ '0'
   334                                      :: List.drop 5 sOutList
   335                              )
   336  
   337                      else if Char.isDigit c then
   338                          let
   339                              sOutNew =
   340                                  String.fromList <| sOutList ++ [ c ]
   341                          in
   342                          case String.toInt (String.slice 5 7 sOutNew) of
   343                              Just mo ->
   344                                  if mo > 12 then
   345                                      ( "", sOut )
   346  
   347                                  else
   348                                      dateHelper ( String.fromList rest, sOutNew )
   349  
   350                              Nothing ->
   351                                  ( "", sOut )
   352  
   353                      else
   354                          ( "", sOut )
   355  
   356                  7 ->
   357                      if c == '-' then
   358                          dateHelper ( String.fromList rest, String.fromList <| sOutList ++ [ c ] )
   359  
   360                      else
   361                          ( "", sOut )
   362  
   363                  8 ->
   364                      checkDigit c rest
   365  
   366                  9 ->
   367                      if Char.isDigit c then
   368                          let
   369                              sOutNew =
   370                                  String.fromList <| sOutList ++ [ c ]
   371                          in
   372                          case String.toInt (String.slice 8 10 sOutNew) of
   373                              Just day ->
   374                                  if day > 31 then
   375                                      ( "", sOut )
   376  
   377                                  else
   378                                      dateHelper ( String.fromList rest, sOutNew )
   379  
   380                              Nothing ->
   381                                  ( "", sOut )
   382  
   383                      else
   384                          ( "", sOut )
   385  
   386                  _ ->
   387                      ( "", sOut )
   388  
   389          _ ->
   390              -- we are done
   391              state