const objToDom=obj => { if(obj instanceof Node) { return obj; } else if(obj[Popup.EM]) { let em=document.createElement('em'); em.appendChild(document.createTextNode(obj[Popup.EM])); return em; } else if(obj[Popup.STRONG]) { let em=document.createElement('strong'); em.appendChild(document.createTextNode(obj[Popup.STRONG])); return em; } else if(typeof obj=='string' || typeof obj=='number') { return document.createTextNode(obj+''); } else if(Array.isArray(obj)) { let ul=document.createElement('ul'); obj.forEach(elem => ul.appendChild(objToDom(elem))); return ul; } else { let table=document.createElement('table'); Object .keys(obj) .forEach(key => { let tr=table.appendChild(document.createElement('tr')); tr.appendChild(document.createElement('th')).appendChild(document.createTextNode(key)); tr.appendChild(document.createElement('td')).appendChild(objToDom(obj[key])); }); return table; } } class Popup { constructor(title, content=[], buttons={}, large=false) { this.title=title; this.content=content.map(objToDom); this.buttons={...buttons}; this.large=large; } addContent(cnt) { this.content.push(objToDom(cnt)); } addText(cnt) { this.content.push(document.createTextNode(cnt)); } addEm(cnt) { this.content.push(objToDom({[Popup.EM]: cnt})); } addStrong(cnt) { this.content.push(objToDom({[Popup.STRONG]: cnt})); } addHeading(cnt, level=2) { let hn=document.createElement('h'+level); hn.innerText=cnt; this.content.push(hn); } async display(parent=document.body) { let outer=document.createElement('div'); outer.classList.add('popup'); let popup=outer.appendChild(document.createElement('div')); popup.classList.add('content'); if(this.large) popup.classList.add('large'); let title=popup.appendChild(document.createElement('h1')); title.innerText=this.title; let contentSection=popup.appendChild(document.createElement('section')); this.content.forEach(elem => contentSection.appendChild(elem)); let buttonSection=popup.appendChild(document.createElement('section')); let buttons=Object.keys(this.buttons).map(btn => { let button=document.createElement('button'); button.innerText=this.buttons[btn]; button.dataset.code=btn; return button; }); buttons.forEach(btn => buttonSection.appendChild(btn)); parent.appendChild(outer); Popup.displayed.push(this); const btnActions=buttons.map(btn => new Promise(ok => { btn.addEventListener('click', e => { e.preventDefault(); return ok(btn.dataset.code); }); })); const dismissAction=new Promise(ok => this.dismiss=ok); const code=await Promise.race(btnActions.concat([dismissAction])); parent.removeChild(outer); Popup.displayed.splice(Popup.displayed.indexOf(this), 1); return code; } } Popup.EM=Symbol('EM'); Popup.STRONG=Symbol('STRONG'); Popup.displayed=[]; Popup.dismiss=arg => { Popup.displayed.forEach(p => p.dismiss(arg)); }; return module.exports=Popup;