simplyview
Version:
Library to rapidly build UI components, using declarative tools
154 lines (145 loc) • 4.52 kB
JavaScript
class SimplyCommands {
constructor(options={}) {
if (!options.app) {
options.app = {}
}
if (!options.app.container) {
options.app.container = document.body
}
this.app = options.app
this.$handlers = options.handlers || defaultHandlers
if (options.commands) {
Object.assign(this, options.commands)
}
const commandHandler = (evt) => {
const command = getCommand(evt, this.$handlers)
if (!command) {
return
}
if (!this[command.name]) {
console.error('simply.command: undefined command '+command.name, command.source);
return
}
const shouldContinue = this[command.name].call(options.app, command.source, command.value)
if (shouldContinue!==true) {
evt.preventDefault()
evt.stopPropagation()
return false
}
}
options.app.container.addEventListener('click', commandHandler)
options.app.container.addEventListener('submit', commandHandler)
options.app.container.addEventListener('change', commandHandler)
options.app.container.addEventListener('input', commandHandler)
}
call(command, el, value) {
if (!this[command]) {
console.error('simply.command: undefined command '+command);
return
}
return this[command].call(this.app, el, value)
}
action(name) {
console.warn('deprecated call to `this.commands.action`')
let params = Array.from(arguments).slice()
params.shift()
return this.app.actions[name](...params)
}
appendHandler(handler) {
this.$handlers.push(handler)
}
prependHandler(handler) {
this.$handlers.unshift(handler)
}
}
export function commands(options={}, optionsCompat) {
if (optionsCompat) {
let app = options
options = optionsCompat
options.app = options
}
return new SimplyCommands(options)
}
function getCommand(evt, handlers) {
var el = evt.target.closest('[data-simply-command]')
if (el) {
for (let handler of handlers) {
if (el.matches(handler.match)) {
if (handler.check(el, evt)) {
return {
name: el.dataset.simplyCommand,
source: el,
value: handler.get(el)
}
}
return null
}
}
}
return null
}
const defaultHandlers = [
{
match: 'input,select,textarea',
get: function(el) {
if (el.tagName==='SELECT' && el.multiple) {
let values = []
for (let option of el.options) {
if (option.selected) {
values.push(option.value)
}
}
return values
}
return el.dataset.simplyValue || el.value
},
check: function(el, evt) {
return evt.type=='change' || (el.dataset.simplyImmediate && evt.type=='input')
}
},
{
match: 'a,button',
get: function(el) {
return el.dataset.simplyValue || el.href || el.value
},
check: function(el,evt) {
return evt.type=='click' && evt.ctrlKey==false && evt.button==0
}
},
{
match: 'form',
get: function(el) {
let data = {}
for (let input of Array.from(el.elements)) {
if (input.tagName=='INPUT'
&& (input.type=='checkbox' || input.type=='radio')
) {
if (!input.checked) {
return;
}
}
if (data[input.name] && !Array.isArray(data[input.name])) {
data[input.name] = [data[input.name]]
}
if (Array.isArray(data[input.name])) {
data[input.name].push(input.value)
} else {
data[input.name] = input.value
}
}
return data
},
check: function(el,evt) {
return evt.type=='submit'
}
},
{
match: '*',
get: function(el) {
return el.dataset.simplyValue
},
check: function(el, evt) {
return evt.type=='click' && evt.ctrlKey==false && evt.button==0
}
}
]