Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <link rel="stylesheet" href="https://unpkg.com/manuel@0.62.0/dist/style.css">
  <title>JS Bin</title>
</head>
<body>
  <script src="https://unpkg.com/manuel@0.62.0/dist/manuel.js"></script>
  <script src="https://cdn.rawgit.com/MithrilJS/mithril.js/v0_2_x/mithril.min.js"></script>
  <script src="https://unpkg.com/mithril-stream@1.1.0/stream.js"></script>
  <script src="https://rawgit.com/ArthurClemens/polythene/master/packages/polythene/polythene-standalone.js"></script>
  
<script>
  
const Maybe = {
  Just(x){
    return { of: Maybe.Just, x}
  }
  ,Nothing(){
    return { of: Maybe.Nothing }
  }
  ,map(f){
    return function(Ma){
      return Ma.of == Maybe.Just
        ? Maybe.Just( f(Ma.x) )
        : Maybe.Nothing()
    }
  }
}
const { 
    IconButton
  , TextField
  , List
  , ListTile
  , Search
  , Button  
  , Icon
  , IndeterminateSpinner: Spinner
} = polythene
const MithrilStreamAutocomplete = manuel({
    hyperscript: m
    ,get: o => o()
    ,set: (o, x) => o(x)
})
const GithubUserSearch = {
  controller(){
      const items = m.stream([])
      const loginIndex = items.map(indexBy( o => o.login))
      const model = {
          list: items.map(
          xs => xs.map(o => o.login)
          )
          ,input: m.stream('JAForb')
          ,chosen: m.stream()
          ,open: m.stream(true)
          ,highlighted: m.stream('')
      }
      
      const loading = m.stream(false)
      const request = 
          afterSilence(1000, model.input).map(function(x){
              return x != null && x.length > 2
              ? Maybe.Just({ 
              method: 'GET'
              , url: 'https://api.github.com/search/users?q=' + x
              })
              : Maybe.Nothing()
          })
      // side effects
      
          .map( 
              Maybe.map(function(req){
                    loading( true )
                  m.request(req)
                  .then( res => res.items )
                  .then( xs => items(xs) )
                  .then( 
                    () => loading(false)
                    ,() => loading(false)
                  )
                  
              })
          )
      m.stream.merge(
        Object.keys(model)
          .map( k => model[k] )
          .concat([ loginIndex, loading ])
      )
        .map( () => m.redraw() )
      const view = () =>
          m('label', 'Search Github Users'
              ,MithrilStreamAutocomplete( model, {
                  filter: () => true
                  ,sort(a, b){
                      var A = loginIndex()[a]
                      var B = loginIndex()[b]
                      return a.score - b.score
                  }
                  ,renderRoot(config){
                     return m('.form'
                            ,{ onkeydown: config.onkeydown
                        }
                            , [
                        m(TextField, {
                            label: 'Github User'
                            ,help: '(Throttled to 1 second)'
                            ,events: {
                                oninput: config.oninput
                             // , onfocus: config.onfocus
                            }
                            ,value: () => model.input()
                        })
                        ,m(Spinner, { show: loading() })
                        ,config.renderItems(config)
                    ])
                  }
                  ,renderItem(x, config){
                    const o = loginIndex()[x]
                    
                    return m('div'
                         ,{ onmousedown: ()=>
                        config.clickItem(x)
                       }
                         ,m(ListTile, {
                        title: 
                            [x]
                          .map( config.highlight )
                          .map(
                            y => x == model.highlighted()
                            ? m('u', y)
                            : y
                          )[0]
                        ,front: 
                          m(Icon, {
                            type: 'large'
                            ,class: 'avatar'
                            ,src: o.avatar_url
                          })
                      })
                    )
                  }
                  ,renderItems(config){
                    return m(List, {
                      borders: true
                      ,tiles: 
                        config.showingDrawer
                        ? config.filteredList.map(function(x){
                            return config.renderItem(x, config)
                        })
                        : []
                    })
                  }
              })
          )
      return { view }
  }
  ,view(o){
    return o.view()
  }
}
const App = {
    view(){
        return m(GithubUserSearch)
    }
}
m.mount(document.body, App);
function afterSilence(ms, s) {
    const r = m.stream()
    var timeoutId
    var last
    s.map(function(){
        last = s()
        clearTimeout(timeoutId);
        timeoutId = setTimeout(function() {
            r(last);
        }, ms);
    })
    return r
}
function indexBy(f){
    return function indexBy$f(xs){
    return xs.reduce(function(p, n){
        p[f(n)] = n
        return p
    }, {})
  }
}
    
</script>
</body>
</html>
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
JAForbespro
0viewers