import bind, { isCheckbox, isRadio, safeParseBoolean } from '../utils/bind'
import { evaluateLater } from '../evaluator'
import { directive } from '../directives'
import { mutateDom } from '../mutation'
import { nextTick } from '../nextTick'
import { isCloning } from '../clone'
import on from '../utils/on'
directive('model', (el, { modifiers, expression }, { effect, cleanup }) => {
let scopeTarget = el
if (modifiers.includes('parent')) {
scopeTarget = el.parentNode
}
let evaluateGet = evaluateLater(scopeTarget, expression)
let evaluateSet
if (typeof expression === 'string') {
evaluateSet = evaluateLater(scopeTarget, `${expression} = __placeholder`)
} else if (typeof expression === 'function' && typeof expression() === 'string') {
evaluateSet = evaluateLater(scopeTarget, `${expression()} = __placeholder`)
} else {
evaluateSet = () => {}
}
let getValue = () => {
let result
evaluateGet(value => result = value)
return isGetterSetter(result) ? result.get() : result
}
let setValue = value => {
let result
evaluateGet(value => result = value)
if (isGetterSetter(result)) {
result.set(value)
} else {
evaluateSet(() => {}, {
scope: { '__placeholder': value }
})
}
}
if (typeof expression === 'string' && el.type === 'radio') {
mutateDom(() => {
if (! el.hasAttribute('name')) el.setAttribute('name', expression)
})
}
let event = (el.tagName.toLowerCase() === 'select')
|| ['checkbox', 'radio'].includes(el.type)
|| modifiers.includes('lazy')
? 'change' : 'input'
let removeListener = isCloning ? () => {} : on(el, event, modifiers, (e) => {
setValue(getInputValue(el, modifiers, e, getValue()))
})
if (modifiers.includes('fill'))
if ([undefined, null, ''].includes(getValue())
|| (isCheckbox(el) && Array.isArray(getValue()))
|| (el.tagName.toLowerCase() === 'select' && el.multiple)) {
setValue(
getInputValue(el, modifiers, { target: el }, getValue())
);
}
if (! el._x_removeModelListeners) el._x_removeModelListeners = {}
el._x_removeModelListeners['default'] = removeListener
cleanup(() => el._x_removeModelListeners['default']())
if (el.form) {
let removeResetListener = on(el.form, 'reset', [], (e) => {
nextTick(() => el._x_model && el._x_model.set(getInputValue(el, modifiers, { target: el }, getValue())))
})
cleanup(() => removeResetListener())
}
el._x_model = {
get() {
return getValue()
},
set(value) {
setValue(value)
},
}
el._x_forceModelUpdate = (value) => {
if (value === undefined && typeof expression === 'string' && expression.match(/\./)) value = ''
window.fromModel = true
mutateDom(() => bind(el, 'value', value))
delete window.fromModel
}