kriptopter/ui.js

102 lines
3.4 KiB
JavaScript

const _s = (ss, ...pp)=> ss.map((s,i)=> s + (pp[i]||'')).join('')
, _a = iterable=> iterable.length > 1 ? iterable : iterable[0]
, Q = (ss, ...pp)=> [...document.querySelectorAll( _s(ss, ...pp))]
, T = document.createElement('template')
, DOM = (ss, ...pp)=> ( T.innerHTML = _s(ss, ...pp), document.adoptNode(T.content).childNodes )
, $ = (ss, ...pp)=> _a( ~_s(ss, ...pp).indexOf('<') ? DOM(ss, ...pp) : Q(ss, ...pp) )
, notify = (html,attrs)=> $`body`.add( $`<ui-toast ${attrs ? attrs : ''}>${html}</ui-toast>` )
, bubbleOn = el=> e=> el.dispatchEvent( new ErrorEvent('Error',{bubbles:true, error:e}) )
, pulse = color=> (document.body.style.background = color) && setTimeout(o=> document.body.style.background = 'lightgrey', 1000)
Node.prototype.add = function( ...els )
{
this.append( ...els )
return _a( els )
}
Node.prototype.$ = function(ss, ...pp)
{
return _a(
~_s(ss, ...pp).indexOf('<')
? this.add(...DOM(ss, ...pp))
: [...this.querySelectorAll( _s(ss, ...pp))]
)
}
Node.prototype.on = function(ss, ...pp)
{
let types = _s( [].concat(ss), ...pp ).split(/[,\s]/)
return (...args)=> ( types.map( type=> this.addEventListener(type,...args)), this )
}
class UI extends HTMLElement {
static get is(){ return 'ui' + this.name.replace(/[A-Z]/g, L=> '-'+L.toLocaleLowerCase()) }
constructor()
{
super()
let tpl = $`template[${this.constructor.is}]`
tpl && this.attachShadow({mode: 'open'})
.appendChild( tpl.content.cloneNode(true) )
}
}
class Toast extends UI {
static get duration(){ return this._duration || 10000 }
static set duration( v ){ this._duration = v }
connectedCallback()
{
setTimeout( toast=> toast.remove(), this.getAttribute('duration') || Toast.duration, this )
}
}
class Data extends UI {
static get observedAttributes(){ return ['bin','uint','utf8','base64','frame'] }
connectedCallback()
{
// this.observer = new MutationObserver(
// changes=> console.log(changes.filter(m=>~['bin','255','utf8','base64','object'].indexOf(m.attributeName)) )
// )
// .observe( this, { attributes: true } )
this.shadowRoot.append(
...Data.observedAttributes
.map( type=> $`<button ${type}>${type}</button>`
.on`click`( e=> this.type = e.target.innerText )
)
)
// this.shadowRoot.$`button`.map( button=> button.onclick = e=> this.type = e.target.innerText )
this.shadowRoot.$`textarea`.on`change`( e=> this._value = CC[this.type+'2buffer'](e.target.value) )
}
get type(){ return this.attributes[0].name }
set type( v ){
if( this.type == v ) return;
[...this.attributes].map( o=> o.ownerElement.removeAttributeNode(o) )
this.setAttribute( v, '' )
}
get value(){ return this._value }
set value( v ){ this._value = v; this.shadowRoot.$`textarea`.value = CC['buffer2'+this.type](v) }
attributeChangedCallback(name, oldValue, newValue)
{
if( newValue == null ) return
console.log(arguments)
if( newValue != null && this._value && CC['buffer2'+this.type] )
this.shadowRoot.$`textarea`.value = CC['buffer2'+this.type]( this._value )
else if( this.type == 'frame' )
this.shadowRoot.$`iframe`.src = URL.createObjectURL(new File([$text.value],'file.jpg',{type: 'image/jpeg'}) )
}
}
;[ Toast, Data ]
.map( klass=> customElements.define(klass.is, klass) )
// document.body.addEventListener('Error', e=> pulse('red') && (notify(e.error.message).style.color = 'red') )
$`body`.on`Error`( e=>
pulse('red') && notify(
`<b>${e.error.code||''} ${e.error.name}</b>: ${e.error.message}`
, 'error')
)