bricks/bricks/bricks.js
2024-10-09 16:09:53 +08:00

559 lines
13 KiB
JavaScript
Executable File

var bricks = window.bricks || {};
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:
*/
bricks.uuid = function(){
var d = crypto.randomUUID();
var lst = d.split('-');
return lst.join('');
}
bricks.deviceid = function(appname){
var deviceid = appname + 'deviceid';
var id = localStorage.getItem(deviceid);
if (!id){
id = bricks.uuid();
localStorage.setItem(deviceid, id);
}
return id;
}
bricks.str2data = function(s, d){
/* fmt like
'my name is ${name}, ${age:type}'
type can be:
int, str, json
*/
funcs = {
'json':JSON.stringify
}
var regex = /\${(\w+)(?::(int|str|json))?}/;
var match = s.match(regex)
if (match){
var key = match[1];
var typ = match[2];
var ss = '${' + key;
if (typ != ''){
ss += ':' + typ;
}
ss += '}';
if (s == ss){
if (!d.hasOwnProperty(key)){
return null;
}
if (typ == ''){
return d[key];
}
var f = funcs[typ];
if (f){
return f(d[key]);
}
return d[key];
}
return s.replace(regex, (k, key, typ) => {
if (d.hasOwnProperty(key)){
var f = funcs[typ];
if (f){
return f(d[key]);
}
return d[key];
}
return '';
});
}
return s;
}
bricks.apply_data = function(desc, data){
if (bricks.is_empty(data)){
return desc;
}
var tmpl = JSON.stringify(desc);
var s = bricks.obj_fmtstr(data, tmpl);
return JSON.parse(s);
}
bricks.widgetBuild = async function(desc, widget, data){
if (! widget){
widget = bricks.Body;
}
var klassname = desc.widgettype;
var base_url = widget.baseURI;
while (klassname == 'urlwidget'){
let url = bricks.absurl(desc.options.url, widget);
base_url = url;
let method = desc.options.method || 'GET';
let opts = desc.options.params || {};
var jc = new bricks.HttpJson();
var desc1 = await jc.httpcall(url, { "method":method, "params":opts});
desc = desc1;
klassname = desc.widgettype;
}
if (data){
desc = bricks.apply_data(desc, data);
}
let klass = bricks.Factory.get(desc.widgettype);
if (! klass){
bricks.debug('widgetBuild():',desc.widgettype, 'not registered', bricks.Factory.widgets_kw);
return null;
}
var options = desc.options || {};
options.baseURI = base_url;
let w = new klass(options);
if (desc.id){
w.set_id(desc.id);
}
if (w.is_container() && desc.subwidgets){
for (let i=0; i<desc.subwidgets.length; i++){
let sdesc = desc.subwidgets[i];
let sw = await (bricks.widgetBuild(sdesc, w, data));
if ( sw ){
w.add_widget(sw);
} else {
bricks.debug('widgetBuild() error: sdesc=', sdesc);
}
}
}
if (desc.hasOwnProperty('binds')){
for (var i=0;i<desc.binds.length; i++){
await bricks.buildBind(w, desc.binds[i]);
}
}
return w;
}
bricks.buildBind = async function(w, desc){
var widget = bricks.getWidgetById(desc.wid, w);
if (!widget){
cnsole.log('desc wid not find', desc);
return;
}
var event = desc.event;
await bricks.buildEventBind(w, widget, event, desc);
}
bricks.buildEventBind = async function(from_widget, widget, event, desc){
var handler = bricks.universal_handler.bind(null,from_widget, widget, desc);
widget.bind(event, handler);
}
bricks.universal_handler = async function(from_widget, widget, desc, event){
var f = await bricks.buildEventHandler(from_widget, desc, event);
if (f){
if (desc.conform){
var c_desc = {
"widgettype":"Conform",
"options":desc.conform
}
var conform_widget = await bricks.widgetBuild(c_desc, widget);
conform_widget.bind('conformed', f);
// handler = conform_widget.open.bind(conform_widget);
} else {
return await f(event);
}
}
bricks.debug('universal_handler() error', 'from_widget=',
from_widget,
'widget=', widget,
'desc=', desc,
event);
}
bricks.buildEventHandler = async function(w, desc, event){
var target = bricks.getWidgetById(desc.target, w);
if (! target){
bricks.debug('target miss desc=', desc, 'w=', w);
return null
}
var rtdata = {};
if (desc.rtdata) rtdata = desc.rtdata;
else if (desc.datawidget){
var data_desc = {
widget:desc.datawidget,
method:desc.datamethod || 'getValue',
params:desc.dataparams,
script:desc.datascript
}
rtdata = await bricks.getRealtimeData(w, data_desc);
}
if (typeof event.params == typeof {}){
rtdata = bricks.extend(rtdata, event.params);
}
switch (desc.actiontype){
case 'urlwidget':
return bricks.buildUrlwidgetHandler(w, target, rtdata, desc);
break;
case 'bricks':
return bricks.buildBricksHandler(w, target, rtdata, desc);
break;
case 'registerfunction':
return bricks.buildRegisterFunctionHandler(w, target, rtdata, desc);
break;
case 'method':
return bricks.buildMethodHandler(w, target, rtdata, desc);
break;
case 'script':
var f = bricks.buildScriptHandler(w, target, rtdata, desc);
return f;
break;
case 'event':
return bricks.buildDispatchEventHandler(w, target, rtdata, desc);
break;
default:
bricks.debug('invalid actiontype', target, desc);
break;
}
}
bricks.getRealtimeData = async function(w, desc){
var target = bricks.getWidgetById(desc.widget, w);
var f;
bricks.debug('getRealtimeData() calling ...');
if (! target){
bricks.debug('target miss', desc);
return null
}
if (desc.method){
f = bricks.buildMethodHandler(null, target, null, desc)
return f();
}
if (desc.script){
f = bricks.buildScriptHandler(null, target, null, desc)
return await f();
}
debug('getRealtimeData():desc=', desc, 'f=', f);
return null;
}
var _buildWidget = async function(from_widget, target, mode, options){
bricks.debug('target=', target, 'mode=', mode, 'options=', options);
var w = await (bricks.widgetBuild(options, from_widget));
if (!w){
bricks.debug('options=', options, 'widgetBuild() failed');
return;
}
if (w.parent) return;
if (mode == 'replace'){
target.clear_widgets();
target.add_widget(w);
} else if (mode == 'insert'){
target.add_widget(w, 0);
} else {
target.add_widget(w);
}
}
bricks.buildUrlwidgetHandler = function(w, target, rtdata, desc){
var f = async function(target, mode, options){
bricks.debug('target=', target, 'mode=', mode, 'options=', options);
var w = await (bricks.widgetBuild(options, w));
if (!w){
bricks.debug('options=', options, 'widgetBuild() failed');
return;
}
if (mode == 'replace'){
target.clear_widgets();
target.add_widget(w);
} else if (mode == 'insert'){
target.add_widget(w, 0);
} else {
target.add_widget(w);
}
}
var options = objcopy(desc.options||{});
var params = options.params || {};
options = bricks.apply_data(options, rtdata);
options.params = bricks.extend(params, rtdata);
var opts = {
"widgettype":"urlwidget",
"options":options
}
return _buildWidget.bind(w, target, target, desc.mode || 'replace', opts);
}
bricks.buildBricksHandler = function(w, target, rtdata, desc){
var f = async function(target, mode, options){
bricks.debug('target=', target, 'mode=', mode, 'options=', options);
var w = await (bricks.widgetBuild(options, wa));
if (!w){
bricks.debug('options=', options, 'widgetBuild() failed');
return;
}
if (mode == 'replace'){
target.clear_widgets();
}
target.add_widget(w);
}
var options = objcopy(desc.options||{});
options = bricks.apply_data(options, rtdata);
return _buildWidget.bind(w, target, target, desc.mode || 'replace', options);
}
bricks.buildRegisterFunctionHandler = function(w, target, rtdata, desc){
var f = bricks.RF.get(desc.rfname);
if( ! f){
bricks.debug('rfname:', desc.rfname, 'not registed', desc);
return null;
}
var params = {};
if (desc.params){
bricks.extend(params, desc.params);
}
if (rtdata){
bricks.extend(params, rtdata);
}
params = bricks.apply_data(params, rtdata);
return f.bind(target, params);
}
bricks.buildMethodHandler = function(w, target, rtdata, desc){
var f = target[desc.method];
if (! f){
bricks.debug('desc:', desc, 'not exists in', target, 'w=', w);
return null;
}
var params = {};
bricks.extend(params, desc.params)
bricks.extend(params, rtdata);
params = bricks.apply_data(params, rtdata);
return f.bind(target, params);
}
bricks.buildScriptHandler = function(w, target, rtdata, desc){
var params = {};
bricks.extend(params, desc.params)
bricks.extend(params, rtdata);
params = bricks.apply_data(params, rtdata);
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
var f = new AsyncFunction('params', 'event', desc.script);
return f.bind(target, params);
}
bricks.buildDispatchEventHandler = function(w, target, rtdata, desc){
var f = function(event_name, params, event){
// console.log('target=', target, 'event_name=', event_name, 'params=', params, 'Arguments=', arguments);
this.dispatch(event_name, params);
}
var params = {};
bricks.extend(params, desc.params)
bricks.extend(params, rtdata);
params = bricks.apply_data(params, rtdata);
return f.bind(target, desc.dispatch_event, params);
}
bricks.getWidgetById = function(id, from_widget){
if (!from_widget){
from_widget = bricks.Body;
}
if (! id){
return from_widget;
}
if (typeof(id) != 'string') return id;
var ids = id.split('.');
var el = from_widget.dom_element;
var new_el = null;
var j = 0;
for (var i=0; i< ids.length; i++){
if (i == 0){
if (ids[i] == 'self'){
el = from_widget.dom_element;
continue;
}
if (ids[i]=='root'){
el = bricks.app.root.dom_element;
continue;
}
if (ids[i]=='app'){
return bricks.app;
}
if (ids[i] == 'window'){
el = bricks.Body.dom_element;
continue;
}
}
try {
if (ids[i][0] == '-'){
var wid = substr(1, ids[i].length - 1)
new_el = el.closest('#' + wid);
} else {
new_el = el.querySelector('#' + ids[i]);
}
}
catch(err){
bricks.debug('getWidgetById():i=', ids[i], id, 'not found', err);
return null;
}
if ( new_el == null ){
bricks.debug('getWidgetById():', id, from_widget, 'el=', el, 'id=', ids[i]);
return null;
}
el = new_el;
}
if (typeof(el.bricks_widget) !== 'undefined'){
return el.bricks_widget;
}
bricks.debug('********', id, 'el=', el, 'found, but not a bricks class with dom element');
return el;
}
bricks.App = class extends bricks.Layout {
constructor(opts){
/*
opts = {
appname:
login_url:
"charsize:
"language":
"i18n":{
"url":'rrr',
"default_lang":'en'
},
"widget":{
"widgettype":"Text",
"options":{
}
}
}
*/
super(opts);
bricks.app = this;
bricks.Body = this;
this.deviceid = bricks.deviceid(opts.appname || 'appname');
this.login_url = opts.login_url;
this.charsize = this.opts.charsize || 20;
this.keyevent_blocked = false;
this.char_size = this.observable('charsize', this.charsize);
if (this.opts.language){
this.lang = this.opts.language;
}
else {
this.lang = navigator.language;
}
this.lang_x = this.observable('lang', this.lang);
this.textList = [];
this.i18n = new bricks.I18n(objget(opts, 'i18n', {}));
this.session_id = null;
this.tooltip = new bricks.Tooltip({otext:'test',i18n:true, wrap:true});
this.add_widget(this.tooltip);
this._Width = this.dom_element.offsetWidth;
this._Height = this.dom_element.offsetHeight;
document.addEventListener('keydown', this.key_down_action.bind(this));
}
create(){
this.dom_element = document.getElementsByTagName('body')[0];
this.set_baseURI(this.dom_element.baseURI);
}
save_session(session){
this.session_id = session;
}
get_session(){
return this.session_id;
}
async setup_i18n(){
let params = {'lang':this.lang};
var jc = new bricks.HttpJson();
d = await jc.httpcall(desc.url, {
"method":desc.method||'GET', params:params});
this.i18n.setup_dict(d);
}
async build(){
var opts = bricks.extend({}, this.opts.widget);
var w = await bricks.widgetBuild(opts, bricks.Body);
if (!w){
bricks.debug('w=', w, 'Body=', bricks.Body, 'Factory=', bricks.Factory)
}
return w;
}
async run(){
await (this.change_language(this));
var w = await this.build();
this.root = w;
if (!w){
bricks.debug('w=', w, 'Body=', bricks.Body, 'Factory=', bricks.Factory)
return null;
}
bricks.Body.add_widget(w);
bricks.Body.down_level();
}
textsize_bigger(){
this.charsize = this.charsize * 1.05;
this.char_size.set(this.charsize);
}
textsize_smaller(){
this.charsize = this.charsize * 0.95;
this.char_size.set(this.charsize);
}
text_resize(){
for (var i=0;i<this.textList.length;i++){
if(this.textList[i].deref()){
var w = this.textList[i].deref();
var ts = this.get_textsize(w.ctype);
w.change_fontsize(ts);
}
}
}
async change_language(lang){
this.lang = lang;
await (this.i18n.change_lang(lang));
this.lang_x.set(this.lang);
}
async key_down_action(event){
if (this.keyevent_blocked){
return;
}
var d = {
key:event.key,
repeat:event.repeat,
altkey:event.altKey,
ctrlkey:event.ctrlKey,
shiftkey:event.shiftKey,
metakey:event.metaKey,
code:event.code
}
this.dispatch('keydown', d);
}
}