1
1
mirror of https://github.com/rsms/inter.git synced 2024-12-20 14:11:51 +03:00
inter/docs/res/bindings.js
Rasmus Andersson edfd488300 website
2018-02-20 02:10:20 -08:00

191 lines
4.3 KiB
JavaScript

// requires index.js
function passThrough(v) { return v }
function Binding(name){
this.name = name
this.value = undefined
this.inputs = []
this.outputs = []
this.listeners = []
this.parser = undefined
this.formatter = passThrough
}
Binding.prototype.addInput = function(el) {
var binding = this
var _onInput = function(ev) {
binding.setValue(el.value, el)
}
var input = {
el: el,
_onInput: _onInput,
}
this.inputs.push(input)
if (this.value === undefined) {
this.value = el.value
} else {
input.el.value = this.formatter(this.value)
}
el.addEventListener('input', _onInput, {passive:true})
}
Binding.prototype.addOutput = function(el) {
this.outputs.push(el)
if (this.value !== undefined) {
el.innerText = this.formatter(this.value)
}
}
// listener signature:
// function(nextval string, prevval string, b Binding)void
//
Binding.prototype.addListener = function(listener) {
this.listeners.push(listener)
}
Binding.prototype.setValue = function(nextval, origin) {
var prevval = this.value
if (this.parser) {
nextval = this.parser(nextval, prevval)
}
if (this.value === nextval) {
return
}
var binding = this
this.value = nextval
var value = binding.formatter(nextval)
this.inputs.forEach(function(input) {
if (input.el !== origin) {
input.el.value = value
}
})
this.outputs.forEach(function(el) {
el.innerText = value
})
this.listeners.forEach(function(listener) {
listener(nextval, prevval, this)
})
}
function Bindings() {
this.bindings = {}
}
Bindings.prototype.getBinding = function(name, input) {
var binding = this.bindings[name]
if (!binding) {
binding = new Binding(name)
this.bindings[name] = binding
}
return binding
}
Bindings.prototype.bindInput = function(name, input) {
var binding = this.getBinding(name)
binding.addInput(input)
}
Bindings.prototype.bindOutput = function(name, el) {
var binding = this.getBinding(name)
binding.addOutput(el)
}
Bindings.prototype.bindAllInputs = function(queryOrInputElementList) {
var bindings = this
var elements = (
typeof queryOrInputElementList == 'string' ? $$(queryOrInputElementList) :
queryOrInputElementList
)
elements.forEach(function(el) {
var bindingName = el.dataset.binding
if (bindingName) {
if (
el.tagName == 'INPUT' ||
el.tagName == 'TEXTAREA' ||
el.tagName == 'SELECT'
) {
bindings.bindInput(bindingName, el)
} else {
bindings.bindOutput(bindingName, el)
}
}
})
}
// listener signature:
// function(nextval string, prevval string, b Binding)void
//
Bindings.prototype.addListener = function(name, listener) {
var binding = this.getBinding(name)
binding.addListener(listener)
}
Bindings.prototype.setValue = function(name, value) {
var binding = this.getBinding(name)
binding.setValue(value)
}
Bindings.prototype.setFormatter = function(name, formatter) {
var binding = this.getBinding(name)
binding.formatter = formatter || passThrough
}
Bindings.prototype.value = function(name, defaultValue) {
var binding = this.bindings[name]
return binding && binding.value !== undefined ? binding.value : defaultValue
}
function fmt_float(nextval, prevval) {
var n = parseFloat(nextval)
return isNaN(n) ? 0 : n
}
function fmt_int(nextval, prevval) {
var n = parseInt(nextval)
return isNaN(n) ? 0 : n
}
// configure is convenience function for setting value, adding a
// listener and associating a parser with a binding.
// If a listener and a value is provided, the value is set and the listener
// is immediately invoked.
//
Bindings.prototype.configure = function(name, value, parser, listener) {
var binding = this.getBinding(name)
if (listener) {
binding.addListener(listener)
}
if (value !== undefined && value !== null) {
binding.setValue(value)
}
if (parser) {
if (typeof parser == 'string') {
switch (parser) {
case 'number':
case 'float':
parser = fmt_float; break;
case 'int':
case 'integer':
parser = fmt_int; break;
default:
throw new Error('unknown parser "' + parser + '"')
}
} else if (typeof parser != 'function') {
throw new Error('parser should be a string or function')
}
binding.parser = parser
}
}