Password Meter with Mithril

by ramnathv

HTML

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">

CSS

#main{margin-top: 30px;}
.progress{height: 10px;}

CoffeeScript

## https://gist.github.com/impinball/5e4d6e64aba2ffb7cd23
## Patches Mithril to accept components as well as strings
@m = ((o) ->
  Object.assign (->
    (if typeof arguments[0] == 'string' then o else o.component).apply undefined, arguments
  ), o
)(m)

m.bind = (prop, args = {}) ->
  args.value = prop()
  args.oninput = m.withAttr("value", prop)
  return args

###
Reference: http://reactkungfu.com/showcases/password-strength-meter/
TODOS:
1. Refactor
2. Add Error State to Input Box
###

goodPasswordPrinciples = [
  {
    label: '6+ characters'
    predicate: (password) -> password.length > 6
  },
  {
    label: 'with at least one digit'
    predicate: (password) -> password.match(/\d+/g) != null
  },
  {
    label: '6+ characters'
    predicate: (password) -> 
      password.match(/[-!$%^&*()_+|~=`{}\[\]:";'<>?,.\/]/) != null
  }
]

ProgressBar = 
  view: (c, props) ->
    principleSatisfied = (principle) -> 
      password = props.text
      principle.predicate(password)
    num = goodPasswordPrinciples
      .filter(principleSatisfied)
      .length
    pct = num*100/3
    type = ['danger', 'warning', 'success'][num - 1]
    m ".progress", 
      m ".progress-bar.progress-bar-#{type}[role='progressbar']", 
        {style: {width: "#{pct}%"}}
        
ProgressText = 
  view: (c, props) ->
    principleSatisfied = (principle) -> 
      password = props.text
      principle.predicate(password)
    principleClass = (principle) ->
      satisfied = principleSatisfied(principle)
      if satisfied then 'text-success' else 'text-danger'
    console.log(goodPasswordPrinciples.map(principleSatisfied))
    m 'ul', goodPasswordPrinciples.map (p) ->
      m 'li', {class: principleClass(p)}, p.label 
      
Panel = 
  view: (c, props) ->
    m '.panel.panel-default', Object.keys(props).map (k) ->
      m ".panel-#{k}", props[k]
        
PasswordInput = 
  view: (c, props) ->
    m 'input[type="password"].form-control', 
      m.bind props.text, {placeholder: "Enter...