manuel
Version:
A super customizable VDOM autocomplete with *production ready* defaults.
226 lines (188 loc) • 3.9 kB
JavaScript
/* eslint-disable fp/no-mutating-methods */
const test = require('tape')
const manuel = require('../')
const m = require('mithril')
const mithrilQuery = require('mithril-query')
const UNUSED_KEY_CODE = 1
const KEY_UP = 38
const KEY_DOWN = 40
const {
compose
, append
, prepend
, split
, join
} = require('ramda')
const render =
require('mithril-node-render')
const renderStdout =
compose(
console.log
, join('\n')
, prepend('--HTML-BEGIN--')
, append('--HTML-END--')
, split('\n')
, render
)
function query(app){
const context =
mithrilQuery(app)
const {
first: $
, find: $$
} = context
return { context, $, $$ }
}
function Model(){
return {
model: {
list: [[]]
,input: ['']
,chosen: [null]
,open: [false]
,highlighted: [null]
}
,modelKeys: {
list: 'list'
,input: 'input'
,chosen: 'chosen'
,open: 'open'
,highlighted: 'highlighted'
}
}
}
function mithrilAutocomplete({model, modelKeys}){
return {
autocomplete:
manuel({
hyperscript: m
,get: k => model[k][0]
,set: (k,v) => model[k].unshift(v)
})
,model
,modelKeys
}
}
test('Mithril v0.2.x', function(t){
const { model, modelKeys, autocomplete } =
mithrilAutocomplete( Model() )
const App = {
controller: function Controller(){
return function view(){
return autocomplete(modelKeys)
}
}
,view: f => f()
}
const { $, $$, context } = query(App)
t.equals(
render(
m('.manuel-complete'
,m('input', { value: "" })
,m('ul')
)
)
, render(context.rootEl)
, 'Basic structure renders'
)
model.input.unshift('Che'); context.redraw()
t.equals(
render(
m('.manuel-complete.not-empty'
,m('input', { value: model.input[0]})
,m('ul')
)
)
, render(context.rootEl)
, 'Autocomplete updates to reflect model, not-empty classes added'
)
$('input').attrs.oninput({
currentTarget: { value: 'Cher' }
})
context.redraw()
t.equals(
model.input[0]
, 'Cher'
, 'Input event updated model'
)
t.equals(
context.rootEl.attrs.className
,'manuel-complete not-empty'
,`Typing with an empty list did not show the drawer
but did add not-empty class to input
`
)
t.equals(
model.open[0]
, true
,'Typing set open to true, even though the list is empty'
)
model.list.unshift([
'Cher'
,'Cherry'
,'Cherries'
,'Chereth Cutestory'
])
context.redraw()
t.equals(
render(
m('.manuel-complete.open.not-empty.loaded'
,m('input', { value: model.input[0]})
,m('ul', model.list[0].map(
x => m(
'li', { class: ""}, [
m('mark', 'Cher')
, x.slice(4)
]
)
) )
)
)
, render(context.rootEl)
, `After adding items to the list:
open and loaded are both added to the root classnames
and matching text is highlighted
`
)
context.redraw()
const prevented = []
context.rootEl.attrs.onkeydown({
keyCode: UNUSED_KEY_CODE
,preventDefault(){
prevented.unshift(UNUSED_KEY_CODE)
}
})
t.equals(
prevented.length
, 0
, 'Pressing an unsed key does not e.preventDefault('
)
context.rootEl.attrs.onkeydown({
keyCode: KEY_DOWN
,preventDefault(){
prevented.unshift(KEY_DOWN)
}
})
t.deepEquals(
prevented
,[KEY_DOWN]
,'Pressing a used key (KEY_DOWN) did prevent default'
)
t.equals(
model.list[0][0]
,model.highlighted[0]
,'First item on a KEY DOWN led to the first item being highlighted'
)
context.redraw()
t.equals(
render($('.highlight'))
,render(
m('li.highlight'
,m('mark', model.highlighted[0] )
)
)
,'Highlight class added to element'
)
t.end()
})
process.on('unhandledRejection', r => console.error(r));