class _TypeIcons { constructor(){ this.kv = {} } get(n, defaultvalue){ return this.kv.get(n, defaultvalue); } register(n, icon){ this.kv[n] = icon; } } TypeIcons = new _TypeIcons(); /** * Current Script Path * * Get the dir path to the currently executing script file * which is always the last one in the scripts array with * an [src] attr */ var currentScriptPath = function () { var currentScript; if (document.currentScript){ currentScript = document.currentScript.src; } else { console.log('has not currentScriot'); var scripts = document.querySelectorAll( 'script[src]' ); if (scripts.length < 1){ return null; } currentScript = scripts[ scripts.length - 1 ].src; } var currentScriptChunks = currentScript.split( '/' ); var currentScriptFile = currentScriptChunks[ currentScriptChunks.length - 1 ]; return currentScript.replace( currentScriptFile, '' ); } var bricks_path = currentScriptPath(); var bricks_resource = function(name){ return bricks_path + name; } /** * Finds all elements in the entire page matching `selector`, even if they are in shadowRoots. * Just like `querySelectorAll`, but automatically expand on all child `shadowRoot` elements. * @see https://stackoverflow.com/a/71692555/2228771 */ function querySelectorAllShadows(selector, el = document.body) { // recurse on childShadows const childShadows = Array.from(el.querySelectorAll('*')). map(el => el.shadowRoot).filter(Boolean); console.log('[querySelectorAllShadows]', selector, el, `(${childShadows.length} shadowRoots)`); const childResults = childShadows.map(child => querySelectorAllShadows(selector, child)); // fuse all results into singular, flat array const result = Array.from(el.querySelectorAll(selector)); return result.concat(childResults).flat(); } var schedule_once = function(f, t){ /* f: function t:time in second unit */ t = t * 1000 window.setTimeout(f, t); } var schedule_interval = function(f, t){ var mf = function(func, t){ func(); schedule_once(f, t); } schedule_once(mf.bind(f,t), t); } var debug = function(){ console.log(...arguments); } var import_cache = new Map() var import_css = async function(url){ if (import_cache.get(url)===1) return; var result = await tget(url); debug('import_css():tget() return', result); var s = document.createElement('style'); s.setAttribute('type', 'text/javascript'); s.innerHTML = result; document.getElementsByTagName("head")[0].appendChild(s); import_cache.set(url, 1); } var import_js = async function(url){ if (import_cache.get(url)===1) return; // var result = await tget(url); // debug('import_js():tget() return', url, result); var s = document.createElement('script'); s.setAttribute('type', 'text/javascript'); s.src=url; // s.innerHTML = result; document.body.appendChild(s); import_cache.set(url, 1); } var extend = function(d, s){ for (var p in s){ if (! s.hasOwnProperty(p)){ continue; } if (d[p] && (typeof(d[p]) == 'object') && (d[p].toString() == '[object Object]') && s[p]){ extend(d[p], s[p]); } else { d[p] = s[p]; } } return d; } var objget = function(obj, key, defval){ if (obj.hasOwnProperty(key)){ return obj[key]; } return defval; } var obj_fmtstr = function(obj, fmt){ /* fmt like 'my name is ${name}, ${age=}' '${name:}, ${age=}' */ var s = fmt; s = s.replace(/\${(\w+)([:=]*)}/g, (k, key, op) => { if (obj.hasOwnProperty(key)){ if (op == ''){ return obj[key]; } else { return key + op + obj[key]; } } return '' }) return s; } Object.prototype.copy = function(){ var o = {} for ( k in this){ if (this.hasOwnProperty(k)){ o[k] = this[k]; } } return o; } Object.prototype.get = function(name, defvalue){ return objget(this, name, defvalue); } Object.prototype.fmtstr = function(fmt){ return obj_fmtstr(this, fmt); } Object.prototype.update = function(obj){ if (obj){ extend(this, obj); } } Object.prototype.updates = function(){ for (var i=0; i i ==okeys[k])){ style[okeys[k]] = this.opts[okeys[k]]; } if (mkeys.find( i => i ==okeys[k])){ var mk = mapping_keys[okeys[k]]; style[mk] = this.opts[okeys[k]]; } this[okeys[k]] = this.opts[okeys[k]]; } this.dom_element.style.update(style); if (this.opts.css){ this.set_css(this.opts.css); } } sizable(){ bricks_app.text_ref(this); } change_fontsize(ts){ ts = convert2int(ts); if (! this.specified_fontsize){ var rate = this.rate || 1; ts = ts * rate; ts = ts + 'px'; this.dom_element.style.fontSize = ts; for(var i=0;i{ this.set_css(c, remove_flg); }) } set_css(css, remove_flg){ if (!remove_flg){ this.dom_element.classList.add(css); } else { this.dom_element.classList.remove(css); } } set_cssObject(cssobj){ this.dom_element.style.update(cssobj); } is_container(){ return this._container; } _create(tagname){ return document.createElement(tagname); } set_id(id){ this.dom_element.id = id; } set_baseURI(url){ this.baseURI = url; } absurl(url){ console.log('this.baseURI=', this.baseURI); if (this.baseURI){ return absurl(url, this); } return url } show(){ this.dom_element.style.display = ''; } hide(){ this.dom_element.style.display = 'none' } bind(eventname, handler){ this.dom_element.addEventListener(eventname, handler); } unbind(eventname, handler){ this.dom_element.removeEventListener(eventname, handler); } dispatch(eventname, params){ var e = new Event(eventname); e.params = params; this.dom_element.dispatchEvent(e); } } class TextBase extends JsWidget { /* { otext: i18n: rate: halign: valign: color: bgtcolor: css } */ constructor(options){ super(options); this.opts = options; this.rate = this.opts.rate || 1; this.specified_fontsize = false; this.set_attrs(); this.dom_element.style.fontWeight = 'normal'; this.sizable(); } set_attrs(){ if (this.opts.hasOwnProperty('text')){ this.text = this.opts.text; } if (this.opts.hasOwnProperty('otext')){ this.otext = this.opts.otext; } if (this.opts.hasOwnProperty('i18n')){ this.i18n = this.opts.i18n; } this._i18n = new I18n(); if (this.i18n && this.otext) { this.text = this._i18n._(this.otext); } this.dom_element.innerHTML = this.text; } set_i18n_text(){ if ( !this.otext){ return; } if (! this.i18n){ return; } this.text = this._i18n._(this.otext); this.dom_element.innerHTML = this.text; } } class Text extends TextBase { constructor(opts){ super(opts); this.ctype = 'text'; this.set_fontsize(); } } class Title1 extends TextBase { constructor(options){ super(options); this.ctype = 'title1'; this.set_fontsize(); this.dom_element.style.fontWeight = 'bold'; } } class Title2 extends TextBase { constructor(options){ super(options); this.ctype = 'title2'; this.set_fontsize(); this.dom_element.style.fontWeight = 'bold'; } } class Title3 extends TextBase { constructor(options){ super(options); this.ctype = 'title3'; this.set_fontsize(); this.dom_element.style.fontWeight = 'bold'; } } class Title4 extends TextBase { constructor(options){ super(options); this.ctype = 'title4'; this.set_fontsize(); this.dom_element.style.fontWeight = 'bold'; } } class Title5 extends TextBase { constructor(options){ super(options); this.ctype = 'title5'; this.set_fontsize(); this.dom_element.style.fontWeight = 'bold'; } } class Title6 extends TextBase { constructor(options){ super(options); this.ctype = 'title6'; this.set_fontsize(); this.dom_element.style.fontWeight = 'bold'; } } Factory.register('Text', Text); Factory.register('Title1', Title1); Factory.register('Title2', Title2); Factory.register('Title3', Title3); Factory.register('Title4', Title4); Factory.register('Title5', Title5); Factory.register('Title6', Title6); var tooltip = null; createTooltip = function(){ tooltip = document.createElement('div'); tooltip.className = 'tooltip'; tooltip.style.left = '50%'; tooltip.style.trabsform = 'translateX(-50%)'; var mouseoutHandler = (event) => { event.target.removeChild(tooltip); } window.addEventListener('mouseover', event => { if (!event.target.tooltop) return true; tooltip.textContent = event.target.tooltip; event.target.addEventListener( 'mouseout', mouseoutHandler, {once:true} ); }); } let bricks_app = null; /* all type of bind action's desc has the following attributes: actiontype:'bricks', wid: event: target: datawidget: datascript: datamethod: datakwargs: rtdata: conform: and each type of binds specified attributes list following urlwidget action: mode:, options:{ method: params:{}, url: } bricks action: mode:, options:{ "widgettype":"gg", ... } method action: method: params: for methods kwargs script action: script: params: registerfunction action: rfname: params: event action: dispatch_event: params: */ var widgetBuild = async function(desc, widget){ if (! widget){ widget = Body; } const klassname = desc.widgettype; var base_url = null; if (klassname == 'urlwidget'){ let url = absurl(desc.options.url, widget); base_url = url; let method = desc.options.method || 'GET'; let opts = desc.options.params || {}; desc = await jcall(url, { "method":method, "params":opts}); } else { base_url = widget.baseURI; } let klass = Factory.get(desc.widgettype); if (! klass){ console.log('widgetBuild():',desc.widgettype, 'not registered', Factory.widgets_kw); return null; } desc.options.baseURI = base_url; let w = new klass(desc.options); if (desc.hasOwnProperty('id')){ w.set_id(desc.id); } if (desc.hasOwnProperty('subwidgets')){ for (let i=0; i `${key}=${encodeURIComponent(data[key])}`).join('&'); } class HttpText { constructor(headers){ /* var _headers = { "Accept":"text/html", } _headers = { "Accept": "application/json", }; */ if (!headers) headers = {}; this.headers = headers || { "Accept":"text/html", }; this.headers.update(headers); this.params = { "_webbricks_":1 } } url_parse(url){ var a = url.split('?'); if (a.length == 1) return url; url = a[0]; var a = a[1].split('&'); for (var i=0;i { w.bind('submit', (event) => { resolve(event.target.getValue()); event.target.dismiss(); }); w.bind('discard', (event) => { resolve(null); event.target.dismiss() }); }); if (login_info){ this.set_authorization_header(params, lgin_info); const fetchResult = await fetch(url, params); var result=null; result = await this.get_result_data(fetchResult); if (fetchResult.ok){ return result; } if (fetchResult.status == 401){ return await this.withLoginInfo(url, params); } } const resp_error = { "type":"Error", "message":result.message || 'Something went wrong', "data":result.data || '', "code":result.code || '' }; const error = new Error(); error.info = resp_error; return error; } set_authorization_header(params, lgin_info){ var auth = 'password' + '::' + login_info.user + '::' + login_info.password; var rsa = bricks_app.rsa; var code = rsa.encrypt(auth); self.header.authorization = btoa(code) } async get(url, {headers=null, params=null}={}){ return await this.httpcall(url, { method:'GET', headers:headers, params:params }); } async post(url, {headers=null, params=null}={}){ return await this.httpcall(url, { method:'POST', headers:headers, params:params }); } } class HttpJson extends HttpText { constructor(headers){ if (!headers) headers = {}; super(headers); this.headers = { "Accept": "application/json", } this.headers.update(headers); } async get_result_data(resp) { return await resp.json() } } var hc = new HttpText(); var tget = hc.get.bind(hc); var tpost = hc.post.bind(hc); jc = new HttpJson(); var jcall = jc.httpcall.bind(jc); var jget = jc.get.bind(jc); var jpost = jc.post.bind(jc); class Oper { constructor(v){ this.value = v; } __plus__(a, b){ console.log(a, b); return new Oper(a.value + b.value); } __add__(a, b){ console.log(a, b); return new Oper(a.value + b.value); } } class Layout extends JsWidget { constructor(options){ super(options); this._container = true; this.children = []; } add_widget(w, index){ if (! index || index>=this.children.length){ w.parent = this; this.children.push(w); this.dom_element.appendChild(w.dom_element); return } var pos_w = this.children[index]; this.dom_element.insertBefore(w.dom_element, pos_w.dom_element); this.children.insert(index+1, w); } remove_widgets_at_begin(cnt){ return this._remove_widgets(cnt, false); } remove_widgets_at_end(cnt){ return this._remove_widgets(cnt, true); } _remove_widgets(cnt, from_end){ var children = this.children.copy(); var len = this.children.length; for (var i=0; i= cnt) break; var k = i; if (from_end) k = len - 1 - i; var w = children[k] this.children.remove(w); this.remove_widget(w); } } remove_widget(w){ delete w.parent; this.children = this.children.filter(function(item){ return item != w; }); this.dom_element.removeChild(w.dom_element); } clear_widgets(w){ for (var i=0;i 0){ for (var i=0;i