[(#REM) DO NOT EDIT this file - sources are in ACA project] if (typeof Array.isArray === 'undefined') { Array.isArray = function(obj) { return Object.prototype.toString.call(obj) === '[object Array]'; }; } if (!Object.keys) { Object.keys = (function() { 'use strict'; let hasOwnProperty = Object.prototype.hasOwnProperty, hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'), dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ], dontEnumsLength = dontEnums.length; return function(obj) { if (typeof obj !== 'function' && (typeof obj !== 'object' || obj === null)) { throw new TypeError('Object.keys called on non-object'); } let result = [], prop, i; for (prop in obj) { if (hasOwnProperty.call(obj, prop)) { result.push(prop); } } if (hasDontEnumBug) { for (i = 0; i < dontEnumsLength; i++) { if (hasOwnProperty.call(obj, dontEnums[i])) { result.push(dontEnums[i]); } } } return result; }; }()); } ;(function(constructor) { if (constructor && constructor.prototype && constructor.prototype.childElementCount == null) { Object.defineProperty(constructor.prototype, 'childElementCount', { get: function() { let i = 0, count = 0, node, nodes = this.childNodes; while (node = nodes[i++]) { if (node.nodeType === 1) count++; } return count; } }); } })(window.Node || window.Element); if (window.NodeList && !NodeList.prototype.forEach) { NodeList.prototype.forEach = function (callback, thisArg) { thisArg = thisArg || window; for (let i = 0; i < this.length; i++) { callback.call(thisArg, this[i], i, this); } }; } 'use strict'; function Babel17(options) { const opts = options == null ? {} : options; const rtl = opts.rtl || ['ar', 'ur', 'fa', 'he', 'az', 'dv']; const defPluralRules = { a: function(n) { if (n < 3) { return ['zero','one','two'][n]; } if (n === 100) return 'other'; const lastTwo = n % 100; if (lastTwo >= 3 && lastTwo <= 10) return 'few'; return 'many'; }, c: function() { return 'other'; }, cz: function(n) { if (n === 1) { return 'one'; } if (n >= 2 && n<=4) { return 'few'; } return 'other'; }, f: function(n) { if (n < 2) { return 'one'; } return 'other'; }, g: function(n) { if (n === 1) { return 'one'; } return 'other'; }, i: function(n) { if (n % 10 === 1) { return 'one'; } return 'other'; }, l: function(n) { if (n % 10 === 1 && n % 100 !== 11) { return 'one'; } return n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19) ? 'few' : 'other'; }, p: function(n) { if (n === 1) { return 'one'; } const end = n % 10; return 2 <= end && end <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 'few' : 'many'; }, r: function(n) { const last2 = n % 100; const end = last2 % 10; if (last2 !== 11 && end === 1) { return 'one'; } if (2 <= end && end <= 4 && !(last2 >= 12 && last2 <= 14)) { return 'few'; } return 'other'; }, s: function(n) { const lastTwo = n % 100; if (lastTwo === 1) { return 'one'; } if (lastTwo === 2) { return 'two'; } if (lastTwo === 3 || lastTwo === 4) { return 'few'; } return 'other'; }, rulesOf : { 'ar': 'a', 'bm': 'c', 'id': 'c', 'ja': 'c', 'ko': 'c', 'lo': 'c', 'ms': 'c', 'th': 'c', 'zh': 'c', 'cs': 'cz', 'sk': 'cz', 'aa': 'f', 'cu': 'f', 'dv': 'f', 'fr': 'f', 'hy': 'f', 'tl': 'f', 'pt-br': 'f', 'fa': 'g', 'da': 'g', 'de': 'g', 'en': 'g', 'es': 'g', 'eu': 'g', 'fi': 'g', 'el': 'g', 'he': 'g', 'hi-IN': 'g', 'hu': 'g', 'it': 'g', 'nl': 'g', 'no': 'g', 'pt': 'g', 'sv': 'g', 'tr': 'g', 'is': 'i', 'lt': 'l', 'pl': 'p', 'ru': 'r', 'bs-Latn-BA': 'r', 'bs-Cyrl-BA': 'r', 'srl-RS': 'r', 'sr-RS': 'r', 'hr': 'r', 'sl': 's' }, }; const bab = this; bab.translations = opts.translations || {}; bab.langVarname = opts.langVarname || 'Babel17Lang'; bab.defaultLang = opts.defaultLang || 'en'; bab.countKeyword = opts.countKeyword || 'count'; bab.debug = (opts.debug !== undefined ? opts.debug : true); bab.pluralRules = opts.pluralRules || defPluralRules; bab.langs = Object.keys(bab.translations); let locale = function() { let l = bab.defaultLang; if (window.localStorage && localStorage.getItem(bab. langVarname)) { l = localStorage.getItem(bab.langVarname); } else { if (opts.locale && (typeof bab.translations[opts.locale] == 'object')) { l = opts.locale; } else { const nl = navigator.language.toLowerCase(); if (typeof bab.translations[nl] == 'object') { l = nl; } else { const navLngPrefix = nl.split('-')[0]; if (typeof bab.translations[navLngPrefix] == 'object') { l = navLngPrefix; } } } } return l; } bab.locale = locale(); bab.direction = rtl.includes(this.locale) ? 'rtl' : 'ltr'; if (!bab.translations[bab.locale]) bab.translations[bab.locale] = {}; if (!bab.translations[bab.defaultLang]) bab.translations[bab.defaultLang] = {}; this.plural = function(n, locale) { if (typeof bab.pluralRules[bab.pluralRules.rulesOf[locale]] == 'function') { return bab.pluralRules[bab.pluralRules.rulesOf[locale]](n); } else { if (typeof bab.pluralRules[bab.pluralRules.rulesOf[locale.split('-')[0]]] == 'function') { return bab.pluralRules[bab.pluralRules.rulesOf[locale.split('-')[0]]](n); } bab.warn('Babel17.plural(' + n + ', "' + locale + '"): no plural rule.'); } return 'other'; } this.t = function(txt, options) { if (txt === '') return ''; let opts = (options == null ? {} : (Number.isInteger(options) ? {'count': options} : options)); let tr = bab.translations[bab.locale][txt] || bab.translations[bab.defaultLang][txt] || txt; if (tr === txt) { bab.warn('"' + txt + '": no translation found in ' + bab.locale + ' or ' + bab.defaultLang); return txt; } if (typeof tr == 'object') { if (Number.isInteger(opts[bab.countKeyword])) { tr = tr[bab.plural(opts[bab.countKeyword], bab.locale)]; if (typeof tr === 'undefined') { bab.warn('Babel17.t(): no translation for ' + bab.plural(opts[bab.countKeyword], bab.locale) + ' ('+ opts[bab.countKeyword] + ') "' + txt + '" in ' + bab.locale); if (bab.translations[bab.defaultLang][txt]) { tr = bab.translations[bab.defaultLang][txt][bab.plural(opts[bab.countKeyword], bab.defaultLang)]; } else { bab.warn('Babel17.t(): no fallback translation for ' + bab.plural(opts[bab.countKeyword], bab.defaultLang) + ' ('+ opts[bab.countKeyword] + ') "' + txt + '" in ' + bab.defaultLang); tr = txt; } } } } for (const opt in opts) { tr = tr.replaceAll('#' + opt, opts[opt]); } return tr; } this.warn = function(msg) { if (bab.debug) console.warn((typeof bab.debug == 'string' ? bab.debug + ' ' : '') + msg); } } EventTarget.prototype._addEventListener = EventTarget.prototype.addEventListener; EventTarget.prototype.addEventListener = function(a, b, c) { if (c==undefined) c=false; this._addEventListener(a,b,c); if (! this.eventListenerList) this.eventListenerList = {}; if (! this.eventListenerList[a]) this.eventListenerList[a] = []; this.eventListenerList[a].push({listener:b,options:c}); }; EventTarget.prototype._removeEventListener = EventTarget.prototype.removeEventListener; EventTarget.prototype.removeEventListener = function(a, b ,c) { if (c==undefined) c=false; this._removeEventListener(a,b,c); if (! this.eventListenerList) this.eventListenerList = {}; if (! this.eventListenerList[a]) this.eventListenerList[a] = []; for(let i=0; i < this.eventListenerList[a].length; i++){ if(this.eventListenerList[a][i].listener==b, this.eventListenerList[a][i].options==c){ this.eventListenerList[a].splice(i, 1); break; } } if(this.eventListenerList[a].length==0) delete this.eventListenerList[a]; }; EventTarget.prototype._getEventListeners = function(a) { if (! this.eventListenerList) this.eventListenerList = {}; if (a==undefined) { return this.eventListenerList; } return this.eventListenerList[a]; }; function listAllEventListeners() { const allElements = Array.prototype.slice.call(document.querySelectorAll('*')); allElements.push(document); allElements.push(window); const types = []; for (let ev in window) { if (/^on/.test(ev)) types[types.length] = ev; } let elements = []; for (let i = 0; i < allElements.length; i++) { const currentElement = allElements[i]; for (let j = 0; j < types.length; j++) { if (typeof currentElement[types[j]] === 'function') { elements.push({ "node": currentElement, "type": types[j], "func": currentElement[types[j]].toString(), }); } } if (typeof currentElement._getEventListeners === 'function') { evts = currentElement._getEventListeners(); if (Object.keys(evts).length >0) { for (let evt of Object.keys(evts)) { for (k=0; k < evts[evt].length; k++) { elements.push({ "node": currentElement, "type": evt, "func": evts[evt][k].listener.toString() }); } } } } } return elements.sort(); } 'use strict'; function ACA(options) { const aca = this; aca.zIndex = 999990000; aca.id = 'aca'; aca.height = 30; aca.components = {}; aca.regMepVar = /\&(\w*)\&/g; aca.regMepTranslate = /\<\:([\w\:]*)\:\>/g; aca.menu = [ {name: 'page', menu: [ {name: 'new', action: '' }, {name: 'option 2', action: '', menu: [ {name: 'option 2a'}, {name: 'option 2b'} ] } ] }, {name: 'component', menu: [ {name: 'new', action: 'editComponent' }, {name: 'list', action: 'showComponents', }, {name: 'sets', action: 'componentsSets', } ] }, {name: 'help', menu: [ {name: 'debug', action: 'debug' }, {name: 'about', action: 'about', } ] } ]; aca.translations = { en: { new: 'Create', component: 'Component', components: 'Components', help: 'Help', list: 'List', page: 'Page', about: 'About aca', about_content: 'Web page editor.', } }; aca.editTranslations = {}; aca.componentClassName = 'component'; aca.pinceau = 'images/pinceau.png'; if (options) { aca.id = options.id || 'aca'; aca.height = options.height || aca.height; aca.components = options.components || aca.components; aca.componentClassName = options.componentClassName || aca.componentClassName; aca.regMepVar = options.regMepVar || aca.regMepVar; aca.regMepTranslate = options.regMepTranslate || aca.regMepTranslate; aca.translations = options.translations || aca.translations; aca.editTranslations = options.editTranslations || aca.editTranslations; aca.pinceau = options.pinceau || aca.pinceau; aca.menu = options.menu || aca.menu; } aca.about = function(e) { aca.popat(_T('about'), _T('about_content'), e); }; aca.debug = function(e) { if (window.localStorage) { for (let i = 0; i < localStorage.length; i++) { let key = localStorage.key(i); let value = localStorage.getItem(key); aca.log("k=" + key + " v=" + value, 'info'); } } else { aca.log('No localStorage', 'warn'); } let infos = document.createElement('span'); infos.style.display = 'inline-block'; infos.style.overflow = 'auto'; infos.style.maxWidth = '1000px'; const cl = JSON.stringify(aca.components,null,3); cl.split(/[\r\n|\n\r|\r|\n]/g).forEach(function(line) { infos.append(line); infos.innerHTML = infos.innerHTML.replaceAll(' ', ' '); infos.append(document.createElement('br')); }); aca.popat(_T('debug'), infos, e); }; aca.editComponent = function(e) { let c = new Component(); let pop = c.edit({showSelect : true}); pop.setPosition(e.clientX, e.clientY); } aca.showComponents = function(e) { let cbg = {}; let widgets = document.createElement('div'); widgets.className = 'widgets'; for (const component in aca.components) { const c = aca.components[component]; cbg[c.group] = []; if (c.instances) { for (const instance in c.instances) { cbg[c.group].push(c); } } else { cbg[c.group].push(c); } widgets.append(cbg); widgets.append(document.createElement('br')); } aca.popat(_T('components'), widgets, e); } aca.init = function() { if (document.getElementById(aca.id)) { removeElt(document.getElementById(aca.id)); } try { aca.bab = new Babel17({translations:aca.translations, debug: false}); if (aca.bab.direction == 'rtl') { aca.left = 'right'; aca.right = 'left'; } else { aca.left = 'left'; aca.right = 'right'; } aca.babEdit = new Babel17({translations:aca.editTranslations, debug: false}); let acaStyle = document.createElement('style'); acaStyle.id = aca.id + '_style'; acaStyle.innerHTML = '#' + aca.id + ' {position:fixed; ' + aca.left + ':0; top:0; background-color:rgba(196,196,196,0.5); z-index: ' + aca.zIndex + 100 + ';}#' + aca.id + '_menu_bar {position: relative;}#' + aca.id + ' ul{list-style: none;margin: 0;padding: 0; min-width:10em;}#' + aca.id + ' .' + aca.id + '_menu_parent {display:block;position: relative;float: ' + aca.left + ';line-height: ' + aca.height + 'px;background-color: #95B4CA;border-' + aca.right + ':#CCC 1px solid;}#' + aca.id + ' li.' + aca.id + '_menu_parent a{margin: 0 10px 0 10px; color: #FFFFFF;text-decoration: none; cursor: default;}#' + aca.id + ' li.' + aca.id + '_menu_parent:hover>ul {display:block;position:absolute;}#' + aca.id + ' li.' + aca.id + '_menu_parent li.' + aca.id + '_menu_parent > a:after {content:">";float:' + aca.right + '}#' + aca.id + ' ul.' + aca.id + '_menu_child {display: none;}#' + aca.id + ' ul.' + aca.id + '_menu_child li {background-color: #F0F0F0;line-height: ' + aca.height + 'px;border-bottom:#CCC 1px solid;border-' + aca.right + ':#CCC 1px solid; width:100%;}#' + aca.id + ' ul.' + aca.id + '_menu_child li a{display: block; color: #000000;}#' + aca.id + ' ul ul ul{' + aca.left + ': 100%;top: 0;margin-' + aca.left + ':1px;}#' + aca.id + ' li:hover {background-color: #4FA0D8;}#' + aca.id + ' .' + aca.id + '_menu_parent li:hover {background-color: #E4EFF7;}.expand{font-size:12px;float:' + aca.right + ';margin-' + aca.right + ':5px;}#' + aca.id + ' #' + aca.id + '_lang_selector {float:' + aca.right + ';margin:2px}div.' + aca.id + '_popup { position:absolute; background:#efefef; border: thin solid black; border-radius: 5px; padding:0; box-shadow:3px 3px 3px #dfdfdf;color: #000000;}div.' + aca.id + '_popup_title_bar { border:0; border-bottom: thin solid black; background:#dfdfdf; border-radius:5px; border-bottom-left-radius:0; border-bottom-right-radius:0; padding:0; text-align:center;}span.' + aca.id + '_popup_title_bar_text {margin-right:5px; margin-left:5px}div.' + aca.id + '_popup_content select.selComponent {margin:5px;margin-bottom:0}div.' + aca.id + '_popup_content select.selInstance {margin:5px;margin-bottom:0}div.' + aca.id + '_popup_content div.component_editor {padding:5px;}div.' + aca.id + '_popup_content hr {margin:0;margin-top:3px;margin-bottom:3px;border:0;height:1px;background:#cfcfcf}span.' + aca.id + '_small_button {text-align:center;width:12px;line-height:8px;margin:2px;padding:3px;border:thin solid #cfcfcf;border-radius:6px;background:#efefef}span.' + aca.id + '_small_button:hover {color:red;border-color:darkred;background:#ffdfdf;border-style:outset;box-shadow: 1px 1px 2px #afafaf;cursor:default}.cadre-composant>.pinceau_placeholder {position: relative; float: right; z-index: 9999;}.cadre-composant>.pinceau_placeholder>em.pinceau { position : absolute; background-image: url(' + aca.pinceau + '); background-repeat: no-repeat; background-size: 20px, 20px; height: 20px; width: 20px; top: -10px; ' + aca.right + ': 10px; cursor: pointer; display: none; z-index: ' + aca.zIndex + 8 + ';}.cadre-composant:hover>.pinceau_placeholder>em.pinceau {display: block !important;}.cadre-composant>.pinceau_placeholder>em.shift {right: -10px;}.' + aca.id + '_alert{color: darkred}'; removeElt(document.getElementById(aca.id + '_style')); document.getElementsByTagName('head')[0].appendChild(acaStyle); initPencils(); aca.menuBar(aca.menu); } catch (e) { aca.log('aca.init() failed. ' + e, 'error'); } aca.log('aca.init() done', 'info'); }; aca.componentsSets = function(e) { let setsHTML = document.createElement('div'); let i = document.createElement('input'); setsHTML.append(i); aca.popat(_T('sets'), setsHTML, e); }; aca.log = function(msg, level) { this.level = 'debug'; if (level && ['error', 'warn', 'log', 'info'].includes(level)) this.level = level; console[this.level](msg); }; aca.menuBar = function(menu) { let langChoice = function() { if (!aca.bab.langs || !window.localStorage) return ''; if (aca.bab.langs.length < 2) return ''; let sel = document.createElement('select'); sel.id = aca.id + '_lang_selector'; aca.bab.langs.forEach(function(lng){ let langInLoc = lng; let langInLang = lng; try { langInLoc = new Intl.DisplayNames([aca.bab.locale], {type: 'language'}).of(lng); langInLang = new Intl.DisplayNames([lng], {type: 'language'}).of(lng); } catch(e) { aca.log('Intl.DisplayNames() not supported', 'warn'); } let o = document.createElement('option'); o.value = lng; o.title = langInLoc; o.label = langInLang; o.selected = (lng == aca.bab.locale); sel.append(o); }); let onChange = function() { localStorage.setItem(aca.bab.langVarname, this.value); aca.init(); } addEventListenerOnce(sel, 'change', onChange); return sel; } let onClick = function(e) { let target = e.target; if (target && target.hasAttribute('aca:action')) { let action = target.getAttribute('aca:action'); if (action.substr(0, 5) == 'goto:') { window.location = action.substr(5); } else if (aca[action] instanceof Function) { aca[action](e); } else { aca.popat(action, '', e); } } } const _drawMenu = function(root, menu, l) { if (!Array.isArray(menu)) return false; l = (typeof l !== 'undefined') ? l : 0; if (l > 0) { let ul = document.createElement('ul'); ul.className = aca.id + '_menu_child'; root.append(ul); root = ul; } menu.forEach(function(menuItem) { let mi0 = _T(menuItem.name); let li = document.createElement('li'); let a = document.createElement('a'); a.txtContent = mi0; a.title = _T(menuItem.name); if (menuItem.action) { a.setAttribute('aca:action', menuItem.action); } a.append(mi0) li.append(a); if (Array.isArray(menuItem.menu)) { li.className = aca.id + '_menu_parent'; _drawMenu(li, menuItem.menu, l + 1); } root.append(li); }); } const acaMenu = document.createElement('div'); acaMenu.id = aca.id; acaMenu.dir = aca.bab.direction; const ul = document.createElement('ul'); ul.id = aca.id + '_menu_bar'; _drawMenu(ul, menu); const br = document.createElement('br'); br.style.clear = 'both'; ul.append(langChoice()); acaMenu.append(ul); acaMenu.append(br); addEventListenerOnce(ul, 'click', onClick); document.getElementsByTagName('body')[0].style.marginTop = aca.height + 'px'; document.getElementsByTagName('body')[0].prepend(acaMenu); }; aca.popat = function(title, content, e) { let pop = new Popup(title, content); pop.setPosition(e.pageX, e.pageY); } let initPencils = function() { let clickPencil = function(e) { let ctype = e.target.getAttribute('component:type'); let cid = e.target.getAttribute('component:id'); let c = new Component(ctype, cid); let pop = c.edit(); pop.setPosition(e.clientX, e.clientY); } document.querySelectorAll('.' + aca.componentClassName).forEach(function(c) { if (c.querySelector('.pinceau')) return; let prefix = Component.prototype.cssPrefix; let s = Component.prototype.cssSep; let classes = c.classList; let shift_class = ''; if (classes.contains('shift')) { shift_class = ' shift'; } for(let i = 0; i < classes.length; i++) { const cls = classes[i]; if (cls.substring(0, cls.indexOf(s)) == prefix) { let ph = document.createElement('span'); ph.className = 'pinceau_placeholder'; let p = document.createElement('em'); p.className = 'pinceau' + shift_class; let ctype = cls.substring(cls.indexOf(s) + s.length); let cid =''; if (ctype.substring(0, ctype.indexOf(s))) { cid = ctype.substring(ctype.indexOf(s) + s.length); ctype = ctype.substring(0, ctype.indexOf(s)); p.setAttribute('component:id', cid); } p.setAttribute('component:type', ctype); p.setAttribute('title', ctype + ' ' + cid); p.style.float = document.dir == 'rtl' ? 'left' : 'right'; ph.append(p); c.parentNode.prepend(ph); addEventListenerOnce(p, 'click', clickPencil); break; } } }); } let initDrag = function() { document.querySelectorAll('.draggable').forEach(function(draggable) { let zIndex = draggable.style.zIndex; draggable.ondragstart = function() { return false; }; draggable.onmousedown = function(e) { if (!e.target.classList.contains('draghandler')) { return true; } let shiftX = e.clientX - draggable.getBoundingClientRect().left; let shiftY = e.clientY - draggable.getBoundingClientRect().top; draggable.style.zIndex = aca.zIndex + 90; draggable.style.cursor = 'move'; moveAt(e.pageX, e.pageY); function moveAt(X, Y) { let newX = X - shiftX; let newY = Y - shiftY; let newBottom = newY + draggable.offsetHeight; if (newBottom > document.documentElement.clientHeight) { let docBottom = document.documentElement.getBoundingClientRect().bottom; let scrollY = Math.min(docBottom - newBottom, 10); if (scrollY < 0) scrollY = 0; window.scrollBy(0, scrollY); newY = Math.min(newY, document.documentElement.clientHeight - draggable.offsetHeight); } if (newY < aca.height) { let scrollY = Math.min(-newY, 10); if (scrollY < 0) scrollY = 0; window.scrollBy(0, -scrollY); newY = Math.max(newY, aca.height); } if (newX < 0) newX = 0; if (newX > document.documentElement.clientWidth - draggable.offsetWidth) { newX = document.documentElement.clientWidth - draggable.offsetWidth; } draggable.style.left = newX + 'px'; draggable.style.top = newY + 'px'; }; function onMouseMove(e) { moveAt(e.pageX, e.pageY); }; function onMouseUp() { document.removeEventListener('mousemove', onMouseMove); draggable.removeEventListener('mousemup', onMouseUp); draggable.onmouseup = null; draggable.style.cursor = ''; draggable.style.top = parseInt(draggable.style.top) + window.clientYOffset + 'px'; draggable.style.position = 'absolute'; draggable.style.zIndex = zIndex; }; document.addEventListener('mousemove', onMouseMove); draggable.addEventListener('mouseup', onMouseUp); }; }) } function Popup(title, content) { const cn = aca.id + '_popup'; let acaPop = document.createElement('div'); acaPop.className = cn + ' draggable'; acaPop.style.zIndex = aca.zIndex + 10; acaPop.dir = aca.bab.direction; let popupClose = function(elt) { let popup = elt.parentElement; if (popup.classList.contains(cn)) { removeElt(popup); } }; this.setPosition = function(left, top) { if (left > pageWidth() - acaPop.offsetWidth) left = Math.max(0, left - acaPop.offsetWidth); if (top > pageHeight() - acaPop.offsetHeight) top = Math.max(aca.height, top - acaPop.offsetHeight); acaPop.style.left = left + 'px'; acaPop.style.top = top + 'px'; } let titleBar = document.createElement('div') titleBar.className = cn + '_title_bar draghandler'; titleBar.style.userSelect = 'none'; let titleBarText = document.createElement('span'); titleBarText.className = cn + '_title_bar_text draghandler'; titleBarText.style.userSelect = 'none'; titleBarText.textContent = title; titleBar.append(titleBarText); titleBar.append(Button('\u2715', popupClose)); let ct = document.createElement('div'); ct.className = cn + '_content'; ct.style.margin = 0; ct.style.padding = 0; ct.append(content); acaPop.append(titleBar); acaPop.append(ct); document.getElementsByTagName('body')[0].append(acaPop); initDrag(); } function _T(txt, options) { return aca.bab.t(txt, options); } function Button(val, callback) { let btnClick = function(event) { try { callback(event.target.parentNode); } catch(e) { aca.log('Button("' + val + '", ' + callback.name + ') - ' + e, 'error'); } } let btn = document.createElement('span'); btn.className = aca.id + '_small_button'; btn.style.userSelect = 'none'; btn.style.float = aca.right; btn.textContent = val; addEventListenerOnce(btn, 'click', btnClick); return btn; } function Component(type, id) { this.type = type; this.id = id; const ci = this; if (aca.components.length > 0) { if (type && aca.components[type].editTranslations) { ci.bab = new Babel17({translations: aca.components[type].editTranslations, debug: false}); } } ci.edit = function(options) { let showSelect = 'none'; if (options) { showSelect = (options.showSelect ? 'inherit': 'none'); } let f = document.createElement('form'); f.className = 'editComponent'; let selC = document.createElement('select'); selC.className = 'selComponent'; for (const c in aca.components) { let opt = document.createElement('option'); opt.setAttribute('value', c); if (c == ci.type) { opt.setAttribute('selected', true); } opt.textContent = c; selC.append(opt); } let selI = document.createElement('select'); selI.className = 'selInstance'; let ce = document.createElement('div'); ce.className = 'component_editor'; ce.setAttribute('style', 'text-align:' + aca.right); let div = document.createElement('div'); div.append(selC); div.append(selI); div.append(document.createElement('hr')); div.style.display = showSelect; f.append(div); f.append(ce); let pop = new Popup(_T('component'), f); selC.addEventListener('change', changeSelComponent); selI.addEventListener('change', componentEditor); selC.dispatchEvent(new Event("change")); function changeSelComponent(e) { selI.textContent = ''; if (aca.components.length == 0) { componentEditor(); return; } const instances = aca.components[e.target.value].instances; for (const id in instances) { const i = instances[id]; const name = (i.name ? i.name : id); let opt = document.createElement('option'); opt.setAttribute('value', id); opt.textContent = name; if (id == ci.id) { opt.setAttribute('selected', true); } selI.append(opt); } if (selI.childElementCount > 0) { selI.style.display = 'inline'; } else { selI.style.display = 'none'; } componentEditor(); } function componentEditor() { ce.textContent = ''; ci.type = selC.value; ci.id = selI.value; const cp = aca.components[ci.type]; let placeHolders = {}; if (!ci.bab || (typeof ci.bab.t !== 'function')) { ci.bab = new Babel17({translations: aca.components[ci.type].editTranslations, debug: false}); } if (cp.mep) { ce.innerHTML = cp.mep.replace(/\s\t/g, '').replaceAll(aca.regMepVar, function(tag) { const dtag = tag.substr(1, tag.length - 2); return '' + dtag + ''; }).replaceAll(aca.regMepTranslate, function(tag, txt) { txt = txt.substr(txt.indexOf(':') + 1); return ci.t(txt); }); const spans = ce.querySelectorAll('span[class~="ctlPlaceHolder"]'); for (const span of spans) { placeHolders[span.textContent.toLowerCase()] = span; } } const variables = cp.variables; for (const variable in variables) { const v = variables[variable]; try { let ctl = newControl(v.type, {'c': ci, 'vid': variable, 'v':v, 'value': ci.get(variable)}); if (placeHolders[variable.toLowerCase()]) { placeHolders[variable.toLowerCase()].replaceWith(ctl); } else { ce.append(ctl); ce.append(document.createElement('br')); if (cp.mep) aca.log('componentEditor(): variable "&' + ucfirst(variable) + '&" NOT found in ' + ci.type + '.mep.', 'warn'); } } catch(e) { let i = document.createElement('i'); i.className = aca.id + '_alert'; i.title = e; i.append(variable); ce.append(document.createElement('br')); ce.append(i); aca.log('componentEditor(): unable to create ' + v.type + ' for ' + ci.type + ' ' + ci.id + ' ' + e, 'error'); } } } return pop; }; ci.get = function(varname) { const c = aca.components[ci.type]; if (c.instances) { if (c.instances[ci.id]) { return c.instances[ci.id][varname] !== undefined ? c.instances[ci.id][varname] : (c.variables[varname]['value'] || ''); } } return c.variables[varname]['value'] || ''; }; ci.set = function(varname, val) { const c = aca.components[ci.type]; if (c.instances) c.instances[ci.id][varname] = val; else c.variables[varname]['value'] = val; }; ci.t = function(txt) { try { if (ci.bab && (typeof ci.bab.t === 'function')) { if (ci.bab.t(txt) !== txt) return ci.bab.t(txt); } if (aca.babEdit && (typeof aca.babEdit.t === 'function')) { if (aca.babEdit.t(txt) !== txt) return aca.babEdit.t(txt); } return _T(txt); } catch(e) { aca.log(ci.type + '("' + txt + '") failed. ' + e, 'error'); return txt; } }; } if (options) { Component.prototype.cssPrefix = options.componentCssPrefix || 'c'; Component.prototype.cssSep = options.componentCssSep || '_'; } function addEventListenerOnce(elt, event, callback) { if (typeof elt !== 'object' || (typeof event !== 'string') || (typeof callback !== 'function')) { aca.log('addEventListenerOnce() called with wrong parameters', 'warn'); return false; } try { elt.removeEventListener(event, callback); elt.addEventListener(event, callback); } catch(e) { aca.log('addEventListenerOnce() on "' + l.elid + '", "' + l.event + '", ' + l.callback.name + '" failed. ' + e, 'error'); } } function newControl(type, p) { const controls = { 'bord': ctlBord, 'choix': ctlChoix, 'color': ctlColor, 'img': ctlImg, 'text': ctlText, 'textarea': ctlTextarea, 'widgets': ctlWidgets, } let span = document.createElement('span'); span.className = aca.id + '_control'; let label = document.createElement('label'); label.className = aca.id + 'Label'; let ctl = controls.hasOwnProperty(type) ? new controls[type](p) : null; label.textContent = ctl.t(p.vid); label.setAttribute('title', p.vid); span.append(label); span.append(' '); if (ctl.labelFor) { label.setAttribute('labelFor', ctl.id); } ctl.elts.forEach(function(elt) { span.append(elt); }); return span; } function Control(p) { this.value = (p.value == undefined ? '' : p.value); this.id = getUID(p.c.type + p.c.id + p.vid); this.elts = []; this.labelFor = true; this.onChange = function() { if (typeof p.c.set === 'function') { p.c.set(p.vid, this.value); } else { aca.log('Control.onChange(): component "' + p.c.type + '" do not exists or cannot set variables.', 'error'); } }; this.t = function(txt) { return (typeof p.c.t === 'function') ? p.c.t(txt) : _T(txt); } function getUID(p) { if (document.getElementById(p)==null) return p; let c = 0,i;p = (typeof p==="string")?p:"";do{i=p+c++;}while(document.getElementById(i)!==null); return i; } } function ctlBord(p) { Control.call(this, p); let ctl = this; ctl.value = ctl.value || {color: '', width: '', style: ''}; let onChange = function(e) { const key = e.target.getAttribute('data-' + aca.id +'-var'); ctl.value[key] = e.target.value; ctl.onChange(); }; let onChangeColor = function(e) { document.getElementById(ctl.id + 'Color').value = e.target.value; document.getElementById(ctl.id + 'Color').dispatchEvent(new Event("change")); } let bc = document.createElement('input'); bc.id = ctl.id + 'Color'; bc.setAttribute('data-' + aca.id +'-var', 'color'); bc.setAttribute('type', 'text'); bc.setAttribute('name', p.vid + 'Color'); bc.setAttribute('value', ctl.value.color); let bcp = document.createElement('input'); bcp.setAttribute('type', 'color'); bcp.setAttribute('value', ctl.value.color); let bw = document.createElement('input'); bw.id = ctl.id + 'Width'; bw.setAttribute('data-' + aca.id +'-var', 'width'); bw.setAttribute('type', 'text'); bw.setAttribute('name', p.vid + 'Width'); bw.setAttribute('value', ctl.value.width); let bs = document.createElement('select'); bs.id = ctl.id + 'Style'; bs.setAttribute('data-' + aca.id +'-var', 'style'); bs.setAttribute('type', 'text'); bs.setAttribute('name', p.vid + 'Style'); bs.setAttribute('value', ctl.value.style); ['','none','solid','dashed','dotted','double','groove','ridge','inset','outset'].forEach(function(style) { const o = document.createElement('option'); o.value = style; if (ctl.value.style === style) o.setAttribute('selected', true); o.textContent = p.c.t(style); bs.append(o); }); addEventListenerOnce(bcp, 'change', onChangeColor); addEventListenerOnce(bc, 'change', onChange); addEventListenerOnce(bw, 'change', onChange); addEventListenerOnce(bs, 'change', onChange); ctl.elts.push(bc); ctl.elts.push(bcp); ctl.elts.push(' '); ctl.elts.push(bw); ctl.elts.push(' '); ctl.elts.push(bs); } function ctlChoix(p) { Control.call(this, p); let ctl = this; let onChange = function(e) { ctl.value = e.target.value; ctl.onChange(); } let span = document.createElement('span'); p.v.options.forEach(function(option){ let i = document.createElement('input'); i.id = ctl.id + option; i.setAttribute('type', 'radio'); i.setAttribute('name', p.vid); i.setAttribute('value', option); i.checked = option == p.value; addEventListenerOnce(i, 'change', onChange); let l = document.createElement('label'); l.setAttribute('for', i.id); l.textContent = ctl.t(option); span.append(i); span.append('\u2007'); span.append(l); }); this.elts.push(span); } function ctlColor(p) { Control.call(this, p); let ctl = this; let onChangeColor = function(e) { document.getElementById(ctl.id).value = e.target.value; document.getElementById(ctl.id).dispatchEvent(new Event("change")); } let i = document.createElement('input'); i.id = ctl.id; i.setAttribute('type', 'text'); i.setAttribute('name', p.vid); i.setAttribute('value', ctl.value); addEventListenerOnce(i, 'change', ctl.onChange); let c = document.createElement('input'); c.setAttribute('type', 'color'); c.setAttribute('value', this.value); addEventListenerOnce(c, 'change', onChangeColor); this.elts.push(i); this.elts.push(c); } function ctlImg(p) { Control.call(this, p); let i = document.createElement('input'); i.id = this.id; i.setAttribute('type', 'text'); i.setAttribute('name', p.vid); i.setAttribute('value', this.value); addEventListenerOnce(i, 'change', this.onChange); this.elts.push(i); } function ctlText(p) { Control.call(this, p); let i = document.createElement('input'); i.id = this.id; i.setAttribute('type', 'text'); i.setAttribute('name', p.vid); i.setAttribute('value', this.value); addEventListenerOnce(i, 'change', this.onChange); this.elts.push(i); } function ctlTextarea(p) { Control.call(this, p); let a = document.createElement('textarea'); a.id = this.id; a.setAttribute('style', 'vertical-align:top'); a.setAttribute('name', p.vid); a.value = this.value; addEventListenerOnce(a, 'change', this.onChange); this.elts.push(a); } function ctlWidgets(p) { Control.call(this, p); const ctl =this; const max = 8; const sep = Component.prototype.cssSep; this.value = []; this.labelFor = false; const onAdd = function(elt) { let divC = elt.querySelector('.components'); if (divC.childElementCount < max) { let sel = selectComponent(null, divC.childElementCount + 1); divC.append(sel); addEventListenerOnce(sel, 'change', onChangeWidget); ctl.value.push({}); } } const onDel = function(elt) { if (elt.querySelector('.components').childElementCount) { const eltToRemove = elt.querySelector('.components').lastChild; removeElt(eltToRemove); ctl.value.pop({}); ctl.onChange(); } } const onChangeWidget = function(e) { const key = e.srcElement.getAttribute('data-' + aca.id + '-key'); const newval = e.target.value; const newType = newval.substring(0, newval.indexOf(sep)); const newId = newval.substring(newval.indexOf(sep) + sep.length); ctl.value[key] = {type: newType, id: newId}; ctl.onChange(); } let selectComponent = function(selected, idx) { let sel = document.createElement('select'); sel.setAttribute('data-' + aca.id + '-key', idx - 1); let opt = document.createElement('option'); sel.append(opt); if (Object.keys(aca.components).length > 0) { for (const c in aca.components) { const instances = aca.components[c].instances; for (const id in instances) { const i = instances[id]; if ((c != p.c.type) || (id != p.c.id)) { let o = document.createElement('option'); o.setAttribute('value', c + sep + id); o.label = (i.name ? i.name : '[' + c + ' ' + id + ']'); if (selected) { o.selected = (c == selected.type && id == selected.id); } sel.append(o); } } } } addEventListenerOnce(sel, 'change', onChangeWidget); let d = document.createElement('div'); d.append(idx + '\u2007'); d.append(sel); return d; } ctl.elts.push(Button('\u2212', onDel)); ctl.elts.push('\u2007'); ctl.elts.push(Button('\u002B', onAdd)); let components = document.createElement('div'); components.className= 'components'; let clist = aca.components[p.c.type].instances[p.c.id].components; clist.forEach(function(c, idx){ components.append(selectComponent(c, idx + 1)); ctl.value.push(c); }); ctl.elts.push(components); } function removeElt(elt) { if (elt == null) return false; elt.parentNode.removeChild(elt); elt = null; } function ucfirst(txt) { return txt[0].toUpperCase() + txt.substring(1); } function pageWidth() { return window.innerWidth != null? window.innerWidth : document.documentElement && document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body != null ? document.body.clientWidth : null; } function pageHeight() { return window.innerHeight != null? window.innerHeight : document.documentElement && document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body != null? document.body.clientHeight : null; } aca.init(); }