diff --git a/README.md b/README.md index d9a412e..59a8b49 100755 --- a/README.md +++ b/README.md @@ -2,21 +2,11 @@ A new web application development framework to make web application development more easier like play bricks ## Documentation -We have English and Chinese versions documents, -Documents in English, please read from [docs](docs/README.md), 中文资料看[这里](docs/cn/README.md) -## Development base on components +We have documents in 3 language -We built web development components which use a options objects as API. -third party can develops their component suply the standard of components API +* [中文](docs/zh/brief.md) +* [日本語](docs/ja/brief.md) +* [English](docs/en/brief.md) -Most front-end development tools only help user to build the front-end UI, and use script to build the app's logic. - -Bricks not only build the UI but also the front-end logic. - -Bricks provide a new mathiciam to description the event fire, and event handler, Bricks use json data to descripts event and it handler, when event fire, according the json data, Bricks dynamicly constructs the event handler. - - -## Dependanance - -[Marked](https://github.com/yumoqing/marked) is a tool for markdown text parser, extends from [MarkedJs marked](https://github.com/markedjs/marked), we extends audio and video link, user can directly use `!v[text](url)` pattern to show a video player, and `!a[text](url)` pattern to show a audio player +NOTE: all the documents was generated by Qwen3-max diff --git a/bricks/.DS_Store b/bricks/.DS_Store index b5aa3f5..07573e0 100755 Binary files a/bricks/.DS_Store and b/bricks/.DS_Store differ diff --git a/bricks/bricks.js b/bricks/bricks.js index a842d33..2bba77c 100644 --- a/bricks/bricks.js +++ b/bricks/bricks.js @@ -1,4 +1,13 @@ var bricks = window.bricks || {}; +bricks.get_current_language=function(){ + var lang = navigator.language.substring(0, 2); + if (bricks.app){ + if (bricks.app.lang) return bricks.app.lang; + bricks.app.lang = lang; + return lang; + } + return; +} bricks.app = null; /* all type of bind action's desc has the following attributes: @@ -231,19 +240,21 @@ bricks.universal_handler = async function(from_widget, widget, desc, event){ bricks.default_popup = function(opts){ var popts = bricks.get_popup_default_options(); bricks.extend(popts, opts); + popts.origin_event = event; return new bricks.Popup(popts); } -bricks.default_popupwindow = function(opts){ +bricks.default_popupwindow = function(opts,event){ var popts = bricks.get_popupwindow_default_options(); bricks.extend(popts, opts); + popts.origin_event = event; return new bricks.PopupWindow(popts); } bricks.buildEventHandler = async function(w, desc, event){ var target; if (desc.target == 'Popup'){ - target = bricks.default_popup(desc.popup_options || {}); + target = bricks.default_popup(desc.popup_options || {}, event); } else if (desc.target == 'PopupWindow') { - target = bricks.default_popupwindow(desc.popup_options || {}); + target = bricks.default_popupwindow(desc.popup_options || {}, event); } else if ( desc.target instanceof bricks.JsWidget ) { target = desc.target; } else { @@ -325,22 +336,11 @@ var _buildWidget = async function(from_widget, target, mode, options, desc){ bricks.debug('options=', options, 'widgetBuild() failed'); return; } - - if (w.parent) { - if (target instanceof bricks.Popup || target instanceof bricks.PopupWindow){ - target.destroy(); - } + if (w instanceof bricks.Popup) { return; } - if (target instanceof bricks.Popup || target instanceof bricks.PopupWindow) { - if (! target.parent){ - bricks.app.add_widget(target); - } - if (desc.popup_options){ - if (desc.popup_options.eventpos){ - target.bind('opened', bricks.relocate_by_eventpos.bind(null, desc.event, target)); - } - } + if (w instanceof bricks.NewWindow) { + return; } if (mode == 'replace'){ target.clear_widgets(); @@ -569,14 +569,15 @@ bricks.App = class extends bricks.Layout { this.lang = this.opts.language; } else { - this.lang = navigator.language; + this.lang = navigator.language.substring(0,2); } this.lang_x = this.observable('lang', this.lang); this.zindex = 10000; 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.tooltip = new bricks.Tooltip({otext:'',i18n:true, wrap:true}); + this.tooltip.hide(); this.add_widget(this.tooltip); this._Width = this.dom_element.offsetWidth; this._Height = this.dom_element.offsetHeight; @@ -598,7 +599,10 @@ bricks.App = class extends bricks.Layout { console.log('event=', event); event.preventDefault(); event.stopPropagation() - this.wins_panel = new bricks.WindowsPanel({}) + var opts = bricks.get_popup_default_options(); + opts.auto_open = false; + this.wins_panel = new bricks.WindowsPanel(opts); + this.wins_panel.open(); } get_color(){ return getComputedStyle(this.dom_element).color; @@ -716,7 +720,7 @@ bricks.App = class extends bricks.Layout { return w; } async run(){ - await (this.change_language(this)); + await (this.change_language(this.lang)); var w = await this.build(); this.root = w; if (!w){ diff --git a/bricks/build.sh b/bricks/build.sh index c14d71f..d29f95a 100755 --- a/bricks/build.sh +++ b/bricks/build.sh @@ -11,7 +11,7 @@ SOURCES=" page_data_loader.js factory.js uitypesdef.js utils.js uitype.js \ llm.js websocket.js datarow.js tabular.js continueaudio.js \ line.js pie.js bar.js gobang.js period.js iconbarpage.js \ keypress.js asr.js webspeech.js countdown.js progressbar.js \ - qaframe.js svg.js videoplayer.js " + qaframe.js svg.js videoplayer.js sctter.js radar.js kline.js heatmap.js map.js" echo ${SOURCES} cat ${SOURCES} > ../dist/bricks.js # uglifyjs --compress --mangle -- ../dist/bricks.js > ../dist/bricks.min.js diff --git a/bricks/css/bricks.css b/bricks/css/bricks.css index 2eb4c43..1813dc4 100755 --- a/bricks/css/bricks.css +++ b/bricks/css/bricks.css @@ -605,3 +605,9 @@ hr { color: #00aaff; background: #f0faff; } + +.mini-window { + width: 50px; + height: 50px; +} + diff --git a/bricks/echartsext.js b/bricks/echartsext.js index 65f896b..77ac65f 100644 --- a/bricks/echartsext.js +++ b/bricks/echartsext.js @@ -22,6 +22,10 @@ bricks.EchartsExt = class extends bricks.VBox { if(!this.idField) this.idField = 'id'; if(!this.nameField) this.nameField = 'name'; if(!this.valueFields) this.valueFields = ['value']; + // === 新增:处理 refresh_period === + this.refresh_period = opts.refresh_period; // 单位:秒 + this._refresh_timer = null; + this.build_title_widget(); this.build_description_widget(); this.holder = new bricks.Filler({}); @@ -33,7 +37,49 @@ bricks.EchartsExt = class extends bricks.VBox { schedule_once(this.render_urldata.bind(this), 0.1); } this.bind('element_resize', this.chart.resize.bind(this.chart)); + // === 启动定时刷新(如果配置了 refresh_period)=== + if (this.refresh_period && this.data_url) { + this.start_auto_refresh(); + } } + // === 启动自动刷新任务 === + start_auto_refresh() { + if (this._refresh_timer) return; // 防止重复启动 + + const doRefresh = () => { + this.render_urldata().then(() => { + // 继续下一轮 + if (this._refresh_timer) { // 检查是否已被取消 + this._refresh_timer = setTimeout(doRefresh, this.refresh_period * 1000); + } + }).catch(err => { + console.error('Auto-refresh failed:', err); + this._refresh_timer = setTimeout(doRefresh, this.refresh_period * 1000); // 失败也重试 + }); + }; + + // 初始延迟后开始第一轮,之后循环 + this._refresh_timer = setTimeout(doRefresh, this.refresh_period * 1000); + } + + // === 停止自动刷新 === + stop_auto_refresh() { + if (this._refresh_timer) { + clearTimeout(this._refresh_timer); + this._refresh_timer = null; + } + } + + // === 覆盖 destroy 方法,清理定时器 === + destroy() { + this.stop_auto_refresh(); // 清理资源 + if (this.chart) { + this.chart.dispose(); + this.chart = null; + } + super.destroy(); + } + pivotify(data){ var series = []; data.forEach(x => { @@ -83,7 +129,6 @@ bricks.EchartsExt = class extends bricks.VBox { this.valueFields = this.get_series(data); data = this.pivotify(data); } - this.chart = echarts.init(this.holder.dom_element); var opts = this.setup_options(data); opts.grid = { left: '3%', diff --git a/bricks/form.js b/bricks/form.js index f97eb79..ece78bc 100644 --- a/bricks/form.js +++ b/bricks/form.js @@ -22,6 +22,11 @@ bricks.FieldGroup = class { this.build_fields(form, dc, fields[i].fields); parent.add_widget(dc); dc = new bricks.DynamicColumn({mobile_cols:2}); + dc.set_id(fields[i].name+'_box'); + if (fields[i].nonuse){ + dc.disabled(true); + dc.hide(); + } } else { var box; if (! form.opts.input_layout || form.opts.input_layout == 'VBox'){ @@ -42,6 +47,11 @@ bricks.FieldGroup = class { height:'auto', i18n:true}); box.add_widget(txt); + box.set_id(fields[i].name + '_box') + if (fields[i].nonuse){ + box.disabled(true); + box.hide(); + } var w = Input.factory(fields[i]); if (w){ box.add_widget(w); @@ -72,6 +82,10 @@ bricks.FormBody = class extends bricks.VScrollPanel { }, ... ] + exclusionfields:[ + [a,b,c], # a,b,c互斥,a enabled,b,c必须disabled + [x,y] # x,y互斥 + ] } */ constructor(form, opts){ @@ -234,7 +248,33 @@ bricks.FormBase = class extends bricks.Layout { } return this.get_formdata(); } - + toggle_disable(field_name, flg){ + var w = bricks.getWidgetById(field_name + '_box', this); + if (! w) return; + w.disabled(flg); + if (flg) w.hide(); + else w.show(); + if (flg) return; + this.exclusionfields.forEach(arr =>{ + if (arr.include(field_name)){ + arr.forEach(x => { + if (x!=field_name){ + var w1 = bricks.getWidgetById(x + '_box', this); + if (w1) { + w1.disabled(true); + w1.hide(); + } + } + }); + } + }); + } + enable_field(field_name){ + this.toggle_disable(field_name, false); + } + disable_field(field_name){ + this.toggle_disable(field_name, true); + } get_formdata(){ var data = new FormData(); var changed = false; @@ -243,6 +283,7 @@ bricks.FormBase = class extends bricks.Layout { continue; } var w = this.name_inputs[name]; + if (w.parent.is_disabled()) continue; var d = w.getValue(); if (w.required && ( d[name] == '' || d[name] === null)){ new bricks.Error({title:'Requirement', message:'required field must input"' + w.label + '"'}) @@ -326,8 +367,19 @@ bricks.Form = class extends bricks.FormBase { toolbar: submit_url: method: + exclussionfields:[ + [a,b,c], + [x,y] + ] fields } + field { + name: + label: + uitype: + nonuse: # 不使用 + ... + } */ constructor(opts){ opts.height = "100%"; diff --git a/bricks/header.tmpl b/bricks/header.tmpl index 81051eb..07fecba 100644 --- a/bricks/header.tmpl +++ b/bricks/header.tmpl @@ -6,7 +6,9 @@ - +{% for mycss in cssfiles() %} + +{% endfor %}
+ + + + + + + + + + + +