diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 8a67f2f..7420a31 --- a/README.md +++ b/README.md @@ -1,2 +1,21 @@ -# bricks +# Bricks +A new web application development framework to make web application development more easier like play bricks +## Documentation +Documents in English, please read from [docs](docs/index.md), 中文资料看[这里](docs/cn/index.md) + +## Development base on components + +We built web development components which use a options objects as API. +third party can develops their component suply the standard of components API + +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 diff --git a/bricks/.DS_Store b/bricks/.DS_Store new file mode 100755 index 0000000..82ec547 Binary files /dev/null and b/bricks/.DS_Store differ diff --git a/bricks/accordion.js b/bricks/accordion.js new file mode 100644 index 0000000..4d9672a --- /dev/null +++ b/bricks/accordion.js @@ -0,0 +1,72 @@ +class Accordion extends VBox { + /* + { + item_size: + items:[ + { + icon: + text: + content:{ + widgettype: + ... + } + } + ] + } + */ + constructor(opts){ + super(opts); + var item_size = this.opts.item_size || '25px'; + this.set_height('100%'); + var items = this.opts.items; + this.items = []; + this.subcontents = {}; + var item_css = this.opts.css || 'accordion' + '-button'; + var content_css = this.opts.css || 'accordion' + '-content'; + for (var i=0; i< items.length; i++){ + var opts = { + name:items[i].name, + icon:items[i].icon, + text:items[i].text, + height:'auto', + orientation:'horizontal' + } + var b = new Button(opts); + b.bind('click', this.change_content.bind(this)); + this.items.push(b); + this.add_widget(b); + } + this.content = new VBox({}); + } + async change_content(evnet){ + var b = event.target.bricks_widget; + var name = b.opts.name; + console.log('accordion: button=', b, 'name=', name); + var pos = -1; + for (var i=0; i< this.opts.items.length; i++){ + if (name == this.opts.items[i].name){ + pos = i; + break + } + } + if (pos==-1){ + debug('Accordion():name=',name, 'not found in items',this.opts.items); + } + var c = objget(this.subcontents,name); + if (! c){ + c = await widgetBuild(this.opts.items[pos].content); + this.subcontents[name] = c; + } + this.content.clear_widgets(); + this.content.add_widget(c); + try { + this.remove_widget(this.content); + } + catch(e){ + ; + } + this.add_widget(this.content, pos+1); + } +} + +Factory.register('Accordion', Accordion); diff --git a/bricks/aggrid.js b/bricks/aggrid.js new file mode 100644 index 0000000..d705f50 --- /dev/null +++ b/bricks/aggrid.js @@ -0,0 +1,46 @@ + +class AG_Grid extends JsWidget { + /* + { + dataurl: + fields: + + } + */ + constructor(opts){ + super(opts); + ag_opts = {} + } + + init(){ + this.datasource = { + getRows:this.getRows, + startRow + this.ag_opts.columnDefs = []; + this.ag_opts.rowModelType = 'infinite'; + this.ag_opts.maxConcurrentDatasourceRequests: 1, + this.ag_opts.datasource = this.datasource; + for (var i=0; i< this.opts.fields.length; i++){ + var f = { + width:this.opts.fields[i].width | 100, + headerName:this.opts.fields[i].label|this.opts.fields[i].name, + field:this.opts.fields[i].name + }, + this.ag_opts.columnDefs.push(f) + } + this.ag_opts.defaultColDef = {sortable: true, filter: true}; + this.ag_opts.rowSelection = 'multiple'; + this.ag_opts.animateRows = true; + this.ag_opts.onCellClicked = this.cell_clicked.bind(this); + this.aggrid = new agGrid.Grid(this.dom_element, this.ag_opts); + fetch(this.opts.dataurl) + .then(response => response.json()) + .then(data => { + // load fetched data into grid + this.ag_opts.api.setRowData(data); + }); + } + cell_clicked(params){ + console.log('clicked, params=', params); + } +} diff --git a/bricks/audio.js b/bricks/audio.js new file mode 100755 index 0000000..3daa272 --- /dev/null +++ b/bricks/audio.js @@ -0,0 +1,34 @@ + +class AudioPlayer extends JsWidget { + /* + { + url: + autoplay: + } + */ + + constructor(options){ + super(options); + this.url = opt.url; + this.audio = this._create('audio'); + // this.audio.autoplay = this.opts.autoplay; + this.audio.controls = true; + if (this.opts.autoplay){ + this.audio.addEventListener('canplay', this.play_audio.bind(this)); + } + this.audio.style.width = "100%" + var s = this._create('source'); + s.src = this.opts.url; + this.audio.appendChild(s); + this.dom_element.appendChild(this.audio); + } + toggle_play(){ + if (this.audio.paused){ + this.audio.play(); + } else { + this.audio.pause(); + } + } +} + +Factory.register('AudioPlayer', AudioPlayer); diff --git a/bricks/baseKnowledge.txt b/bricks/baseKnowledge.txt new file mode 100755 index 0000000..947c3c1 --- /dev/null +++ b/bricks/baseKnowledge.txt @@ -0,0 +1,10 @@ +css 子元素按照父元素位置定位 + +``` +#parentDiv { position:relative; } +#childDiv { position:absolute; left:50px; top:20px; } +``` +css 子元素按照window位置定位( use top:, left:, right:, and bottom: to position as you see fit.) +``` +#yourDiv { position:fixed; bottom:40px; right:40px; } +``` diff --git a/bricks/bricks.js b/bricks/bricks.js new file mode 100755 index 0000000..0f119de --- /dev/null +++ b/bricks/bricks.js @@ -0,0 +1,460 @@ +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.title { + background-color: #a0a0a0; +} + +.message { + padding: 10px; + width: 30%; + height: 30%; + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 5px; + margin-bottom: 10px; +} + +.error { + padding: 10px; + width: 30%; + height: 30%; + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 5px; + margin-bottom: 10px; +} + +.message>.title { + background-color: #3030f0; +} + +.vscroll { + overflow-x: scroll; +} + +.hscroll { + overflow-y: scroll; +} + +.scroll { + overflow:scroll; +} + +.error>.title { + background-color: #f03030; +} + +.vcontainer { + display: flex; + flex-direction: column; + height:100%; + scroll:auto; +} + +.vbox { + display: flex; + flex-direction: column; +} + +.hcontainer { + display: flex; + flex-direction: row; + width:100%; + scroll:auto; +} + +.hbox { + display: flex; + flex-direction: row; +} + +.fixitem { + flex:none; +} + +.filler, .hfiller, .vfiller { + flex: auto; + scroll:auto; +} + +.vfiller .vbox:last-child { + overflow-x: overlay; +} + +.vline { + width:1px; + height:100%; + background-colir:#999; +} + +.hline { + height:1px; + width:100%; + background-colir:#999; +} +.hfiller::-webkit-scrollbar { + display: none; +} + +.flc { + width: 203px; + overflow-y: scroll; + overflow-x: visible; +} + +.vtoolbar { + heigth: 100%; + background-color: #f1f1f1; + border: 1px solid #ccc; +} + +.selected { + background-color: #d4d4d4; +} + +.htoolbar { + width: 100%; + height: 40px; + background-color: #f1f1f1; + border: 1px solid #ccc; +} + +.toolbar-button { + background-color: inherit; + float: left; + border: none; + outline: none; + cursor: pointer; + padding: 14px 16px; + transition: 0.3s; + border: 1px solid #888; +} + +.toolbar-button-active { + background-color: #ddd; +} + +.tabpanel { + background-color: #ededed; + border: 3px solid #888; +} + +.tabpanel-content { + background-color: #f8f8f8; + border: 2px solid #888; +} + +.multicolumns { + column-width: 340px; + colomn-gap: 10px'; + overflow-x:none; +} + +.popup { + z-index: 1000; + position: absolution; + background-color: #f1f1f1; + border: 1px solid #c1c1c1; +} + +.inputbox { + background-color: #cccccc; + border: 1px solid #bbbbbb; + padding: 10px; + margin: 0 0 1em 0; +} + +button[tooltip]:hover::after { + content: attr(tooltip); + display: block; + position: absolute; + transform: translateX(-50%); +} + +div[tooltip]:hover::after { + content: attr(tooltip); + display: block; + position: absolute; + transform: translateX(-50%); +} + +input[tooltip], +div[tooltip] { + width: max-content; + margin: auto; +} + +.datagrid { + display:flex; + flex-direction:column; + width:100%; + height:100%; +} + +.datagrid-grid { + width: 100%; + flex: 1; + overflow: auto; + + display: flex; + flex-direction: row; +} + +.datagrid-left { + height:100%; + display: flex; + flex-direction: column; + overflow: auto; +} +.datagrid-left>.scrollbar { + width:0px; + opacity:0; +} +.datagrid-right { + flex:1 0 ; + height:100%; + overflow: auto; + display: flex; + flex-direction: column; +} +.grid_header, .grid_footer { + height: 50px; + background-color: blue; +} +.datagrid-row { + flex:0 0 150px; + display: flex; + flex-direction: row; +} +.datagrid-body { + width: 100%; + flex: 1; + overflow: auto; + display: flex; + flex-direction: column; +} diff --git a/bricks/datagrid.js b/bricks/datagrid.js new file mode 100644 index 0000000..02249a2 --- /dev/null +++ b/bricks/datagrid.js @@ -0,0 +1,384 @@ +class Row { + constructor(dg, rec) { + this.dg = dg; + this.data = objcopy(rec); + this.freeze_cols = []; + this.normal_cols = []; + this.name_widgets = {}; + this.click_handler = this.dg.click_handler.bind(this.dg, this); + this.freeze_row = this.create_col_widgets(this.dg.freeze_fields, this.freeze_cols); + if (this.freeze_row){ + // this.freeze_row.set_css('datagrid-row'); + this.freeze_row.set_style('width', this.freeze_width + 'px'); + } + this.normal_row = this.create_col_widgets(this.dg.normal_fields, this.normal_cols); + if (this.normal_row){ + // this.normal_row.set_css('datagrid-row'); + this.normal_row.set_style('width', this.normal_width + 'px'); + } + } + create_col_widgets(fields, cols) { + for (var i = 0; i < fields.length; i++) { + var f = fields[i]; + var opts = f.uioptions || {}; + var w; + extend(opts, { + name: f.name, + label: f.label, + uitype: f.uitype, + width: f.width, + required: true, + row_data: objcopy(this.data), + readonly: true + }); + if (opts.uitype == 'button') { + opts.icon = f.icon; + opts.action = f.action; + opts.action.params = objcopy(this.data); + opts.action.params.row = this; + w = new Button(opts); + w.bind('click', this.button_click.bind(w)) + } else { + w = viewFactory(opts, this.data); + w.bind('click', this.click_handler); + } + w.desc_dic = opts; + w.rowObj = this; + w.dom_element.style['min-width'] = w.width + 'px'; + w.set_style('flex', '0 0 ' + convert2int(f.width) + 'px'); + cols.push(w); + this.name_widgets[f.name] = w; + } + if (cols.length > 0) { + var row = new HBox({ height: 'auto' }) + for (var i = 0; i < cols.length; i++) { + row.add_widget(cols[i]); + } + return row; + } + return null; + } + button_click(event){ + this.getValue=function(){ + return this.desc_dic.row_data; + } + var desc = this.desc_dic.action; + desc.datawidget = this; + desc.datamethod = 'getValue'; + var f = universal_handler(this, this.rowObj, desc); + } + selected() { + if (this.freeze_row) { + this.freeze_cols.forEach(w => { w.set_css('selected', false) }) + } + if (this.normal_row) { + this.normal_cols.forEach(w => { w.set_css('selected', false) }) + } + } + unselected() { + if (this.freeze_row) { + this.freeze_cols.forEach(w => { w.set_css('selected', true) }) + } + if (this.normal_row) { + this.normal_cols.forEach(w => { w.set_css('selected', true) }) + } + } + toogle_select(e, f) { + if (f) e.classList.add('selected'); + else e.classList.remove('selected'); + } +} + +class DataGrid extends VBox { + /* + { + data: + dataurl: + method: + params: + title: + description: + show_info: + miniform: + toolbar: + tailer: + row_height: + header_css: + body_css: + fields:[ + { + name: + label: + datatype: + uitype: + uioptions: + freeze: + width: + } + ] + } + */ + constructor(opts) { + super(opts); + this.loading = false; + this.select_row = null; + this.set_css('datagrid'); + this.dataurl = opts.dataurl; + this.method = opts.method; + this.params = opts.params; + this.title = opts.title; + this.check = opts.check || false; + this.lineno = opts.lineno || false; + this.description = opts.description; + this.show_info = opts.show_info; + this.admin = opts.admin; + this.row_height = opts.row_height; + this.fields = opts.fields; + this.header_css = opts.header_css || 'grid_header'; + this.body_css = opts.body_css || 'grid_body'; + if (this.title) { + this.title_bar = new HBox({ height: 'auto' }); + this.add_widget(this.title_bar); + var tw = new Title1({ otext: this.title, i18n: true }); + this.title_bar.add_widget(tw); + } + if (this.description) { + this.descbar = new HBox({ height: 'auto' }); + this.add_widget(this.descbar); + var dw = new Text({ otext: this.description, i18n: true }); + this.descbar.add_widget(dw); + } + + if (this.opts.miniform || this.opts.toolbar){ + this.admin_bar = new HBox({height:'auto'}); + } + if (this.opts.miniform){ + this.miniform = new MiniForm(this.opts.miniform); + this.miniform.bind('input', this.miniform_input.bind(this)); + this.admin_bar.add_widget(this.miniform); + } + if (this.opts.toolbar) { + this.admin_bar.add_widget(new HFiller({})); + self.toolbar = new Toolbar(this.opts.toolbar); + self.toolbar.bind('command', this.command_handle.bind(this)); + this.admin_bar.add_widget(this.toolbar); + } + this.create_parts(); + if (this.show_info) { + this.infow = new HBox({ height: '40px' }); + this.add_widget(this.infow); + } + if (this.dataurl) { + this.loader = new BufferedDataLoader(this, { + pagerows: 80, + buffer_pages: 5, + url: absurl(this.dataurl, this), + method: this.method, + params: this.params + }) + schedule_once(this.loader.loadData.bind(this.loader), 0.01); + if (this.freeze_body) { + this.freeze_body.bind('min_threshold', this.loader.previousPage.bind(this.loader)); + this.freeze_body.bind('max_threshold', this.loader.nextPage.bind(this.loader)); + } + this.normal_body.bind('min_threshold', this.loader.previousPage.bind(this.loader)); + this.normal_body.bind('max_threshold', this.loader.nextPage.bind(this.loader)); + } else { + if (this.data) { + this.add_rows(this.data); + } + } + } + clear_data(){ + if (this.normal_body) + this.normal_body.clear_widgets(); + if (this.freeze_body) + this.freeze_body.clear_widgets() + this.selected_row = null; + } + miniform_input(event){ + var params = this.miniform.getValue(); + this.loadData(params); + } + loadData(params){ + this.loader.loadData(params) + } + command_handle(event){ + } + del_old_rows(cnt, direction) { + if (this.freeze_body) { + if (direction == 'down') { + this.freeze_body.remove_widgets_at_begin(cnt); + } else { + this.freeze_body.remove_widgets_at_end(cnt); + } + } + if (direction == 'down') { + this.normal_body.remove_widgets_at_begin(cnt); + } else { + this.normal_body.remove_widgets_at_end(cnt); + } + } + add_rows(records, direction) { + if (! direction) direction = 'down'; + var index = null; + if (direction == 'down') { + index = 0 + } + + for (var i = 0; i < records.length; i++) { + this.add_row(records[i], index); + } + } + add_row(data, index) { + var row = new Row(this, data); + if (this.freeze_body) + this.freeze_body.add_widget(row.freeze_row, index); + if (this.normal_body) + this.normal_body.add_widget(row.normal_row, index); + } + check_desc() { + return { + freeze:true, + uitype: 'check', + name: '_check', + width: '20px' + } + } + lineno_desc() { + return { + freeze:true, + uitype: 'int', + name: '_lineno', + label: '#', + width: '100px' + } + } + create_parts() { + this.freeze_width = 0; + this.normal_width = 0; + var hbox = new HBox({}); + hbox.set_css('datagrid-grid'); + this.add_widget(hbox); + this.freeze_fields = []; + this.normal_fields = []; + if (this.check) { + this.fields.push(this.check_desc()); + } + if (this.lineno) { + this.fields.push(this.lineno_desc()); + } + for (var i = 0; i < this.fields.length; i++) { + var f = this.fields[i]; + if (!f.width || f.width <= 0 ) f.width = 100; + if (f.freeze) { + this.freeze_fields.push(f); + this.freeze_width += convert2int(f.width); + } else { + this.normal_fields.push(f); + this.normal_width += convert2int(f.width); + + } + } + this.freeze_part = null; + this.normal_part = null; + console.log('width=', this.freeze_width, '-', this.normal_width, '...'); + if (this.freeze_fields.length > 0) { + this.freeze_part = new VBox({}); + this.freeze_part.set_css('datagrid-left'); + this.freeze_part.set_style('width', this.freeze_width + 'px'); + this.freeze_header = new HBox({ height: this.row_height + 'px', width: this.freeze_width + 'px'}); + this.freeze_body = new VScrollPanel({ height: "100%", + width: this.freeze_width + 'px' }) + this.freeze_body.set_css('datagrid-body'); + this.freeze_body.bind('scroll', this.coscroll.bind(this)); + } + if (this.normal_fields.length > 0) { + this.normal_part = new VBox({ + width: this.normal_width + 'px', + height:'100%', + csses:"hscroll" + }); + this.normal_part.set_css('datagrid-right'); + this.normal_header = new HBox({ height: this.row_height + 'px', width: this.normal_width + 'px'}); + // this.normal_header.set_css('datagrid-row'); + this.normal_body = new VScrollPanel({ + height:"100%", + width: this.normal_width + 'px' + }); + this.normal_body.set_css('datagrid-body') + } + this.create_header(); + if (this.freeze_fields.length > 0) { + this.freeze_part.add_widget(this.freeze_header); + this.freeze_part.add_widget(this.freeze_body); + hbox.add_widget(this.freeze_part); + } + if (this.normal_fields.length > 0) { + this.normal_part.add_widget(this.normal_header); + this.normal_part.add_widget(this.normal_body); + this.normal_body.bind('scroll', this.coscroll.bind(this)); + this.normal_body.bind('min_threshold', this.load_previous_data.bind(this)); + this.normal_body.bind('max_threshold', this.load_next_data.bind(this)); + hbox.add_widget(this.normal_part); + } + } + load_previous_data() { + console.log('event min_threshold fired ........'); + this.loader.previousPage(); + } + load_next_data() { + console.log('event max_threshold fired ........'); + this.loader.nextPage(); + } + coscroll(event) { + var w = event.target.bricks_widget; + if (w == this.freeze_body) { + this.normal_body.dom_element.scrollTop = w.dom_element.scrollTop; + } else if (w == this.normal_body && this.freeze_body) { + this.freeze_body.dom_element.scrollTop = w.dom_element.scrollTop; + } + } + + create_header() { + for (var i = 0; i < this.freeze_fields.length; i++) { + var f = this.freeze_fields[i]; + var t = new Text({ + otext: f.label || f.name, + i18n: true, + }); + if (f.width) { + t.set_style('flex','0 0 ' + convert2int(f.width) + 'px'); + } else { + t.set_style('flex','0 0 100px'); + } + this.freeze_header.add_widget(t); + t.dom_element.column_no = 'f' + i; + } + for (var i = 0; i < this.normal_fields.length; i++) { + var f = this.normal_fields[i]; + var t = new Text({ + otext: f.label || f.name, + i18n: true, + }); + if (f.width) { + t.set_style('flex','0 0 ' + convert2int(f.width) + 'px'); + } else { + t.set_style('flex','0 0 100px'); + } + this.normal_header.add_widget(t); + t.dom_element.column_no = 'n' + i; + } + } + click_handler(row, event) { + if (this.selected_row) { + this.selected_row.unselected(); + } + this.selected_row = row; + this.selected_row.selected(); + this.dispatch('row_click', row); + console.log('DataGrid():click_handler, row=', row, 'event=', event); + } +} + +Factory.register('DataGrid', DataGrid); diff --git a/bricks/dataviewer.js b/bricks/dataviewer.js new file mode 100644 index 0000000..7e2de46 --- /dev/null +++ b/bricks/dataviewer.js @@ -0,0 +1,70 @@ + +class DataViewer extends VScrollPanel { + /* + opts={ + dataurl: + pagerows: + params: + buffer_page: + viewer_url: or + viewer_tmpl: + } + */ + constructor(opts){ + opts.width = '100%'; + super(opts); + this.loader = new BufferedDataLoader(this, { + pagerows: opts.pagerows || 80, + buffer_pages: opts.buffer_pages || 5, + url: opts.dataurl, + method: opts.method || 'GET', + params: opts.params + }); + this.set_css('multicolumns'); + this.bind('min_threshold', + this.loader.previousPage.bind(this.loader)) + this.bind('max_threshold', + this.loader.nextPage.bind(this.loader)) + if (opts.viewer_tmpl){ + this.viewer_tmpl = opts.viewer_tmpl; + } + if (opts.viewer_url){ + this.get_tmpl_string(); + } + } + loadData(params){ + this.loader.loadData(params) + } + get_tmpl_string(){ + fetch(this.opts.viewer_url) + .then(response => response.text()) + .then(data => { + console.log('viewer_tmpl=', data); + this.viewer_tmpl = data + schedule_once(this.loader.loadData.bind(this.loader), 0.01); + }); + } + clear_data(){ + this.clear_widgets(); + } + add_rows = async function(rows, direction){ + for (var 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", + }; + extend(this.headers, 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", + } + extend(this.headers, 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); + diff --git a/bricks/layout.js b/bricks/layout.js new file mode 100755 index 0000000..154d1bb --- /dev/null +++ b/bricks/layout.js @@ -0,0 +1,98 @@ +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 = objcopy(this.children); + 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 +*/ + +class MdText extends JsWidget { + /* options + { + "md_url": + "method":"GET" + "params":{} + } + */ + + constructor(options){ + super(options); + var f = this.build.bind(this); + this.load_event = new Event('loaded'); + this.dom_element.style.overFlow='auto'; + window.addEventListener('scroll', this.show_scroll.bind(this)); + schedule_once(f, 0.01); + } + show_scroll(event){ + console.log('scrollY=', window.scrollY); + } + build = async function(){ + this._build(this.opts.md_url); + } + _build = async function(md_url){ + var md_content = await tget(md_url); + this.dom_element.innerHTML = marked.parse(md_content); + + /* change links in markdown to a bricks action */ + var links = this.dom_element.getElementsByTagName('a'); + for (var i=0; i 0){ + for (var i=0;i 0){ + this.task = schedule_once(this.dismiss.bind(this), this.timeout); + } + } + add_widget(w, idx){ + this.content.add_widget(w, idx); + if (this.opts.auto_open){ + this.open(); + } + } + dismiss(){ + if (this.task){ + this.task.cancel(); + this.task = null + } + this.holder.remove_widget(this); + } +} + +class BMessage extends BPopup { + /* + { + title: + message: + params: + auto_open: + auto_dismiss: + archor:cc + timeout: + } + */ + constructor(opts){ + super(opts); + var t = new Text({otext:this.opts.message, + i18n:true}); + this.add_widget(t); + } +} + +class BError extends BMessage { + constructor(opts){ + super(opts); + this.set_css('error'); + } +} + +class PopupForm extends BPopup { + /* + { + form:{ + } + } + */ + constructor(options){ + super(options); + this.form = new Form(this.opts.form); + this.add_widget(this.form); + this.form.bind('submit', this.close_popup.bind(this)); + this.form.bind('discard', this.close_popup.bind(this)); + } + close_popup(e){ + this.dismiss(); + } +} +Factory.register('BMessage', BMessage); +Factory.register('BError', BError); +Factory.register('PopupForm', PopupForm); diff --git a/bricks/miniform.js b/bricks/miniform.js new file mode 100644 index 0000000..0975876 --- /dev/null +++ b/bricks/miniform.js @@ -0,0 +1,83 @@ +class MiniForm extends HBox { + /* + { + defaultname: + label_width: + input_width: + params: + "fields":[ + { + name: + label: + icon: + uitype: + uiparams: + } + ... + ] + } + */ + constructor(opts){ + opts.width = 'auto'; + opts.height = 'auto'; + super(opts); + this.build(); + } + build(){ + var name = this.opts.defaultname; + if (!name){ + name = this.opts.fields[0].name; + } + this.build_options(); + this.build_widgets(name); + } + build_widgets(name){ + if (this.input){ + this.input.unbind('input', this.input_handle.bind(this)); + } + this.clear_widgets(); + this.add_widget(this.choose); + var f = this.opts.fields.find( i => i.name==name); + var desc = objcopy(f); + desc.width = 'auto'; + var i = Input.factory(desc); + i.bind('input', this.input_handle.bind(this)); + this.add_widget(i); + this.input = i; + } + build_options(){ + var desc = { + width:"90px", + name:"name", + uitype:"code", + valueField:'name', + textField:'label', + data:this.opts.fields + }; + var w = Input.factory(desc); + w.bind('changed', this.change_input.bind(this)); + this.choose = w; + this.add_widget(w); + } + show_options(e){ + console.log('show_options() called ...'); + this.choose.show(); + } + change_input(e){ + var name = this.choose.value; + this.build_widgets(name); + } + input_handle(e){ + var d = this.getValue(); + console.log('input_handle() ..', d); + this.dispatch('input', d); + } + getValue(){ + var d = this.opts.params || {}; + var v = this.input.getValue(); + extend(d, v); + return d; + } +} + +Factory.register('MiniForm', MiniForm); diff --git a/bricks/minify_tools.txt b/bricks/minify_tools.txt new file mode 100755 index 0000000..8726b44 --- /dev/null +++ b/bricks/minify_tools.txt @@ -0,0 +1,4 @@ +AJaxMin from Microsoft +https://developers.google.com/closure/compiler +YUI Compressor +Uglify-js diff --git a/bricks/modal.js b/bricks/modal.js new file mode 100755 index 0000000..312b9c0 --- /dev/null +++ b/bricks/modal.js @@ -0,0 +1,121 @@ +class Modal extends Layout { + constructor(options){ + /* + { + auto_open: + auto_close: + org_index: + width: + height: + bgcolor: + title: + archor: cc ( tl, tc, tr + cl, cc, cr + bl, bc, br ) + } + */ + super(options); + this.set_width('100%'); + this.set_height('100%'); + this.ancestor_add_widget = Layout.prototype.add_widget.bind(this); + this.panel = new VBox({}); + this.ancestor_add_widget(this.panel); + this.panel.set_width(this.opts.width); + this.panel.dom_element.style.backgroundColor = this.opts.bgcolor|| '#e8e8e8'; + this.panel.set_height(this.opts.height); + this.panel.set_css('modal'); + archorize(this.panel.dom_element, objget(this.opts, 'archor', 'cc')); + this.create_title(); + this.content = new VBox({width:'100%'}); + this.panel.add_widget(this.content); + } + create_title(){ + this.title_box = new HBox({width:'100%', height:'auto'}); + this.title_box.set_css('title'); + this.panel.add_widget(this.title_box); + this.title = new HBox({height:'100%'}); + var icon = new Icon({url:bricks_resource('imgs/delete.png')}); + icon.bind('click', this.dismiss.bind(this)); + this.title_box.add_widget(this.title); + this.title_box.add_widget(icon); + } + create(){ + var e = document.createElement('div'); + e.style.display = "none"; /* Hidden by default */ + e.style.position = "fixed"; /* Stay in place */ + e.style.zIndex = objget(this.opts, 'org_index', 0) + 1; /* Sit on top */ + e.style.paddingTop = "100px"; /* Location of the box */ + e.style.left = 0; + e.style.top = 0; + e.style.width = "100%"; /* Full width */ + e.style.height = "100%"; /* Full height */ + e.style.backgroundColor = 'rgba(0,0,0,0.4)'; /* Fallback color */ + this.dom_element = e; + } + + add_widget(w, index){ + this.content.add_widget(w, index); + if (this.opts.auto_open){ + this.open(); + } + } + click_handler(event){ + if (event.target == this.dom_element){ + this.dismiss(); + } else { + console.log('modal():click_handler()'); + } + } + open(){ + if (this.opts.auto_close){ + var f = this.click_handler.bind(this); + this.bind('click', f); + } + this.dom_element.style.display = ""; + } + dismiss(){ + this.dom_element.style.display = "none"; + if (this.opts.auto_close){ + this.unbind('click', this.click_handler.bind(this)); + } + } +} + +class ModalForm extends Modal { + /* + { + auto_open: + auto_close: + org_index: + width: + height: + bgcolor: + archor: cc ( tl, tc, tr + cl, cc, cr + bl, bc, br ) + title: + description: + dataurl: + submit_url: + fields: + } + */ + constructor(opts){ + super(opts); + this.build_form(); + } + build_form(){ + var opts = { + title:this.opts.title, + description:this.opts.description, + dataurl:this.opts.dataurl, + submit_url:this.opts.submit_url, + fields:this.opts.fields + } + this.form = new Form(opts); + this.form.bind('submit', this.dismiss.bind(this)); + } +} +Factory.register('Modal', Modal); +Factory.register('ModalForm', ModalForm); + diff --git a/bricks/multiple_state_image.js b/bricks/multiple_state_image.js new file mode 100644 index 0000000..dca6847 --- /dev/null +++ b/bricks/multiple_state_image.js @@ -0,0 +1,75 @@ +class MultipleStateImage extends Layout { + /* + { + state: + urls:{ + state1:url1, + state2:url2, + ... + } + width: + height: + } + */ + constructor(opts){ + super(opts); + this.state = this.opts.state + var desc = { + urls : this.opts.urls[this.state], + width:this.opts.width, + height:this.opts.height + } + this.img = new Image(desc); + this.add_widget(this.img); + this.img.bind('click', this.change_state.bind(this)); + } + set_state(state){ + this.state = state; + this.img.set_url(this.opts.urls[state]); + } + + change_state(event){ + event.stopPropagation(); + var states = Object.keys(this.opts.urls); + for (var i=0;i= states.length) k = 0; + this.state = states[k]; + this.img.set_url(this.opts.urls[this.state]); + this.dispatch('state_changed', this.state); + break; + } + } + } +} + +class MultipleStateIcon extends Icon { + constructor(opts){ + opts.url = opts.urls[opts.state]; + super(opts); + this.state = opts.state; + this.urls = opts.urls; + this.bind('click', this.change_state.bind(this)); + } + change_state(event){ + event.stopPropagation(); + var states = Object.keys(this.urls); + for (var i=0;i= states.length) k = 0; + this.set_state(states[k]); + this.dispatch('state_changed', this.state); + break; + } + } + } + set_state(state){ + this.state = state; + this.set_url(this.urls[state]); + } + +} +Factory.register('MultipleStateImage', MultipleStateImage); + diff --git a/bricks/myoperator.js b/bricks/myoperator.js new file mode 100755 index 0000000..f893759 --- /dev/null +++ b/bricks/myoperator.js @@ -0,0 +1,13 @@ +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); + } +} diff --git a/bricks/paging.js b/bricks/paging.js new file mode 100644 index 0000000..8f32992 --- /dev/null +++ b/bricks/paging.js @@ -0,0 +1,91 @@ +class BufferedDataLoader { + /* + { + url: + method: + params: + buffer_pages: + pagerows: + } + usage: + var p = Paging({...}); + p.loadData(); // return page(1) data + p.getPage(5); // return page(5) data + p.nextPage() + p.previousPage() + */ + constructor(w, opts){ + this.widget = w; + this.url = opts.url; + this.loading = false + this.method = opts.method || 'GET'; + this.params = opts.params || {}; + this.buffer_pages = opts.buffer_pages || 5; + this.pagerows = opts.pagerows || 60; + this.initial(); + } + initial(){ + this.cur_page = -1; + this.buffer = {}; + this.buffered_pages = 0; + this.total_record = -1; + this.cur_params = {}; + } + async loadData(params){ + this.initial(); + this.widget.clear_data(); + this.buffer = {}; + if (!params) params = {}; + var p = objcopy(this.params); + extend(p, params); + p.rows = this.pagerows; + this.cur_params = p; + this.cur_page = 1; + return this.loadPage(); + } + + async loadPage(page){ + if (this.loading) return; + this.loading = true; + if (this.buffered_pages >= this.buffer_pages){ + this.widget.del_old_rows(this.pagerows, this.direction); + this.buffered_pages -= 1; + } + var params = objcopy(this.cur_params); + params.page = this.cur_page; + params.rows = this.pagerows; + var d = await jcall(this.url, { + method:this.method, + params:params}); + this.total_records = d.total; + d.page = this.cur_page; + d.total_page = this.total_records / this.pagerows; + if (d.total_page * this.pagerows < this.total_record){ + d.total_page += 1; + } + this.total_page = d.total_page; + this.widget.add_rows(d.rows, this.direction); + this.buffered_pages += 1; + this.loading = false; + return d; + } + + async nextPage(){ + if (this.loading) return; + if (this.cur_page >= this.total_page){ + return; + } + this.direction = 'down'; + this.cur_page += 1; + return await this.loadPage(); + } + async previousPage(){ + if (this.loading) return; + if (this.cur_page <= 1){ + return + } + this.direction = 'up'; + this.cur_page -= 1; + return await this.loadPage(); + } +} diff --git a/bricks/registerfunction.js b/bricks/registerfunction.js new file mode 100755 index 0000000..4e5cfa1 --- /dev/null +++ b/bricks/registerfunction.js @@ -0,0 +1,11 @@ +class RegisterFunction { + constructor(){ + this.rfs = {}; + } + register(n, f){ + extend(this.rfs, {n:f}); + } + get(n){ + return objget(this.rfs, n); + } +} diff --git a/bricks/scroll.js b/bricks/scroll.js new file mode 100644 index 0000000..aeab87f --- /dev/null +++ b/bricks/scroll.js @@ -0,0 +1,86 @@ + +var low_handle = function(widget, dim, last_pos, cur_pos, maxlen, winsize){ + var dir = cur_pos - last_pos; + var max_rate = cur_pos / (maxlen - winsize); + var min_rate = cur_pos / maxlen; + if (!widget.threshold && dir > 0 && max_rate >= widget.max_threshold){ + widget.thresgold = true; + widget.dispatch('max_threshold'); + return + } + if (!widget.threshold && dir < 0 && min_rate <= widget.min_threshold){ + widget.thresgold = true; + widget.dispatch('min_threshold'); + return + } +} + +class HScrollPanel extends HFiller { + /* + { + min_threshold: + max_threshold: + } + */ + constructor(opts){ + super(opts); + this.min_threshold = opts.min_threshold || 0.02; + this.max_threshold = opts.max_threshold || 0.95; + this.bind('scroll', this.scroll_handle.bind(this)) + this.last_scrollLeft = this.dom_element.scrollLeft; + this.threshold = false; + } + scroll_handle(event){ + if (event.target != this.dom_element){ + // console.log('HScroll():scroll on other', event.target); + return; + } + var e = this.dom_element; + if ( e.scrollWidth - e.clientWidth < 1) { + // console.log('HScroll():same size'); + return; + } + low_handle(this, 'x', this.last_scrollLeft, + e.scrollLeft, + e.scrollWidth, + e.clientWidth); + + this.last_scrollLeft = e.scrollLeft; + } +} + +class VScrollPanel extends VFiller { + /* + { + min_threshold: + max_threshold: + } + */ + constructor(opts){ + super(opts); + this.min_threshold = opts.min_threshold || 0.02; + this.max_threshold = opts.max_threshold || 0.95; + this.bind('scroll', this.scroll_handle.bind(this)) + this.last_scrollTop = this.dom_element.scrollTop; + } + scroll_handle(event){ + if (event.target != this.dom_element){ + // console.log('scroll on other', event.target); + return; + } + var e = this.dom_element; + if ( e.scrollHeight - e.clientHeight < 2) { + // console.log('same size'); + return; + } + low_handle(this, 'y', this.last_scrollTop, + e.scrollTop, + e.scrollHeight, + e.clientHeight); + this.last_scrollTop = e.scrollTop; + } +} + +Factory.register('VScrollPanel', VScrollPanel); +Factory.register('HScrollPanel', HScrollPanel); + diff --git a/bricks/stdhtml.html b/bricks/stdhtml.html new file mode 100644 index 0000000..c0101d9 --- /dev/null +++ b/bricks/stdhtml.html @@ -0,0 +1,27 @@ + + + + + + + + + Standard Html + + + + + + + diff --git a/bricks/tab.js b/bricks/tab.js new file mode 100755 index 0000000..a9b2cd3 --- /dev/null +++ b/bricks/tab.js @@ -0,0 +1,125 @@ +class TabPanel extends Layout { + /* + options + { + css: + tab_long: 100% + tab_pos:"top" + items:[ + { + name: + label:"tab1", + icon: + removable: + refresh:false, + content:{ + "widgettype":... + } + } + ] + } + css: + tab + tab-button + tab-button-active + tab-button-hover + tab-content + */ + constructor(options){ + super(options); + this.content_buffer = {}; + this.cur_tab_name = ''; + this.content_container = new VFiller({}); + if (this.opts.tab_pos == 'top' || this.opts.tab_pos == 'bottom'){ + this.set_css('vbox'); + var height = this.opts.tab_wide || 'auto'; + this.tab_container = new VBox({height:height}); + this.tab_container.dom_element.style.width = this.opts.tab_long || '100%'; + } else { + this.set_css('hbox'); + var width= this.opts.tab_wide || 'auto'; + this.tab_container = new VBox({width:width}); + this.tab_container.dom_element.style.height = this.opts.tab_long || '100%'; + } + if (this.opts.tab_pos == 'top' || this.opts.tab_pos == 'left'){ + this.add_widget(this.tab_container); + this.add_widget(this.content_container); + } else { + this.add_widget(this.content_container); + this.add_widget(this.tab_container); + } + this.createToolbar(); + this.set_css('tabpanel'); + this.content_container.set_css('tabpanel-content'); + } + show_first_tab(){ + this.show_content_by_tab_name(this.opts.items[0].name); + } + show_content_by_tab_name(name){ + this.toolbar.click(name); + } + createToolbar(){ + var desc = { + tools:this.opts.items + }; + var orient; + if (this.opts.tab_pos == 'top' || this.opts.tab_pos == 'bottom'){ + orient = 'horizontal'; + } else { + orient = 'vertical'; + } + desc.orientation = orient; + this.toolbar = new Toolbar(desc); + this.toolbar.bind('command', this.show_tabcontent.bind(this)); + this.toolbar.bind('remove', this.tab_removed.bind(this)); + this.toolbar.bind('ready', this.show_first_tab.bind(this)); + this.tab_container.add_widget(this.toolbar); + } + show_tabcontent = async function(event){ + var tdesc = event.params; + var items = this.opts.items; + if (tdesc.name == this.cur_tab_name){ + console.log('TabPanel(): click duplication click on same tab', tdesc) + return; + } + for (var i=0;i 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 (objget(import_cache, 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 (objget(import_cache, 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; +} + +var archorize = function(ele,archor){ + /* archor maybe one of the: + "tl", "tc", "tr", + "cl", "cc", "cr", + "bl", "bc", "br" + */ + if (! archor) + archor = 'cc'; + var v = archor[0]; + var h = archor[1]; + var y = "0%"; + switch(v){ + case 't': + y = "0%"; + break; + case 'b': + y = '100%'; + break; + case 'c': + y = '50%'; + break; + default: + y = '50%'; + break; + } + var x = "0%"; + switch(h){ + case 'l': + x = "0%"; + break; + case 'r': + x = '100%'; + break; + case 'c': + x = '50%'; + break; + default: + x = '50%'; + break; + } + ele.style.top = y; + ele.style.left = x; + var o = { + 'x':x, + 'y':y + } + var tsf = obj_fmtstr(o, 'translateY(-${y}) translateX(-${x})'); + console.log('archorize(): tsf=', tsf); + ele.style.transform = tsf; + ele.style.position = "absolute"; +} + +Array.prototype.insert = function ( index, ...items ) { + this.splice( index, 0, ...items ); +}; + +Array.prototype.remove = function(item){ + var idx = this.indexOf(item); + if (idx >= 0){ + this.splice(idx, 1); + } + return this; +} + +var absurl = function(url, widget){ + if (url.startsWith('http://') || url.startsWith('https://')){ + return url; + } + var base_uri = widget.baseURI; + if (url.startsWith('/')){ + base_uri = Body.baseURI; + url = url.substring(1); + } + paths = base_uri.split('/'); + delete paths[paths.length - 1]; + var ret_url = paths.join('/') + url; + return ret_url; +} + +var debug = function(...args){ + console.log(...args); +} + +var convert2int = function(s){ + if (typeof(s) == 'number') return s; + var s1 = s.match(/\d+/); + return parseInt(s1[0]); +} + +function setCookie(name,value,days) { + var expires = ""; + if (days) { + var date = new Date(); + date.setTime(date.getTime() + (days*24*60*60*1000)); + expires = "; expires=" + date.toUTCString(); + } + document.cookie = name + "=" + (value || "") + expires + "; path=/"; +} +function getCookie(name) { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + for(var i=0;i < ca.length;i++) { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); + } + return null; +} +function eraseCookie(name) { + document.cookie = name +'=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; +} + +var set_max_height = function(w1, w2){ + var v1 = w1.dom_element.offsetHeight; + var v2 = w2.dom_element.offsetHeight; + var v = v1 - v2; + if (v < 0){ + w1.set_height(w2.dom_element.offsetHeight); + } else if (v > 0) { + w2.set_height(w1.dom_element.offsetHeight); + } +} +var objcopy = function(obj){ + var o = {} + for ( k in obj){ + if (obj.hasOwnProperty(k)){ + o[k] = obj[k]; + } + } + return o; +} diff --git a/bricks/video.js b/bricks/video.js new file mode 100755 index 0000000..8fe6b23 --- /dev/null +++ b/bricks/video.js @@ -0,0 +1,72 @@ +/* +we use videojs for video play +https://videojs.com +*/ +class Video extends JsWidget { + /* + { + vtype: + url: + autoplay: + } + */ + constructor(options){ + super(options); + this.dom_element.type="application/vnd.apple.mpegurl"; + this.set_css('video-js'); + this.set_css('vjs-big-play-centered'); + this.set_css('vjs-fluid'); + this.cur_url = options.url; + this.cur_vtype = options.vtype; + console.log('here1'); + schedule_once(this.create_player.bind(this), 0.1); + } + create(){ + this.dom_element = document.createElement('video'); + } + create_player(){ + console.log('here2'); + this.player = videojs(this.dom_element); + console.log('here3'); + this._set_source(); + } + _set_source(){ + console.log('--------set source ---------'); + } + set_source(url){ + this.cur_url = url; + this._set_source(); + } +} + +class VideoPlayer extends VBox { + /* + we use [indigo-player](https://github.com/matvp91/indigo-player) as a base. + inside body, need to add following line before bricks.js + + options + { + url: + } + */ + constructor(options){ + super(options); + var autoplay = ''; + if (this.opts.autoplay){ + autoplay = 'autoplay'; + } + var url = this.opts.url; + this.dom_element.innerHTML = ``; + this.video = this.dom_element.querySelector('video'); + } + toggle_play(){ + if (this.video.paused){ + this.video.play(); + } else { + this.video.pause(); + } + } + +} +Factory.register('VideoPlayer', VideoPlayer); +Factory.register('Video', Video); diff --git a/bricks/views.js b/bricks/views.js new file mode 100644 index 0000000..b6606ca --- /dev/null +++ b/bricks/views.js @@ -0,0 +1,49 @@ +/* +uitype: +str +password +int +float +tel +email +file +'check +checkbox +date +text +code +video +audio + +*/ + +var ViewStr = function(desc){ + var w = Text({ + 'text':desc.value, + 'halign':'left' + }) + if (desc.row_data) + w.desc_object = desc; + return w; +} + +uitypesdef.setViewKlass('str', ViewStr); + +var ViewPassword = function(desc){ + var w = Text({ + 'text':"****", + 'halign':'left' + }) + if (desc.row_data) + w.data = desc.row_data; + return w; +} +class ViewType extends JsWidget { + constructor(opts){ + super(opts) + } +} + +class ViewStr extends ViewType { + +} diff --git a/bricks/widget.js b/bricks/widget.js new file mode 100755 index 0000000..6caf4a9 --- /dev/null +++ b/bricks/widget.js @@ -0,0 +1,310 @@ + +class JsWidget { + dom_element = null; + constructor(options){ + if (!options){ + options = {} + } + this.baseURI = options.baseURI; + this.opts = options; + this.create(); + this.dom_element.bricks_widget = this; + this.opts_set_style(); + if (this.opts.tooltip){ + this.dom_element.tooltip = this.opts.tooltip; + } + this._container = false; + this.parent = null; + this.sizable_elements = []; + if (options.css){ + this.set_css(options.css); + } + if (options.csses){ + this.set_csses(options.csses); + } + } + create(){ + this.dom_element = document.createElement('div'); + } + opts_set_style(){ + var keys = [ + "width", + "x", + "y", + "height", + "margin", + "padding", + "align", + "textAlign", + "overflowY", + "overflowX", + "overflow", + "color" + ] + var mapping_keys = { + "z-index":"zIndex", + "overflow-x":"overflowX", + "opveflow-y":"overflowY", + "bgcolor":"backgroundColor" + }; + var mkeys = Object.keys(mapping_keys); + var style = {}; + var okeys = Object.keys(this.opts); + for (var k=0; k 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]]; + } + extend(this.dom_element.style, 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){ + extend(this.dom_element.style, 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){ + 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); + diff --git a/bricks/wterm.js b/bricks/wterm.js new file mode 100644 index 0000000..af4cbf4 --- /dev/null +++ b/bricks/wterm.js @@ -0,0 +1,52 @@ +/* +dependent on xterm.js +*/ +class Wterm extends JsWidget { + /* + { + ws_url: + host: + ssh_port: + user: + } + */ + constructor(opts){ + super(opts); + schedule_once(this.open.bind(this), 0.5); + } + async open(){ + var term = new Terminal(); + this.term = term; + term.open(this.dom_element); + var ws = new WebSocket(this.opts.ws_url); + console.log('FitAddon=', FitAddon); + this.fitAddon = new FitAddon.FitAddon() + term.loadAddon(this.fitAddon) + // this.fitAddon.fit() + this.bind('resize', this.term_resize.bind(this)) + ws.onmessage = msg => { + term.write(JSON.parse(msg.data).data); + }; + + term.onData(function(key) { + //Enter + let msg = { + data:{data:key}, + type:1 + } + ws.send(key); + }); + term.focus(); + term.paste("ls -l\n"); + } + term_resize(){ + try { + this.fitAddon.fit(); + } catch(e){ + console.log('resize error', e); + } + } +} + +Factory.register('Wterm', Wterm); + diff --git a/dist/README.md b/dist/README.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/.DS_Store b/docs/.DS_Store new file mode 100755 index 0000000..fa8dcf1 Binary files /dev/null and b/docs/.DS_Store differ diff --git a/docs/BoxLayout.md b/docs/BoxLayout.md new file mode 100755 index 0000000..37b2f06 --- /dev/null +++ b/docs/BoxLayout.md @@ -0,0 +1,21 @@ +# BoxLayout +Boxlayout is a one direction layout, it layout subwidgets on vertical direction or horizontal direction. + +## use case +none +## inheritance +BoxLayout inherited from Layout +## options +``` +{ + orientation: +} +``` +### orientation +orientation get value of 'vertical' or 'horizontal', means layout child widget in veritcal or horizontal direction + +### +## method +none +## event +none diff --git a/docs/HBox.md b/docs/HBox.md new file mode 100755 index 0000000..13d5800 --- /dev/null +++ b/docs/HBox.md @@ -0,0 +1,11 @@ +# HBox +Hbox is a horizontal layout widget, it layout subwidgeta in horizontal direction +## use case +## inheritance +HBox inherited fromm BoxLayout +## options + +## method +none +## event +none diff --git a/docs/README.md b/docs/README.md new file mode 100755 index 0000000..96ca86b --- /dev/null +++ b/docs/README.md @@ -0,0 +1,41 @@ +# Bricks documentation +A web application development platform to make the web application development more easy. +It let developments choose the UI components provide by bricks or provide by third parts to construct his or her application just like use bricks to build toys. + +## Installation +## Use Case +## Widget List +[Widgets](widgets.md) + +## UI Components +### Layout +Layout is the base Layout, please click [Layout](layout.md) for more detail. + +### BoxLayout +BoxLayout is a one direction layout, for more information, please click [BoxLayout](boxlayout.md) + + +### HBox +HBox is a layout to layout subwidgets in horizontal direction, please click [HBox](hbox.md) for more information. +### VBox +VBox is a layout to layout its subwidgets in vertical direction, please click [VBox](vbox.md) for more information. +### Text +### Title1 +### Title2 +### Title3 +### Title4 +### Title5 +### Title6 +### Image +Image show image on you dom tree, please click [image](image.md) for more information about Image widget + +### MarkdownViewer +a markdown document viewer widget, for more information, please see [markdownviewer](markdownviewer.md) + +### VideoPlayer +a video player widget base on [indigo-player](https://github.com/matvp91/indigo-player), please look at [videoplayer](videoplayer.md) for more information. + +### Modal +### Toolbar +toolbar component provide user a toobar service, for more information pleaseclick [toolbar](toolbar.md) + diff --git a/docs/cn/bricks.md b/docs/cn/bricks.md new file mode 100644 index 0000000..f5f67dd --- /dev/null +++ b/docs/cn/bricks.md @@ -0,0 +1,135 @@ +# widgetBuild +函数用于创建bricks框架的控件实例。 + +## 语法 +var w = widgetBuild(desc, widget) + +## 参数说明 +### desc +desc是一个对象类型数据,创建控件参数,必须有"widgettype", "options"属性, 可选属性有"subwidegets","binds" + +### widget +widget是一个控件实例,用于解析desc中出现的url + +## 返回值 +* null 出错,可能1)widgettype类型未注册或不存在;2)json文件格式不对 +* 新创建的控件实体 + +## 例子 +tree.json +``` + { + "widgettype":"Tree", + "options":{ + "idField":"id", + "textField":"text", + "data":[ + { + "id":1, + "text":"node1", + "is_leaf":false, + "children":[ + { + "id":11, + "text":"node11", + "is_leaf":false, + "children":[ + { + "id":112, + "text":"node.12", + "is_leaf":false, + "children":[ + { + "id":1112, + "text":"node1112", + "is_leaf":true + }, + { + "id":1113, + "text":"node113", + "is_leaf":true + } + ] + }, + { + "id":113, + "text":"node113", + "is_leaf":true + } + ] + }, + { + "id":12, + "text":"node12", + "is_leaf":true + }, + { + "id":13, + "text":"node13", + "is_leaf":true + } + ] + }, + { + "id":2, + "text":"node2", + "is_leaf":false, + "children":[ + { + "id":21, + "text":"node21", + "is_leaf":true + }, + { + "id":22, + "text":"node22", + "is_leaf":true + }, + { + "id":23, + "text":"node23", + "is_leaf":true + } + ] + }, + { + "id":3, + "text":"node3", + "is_leaf":true + } + ] + } + } +``` +tree.html +``` + + + + + + + + + + +``` +这是一个树形控件, 运行[这里](https://github.com/bricks/examples/tree.html) +更多的例子请看 +[bricks控件例子](https://github.com/yumoqing/bricks/examples) + + diff --git a/docs/cn/bricksapp.md b/docs/cn/bricksapp.md new file mode 100644 index 0000000..68c9b16 --- /dev/null +++ b/docs/cn/bricksapp.md @@ -0,0 +1,60 @@ +# BricksApp +BricksApp是Bricks框架的应用类, BricksApp用来初始化Bricks环境,创建Bricks页面的根控件 + +并将生成的根控件插入的全局控件Body中, + +Body对应的dom_element为页面的“body”元素。 + +后续可以通过bricks_app全局变量来引用BricksApp实例。 + +## 构建选项 +``` + opts = { + login_url: + "charsize: + "language": + "i18n":{ + "url":'rrr', + "default_lang":'en' + }, + "widget":{ + "widgettype":"Text", + "options":{ + } + } + } +``` +### login_url + 登录url,按照后台设置,当需要访问受控url时会从此URL返回的json数据创建登录窗体,用户登录 + +### chartsize +字符大小,缺省16px + +### languange +页面使用的语言,两个字符的语言 + +### i18n +定义国际化数据获取路径,url按照GET方式,language作为参数,像后台获取改语言的json格式的翻译数据。 +### widget +根控件描述对象 + +## 属性 + +### opts +保存创建选项 + +### login_url +用于构建登录控件的url + +### charsize +字符大小,所有输入控件,Text, Icon,Title?都受此影响控件大小。 +### lang +前端界面语言,选项指定或获取缺省语言 +### textList + +### i18n +### session_id +## 方法 + +## 事件 + diff --git a/docs/cn/descjson.md b/docs/cn/descjson.md new file mode 100644 index 0000000..32730e4 --- /dev/null +++ b/docs/cn/descjson.md @@ -0,0 +1,78 @@ +# 创建控件的Json文件格式说明 +Bricks在服务器端使用Json文件格式存储控件描述文件,前端获得json文件后转化为json对象,并用词json对象调用widgetBuild函数创建Bricks控件。 + +控件描述json文件必须含有“widgettype” 和”options“两个属性。“subwidgets”属性用来定义此控件包含的子控件。“binds”用于定义此控件或其子控件的事件处理 + + +## widgettype说明 +widgettype是一个字符串属性。其值为Bricks中的所有控件类型或"urlwidget" +可用的控件类型可以在[控件类型清单](widgettypes.md)中查找 + +## options +对象类型,每个控件有特定的options属性,清参看每个控件的说明 + +## subwidgets +数组类型,数组中的每个元素必须是一个对象类型数据,与desc作用一样。 +参见widgetBuild函数的desc说明 + +## binds +一个数组,在控件上定义一到多个事件绑定,数组中的每一个元素定义一个绑定, +Bricks支持5种数据绑定 +每种绑定类型都支持下述属性 +### wid +字符串类型或控件类型,绑定事件的控件,缺省是binds坐在的构造控件。 +### event +字符串类型,事件名称, 绑定针对的事件字符串名称 + +### actiontype +绑定类型,支持“urlwidget", "method", "script", "registerfunction", "event" + +### conform +对象类型,确认控件的options,如存在,则此绑定需要用户确认后再执行 + +### 获取实时数据作为参数 +绑定任务获取实时数据作为参数,需要给定以下属性: +* datawidget:字符串或控件类型,获取实时数据的控件 +* datamethod:字符串类型,控件的方法,使用params作为参数调用, +获取实时数据的方法 +* datascript:字符串类型, js脚本,使用return返回数据 +* dataparams:参数 +datamethod 优先datascript,从datawidget控件中通过datamethod + +### target +字符串或控件实例,目标控件实例,如果是字符串,使用”getWidgetById“函数获得目标控件实例 + +### urlwidget绑定 + +urlwidget绑定需要一个options属性和一个mode属性,在此属性中需要 +* url:字符串类型, 获取desc数据的url +* mehtod:字符串类型,url调用的方法,缺省”GET“ +* params:对象类型,调用的参数 +绑定创建的控件添加到target控件中 +### method +需要指定target参数和method参数, +* target:类型为字符串或控件类型, +如果是字符串,使用“getWidgetById”函数获取控件实例。 +* method:字符串,target实例的方法, +* params:传递给方法的参数 +method绑定方法,将事件绑定到target控件的一个方法,并用params传递参数 + +### script +绑定脚本,此方法将事件绑定到一个脚本,支持以下属性 +* script:字符串,脚本正文 +* params:对象类型,脚本可以访问params变量来获取参数。 + +### registerfunction +事件绑定一个注册函数, 参看[RegisterFunction](registerfunction.md) +支持以下属性: +rfname:字符串,已注册的函数名称 +params:对象类型,调用注册函数时作为参数传递给注册函数。 + +### event +绑定事件,需指定target,触发target对象的一个事件 +支持以下属性 +dispatch_event:需触发的事件名 +params:传递给事件的参数,处理函数可以使用evemt.params获得此参数 + +作为参数调用target实例的方法 + diff --git a/docs/cn/index.md b/docs/cn/index.md new file mode 100644 index 0000000..4184e34 --- /dev/null +++ b/docs/cn/index.md @@ -0,0 +1,58 @@ +# bricks +像搭积木一样的编写前端应用,bricks希望提供开发者所需的底层显示控件,开发应用时采用简单的组装和插拔方式完成应用的开发 + +使用bricks开发应用的好处 +* 质量和性能可控,开发者开发的应用质量和性能依赖bricks提供的提供底层控件。 +* 简单的开发方式,开发者以编写json数据文件的形式开发前端应用,以后可以提供一个可视化开发平台 + +## Bricks控件描述文件 +Bricks使用json格式描述控件,具体格式要求请看[控件描述文件](descjson.md) + +## BricksApp +Bricks应用类,参见[BricksApp](bricksapp.md) + +## bricks主要函数 +### widgetBuild +创建控件函数,详细说明请看[这里](bricks.md) + +### getWigetById +从DOM树查找控件,详细说明请看[这里](bricks.md) + +## bricks控件 +Bricks的所有控件均继承自JsWidget,控件间的继承关系请看[控件继承树](inherittree.md) + +控件是bricks的基础,每个控件实现了特定显示功能或布局能力,开发者使用这些控件来构建应用 + +bricks的开发理念是:应用开发可分为底层控件的开发以及操控底层控件来搭建应用。 + +通过这样分工,让精通底层开发的人员专心开发底层控件,而精通操控控件的人员专心搭建应用,从而提高开发效率和开发质量,希望大家参与进来一起做。 + +关于控件更多的信息,请看[控件](widgettypes.md) + +## 依赖 +如果要使用Markdown,需要引用marked模块, + +如果用到图表, 需要引用echarts + +* [Marked](https://github.com/markedjs/marked) + +* [echarts](https://echarts.apache.org/zh/index.html) + +## build +bricks 使用uglifyjs 压缩 +在bricks目录下执行 +``` +./build.sh +``` +命令执行完后在项目的dist目录下会生成bricks.js 和bricks.min.js,并将examples和docs目录复制到本机到wwwroot目录 + +按照开发者本地web服务器的配置,请修改build.sh的目标路径。 +## 引用 +``` + + + +``` +## 例子 +配置好本地服务器后,可以使用build.sh将bricks项目内容复制到本地网站后台,之后在网站的examples目录中查看bricks提供的例子程序 + diff --git a/docs/cn/inherittree.md b/docs/cn/inherittree.md new file mode 100644 index 0000000..2949436 --- /dev/null +++ b/docs/cn/inherittree.md @@ -0,0 +1,102 @@ +# Bricks控件继承树 + +``` +JsWidget + | + --- AudioPlayer + | + --- Image + | | + | --- Icon + | + ___ BlankIcon + | + ___ Layout + | | + | --- VBox + | | | + | | --- Accordion + | | | + | | --- DataGrid + | | | + | | --- Form + | | | + | | --- MarkdownViewer + | | | + | | --- Menu + | | | + | | --- Message + | | | | + | | | --- Error + | | | + | | --- Popup + | | | + | | --- ScrollPanel + | | | + | | --- TreeNode + | | | + | | --- Tree + | | | | + | | | --- EditableTree + | | | + | | --- VideoPlayer + | | + | --- HBox + | | | + | | --- MiniForm + | | + | --- MultipleStateImage + | | + | --- Toolbar + | | + | --- TabPanel + | | + | --- Modal + | | + | --- HFiller + | | + | --- VFiller + | | + | --- Button + | | + | --- UiType + | | | + | | --- UiStr + | | | | + | | | --- UiPassword + | | | | + | | | --- UiInt + | | | | | + | | | | --- UiFloat + | | | | + | | | --- UiTel + | | | | + | | | --- UiEmail + | | | | + | | | --- UiFile + | | | | + | | | --- UiDate + | | | | + | | | --- UiAudio + | | | | + | | | --- UiVideo + | | | + | | --- UiCheck + | | | + | | --- UiCheckBox + | | | + | | --- UiText + | | | + | | --- UiCode + | + --- MdText + | + ___ Video + | + --- TextBase + | + --- Text + | + --- Title1, Title2, Title3, Title4, Title5, Title6 +``` + diff --git a/docs/cn/jswidget.md b/docs/cn/jswidget.md new file mode 100644 index 0000000..70b4ac9 --- /dev/null +++ b/docs/cn/jswidget.md @@ -0,0 +1,25 @@ +# JsWidget +Bricks框架的最原始的控件,所有Bricks的控件均继承自JsWidget或其后代。 + +## 构建选项 + +## 属性 + +### dom_element +dom_element是控件对应的dom元素。 + +## 方法 + +### create() +创建dom元素的方法,并将新创建的元素保存在dom_element属性中,JsWidget创建一个”div“的元素, 子类通过提供自己的create()函数创建自己特定的dom元素。 +### set_css(css_name, delflg) + +增加或删除一个css类, 当delflg为真时删除一个“css_name”css类,否则增加一个“css_name”类 + +### sizable() +sizable函数让当前类有按照bricks_app.charsize的大小设置自身大小的能力,并在charsize变化时改变自身的大小 + +### change_fontsize(ts) +change_fontsize函数由bricks_app.textsize_bigger(),textsize_smaller()函数调用,用来改变控件的大小 +## 事件 +无 diff --git a/docs/cn/pattern.md b/docs/cn/pattern.md new file mode 100644 index 0000000..e29f7f2 --- /dev/null +++ b/docs/cn/pattern.md @@ -0,0 +1,9 @@ +# XXX + +## 创建选项 + +## 属性 + +## 方法 + +## 事件 diff --git a/docs/cn/widgettypes.md b/docs/cn/widgettypes.md new file mode 100644 index 0000000..73698a3 --- /dev/null +++ b/docs/cn/widgettypes.md @@ -0,0 +1,45 @@ +# 控件列表 +Bricks内置许多的显示控件,所有显示控件都继承自JsWidget,容器控件Layout几就继承自JsWidget,其他的容器HBox, VBox继承自Layout + +# 控件继承树 + +# 控件清单 +* [JsWidget](jswidget.md): 祖先控件,对应于
元素 +* [Accordion](accordion.md):可折叠控件 +* [AudioPlayer](audioplayer.md):音频播放器 +* [Button](button.md):按钮控件 +* [DataGrid](datagrid.md):数据表格控件 +* [Form](form.md):输入表单控件 +* [Image](image.md):图片控件 +* [Icon](icon.md):图标控件 +* [BlankIcon](blackicon.js):空白图标控件 +* [HBox](hbox.md):横向布局器 +* [VBox](vbox.md):纵向布局器 +* [HFiller](hfiller.md):横向填充控件 +* [VFiller](vfiller.md):纵向填充控件 +* [MarkdownViewer](markdonwviewer.md):markdown文档显示控件 +* [Menu](menu.md):菜单控件 +* [Message](message.md):消息控件 +* [Error](error.md):错误信息控件 +* [PopupForm](popupform.md):弹出表单控件 +* [MiniForm](meniform.md):多选单一输入表单 +* [Modal](modal.md):独占控件 +* [ModalForm](modalform.md):独占表单 +* [MultipleStateImage](multiplestateimage.md):多状态图像显示控件 +* [ScrollPanel](scrollpanel.md):滚动面板 +* [VScrollPanel](vscrollpanel.md):纵向滚动面板 +* [HScrollPanel](hscrollpanel.md):横向滚动面板 +* [TabPanel][tabpanel.md):标签面板控件 +* [Toolbar](toolbar.md):工具条控件 +* [Tree](tree.md):树状显示控件 +* [EditableTree](editabletree.md):可编辑树状显示控件 +* [VideoPlayer](videoplayer.md):视频播放器控件 +* [Text](text.md):正文控件 +* [Title1](title1.md):标题1控件 +* [Title2](title2.md):标题2控件 +* [Title3](title3.md):标题3控件 +* [Title4](title4.md):标题4控件 +* [Title5](title5.md):标题5控件 +* [Title6](title6.md):标题6控件 + +# diff --git a/docs/image.md b/docs/image.md new file mode 100755 index 0000000..9a0e839 --- /dev/null +++ b/docs/image.md @@ -0,0 +1,57 @@ +# Image +Image widget show image +## use case +``` + + + + + + + + + + +``` +the result is
+![image](image.png) + +## inheritance +Image inherited from JsWidget + +## options +``` +{ + "source": + "width": + "height": +} +``` +### source +source is url to the image +### width +optional, default is 100%, specified the image's width +### height +optional, default is 100%, specified the image's height + +## method +none +## event +none diff --git a/docs/image.png b/docs/image.png new file mode 100755 index 0000000..a1c494a Binary files /dev/null and b/docs/image.png differ diff --git a/docs/index.md b/docs/index.md new file mode 120000 index 0000000..42061c0 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/docs/layout.md b/docs/layout.md new file mode 100755 index 0000000..5ad3b81 --- /dev/null +++ b/docs/layout.md @@ -0,0 +1,16 @@ +# Layout +Layout is a layout widget for layout widgets inside it +## use case +none +## inheritance +Layout inherited from JsWidget +## options +## method +### add_widget +add_widget(w) append a widget name by w, to the caller +### remove_widget +remove_widget(w) remove widget named by w from caller's children +### clear_widgets +clear_widgets() remove all children widget. +## event +none diff --git a/docs/markdownviewer.md b/docs/markdownviewer.md new file mode 100755 index 0000000..21ef722 --- /dev/null +++ b/docs/markdownviewer.md @@ -0,0 +1,13 @@ +# MarkdownView + +## Options attributes +MarkdownViewer has following attributes: +### md_url +md_url is a url address in which it is a markdown text file. + +## Description +MarkdownViewer parses and show the markdown content child dom element. and ifound and modify element with tag name "a" to change href to '#' and add onclick action to get and show the markdown content inside this MarkdownViewer dom elementame "a" in markdown content. + +## Event +none + diff --git a/docs/pw.md b/docs/pw.md new file mode 100755 index 0000000..d69cb35 --- /dev/null +++ b/docs/pw.md @@ -0,0 +1,7 @@ +# Widget Name +description of the Widget +## use case +## inheritance +## options +## method +## event diff --git a/docs/text.md b/docs/text.md new file mode 100755 index 0000000..8eaf693 --- /dev/null +++ b/docs/text.md @@ -0,0 +1,7 @@ +# Text +Text is a widget to show text +## use case +## inheritance +## options +## method +## event diff --git a/docs/toolbar.md b/docs/toolbar.md new file mode 100755 index 0000000..ea7bf7f --- /dev/null +++ b/docs/toolbar.md @@ -0,0 +1,105 @@ +# Toolbar +The Toolbar widget provides a toolbar componets which provide a tool bar interface service, and you can add, delete tool at runtime dynamicly. +## use case +``` + + + + + + + + + + +``` +and the result like this:
+![toolbar screenshot](toolbar.png) + +## inheritance +Toolbar inherited from BoxLayout + +## options +``` + { + orientation: + tools: + } +``` +### orientation +should be 'vertical' means tool widgets will arrange in vertical or 'horizontal' means tool widgets will arrange in horizontal +### tools: +a array contains a list of tool objects + +### tool object +tool object has following properties: +``` + { + icon: + name: + label: + removable: + } +``` +#### icon is a image url, it is optional, if present, the tool will show a icon before the tool's text +#### name +name is a itendify field for the tools, it should be unique in this tools of this options scope. +#### label +label will translate by i18n for the language user used, and the result will be show. if label is miss, use the name of the tool object. +#### removable +if removable is true, the tool widget will append a delete image widget, and will remove the tool widget if user click the delete image widget. + + +## method +### createTool +createTool(toolOptions) + +createTool create a tool widget and append the to end of the toolbar. + +## event +toolbar has some events other widgets can bind to, they are: +### ready +after constructor call finished, and all the tools built, toolbar will fire this event + +### command +after user click on one of the tool widgets, toolbar will fire this event with the tool's options used to construct it as the parameters, can get the parameters using "event.params" +. +### remove +after user click delete image widget, toolbar delete the tool widget from toolbar, and fire this event. diff --git a/docs/toolbar.png b/docs/toolbar.png new file mode 100755 index 0000000..fcdcda7 Binary files /dev/null and b/docs/toolbar.png differ diff --git a/docs/vbox.md b/docs/vbox.md new file mode 100755 index 0000000..fb3098c --- /dev/null +++ b/docs/vbox.md @@ -0,0 +1,11 @@ +# VBox +Vbox is a vertical layout widget, it layout subwidgeta in vertical direction +## use case +## inheritance +VBox inherited fromm BoxLayout +## options + +## method +none +## event +none diff --git a/docs/videoplayer.md b/docs/videoplayer.md new file mode 100755 index 0000000..6d276a5 --- /dev/null +++ b/docs/videoplayer.md @@ -0,0 +1,87 @@ +# VideoPlayer + +## Usage +### play a mp4 file +``` + + + + + + + + +``` +### play a m3u8 stream +``` + + + + + + + + + +``` +you will see ti like this +![example video](m3u8.png "see it?") +## options +to be a VideoPlayer instance, you need to provide a options with contains +following attributes +### source +the url of a video resouce, VideoPlayer can play mp4, m3u8 video +### srctype +specify the source type, should be 'mp4' or 'hls' for m3u8 'dash' for play a Dash manifest +## play avi file +!v[sample video](http://kimird.com/video/sample-avi-file.avi) +## play flv file +!v[sample video](http://kimird.com/video/sample-flv-file.flv) +## play mkv file +!v[sample video](http://kimird.com/video/sample-mkv-file.mkv) +## play mov file +!v[sample video](http://kimird.com/video/sample-mov-file.mov) +## play mp4 file +!v[sample video](http://kimird.com/video/sample-mp4-file.mp4) +## play webm file +!v[sample video](http://kimird.com/video/sample-webm-file.webm) +## play m3u8 file +!v[abc news TV](https://abc-iview-mediapackagestreams-2.akamaized.net/out/v1/6e1cc6d25ec0480ea099a5399d73bc4b/index.m3u8) diff --git a/docs/widgets.md b/docs/widgets.md new file mode 100644 index 0000000..29f0879 --- /dev/null +++ b/docs/widgets.md @@ -0,0 +1,49 @@ +# Bricks widgets +## Accordion +## AudioPlayer +## BlankIcon +## BoxLayout +[boxlayout](BoxLayout.md) +## Button +## DataGrid +## EditableTree +## Error +## Form +## HBox +[hbox](HBox.md) + +## HFiller +## HScrollPanel +## Icon +## Image +[image](image.md) +## MarkdownViewer +(markdown viewer](markdownviewer.md) +## Menu +## Message +## MiniForm +## Modal +## ModalForm +## MultipleStateImage +## PopupForm +## TabForm +## TabPanel +## Text +[text](text.md) +## Title1 +## Title2 +## Title3 +## Title4 +## Title5 +## Title6 +## Toolbar +[Toolbar](toolbar.md) +## Tree +## VBox +[VBox](vbox.md) +## VFiller +## VScrollPanel +## Video +## VideoPlayer +[VideoPlayer](videoplayer.md) +## XTerminal diff --git a/examples/.DS_Store b/examples/.DS_Store new file mode 100755 index 0000000..14aeab6 Binary files /dev/null and b/examples/.DS_Store differ diff --git a/examples/accordion.html b/examples/accordion.html new file mode 100644 index 0000000..fd996f6 --- /dev/null +++ b/examples/accordion.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + diff --git a/examples/audio.html b/examples/audio.html new file mode 100755 index 0000000..4ab4a02 --- /dev/null +++ b/examples/audio.html @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/examples/bricks.tmpl b/examples/bricks.tmpl new file mode 100755 index 0000000..28c6417 --- /dev/null +++ b/examples/bricks.tmpl @@ -0,0 +1,8 @@ +{% if not webbricks or webbricks==0 %} +{% include "header.html" %} +{% endif -%} +{% include content %} +{% if not webbricks %} +{% include "footer.html" %} +{% endif -%} + diff --git a/examples/button.html b/examples/button.html new file mode 100644 index 0000000..36240d0 --- /dev/null +++ b/examples/button.html @@ -0,0 +1,57 @@ + + + + + + + + + + diff --git a/examples/config.js b/examples/config.js new file mode 100755 index 0000000..cc40a35 --- /dev/null +++ b/examples/config.js @@ -0,0 +1,344 @@ +alert('here ....'); +const langs = [ + { title: 'English', path: '/home', matchPath: /^\/(home|ecosystem|support)/ }, + { title: '简体中文', path: '/zh-Hans/', matchPath: /^\/zh-Hans/ }, +]; + +docute.init({ + landing: 'landing.html', + title: 'APlayer', + repo: 'DIYgod/APlayer', + twitter: 'DIYgod', + 'edit-link': 'https://github.com/MoePlayer/APlayer/tree/master/docs', + nav: { + default: [ + { + title: 'Home', path: '/home' + }, + { + title: 'Ecosystem', path: '/ecosystem' + }, + { + title: 'Support APlayer', path: '/support' + }, + { + title: 'Languages', type: 'dropdown', items: langs + } + ], + 'zh-Hans': [ + { + title: '首页', path: '/zh-Hans/' + }, + { + title: '生态', path: '/zh-Hans/ecosystem' + }, + { + title: '支持 APlayer', path: '/zh-Hans/support' + }, + { + title: '选择语言', type: 'dropdown', items: langs + } + ], + }, + plugins: [ + docsearch({ + apiKey: '', + indexName: 'aplayer', + tags: ['english', 'zh-Hans'], + url: 'https://aplayer.js.org' + }), + evanyou(), + player() + ] +}); + +function player () { + return function (context) { + context.event.on('landing:updated', function () { + console.log('landing:updated'); + clearPlayer(); + aplayer0(); + aplayer1(); + }); + context.event.on('content:updated', function () { + console.log('content:updated'); + clearPlayer(); + for (let i = 0; i < document.querySelectorAll('.load').length; i++) { + document.querySelectorAll('.load')[i].addEventListener('click', function () { + window[this.parentElement.id] && window[this.parentElement.id](); + }); + } + }); + }; +} + +function clearPlayer () { + for (let i = 0; i < 10; i++) { + if (window['ap' + i]) { + window['ap' + i].destroy(); + } + } +} + +function aplayer1 () { + window.ap1 = new APlayer({ + container: document.getElementById('aplayer1'), + theme: '#F57F17', + lrcType: 3, + audio: [{ + name: '光るなら', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc', + theme: '#ebd0c2' + }, { + name: 'トリカゴ', + artist: 'XX:me', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc', + theme: '#46718b' + }, { + name: '前前前世', + artist: 'RADWIMPS', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc', + theme: '#505d6b' + }] + }); +} + +function aplayer0 () { + window.ap0 = new APlayer({ + container: document.getElementById('aplayer0'), + fixed: true, + lrcType: 3, + audio: [{ + name: '前前前世', + artist: 'RADWIMPS', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc', + theme: '#505d6b' + }, { + name: 'トリカゴ', + artist: 'XX:me', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc', + theme: '#46718b' + }, { + name: '光るなら', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc', + theme: '#ebd0c2' + }] + }); +} + +function aplayer2 () { + window.ap2 = new APlayer({ + container: document.getElementById('aplayer2'), + audio: [{ + name: '光るなら', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + theme: '#ebd0c2' + }] + }); +} + +function aplayer3 () { + window.ap3 = new APlayer({ + container: document.getElementById('aplayer3'), + mini: false, + autoplay: false, + loop: 'all', + order: 'random', + preload: 'auto', + volume: 0.7, + mutex: true, + listFolded: false, + listMaxHeight: 90, + lrcType: 3, + audio: [{ + name: '光るなら', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc', + theme: '#ebd0c2' + }, { + name: 'トリカゴ', + artist: 'XX:me', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc', + theme: '#46718b' + }, { + name: '前前前世', + artist: 'RADWIMPS', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc', + theme: '#505d6b' + }] + }); +} + +function aplayer4 () { + window.ap4 = new APlayer({ + container: document.getElementById('aplayer4'), + lrcType: 3, + audio: [{ + name: '光るなら', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc', + theme: '#ebd0c2' + }] + }); +} + +function aplayer5 () { + window.ap5 = new APlayer({ + container: document.getElementById('aplayer5'), + lrcType: 3, + audio: [{ + name: '光るなら', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc', + theme: '#ebd0c2' + }, { + name: 'トリカゴ', + artist: 'XX:me', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc', + theme: '#46718b' + }, { + name: '前前前世', + artist: 'RADWIMPS', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc', + theme: '#505d6b' + }] + }); +} + +function aplayer6 () { + window.ap6 = new APlayer({ + container: document.getElementById('aplayer6'), + mini: true, + audio: [{ + name: '光るなら', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + theme: '#ebd0c2' + }] + }); +} + +function aplayer7 () { + window.ap7 = new APlayer({ + container: document.getElementById('aplayer7'), + audio: [{ + name: '光るなら(HLS)', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hls/hikarunara.m3u8', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + theme: '#ebd0c2', + type: 'hls' + }, { + name: '光るなら', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + theme: '#ebd0c2' + }, { + name: 'トリカゴ', + artist: 'XX:me', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg', + theme: '#46718b' + }, { + name: '前前前世', + artist: 'RADWIMPS', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg', + theme: '#505d6b' + }] + }); +} + +function aplayer8 () { + window.ap8 = new APlayer({ + container: document.getElementById('aplayer8'), + theme: '#e9e9e9', + audio: [{ + name: '光るなら', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + }, { + name: 'トリカゴ', + artist: 'XX:me', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg', + }, { + name: '前前前世', + artist: 'RADWIMPS', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg', + }] + }); + + const colorThief = new ColorThief(); + window.ap8.on('switchaudio', function (index) { + if (!window.ap8.options.audio[index].theme) { + colorThief.getColorAsync(window.ap8.options.audio[index].cover, function (color) { + window.ap8.theme(`rgb(${color[0]}, ${color[1]}, ${color[2]})`, index); + }); + } + }); +} + +function aplayer9 () { + window.ap9 = new APlayer({ + container: document.getElementById('aplayer9'), + fixed: true, + lrcType: 3, + audio: [{ + name: '光るなら', + artist: 'Goose house', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc', + theme: '#ebd0c2' + }, { + name: 'トリカゴ', + artist: 'XX:me', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc', + theme: '#46718b' + }, { + name: '前前前世', + artist: 'RADWIMPS', + url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3', + cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg', + lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc', + theme: '#505d6b' + }] + }); +} diff --git a/examples/datagrid.html b/examples/datagrid.html new file mode 100644 index 0000000..858633e --- /dev/null +++ b/examples/datagrid.html @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/examples/datagrid.json b/examples/datagrid.json new file mode 100644 index 0000000..1eb9268 --- /dev/null +++ b/examples/datagrid.json @@ -0,0 +1,893 @@ +{ + "widgettype": "DataGrid", + "options": { + "data": [ + { + "id": 0, + "tv_group": "中央电视台0211s大多数大多", + "tv_name": "cctv1", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_grade123":"1233333333333333", + "channel_grade456":"45666666666666", + "channel_code": 0 + }, + { + "id": 1, + "tv_group": "中央电视台1但是对方的三个都是人生", + "tv_name": "cctv2", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 1 + }, + { + "id": 2, + "tv_group": "中央电视台2是的SV程序多渠道", + "tv_name": "cctv3", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 2 + }, + { + "id": 3, + "tv_group": "中央电视台3广发鬼地方个大概的", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 3, + "tv_group": "中央电视台3三大SV徐秩序发生", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 3, + "tv_group": "中央电视台3所发生的公司根深蒂固", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 4, + "tv_group": "中央电视台3发顺丰第三方士大夫", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 5, + "tv_group": "中央电视台3发送到仨女的是否", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 6, + "tv_group": "中央电视台3胜多负少的城市的城市", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 7, + "tv_group": "中央电视台3阿发撒撒发", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 8, + "tv_group": "中央电视台3是撒让人本地服务", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 9, + "tv_group": "中央电视台3VS对方水电费", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 10, + "tv_group": "中央电视台3八分熟", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 11, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 12, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 13, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 14, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 15, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 16, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 17, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 18, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 19, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 20, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 21, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, { + "id": 22, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, { + "id": 23, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, { + "id": 24, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, { + "id": 25, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + ",channel_code": 3 + }, { + "id": 26, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, { + "id": 27, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, { + "id": 28, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, { + "id": 29, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 30, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 31, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 32, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + }, + { + "id": 33, + "tv_group": "中央电视台3", + "tv_name": "cctv4", + "logo_url": "baidu", + "url": "http://www.baidu.com", + "media_type": "广告,电影", + "download_date": "2022.12.12 12:02:02", + "channel_delay": "3000", + "channel_grade": "一级", + "channel_code": 3 + } + + ], + "title": "Test", + "description": "get all iptv channels", + "fields": [ + { + "name": "id", + "uitype": "str", + "datatype": "str", + "label": "编号", + "width": 210.0, + "readonly": true, + "freeze": true + }, + { + "name": "tv_group", + "uitype": "str", + "datatype": "str", + "label": "频道组", + "width": 210.0, + "readonly": true, + "freeze":true + }, + { + "name": "tv_name", + "uitype": "str", + "datatype": "str", + "label": "频道名称", + "width": 210.0, + "readonly": true, + "freeze": true + }, + { + "name": "logo_url", + "uitype": "str", + "datatype": "str", + "label": "台标url", + "width": 210.0, + "readonly": true + }, + { + "name": "url", + "uitype": "str", + "datatype": "str", + "label": "url", + "width": 210.0, + "readonly": true + }, + { + "name": "media_type", + "uitype": "str", + "datatype": "str", + "label": "媒体类型", + "width": 210.0, + "readonly": true + }, + { + "name": "download_date", + "uitype": "date", + "datatype": "str", + "label": "下载日期", + "width": 140.0, + "readonly": true + }, + { + "name": "channel_delay", + "uitype": "int", + "datatype": "long", + "label": "频道延迟", + "width": 210.0, + "dec": 0, + "readonly": true + }, + { + "name": "channel_grade", + "uitype": "int", + "datatype": "long", + "label": "频道等级", + "width": 210.0, + "dec": 0, + "readonly": true + }, + { + "name": "channel_grade123", + "uitype": "int", + "datatype": "long", + "label": "频道等级123", + "width": 210.0, + "dec": 0, + "readonly": true + }, + { + "name": "channel_grade456", + "uitype": "int", + "datatype": "long", + "label": "频道等级456", + "width": 210.0, + "dec": 0, + "readonly": true + } + ] + } +} diff --git a/examples/datagrid1.html b/examples/datagrid1.html new file mode 100644 index 0000000..9b74065 --- /dev/null +++ b/examples/datagrid1.html @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/examples/docs.html b/examples/docs.html new file mode 100755 index 0000000..ccb4f7b --- /dev/null +++ b/examples/docs.html @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/examples/echo.ws b/examples/echo.ws new file mode 100644 index 0000000..d5ccc49 --- /dev/null +++ b/examples/echo.ws @@ -0,0 +1 @@ +return 'resp:' + ws_data diff --git a/examples/editabletree.html b/examples/editabletree.html new file mode 100644 index 0000000..3cfe04e --- /dev/null +++ b/examples/editabletree.html @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/examples/editabletree.json b/examples/editabletree.json new file mode 100644 index 0000000..f0e41b0 --- /dev/null +++ b/examples/editabletree.json @@ -0,0 +1,84 @@ + + { + "widgettype":"EditableTree", + "options":{ + "idField":"id", + "admin":{}, + "textField":"text", + "data":[ + { + "id":1, + "text":"node1", + "is_leaf":false, + "children":[ + { + "id":11, + "text":"node11", + "is_leaf":false, + "children":[ + { + "id":112, + "text":"node.12", + "is_leaf":false, + "children":[ + { + "id":1112, + "text":"node1112", + "is_leaf":true + }, + { + "id":1113, + "text":"node113", + "is_leaf":true + } + ] + }, + { + "id":113, + "text":"node113", + "is_leaf":true + } + ] + }, + { + "id":12, + "text":"node12", + "is_leaf":true + }, + { + "id":13, + "text":"node13", + "is_leaf":true + } + ] + }, + { + "id":2, + "text":"node2", + "is_leaf":false, + "children":[ + { + "id":21, + "text":"node21", + "is_leaf":true + }, + { + "id":22, + "text":"node22", + "is_leaf":true + }, + { + "id":23, + "text":"node23", + "is_leaf":true + } + ] + }, + { + "id":3, + "text":"node3", + "is_leaf":true + } + ] + } + } diff --git a/examples/error.html b/examples/error.html new file mode 100644 index 0000000..432bc26 --- /dev/null +++ b/examples/error.html @@ -0,0 +1,105 @@ + + + + + + + + + diff --git a/examples/fileupload.dspy b/examples/fileupload.dspy new file mode 100755 index 0000000..197d7b7 --- /dev/null +++ b/examples/fileupload.dspy @@ -0,0 +1,2 @@ +print(params_kw) +return params_kw diff --git a/examples/fileupload.html b/examples/fileupload.html new file mode 100755 index 0000000..b266316 --- /dev/null +++ b/examples/fileupload.html @@ -0,0 +1,64 @@ + + + + +
+ +
+ + + + diff --git a/examples/footer.html b/examples/footer.html new file mode 100755 index 0000000..55d5d50 --- /dev/null +++ b/examples/footer.html @@ -0,0 +1,4 @@ + ; + const app = BricksApp(opts); + app.run(); + diff --git a/examples/form.html b/examples/form.html new file mode 100644 index 0000000..007b637 --- /dev/null +++ b/examples/form.html @@ -0,0 +1,167 @@ + + + + + + + + + diff --git a/examples/hbox.html b/examples/hbox.html new file mode 100755 index 0000000..2e8d26c --- /dev/null +++ b/examples/hbox.html @@ -0,0 +1,65 @@ + + + + + + + + diff --git a/examples/header.html b/examples/header.html new file mode 100755 index 0000000..99f1be7 --- /dev/null +++ b/examples/header.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/examples/iptvchannels.bcrud b/examples/iptvchannels.bcrud new file mode 100644 index 0000000..5b2e934 --- /dev/null +++ b/examples/iptvchannels.bcrud @@ -0,0 +1,53 @@ +{ + "database":"iptvdb", + "table":"iptvchannels", + "browser":{ + "lineno":true, + "include":[ + { + "freeze":true, + "name":"play_btn", + "label":"Play", + "uitype":"button", + "color":"#2222d4", + "width":"60px", + "uioptions":{ + "bgcolor":"#2222ff", + "nonepack":true + }, + "action":{ + "actiontype":"script", + "target":"self", + "script":"console.log(params.url); window.open(params.url);" + } + }, + { + "freeze":true, + "name":"del_btn", + "label":"del", + "uitype":"button", + "bgcolor":"#d4d4d4", + "color":"#2222d4", + "width":"60px", + "uioptions":{ + "bgcolor":"#2222ff", + "nonepack":true + }, + "action":{ + "actiontype":"script", + "target":"self", + "script":"console.log(params); window.open(params.url);" + } + } + ], + "exclude":["id", "media_type"], + "alter":{ + "url":{ + "width":"410px" + }, + "tv_group":{ + "width":"100px" + } + } + } +} diff --git a/examples/list_tables.dspy b/examples/list_tables.dspy new file mode 100644 index 0000000..93a6cc4 --- /dev/null +++ b/examples/list_tables.dspy @@ -0,0 +1,15 @@ +db = DBPools(); +if params_kw.get('page', '1') != '1': + print(params_kw) + return { + "total":"0", + "rows":[] + } +async with db.sqlorContext('kboss') as sor: + d = await sor.tables(); + print(len(d)) + return { + "total":len(d), + "rows":d + } + diff --git a/examples/login_form.json b/examples/login_form.json new file mode 100644 index 0000000..16d6455 --- /dev/null +++ b/examples/login_form.json @@ -0,0 +1,19 @@ +{ + "widgettype":"Form", + "options":{ + "submit_url":"/checkuserpw.dspy", + "fileds":[ + { + "name":"name", + "uitype":"str", + "label":"user name" + }, + { + "name":"passwd", + "uitype":"password", + "label":"password" + } + ] + } +} + diff --git a/examples/m3u8.html b/examples/m3u8.html new file mode 100755 index 0000000..46a8e0f --- /dev/null +++ b/examples/m3u8.html @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/examples/markdonw.html b/examples/markdonw.html new file mode 100755 index 0000000..e69de29 diff --git a/examples/markdown.html b/examples/markdown.html new file mode 100755 index 0000000..51c125e --- /dev/null +++ b/examples/markdown.html @@ -0,0 +1,38 @@ + + + + +
+ + + + + diff --git a/examples/menu.tmpl b/examples/menu.tmpl new file mode 100755 index 0000000..1dae7b4 --- /dev/null +++ b/examples/menu.tmpl @@ -0,0 +1,26 @@ +{ + "widgettype":"Menu", + "options":{ + "target":"workarea", + "bgcolor":"#ededed", + "items":[ + { + "name":"file", + "label":"File", + "items":[ + { + "name":"test1" + }, + { + "name":"test2" + } + ] + }, + { + "name":"edit", + "label":"Edit", + "url":"lllll" + } + ] + } +} diff --git a/examples/message.html b/examples/message.html new file mode 100644 index 0000000..b4b8ae2 --- /dev/null +++ b/examples/message.html @@ -0,0 +1,107 @@ + + + + + + + + + + + diff --git a/examples/miniform.html b/examples/miniform.html new file mode 100644 index 0000000..ed36207 --- /dev/null +++ b/examples/miniform.html @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/examples/miniform.json b/examples/miniform.json new file mode 100644 index 0000000..dee8deb --- /dev/null +++ b/examples/miniform.json @@ -0,0 +1,25 @@ +{ + "widgettype":"MiniForm", + "options":{ + "label_width":"100px", + "fields":[ + { + "name":"test1", + "label":"姓名", + "uitype":"str" + }, + { + "name":"test2", + "label":"性别", + "uitype":"str" + }, + { + "name":"test3", + "label":"地址", + "uitype":"str" + } + ] + } +} + + diff --git a/examples/modal.html b/examples/modal.html new file mode 100755 index 0000000..e6a31c9 --- /dev/null +++ b/examples/modal.html @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/examples/modal.json b/examples/modal.json new file mode 100644 index 0000000..3668ecc --- /dev/null +++ b/examples/modal.json @@ -0,0 +1,19 @@ +{ + "id":"mymodal", + "widgettype":"Modal", + "options":{ + "auto_close":true, + "auto_open":true, + "width":"700px", + "height":"400px", + "archor":"cl" + }, + "subwidgets":[ + { + "widgettype":"Text", + "options":{ + "text":"This is a test" + } + } + ] +} diff --git a/examples/scroll.html b/examples/scroll.html new file mode 100644 index 0000000..8af9d9a --- /dev/null +++ b/examples/scroll.html @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/examples/scroll.json b/examples/scroll.json new file mode 100644 index 0000000..8281360 --- /dev/null +++ b/examples/scroll.json @@ -0,0 +1,31 @@ +{ + "widgettype":"ScrollPanel", + "options":{ + "scrollY":"hidden" + }, + "subwidgets":[ + { + "widgettype":"HBox", + "options":{ + "height":"auto", + "width":"auto" + }, + "subwidgets":[ + { + "widgettype":"Text", + "options":{ + "width":"3000px", + "text":"this is long text" + } + } + ] + }, + { + "widgettype":"VScrollPanel", + "options":{ + }, + "subwidgets":[ + ] + } + ] +} diff --git a/examples/t1.html b/examples/t1.html new file mode 100755 index 0000000..72104ee --- /dev/null +++ b/examples/t1.html @@ -0,0 +1,69 @@ + + + + + + +
+ + + diff --git a/examples/tab.html b/examples/tab.html new file mode 100755 index 0000000..adf510f --- /dev/null +++ b/examples/tab.html @@ -0,0 +1,75 @@ + + + + + + + + + + diff --git a/examples/tableinfo.dspy b/examples/tableinfo.dspy new file mode 100644 index 0000000..b94d15b --- /dev/null +++ b/examples/tableinfo.dspy @@ -0,0 +1,6 @@ +db = DBPools() + +async with db.sqlorContext('kboss') as sor: + r = await sor.I(params_kw.get('tablename', 'user')) + return r + diff --git a/examples/tables.html b/examples/tables.html new file mode 100644 index 0000000..83df085 --- /dev/null +++ b/examples/tables.html @@ -0,0 +1,25 @@ + + + + + + + + + + + diff --git a/examples/tables.json b/examples/tables.json new file mode 100644 index 0000000..3b39093 --- /dev/null +++ b/examples/tables.json @@ -0,0 +1,22 @@ +{ + "widgettype":"DataGrid", + "options": { + "dataurl":"list_tables.dspy", + "title":"数据表清单", + "idField":"name", + "fields":[ + { + "name":"name", + "label":"Name", + "width":"200px", + "uitype":"str" + }, + { + "name":"title", + "label":"中文表名", + "width":"420px", + "uitype":"str" + } + ] + } +} diff --git a/examples/terminal.html b/examples/terminal.html new file mode 100644 index 0000000..ed3bd6e --- /dev/null +++ b/examples/terminal.html @@ -0,0 +1,39 @@ + + + + + + +
+ + + diff --git a/examples/test.tmpl b/examples/test.tmpl new file mode 100755 index 0000000..7d1b624 --- /dev/null +++ b/examples/test.tmpl @@ -0,0 +1,5 @@ +{% if not webbricks %} +{% include "head.html" %} + +{% include "footer.html" %} + diff --git a/examples/test1.md b/examples/test1.md new file mode 100755 index 0000000..d67c5bb --- /dev/null +++ b/examples/test1.md @@ -0,0 +1,8 @@ +# This is a test markdown +## title 2 +[other markdown](test2.md) +## Test +leegwk wer gwelrgerw +!v[test video](http://kimird.com/video/sample-mp4-file.mp4) +RR + diff --git a/examples/test11.html b/examples/test11.html new file mode 100644 index 0000000..b9fd7dd --- /dev/null +++ b/examples/test11.html @@ -0,0 +1,144 @@ + + + + + + +
Test Grid table
+
+
+ + + diff --git a/examples/test2.md b/examples/test2.md new file mode 100755 index 0000000..8b22815 --- /dev/null +++ b/examples/test2.md @@ -0,0 +1,13 @@ +# Bricks +## event handle types + +### bricks +### method +### script +### event +### registerfunction + +[other markdown](test2.md) +## Test +leegwk wer gwelrgerw + diff --git a/examples/test_code.json b/examples/test_code.json new file mode 100644 index 0000000..7414b96 --- /dev/null +++ b/examples/test_code.json @@ -0,0 +1,14 @@ +[ + { + "value":1, + "text":"aaaaaaaaaaaa" + }, + { + "value":2, + "text":"bbbbbbbbbbbb" + }, + { + "value":3, + "text":"ccccccccccc" + } +] diff --git a/examples/testlogin.html b/examples/testlogin.html new file mode 100644 index 0000000..bd54065 --- /dev/null +++ b/examples/testlogin.html @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/examples/text.html b/examples/text.html new file mode 100755 index 0000000..7d1b3cf --- /dev/null +++ b/examples/text.html @@ -0,0 +1,117 @@ + + + + + + + + + + + diff --git a/examples/toolbar.html b/examples/toolbar.html new file mode 100755 index 0000000..c8b8549 --- /dev/null +++ b/examples/toolbar.html @@ -0,0 +1,48 @@ + + + + + + + + + + diff --git a/examples/tree.html b/examples/tree.html new file mode 100644 index 0000000..d8af8b8 --- /dev/null +++ b/examples/tree.html @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/examples/tree.json b/examples/tree.json new file mode 100644 index 0000000..1eae734 --- /dev/null +++ b/examples/tree.json @@ -0,0 +1,83 @@ + + { + "widgettype":"Tree", + "options":{ + "idField":"id", + "textField":"text", + "data":[ + { + "id":1, + "text":"node1", + "is_leaf":false, + "children":[ + { + "id":11, + "text":"node11", + "is_leaf":false, + "children":[ + { + "id":112, + "text":"node.12", + "is_leaf":false, + "children":[ + { + "id":1112, + "text":"node1112", + "is_leaf":true + }, + { + "id":1113, + "text":"node113", + "is_leaf":true + } + ] + }, + { + "id":113, + "text":"node113", + "is_leaf":true + } + ] + }, + { + "id":12, + "text":"node12", + "is_leaf":true + }, + { + "id":13, + "text":"node13", + "is_leaf":true + } + ] + }, + { + "id":2, + "text":"node2", + "is_leaf":false, + "children":[ + { + "id":21, + "text":"node21", + "is_leaf":true + }, + { + "id":22, + "text":"node22", + "is_leaf":true + }, + { + "id":23, + "text":"node23", + "is_leaf":true + } + ] + }, + { + "id":3, + "text":"node3", + "is_leaf":true + } + ] + } + } diff --git a/examples/vbox.html b/examples/vbox.html new file mode 100755 index 0000000..aa359df --- /dev/null +++ b/examples/vbox.html @@ -0,0 +1,70 @@ + + + + + + + + + diff --git a/examples/vbox.tmpl b/examples/vbox.tmpl new file mode 100755 index 0000000..9da8957 --- /dev/null +++ b/examples/vbox.tmpl @@ -0,0 +1,21 @@ +{ + "widgettype":"VBox"; + "options":{}, + "subwidgets":[ + { + "widgettype":"Title1", + "options":{ + "otext":"Title1", + "i18n":true + } + }, + { + "widgettype":"Text", + "options":{ + "otext":"Text 1", + "i18n":true + } + } + ] +} + diff --git a/examples/video.html b/examples/video.html new file mode 100755 index 0000000..1ed16ac --- /dev/null +++ b/examples/video.html @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/examples/xterminal.json b/examples/xterminal.json new file mode 100644 index 0000000..06bde61 --- /dev/null +++ b/examples/xterminal.json @@ -0,0 +1,6 @@ +{ + "widgettype":"XTerminal", + "options":{ + "ws_url":"echo.ws" + } +} diff --git a/examples/xterminal.ui b/examples/xterminal.ui new file mode 100644 index 0000000..a145c17 --- /dev/null +++ b/examples/xterminal.ui @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/package.json b/package.json new file mode 100755 index 0000000..cb22579 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name":"bricks", + "version":"0.1.1", + "repository":{ + "type":"git", + "url":"https://github.com/yumoqing/bricks", + "directory":"bricks" + }, + "description":"bricks is a framework for front-end app", + "keywords":[ + "framework", + "front-end", + "javascript", + "ui", + "web" + ], + "homepage":"https://github.com/yumoqing/bricks", + "bugs":"https://github.com/yumoqing/bricks/issues", + "author":"yu moqing", + "license":"MIT", + "files":[ + "dist/" + ] +} +