bugfix
21
README.md
Normal file → Executable file
@ -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
|
||||||
|
BIN
bricks/.DS_Store
vendored
Executable file
72
bricks/accordion.js
Normal file
@ -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);
|
46
bricks/aggrid.js
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
34
bricks/audio.js
Executable file
@ -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);
|
10
bricks/baseKnowledge.txt
Executable file
@ -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; }
|
||||||
|
```
|
460
bricks/bricks.js
Executable file
@ -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<desc.subwidgets.length; i++){
|
||||||
|
let sdesc = desc.subwidgets[i];
|
||||||
|
let sw = await widgetBuild(sdesc, w);
|
||||||
|
if ( sw ){
|
||||||
|
w.add_widget(sw);
|
||||||
|
} else {
|
||||||
|
console.log('widgetBuild() error: sdesc=', sdesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (desc.hasOwnProperty('binds')){
|
||||||
|
for (var i=0;i<desc.binds.length; i++){
|
||||||
|
buildBind(w, desc.binds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildBind = function(w, desc){
|
||||||
|
var widget = getWidgetById(desc.wid, w);
|
||||||
|
if (!widget){
|
||||||
|
cnsole.log('desc wid not find', desc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var event = desc.event;
|
||||||
|
buildEventBind(w, widget, event, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildEventBind = function(from_widget, widget, event, desc){
|
||||||
|
var handler = universal_handler.bind(null,from_widget, widget, desc);
|
||||||
|
if (desc.conform){
|
||||||
|
var conform_widget = widgetBuild(desc.conform, widget);
|
||||||
|
conform_widget.bind('on_conform', handler);
|
||||||
|
handler = conform_widget.open.bind(conform_widget);
|
||||||
|
}
|
||||||
|
widget.bind(event, handler);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var universal_handler = function(from_widget, widget, desc, event){
|
||||||
|
debug('universal_handler() info', 'from_widget=',
|
||||||
|
from_widget,
|
||||||
|
'widget=', widget,
|
||||||
|
'desc=', desc,
|
||||||
|
event);
|
||||||
|
var f = buildEventHandler(from_widget, desc);
|
||||||
|
if (f){
|
||||||
|
return f(event);
|
||||||
|
}
|
||||||
|
debug('universal_handler() error', 'from_widget=',
|
||||||
|
from_widget,
|
||||||
|
'widget=', widget,
|
||||||
|
'desc=', desc,
|
||||||
|
event);
|
||||||
|
}
|
||||||
|
var buildEventHandler = function(w, desc){
|
||||||
|
var target = getWidgetById(desc.target, w);
|
||||||
|
if (! target){
|
||||||
|
console.log('target miss desc=', desc, 'w=', w);
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
var rtdata = null;
|
||||||
|
if (desc.rtdata) rtdata = desc.rtdata;
|
||||||
|
else if (desc.datawidget){
|
||||||
|
var data_desc = {
|
||||||
|
widget:desc.datawidget,
|
||||||
|
method:desc.datamethod,
|
||||||
|
params:desc.dataparams,
|
||||||
|
script:desc.datascript
|
||||||
|
}
|
||||||
|
rtdata = getRealtimeData(w, data_desc);
|
||||||
|
}
|
||||||
|
switch (desc.actiontype){
|
||||||
|
case 'urlwidget':
|
||||||
|
return buildUrlwidgetHandler(w, target, rtdata, desc);
|
||||||
|
break;
|
||||||
|
case 'bricks':
|
||||||
|
return buildBricksHandler(w, target, rtdata, desc);
|
||||||
|
break;
|
||||||
|
case 'registerfunction':
|
||||||
|
return buildRegisterFunction(w, target, rtdata, desc);
|
||||||
|
break;
|
||||||
|
case 'method':
|
||||||
|
return buildMethodHandler(w, target, rtdata, desc);
|
||||||
|
break;
|
||||||
|
case 'script':
|
||||||
|
var f = buildScriptHandler(w, target, rtdata, desc);
|
||||||
|
return f;
|
||||||
|
break;
|
||||||
|
case 'event':
|
||||||
|
return buildDispatchEventHandler(w, target, rtdata, desc);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log('invalid actiontype', target, desc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var getRealtimeData = function(w, desc){
|
||||||
|
var target = getWidgetById(desc.widget, w);
|
||||||
|
var f;
|
||||||
|
if (! target){
|
||||||
|
console.log('target miss', desc);
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (desc.method){
|
||||||
|
f = buildMethodHandler(null, target, null, desc)
|
||||||
|
return f();
|
||||||
|
}
|
||||||
|
if (desc.script){
|
||||||
|
f = buildScriptHandler(null, target, null, desc)
|
||||||
|
return f();
|
||||||
|
}
|
||||||
|
debug('getRealtimeData():desc=', desc, 'f=', f);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildUrlwidgetHandler = function(w, target, rtdata, desc){
|
||||||
|
var f = async function(target, mode, options){
|
||||||
|
console.log('target=', target, 'mode=', mode, 'options=', options);
|
||||||
|
var w = await widgetBuild(options, w);
|
||||||
|
if (!w){
|
||||||
|
console.log('options=', options, 'widgetBuild() failed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mode == 'replace'){
|
||||||
|
target.clear_widgets();
|
||||||
|
}
|
||||||
|
target.add_widget(w);
|
||||||
|
}
|
||||||
|
var options = objcopy(desc.options);
|
||||||
|
extend(options.params, rtdata);
|
||||||
|
var opts = {
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":options
|
||||||
|
}
|
||||||
|
return f.bind(target, target, desc.mode || 'replace', opts);
|
||||||
|
}
|
||||||
|
var buildBricksHandler = function(w, target, rtdata, desc){
|
||||||
|
var f = async function(target, mode, options){
|
||||||
|
console.log('target=', target, 'mode=', mode, 'options=', options);
|
||||||
|
var w = await widgetBuild(options, w);
|
||||||
|
if (!w){
|
||||||
|
console.log('options=', options, 'widgetBuild() failed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mode == 'replace'){
|
||||||
|
target.clear_widgets();
|
||||||
|
}
|
||||||
|
target.add_widget(w);
|
||||||
|
}
|
||||||
|
var options = objcopy(desc.options);
|
||||||
|
extend(options.options, rtdata);
|
||||||
|
return f.bind(target, target, desc.mode || 'replace', options);
|
||||||
|
}
|
||||||
|
var buildRegisterFunctionHandler = function(w, target, rtdata, desc){
|
||||||
|
var f = objget(registerfunctions, desc.rfname);
|
||||||
|
if( ! f){
|
||||||
|
console.log('rfname:', desc.rfname, 'not registed', desc);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var params = {};
|
||||||
|
if (desc.params){
|
||||||
|
extend(params, desc.params);
|
||||||
|
}
|
||||||
|
if (rtdata){
|
||||||
|
extend(params, rtdata);
|
||||||
|
}
|
||||||
|
return f.bind(target, params);
|
||||||
|
}
|
||||||
|
var buildMethodHandler = function(w, target, rtdata, desc){
|
||||||
|
var f = target[desc.method];
|
||||||
|
if (! f){
|
||||||
|
console.log('method:', desc.method, 'not exists in', target, 'w=', w);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var params = {};
|
||||||
|
extend(params, desc.params)
|
||||||
|
extend(params, rtdata);
|
||||||
|
return f.bind(target, params);
|
||||||
|
}
|
||||||
|
var buildScriptHandler = function(w, target, rtdata, desc){
|
||||||
|
var params = {};
|
||||||
|
extend(params, desc.params)
|
||||||
|
extend(params, rtdata);
|
||||||
|
var f = new Function('target', 'params', 'event', desc.script);
|
||||||
|
console.log('params=', params, 'buildScriptHandler() ..........');
|
||||||
|
return f.bind(target, target, params);
|
||||||
|
}
|
||||||
|
var buildDispatchEventHandler = function(w, target, rtdata, desc){
|
||||||
|
var params = {};
|
||||||
|
extend(params, desc.params)
|
||||||
|
extend(params, rtdata);
|
||||||
|
var f = function(target, event_name, params){
|
||||||
|
target.dispatch(event_name, params);
|
||||||
|
}
|
||||||
|
return f.bind(target, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
var getWidgetById = function(id, from_widget){
|
||||||
|
if (! id){
|
||||||
|
return from_widget;
|
||||||
|
}
|
||||||
|
if (typeof(id) != 'string') return id;
|
||||||
|
var ids = id.split('/');
|
||||||
|
var el = from_widget.dom_element;
|
||||||
|
var new_el = null;
|
||||||
|
var j = 0;
|
||||||
|
for (var i=0; i< ids.length; i++){
|
||||||
|
if (i == 0){
|
||||||
|
if (ids[i] == 'self'){
|
||||||
|
el = from_widget.dom_element;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ids[i]=='root'){
|
||||||
|
el = bricks_app.root.dom_element;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ids[i]=='app'){
|
||||||
|
return bricks_app;
|
||||||
|
}
|
||||||
|
if (ids[i] == 'window'){
|
||||||
|
el = Body.dom_element;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (ids[i][0] == '-'){
|
||||||
|
var wid = substr(1, ids[i].length - 1)
|
||||||
|
new_el = el.closest('#' + wid);
|
||||||
|
} else {
|
||||||
|
new_el = el.querySelector('#' + ids[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(err){
|
||||||
|
console.log('getWidgetById():i=', ids[i], id, 'not found', err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ( new_el == null ){
|
||||||
|
console.log('getWidgetById():', id, from_widget, 'el=', el, 'id=', ids[i]);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
el = new_el;
|
||||||
|
}
|
||||||
|
if (typeof(el.bricks_widget) !== 'undefined'){
|
||||||
|
console.log('getWidgetById():', id, from_widget, el, 'widget');
|
||||||
|
return el.bricks_widget;
|
||||||
|
}
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
class BricksApp {
|
||||||
|
constructor(opts){
|
||||||
|
/*
|
||||||
|
opts = {
|
||||||
|
login_url:
|
||||||
|
"charsize:
|
||||||
|
"language":
|
||||||
|
"i18n":{
|
||||||
|
"url":'rrr',
|
||||||
|
"default_lang":'en'
|
||||||
|
},
|
||||||
|
"widget":{
|
||||||
|
"widgettype":"Text",
|
||||||
|
"options":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
this.opts = opts;
|
||||||
|
bricks_app = this;
|
||||||
|
this.login_url = opts.login_url;
|
||||||
|
this.charsize = this.opts.charsize || 20;
|
||||||
|
if (this.opts.language){
|
||||||
|
this.lang = this.opts.language;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.lang = navigator.language;
|
||||||
|
}
|
||||||
|
this.textList = [];
|
||||||
|
this.i18n = new I18n(objget(opts, 'i18n', {}));
|
||||||
|
this.session_id = null;
|
||||||
|
createTooltip();
|
||||||
|
}
|
||||||
|
save_session(session){
|
||||||
|
this.session_id = session;
|
||||||
|
}
|
||||||
|
get_session(){
|
||||||
|
return this.session_id;
|
||||||
|
}
|
||||||
|
get_textsize(ctype){
|
||||||
|
var tsize = this.charsize;
|
||||||
|
var stimes = {
|
||||||
|
"text":1.0,
|
||||||
|
"title1":1.96,
|
||||||
|
"title2":1.80,
|
||||||
|
"title3":1.64,
|
||||||
|
"title4":1.48,
|
||||||
|
"title5":1.32,
|
||||||
|
"title6":1.16
|
||||||
|
}
|
||||||
|
tsize = parseInt(stimes[ctype] * tsize);
|
||||||
|
return tsize + 'px';
|
||||||
|
}
|
||||||
|
text_ref(textWidget){
|
||||||
|
this.textList.push(new WeakRef(textWidget));
|
||||||
|
}
|
||||||
|
text_remove_dead(){
|
||||||
|
var tList = this.textList;
|
||||||
|
for (var i=0;i<tList.length;i++){
|
||||||
|
if (! tList[i].deref()){
|
||||||
|
this.textList.remove(tList[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async setup_i18n(){
|
||||||
|
let params = {'lang':this.lang};
|
||||||
|
d = await jcall(desc.url, {
|
||||||
|
"method":desc.method||'GET', params:params});
|
||||||
|
this.i18n.setup_dict(d);
|
||||||
|
}
|
||||||
|
async build(){
|
||||||
|
console.log('build() begin', this.opts.widget, 'body=', Body);
|
||||||
|
var opts = structuredClone(this.opts.widget);
|
||||||
|
var w = await widgetBuild(opts, Body);
|
||||||
|
console.log('build() end', this.opts.widget, w, 'body=', Body);
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
async run(){
|
||||||
|
await this.change_language(this);
|
||||||
|
var w = await this.build();
|
||||||
|
this.root = w;
|
||||||
|
console.log('w=', w, 'Body=', Body, Wterm, 'Factory=', Factory)
|
||||||
|
Body.add_widget(w);
|
||||||
|
}
|
||||||
|
textsize_bigger(){
|
||||||
|
this.charsize = this.charsize * 1.05;
|
||||||
|
this.text_resize();
|
||||||
|
}
|
||||||
|
textsize_smaller(){
|
||||||
|
this.charsize = this.charsize * 0.95;
|
||||||
|
this.text_resize();
|
||||||
|
}
|
||||||
|
text_resize = function(){
|
||||||
|
for (var i=0;i<this.textList.length;i++){
|
||||||
|
if(this.textList[i].deref()){
|
||||||
|
var w = this.textList[i].deref();
|
||||||
|
var ts = this.get_textsize(w.ctype);
|
||||||
|
w.change_fontsize(ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
change_language = async function(lang){
|
||||||
|
this.lang = lang;
|
||||||
|
await this.i18n.change_lang(lang);
|
||||||
|
for (var i=0;i<this.textList.length;i++){
|
||||||
|
if(this.textList[i].deref()){
|
||||||
|
var w = this.textList[i].deref();
|
||||||
|
if (w.opts.i18n) {
|
||||||
|
w.set_i18n_text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
bricks/build.cmd
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
set SOURCES=utils.js i18n.js factory.js widget.js bricks.js image.js jsoncall.js myoperator.js layout.js menu.js modal.js markdown_viewer.js video.js audio.js toolbar.js tab.js input.js registerfunction.js button.js accordion.js tree.js multiple_state_image.js form.js message.js paging.js scroll.js datagrid.js miniform.js terminal.js
|
||||||
|
del ..\dist\bricks.js
|
||||||
|
echo %SOURCES%
|
||||||
|
type %SOURCES% > ..\dist\bricks.js
|
||||||
|
copy css\*.* ..\dist\css
|
||||||
|
copy imgs/*.* ..\dist\imgs
|
||||||
|
copy ..\examples\*.* ..\dist\examples
|
||||||
|
copy ..\docs\*.* ..\dist\docs
|
||||||
|
rem uglifyjs --compress --mangle %SOURCES% > ..\dist\bricks.min.js
|
32
bricks/build.sh
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
SOURCES="uitypesdef.js utils.js i18n.js factory.js widget.js \
|
||||||
|
bricks.js image.js \
|
||||||
|
jsoncall.js myoperator.js layout.js menu.js modal.js \
|
||||||
|
markdown_viewer.js video.js audio.js toolbar.js tab.js \
|
||||||
|
input.js registerfunction.js button.js accordion.js \
|
||||||
|
tree.js multiple_state_image.js form.js message.js \
|
||||||
|
paging.js scroll.js datagrid.js dataviewer.js \
|
||||||
|
miniform.js wterm.js "
|
||||||
|
echo ${SOURCES}
|
||||||
|
cat ${SOURCES} > ../dist/bricks.js
|
||||||
|
uglifyjs --compress --mangle -- ../dist/bricks.js > ../dist/bricks.min.js
|
||||||
|
if [ ! -d ../dist/css ];then
|
||||||
|
rm -rf ../dist/css
|
||||||
|
mkdir ../dist/css
|
||||||
|
fi
|
||||||
|
if [ ! -d ../dist/examples ];then
|
||||||
|
rm -rf ../dist/examples
|
||||||
|
mkdir ../dist/examples
|
||||||
|
fi
|
||||||
|
if [ ! -d ../dist/docs ];then
|
||||||
|
rm -rf ../dist/docs
|
||||||
|
mkdir ../dist/docs
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp -a css/* ../dist/css
|
||||||
|
cp -a imgs/* ../dist/imgs
|
||||||
|
cp -a ../examples ../dist
|
||||||
|
cp -a ../docs ../dist
|
||||||
|
cp -a ../dist/* ~/www/wwwroot/bricks
|
||||||
|
# cd ../dist
|
||||||
|
# cp -a * ~/www/wwwroot/bricks
|
||||||
|
|
92
bricks/button.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
class Button extends Layout {
|
||||||
|
/*
|
||||||
|
orientation:
|
||||||
|
height:100%,
|
||||||
|
width:100%,
|
||||||
|
item_rate:
|
||||||
|
tooltip:
|
||||||
|
color:
|
||||||
|
nonepack:
|
||||||
|
name:
|
||||||
|
icon:
|
||||||
|
label:
|
||||||
|
css:
|
||||||
|
action:{
|
||||||
|
target:
|
||||||
|
datawidget:
|
||||||
|
datamethod:
|
||||||
|
datascript:
|
||||||
|
dataparams:
|
||||||
|
rtdata:
|
||||||
|
actiontype:
|
||||||
|
...
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
var style = {
|
||||||
|
display:"flex",
|
||||||
|
justifyContent:"center",
|
||||||
|
textAlign:"center",
|
||||||
|
alignItem:"center",
|
||||||
|
width:"auto",
|
||||||
|
height:"auto",
|
||||||
|
};
|
||||||
|
if (opts.nonepack){
|
||||||
|
style.padding = '0px';
|
||||||
|
style.border = '0';
|
||||||
|
} else {
|
||||||
|
style.padding = '0.5rem';
|
||||||
|
}
|
||||||
|
if (this.opts.orientation == 'horizontal'){
|
||||||
|
style.flexDirection = 'rows';
|
||||||
|
this.orient = 'h';
|
||||||
|
} else {
|
||||||
|
style.flexDirection = 'column';
|
||||||
|
this.orient = 'v';
|
||||||
|
}
|
||||||
|
this.item_rate = opts.item_rate || 1;
|
||||||
|
this.set_id(this.opts.name);
|
||||||
|
this.opts_setup();
|
||||||
|
extend(this.dom_element.style, style);
|
||||||
|
}
|
||||||
|
create(){
|
||||||
|
this.dom_element = document.createElement('button');
|
||||||
|
}
|
||||||
|
opts_setup(){
|
||||||
|
var item_size = this.opts.item_size || bricks_app.charsize;
|
||||||
|
if (this.opts.icon){
|
||||||
|
var icon = new Icon({
|
||||||
|
rate:this.item_rate,
|
||||||
|
url:this.opts.icon
|
||||||
|
})
|
||||||
|
this.add_widget(icon);
|
||||||
|
icon.bind('click', this.target_clicked.bind(this));
|
||||||
|
}
|
||||||
|
if (this.opts.label){
|
||||||
|
var opts = {
|
||||||
|
rate:this.item_rate,
|
||||||
|
color:this.opts.color,
|
||||||
|
bgcolor:this.opts.bgcolor,
|
||||||
|
otext:this.opts.label,
|
||||||
|
i18n:true};
|
||||||
|
var txt = new Text(opts);
|
||||||
|
this.add_widget(txt);
|
||||||
|
txt.bind('click', this.target_clicked.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
target_clicked(event){
|
||||||
|
console.log('target_clicked() .... called ');
|
||||||
|
event.stopPropagation();
|
||||||
|
this.dispatch('click', this.opts);
|
||||||
|
if (this.opts.action){
|
||||||
|
if (this.opts.debug){
|
||||||
|
console.log('debug:opts=', this.opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Factory.register('Button', Button);
|
7
bricks/css.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
var css = {
|
||||||
|
multicolumns:{
|
||||||
|
columnWidth:'350px',
|
||||||
|
colummGap:'10px'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
254
bricks/css/bricks.css
Executable file
@ -0,0 +1,254 @@
|
|||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.griddata {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
padding: 10px;
|
||||||
|
color: #e8e8e8;
|
||||||
|
background-color: rgba(0.3, 0.3, 0.3, 1);
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal>.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;
|
||||||
|
}
|
384
bricks/datagrid.js
Normal file
@ -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);
|
70
bricks/dataviewer.js
Normal file
@ -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<rows.length;i++){
|
||||||
|
await this.add_row(rows[i], direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_row = async function(row, direction){
|
||||||
|
var s = obj_fmtstr(row, this.viewer_tmpl);
|
||||||
|
var desc = JSON.parse(s);
|
||||||
|
var w = await widgetBuild(desc, this);
|
||||||
|
if (! w){
|
||||||
|
console.log(desc, 'widgetBuild() failed...........');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w.row_data = row;
|
||||||
|
var index = null;
|
||||||
|
if (direction == 'down') index = 0;
|
||||||
|
console.log('w=', w, 'this=', this);
|
||||||
|
this.add_widget(w, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Factory.register('DataViewer', DataViewer);
|
17
bricks/factory.js
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
class Factory_ {
|
||||||
|
constructor(){
|
||||||
|
this.widgets_kv = new Object();
|
||||||
|
this.widgets_kv['_t_'] = 1;
|
||||||
|
}
|
||||||
|
register(name, widget){
|
||||||
|
this.widgets_kv[name] = widget;
|
||||||
|
}
|
||||||
|
get(name){
|
||||||
|
if (this.widgets_kv.hasOwnProperty(name)){
|
||||||
|
return this.widgets_kv[name];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const Factory = new Factory_();
|
||||||
|
|
213
bricks/form.js
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
|
||||||
|
class FormBody extends VBox {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
title:
|
||||||
|
description:
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
"name":,
|
||||||
|
"label":,
|
||||||
|
"removable":
|
||||||
|
"icon":
|
||||||
|
"content":
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
opts.width = '100%';
|
||||||
|
opts.scrollY = 'scroll';
|
||||||
|
super(opts);
|
||||||
|
this.name_inputs = {};
|
||||||
|
if (this.opts.title){
|
||||||
|
var t = new Title2({
|
||||||
|
otext:this.opts.title,
|
||||||
|
height:'auto',
|
||||||
|
i18n:true});
|
||||||
|
this.add_widget(t);
|
||||||
|
}
|
||||||
|
if (this.opts.description){
|
||||||
|
var d = new Text({
|
||||||
|
otext:this.opts.description,
|
||||||
|
height:'auto',
|
||||||
|
i18n:true});
|
||||||
|
this.add_widget(d);
|
||||||
|
}
|
||||||
|
this.form_body = new Layout({width:'100%',
|
||||||
|
overflow:'auto'
|
||||||
|
});
|
||||||
|
this.add_widget(this.form_body);
|
||||||
|
this.form_body.set_css('multicolumns');
|
||||||
|
this.build_fields();
|
||||||
|
}
|
||||||
|
reset_data(){
|
||||||
|
for (var name in this.name_inputs){
|
||||||
|
if (! this.name_inputs.hasOwnProperty(name)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var w = this.name_inputs[name];
|
||||||
|
w.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getValue(){
|
||||||
|
var data = {};
|
||||||
|
for (var name in this.name_inputs){
|
||||||
|
if (! this.name_inputs.hasOwnProperty(name)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var w = this.name_inputs[name];
|
||||||
|
var d = w.getValue();
|
||||||
|
if (w.required && ( d[name] == '' || d[name] === null)){
|
||||||
|
console.log('data=', data, 'd=', d);
|
||||||
|
w.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extend(data, d);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
async validation(){
|
||||||
|
var data = this.getValue();
|
||||||
|
if (this.submit_url){
|
||||||
|
var rzt = await jcall(this.submit_url,
|
||||||
|
{
|
||||||
|
params:data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.dispatch('submit', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
build_fields(){
|
||||||
|
var fields = this.opts.fields;
|
||||||
|
for (var i=0; i<fields.length; i++){
|
||||||
|
var box = new VBox({height:'auto',overflow:'none'});
|
||||||
|
box.set_css('inputbox');
|
||||||
|
this.form_body.add_widget(box);
|
||||||
|
var txt = new Text({
|
||||||
|
otext:fields[i].label||fields[i].name,
|
||||||
|
height:'auto',
|
||||||
|
i18n:true});
|
||||||
|
box.add_widget(txt);
|
||||||
|
var w = Input.factory(fields[i]);
|
||||||
|
if (w){
|
||||||
|
box.add_widget(w);
|
||||||
|
this.name_inputs[fields[i].name] = w;
|
||||||
|
console.log(fields[i].uitype, 'create Input ok');
|
||||||
|
} else {
|
||||||
|
console.log(fields[i], 'createInput failed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Form extends VBox {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
title:
|
||||||
|
description:
|
||||||
|
notoolbar:False,
|
||||||
|
cols:
|
||||||
|
dataurl:
|
||||||
|
toolbar:
|
||||||
|
submit_url:
|
||||||
|
fields
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.body = new FormBody(opts);
|
||||||
|
this.add_widget(this.body);
|
||||||
|
if (! opts.notoolbar)
|
||||||
|
this.build_toolbar(this);
|
||||||
|
}
|
||||||
|
build_toolbar(widget){
|
||||||
|
var box = new HBox({height:'auto', width:'100%'});
|
||||||
|
widget.add_widget(box);
|
||||||
|
var tb_desc = this.opts.toolbar || {
|
||||||
|
width:"auto",
|
||||||
|
tools:[
|
||||||
|
{
|
||||||
|
icon:bricks_resource('imgs/submit.png'),
|
||||||
|
name:'submit',
|
||||||
|
label:'Submit'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon:bricks_resource('imgs/cancel.png'),
|
||||||
|
name:'cancel',
|
||||||
|
label:'Cancel'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
var tbw = new Toolbar(tb_desc);
|
||||||
|
tbw.bind('command', this.command_handle.bind(this));
|
||||||
|
box.add_widget(new HFiller());
|
||||||
|
box.add_widget(tbw);
|
||||||
|
box.add_widget(new HFiller());
|
||||||
|
}
|
||||||
|
command_handle(event){
|
||||||
|
var params = event.params;
|
||||||
|
console.log('Form(): click_handle() params=', params);
|
||||||
|
if (!params){
|
||||||
|
error('click_handle() get a null params');
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (params.name == 'submit'){
|
||||||
|
this.body.validation();
|
||||||
|
} else if (params.name == 'cancel'){
|
||||||
|
this.cancel();
|
||||||
|
} else if (params.name == 'reset'){
|
||||||
|
this.body.reset_data();
|
||||||
|
} else {
|
||||||
|
if (params.action){
|
||||||
|
f = buildEventHandler(this, params);
|
||||||
|
if (f) f(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getValue(){
|
||||||
|
return this.body.getValue();
|
||||||
|
}
|
||||||
|
cancel(){
|
||||||
|
this.dispatch('cancel');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class TabForm extends Form {
|
||||||
|
/*
|
||||||
|
options
|
||||||
|
{
|
||||||
|
css:
|
||||||
|
tab_long: 100%
|
||||||
|
tab_pos:"top"
|
||||||
|
items:[
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
label:"tab1",
|
||||||
|
icon:
|
||||||
|
removable:
|
||||||
|
refresh:false,
|
||||||
|
content:{
|
||||||
|
"widgettype":...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
...
|
||||||
|
fields:[
|
||||||
|
{
|
||||||
|
}
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
}
|
||||||
|
build_fields(fields){
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Factory.register('Form', Form);
|
||||||
|
// Factory.register('TabForm', TabForm);
|
50
bricks/i18n.js
Executable file
@ -0,0 +1,50 @@
|
|||||||
|
class I18n {
|
||||||
|
constructor(url, default_lang){
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
url:
|
||||||
|
method:
|
||||||
|
default_lang
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
this.url = opts.url;
|
||||||
|
this.default_lang = opts.default_lang||'en';
|
||||||
|
this.method = opts.method || 'GET';
|
||||||
|
this.lang_msgs = {};
|
||||||
|
this.msgs = {};
|
||||||
|
}
|
||||||
|
_(txt, obj){
|
||||||
|
if (this.msgs.hasOwnProperty(txt)){
|
||||||
|
itxt = this.msgs[txt];
|
||||||
|
}
|
||||||
|
if (obj instanceof Object){
|
||||||
|
return obj_fmtstr(obj, itxt);
|
||||||
|
}
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
|
is_loaded(lang){
|
||||||
|
if (objget(this.lang_msgs, lang)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setup_dict(dic, lang){
|
||||||
|
this.cur_lang = lang;
|
||||||
|
extend(this.lang_msgs, {lang:dic});
|
||||||
|
this.msgs = dic;
|
||||||
|
}
|
||||||
|
async change_lang(lang){
|
||||||
|
if (objget(this.lang_msgs, lang)){
|
||||||
|
this.msgs = objget(this.lang_msgs, lang);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! this.url) return;
|
||||||
|
|
||||||
|
let params = {'lang':lang};
|
||||||
|
d = await jcall(desc.url, {
|
||||||
|
"method":this.method || 'GET',
|
||||||
|
params:params
|
||||||
|
});
|
||||||
|
this.setup_dict(d, lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
94
bricks/image.js
Executable file
@ -0,0 +1,94 @@
|
|||||||
|
class Image extends JsWidget {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
url:
|
||||||
|
height:
|
||||||
|
width:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.opts = opts;
|
||||||
|
this.options_parse();
|
||||||
|
}
|
||||||
|
create(){
|
||||||
|
this.dom_element = document.createElement('img');
|
||||||
|
}
|
||||||
|
options_parse(){
|
||||||
|
if (this.opts.hasOwnProperty('url')){
|
||||||
|
this.set_url(this.opts.url);
|
||||||
|
}
|
||||||
|
if (this.opts.hasOwnProperty('width')){
|
||||||
|
this.width = this.opts.width;
|
||||||
|
this.dom_element.style.width = this.width;
|
||||||
|
}
|
||||||
|
if (this.opts.hasOwnProperty('height')){
|
||||||
|
this.height = this.opts.height;
|
||||||
|
this.dom_element.style.height = this.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_url(url){
|
||||||
|
this.url = url;
|
||||||
|
this.dom_element.src = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Icon extends Image {
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.opts.width = bricks_app.charsize;
|
||||||
|
this.opts.height = bricks_app.charsize;
|
||||||
|
this.ctype = 'text';
|
||||||
|
this.sizable();
|
||||||
|
this.set_fontsize();
|
||||||
|
}
|
||||||
|
change_fontsize(ts){
|
||||||
|
var siz = bricks_app.charsize;
|
||||||
|
this.set_width(siz);
|
||||||
|
this.set_height(siz);
|
||||||
|
}
|
||||||
|
set_fontsize(){
|
||||||
|
var siz = bricks_app.charsize;
|
||||||
|
this.set_width(siz);
|
||||||
|
this.set_height(siz);
|
||||||
|
}
|
||||||
|
set_width(siz){
|
||||||
|
this.dom_element.width = siz;
|
||||||
|
}
|
||||||
|
set_height(siz){
|
||||||
|
this.dom_element.height = siz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BlankIcon extends JsWidget {
|
||||||
|
constructor(opts){
|
||||||
|
opts.width = bricks_app.charsize;
|
||||||
|
opts.height = bricks_app.charsize;
|
||||||
|
super(opts);
|
||||||
|
this.ctype = 'text';
|
||||||
|
this.sizable();
|
||||||
|
this.set_fontsize();
|
||||||
|
}
|
||||||
|
change_fontsize(ts){
|
||||||
|
var siz = bricks_app.charsize + 'px';
|
||||||
|
this.set_width(siz);
|
||||||
|
this.set_height(siz);
|
||||||
|
}
|
||||||
|
set_fontsize(){
|
||||||
|
var siz = bricks_app.charsize + 'px';
|
||||||
|
this.set_width(siz);
|
||||||
|
this.set_height(siz);
|
||||||
|
}
|
||||||
|
set_width(siz){
|
||||||
|
this.dom_element.width = siz;
|
||||||
|
this.dom_element.style.width = siz;
|
||||||
|
}
|
||||||
|
set_height(siz){
|
||||||
|
this.dom_element.height = siz;
|
||||||
|
this.dom_element.style.height = siz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Factory.register('Image', Image);
|
||||||
|
Factory.register('Icon', Icon);
|
||||||
|
Factory.register('BlankIcon', BlankIcon);
|
BIN
bricks/imgs/.DS_Store
vendored
Normal file
BIN
bricks/imgs/add.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
bricks/imgs/checkbox-checked.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
bricks/imgs/checkbox-unchecked.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
bricks/imgs/delete.png
Executable file
After Width: | Height: | Size: 14 KiB |
BIN
bricks/imgs/delete_node.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
bricks/imgs/down_arrow.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
bricks/imgs/down_dir.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
bricks/imgs/edit.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
bricks/imgs/folder.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
bricks/imgs/move_bottom.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
bricks/imgs/move_down.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
bricks/imgs/move_top.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
bricks/imgs/move_up.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
bricks/imgs/reset.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
bricks/imgs/right_arrow.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
bricks/imgs/submit.png
Normal file
After Width: | Height: | Size: 12 KiB |
707
bricks/input.js
Executable file
@ -0,0 +1,707 @@
|
|||||||
|
class UiType extends Layout {
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.name = this.opts.name;
|
||||||
|
this.required = opts.required || false;
|
||||||
|
this.ctype = 'text';
|
||||||
|
this.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(){
|
||||||
|
var o = {}
|
||||||
|
o[this.name] = this.resultValue();
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
focus(){
|
||||||
|
this.dom_element.focus();
|
||||||
|
}
|
||||||
|
reset(){
|
||||||
|
var v = this.opts.value||this.opts.defaultvalue|| '';
|
||||||
|
this.setValue(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(v){
|
||||||
|
if (! v)
|
||||||
|
v = '';
|
||||||
|
this.vlaue = v;
|
||||||
|
this.dom_element.value = v;
|
||||||
|
}
|
||||||
|
set_disabled(f){
|
||||||
|
this.dom_element.disabled = f;
|
||||||
|
}
|
||||||
|
set_readonly(f){
|
||||||
|
this.dom_element.readOnly = f;
|
||||||
|
}
|
||||||
|
set_required(f){
|
||||||
|
this.dom_element.required = f;
|
||||||
|
this.required = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UiStr extends UiType {
|
||||||
|
static uitype='str';
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
value:
|
||||||
|
defaultValue:
|
||||||
|
align:"left", "center", "right"
|
||||||
|
length:
|
||||||
|
minlength:
|
||||||
|
tip:
|
||||||
|
width:
|
||||||
|
readonly:
|
||||||
|
required:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.sizable();
|
||||||
|
this.set_fontsize();
|
||||||
|
if (opts.readonly) {
|
||||||
|
this.set_readonly("Y");
|
||||||
|
} else {
|
||||||
|
this.set_readonly(false);
|
||||||
|
}
|
||||||
|
if (opts.width){
|
||||||
|
this.dom_element.style.width = opts.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
create(){
|
||||||
|
var el = this._create('input');
|
||||||
|
this.dom_element = el;
|
||||||
|
this.pattern = '.*';
|
||||||
|
el.type = 'text';
|
||||||
|
el.id = el.name = this.opts.name;
|
||||||
|
if (this.opts.required)
|
||||||
|
el.required = true;
|
||||||
|
if (this.opts.css){
|
||||||
|
el.classList.add(this.opts.css);
|
||||||
|
this.actived_css = this.opts.css + '-actived';
|
||||||
|
} else {
|
||||||
|
el.classList.add('input');
|
||||||
|
this.actived_css = 'input_actived';
|
||||||
|
}
|
||||||
|
el.style.textAlign = this.opts.align || 'left';
|
||||||
|
if (this.opts.hasOwnProperty('length'))
|
||||||
|
el.maxlength = this.opts.length;
|
||||||
|
if (this.opts.hasOwnProperty('minlength'))
|
||||||
|
el.minlength = this.opts.minlength;
|
||||||
|
if (this.opts.hasOwnProperty('value'))
|
||||||
|
this.value = this.opts.value;
|
||||||
|
if (this.opts.defaultVlaue)
|
||||||
|
el.defaultValue = this.opts.defaultValue;
|
||||||
|
this.reset()
|
||||||
|
if (this.opts.tip)
|
||||||
|
el.placeholder = bricks_app.i18n._(this.opts.tip);
|
||||||
|
el.addEventListener('focus', this.onfocus.bind(this));
|
||||||
|
el.addEventListener('blur', this.onblur.bind(this));
|
||||||
|
el.addEventListener('input', this.set_value_from_input.bind(this))
|
||||||
|
}
|
||||||
|
onblur(event){
|
||||||
|
this.dom_element.classList.remove(this.actived_css);
|
||||||
|
}
|
||||||
|
onfocus(event){
|
||||||
|
this.dom_element.classList.add(this.actived_css);
|
||||||
|
}
|
||||||
|
check_pattern(value){
|
||||||
|
var r = new RegExp(this.pattern);
|
||||||
|
var v = value.match(r);
|
||||||
|
if (! v || v[0] == ''){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return v[0];
|
||||||
|
}
|
||||||
|
set_value_from_input(event){
|
||||||
|
var e = event.target;
|
||||||
|
if (e.value == ''){
|
||||||
|
this.value = '';
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (e.type == 'file'){
|
||||||
|
this.value = e.value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var v = this.check_pattern(e.value);
|
||||||
|
if (v == null){
|
||||||
|
e.value = this.value;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.value = v;
|
||||||
|
var o = this.getValue();
|
||||||
|
this.dispatch('changed', o);
|
||||||
|
}
|
||||||
|
resultValue(){
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
setValue(v){
|
||||||
|
if (! v)
|
||||||
|
v = '';
|
||||||
|
this.value = v;
|
||||||
|
this.dom_element.value = '' + this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UiPassword extends UiStr {
|
||||||
|
static uitype='password';
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
value:
|
||||||
|
defaultValue:
|
||||||
|
align:"left", "center", "right"
|
||||||
|
length:
|
||||||
|
minlength:
|
||||||
|
tip:
|
||||||
|
readonly:
|
||||||
|
required:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.dom_element.type = 'password';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class UiInt extends UiStr {
|
||||||
|
static uitype='int';
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
length:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.dom_element.style.textAlign = 'right';
|
||||||
|
this.dom_element.type = 'number';
|
||||||
|
this.pattern = '\\d*';
|
||||||
|
}
|
||||||
|
resultValue(){
|
||||||
|
return parseInt(this.value);
|
||||||
|
}
|
||||||
|
setValue(v){
|
||||||
|
if (! v)
|
||||||
|
v = '';
|
||||||
|
this.value = '' + v;
|
||||||
|
this.dom_element.value = '' + v;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
class UiFloat extends UiInt {
|
||||||
|
static uitype='float';
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
dec_len:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.pattern = '\\d*\\.?\\d+';
|
||||||
|
var dec_len = this.opts.dec_len || 2;
|
||||||
|
var step = 1;
|
||||||
|
for (var i=0; i<dec_len; i++)
|
||||||
|
step = step / 10;
|
||||||
|
this.dom_element.step = step;
|
||||||
|
}
|
||||||
|
resultValue(){
|
||||||
|
return parseFloat(this.value);
|
||||||
|
}
|
||||||
|
setValue(v){
|
||||||
|
if (! v)
|
||||||
|
v = '';
|
||||||
|
this.value = '' + v;
|
||||||
|
this.dom_element.value = '' + v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class UiTel extends UiStr {
|
||||||
|
static uitype='tel';
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
|
||||||
|
pattern:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.dom_element.type = 'tel';
|
||||||
|
if (this.opts.pattern)
|
||||||
|
this.dom_element.pattern = this.opts.pattern;
|
||||||
|
this.pattern = '[+]?\\d+';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UiEmail extends UiStr {
|
||||||
|
static uitype='email';
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.dom_element.type = 'email';
|
||||||
|
if (this.opts.pattern)
|
||||||
|
this.dom_element.pattern = this.opts.pattern;
|
||||||
|
if (this.opts.pattern)
|
||||||
|
this.dom_element.pattern = this.opts.pattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UiFile extends UiStr {
|
||||||
|
static uitype='file';
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
accept:
|
||||||
|
capture:"user" or "environment"
|
||||||
|
multiple:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.dom_element.type = 'file';
|
||||||
|
if (this.opts.accept)
|
||||||
|
this.dom_element.accept = this.opts.accept;
|
||||||
|
if (this.opts.capture)
|
||||||
|
this.dom_element.capture = this.opts.capture;
|
||||||
|
if (this.opts.multiple)
|
||||||
|
this.dom_element.multiple = true;
|
||||||
|
}
|
||||||
|
setValue(v){
|
||||||
|
return;
|
||||||
|
this.value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class UiCheck extends UiType {
|
||||||
|
static uitype = 'check';
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
extend(UiCheck.prototype, Layout.prototype);
|
||||||
|
this.add_widget = Layout.prototype.add_widget.bind(this);
|
||||||
|
this.dom_element.style.width = 'auto';
|
||||||
|
this.dom_element.style.height = 'auto';
|
||||||
|
var state = 'unchecked';
|
||||||
|
if (opts.value){
|
||||||
|
state = 'checked';
|
||||||
|
}
|
||||||
|
this.ms_icon = new MultipleStateIcon({
|
||||||
|
state:state,
|
||||||
|
urls:{
|
||||||
|
checked:bricks_resource('imgs/checkbox-checked.png'),
|
||||||
|
unchecked:bricks_resource('imgs/checkbox-unchecked.png')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.add_widget(this.ms_icon)
|
||||||
|
this.ms_icon.bind('state_changed', this.set_value_from_input.bind(this));
|
||||||
|
|
||||||
|
}
|
||||||
|
set_value_from_input(e){
|
||||||
|
var v;
|
||||||
|
if (this.ms_icon.state=='checked')
|
||||||
|
v = true;
|
||||||
|
else
|
||||||
|
v = false;
|
||||||
|
this.value = v;
|
||||||
|
var o = {};
|
||||||
|
o[this.name] = this.value;
|
||||||
|
this.dispatch('changed', o);
|
||||||
|
}
|
||||||
|
setValue(v){
|
||||||
|
this.value = v;
|
||||||
|
if (v)
|
||||||
|
this.ms_icon.set_state('checked');
|
||||||
|
else
|
||||||
|
this.ms_icon.set_state('unchecked');
|
||||||
|
}
|
||||||
|
resultValue(){
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UiCheckBox extends UiType {
|
||||||
|
static uitype='checkbox';
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
label:
|
||||||
|
value:
|
||||||
|
textField:'gg',
|
||||||
|
valueField:'hh',
|
||||||
|
otherField:'b',
|
||||||
|
data:[
|
||||||
|
{
|
||||||
|
'gg':
|
||||||
|
'hh':
|
||||||
|
'b':
|
||||||
|
}
|
||||||
|
]
|
||||||
|
or:
|
||||||
|
dataurl:
|
||||||
|
params:{},
|
||||||
|
method:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.valueField = opts.valueField || 'value';
|
||||||
|
this.textField = opts.textField || 'text';
|
||||||
|
this.value = this.opts.value || this.opts.defaultValue||[];
|
||||||
|
if (! Array.isArray(this.value)){
|
||||||
|
this.value = [ this.value ];
|
||||||
|
}
|
||||||
|
this.set_fontsize();
|
||||||
|
this.el_legend = this._create('legend');
|
||||||
|
var label = this.opts.label||this.opts.name;
|
||||||
|
this.el_legend.innerText = bricks_app.i18n._(label);
|
||||||
|
if (this.opts.dataurl){
|
||||||
|
schedule_once(this.load_data_onfly.bind(this), 0.01);
|
||||||
|
} else {
|
||||||
|
this.data = opts.data;
|
||||||
|
this.build_checkboxs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
create(){
|
||||||
|
this.dom_element = this._create('fieldset');
|
||||||
|
}
|
||||||
|
build_checkboxs(){
|
||||||
|
var data = this.data;
|
||||||
|
this.input_boxs = [];
|
||||||
|
for (var i=0; i<data.length;i++){
|
||||||
|
var hbox = new HBox({height:"auto",width:"100%"});
|
||||||
|
var opts = {}
|
||||||
|
var value = data[i][this.valueField];
|
||||||
|
if (this.value == value){
|
||||||
|
opts.value = true;
|
||||||
|
}
|
||||||
|
var check = new UiCheck(opts);
|
||||||
|
var otext = data[i][this.textField];
|
||||||
|
var txt = new Text({
|
||||||
|
otext:otext,
|
||||||
|
align:'left',
|
||||||
|
i18n:true});
|
||||||
|
txt.ht_left();
|
||||||
|
check.bind('changed', this.set_value_from_input.bind(this));
|
||||||
|
hbox.add_widget(check);
|
||||||
|
hbox.add_widget(txt);
|
||||||
|
this.add_widget(hbox);
|
||||||
|
this.input_boxs.push(check);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async load_data_onfly(){
|
||||||
|
var data = await jcall(this.opts.dataurl, {
|
||||||
|
"method":this.opts.method||'GET',
|
||||||
|
"params":this.opts.params});
|
||||||
|
this.data = data;
|
||||||
|
this.build_checkboxs();
|
||||||
|
}
|
||||||
|
set_value_from_input(event){
|
||||||
|
event.stopPropagation();
|
||||||
|
var e = event.target;
|
||||||
|
if (e.state=='checked'){
|
||||||
|
this.value.push(e.value);
|
||||||
|
} else {
|
||||||
|
this.value.remove(e.value)
|
||||||
|
}
|
||||||
|
var o = {};
|
||||||
|
o[this.name] = this.value;
|
||||||
|
this.dispatch('changed', o);
|
||||||
|
}
|
||||||
|
resultValue(){
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
setValue(v){
|
||||||
|
if (Array.isArray(v)){
|
||||||
|
this.value = v;
|
||||||
|
} else {
|
||||||
|
this.value = [v];
|
||||||
|
}
|
||||||
|
for (var i=0; i<this.input_boxs.length; i++){
|
||||||
|
if (this.value.includes(this.data[i][this.valueField])){
|
||||||
|
this.input_boxs[i].setValue(true);
|
||||||
|
} else {
|
||||||
|
this.input_boxs[i].setValue(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UiDate extends UiStr {
|
||||||
|
static uitype='date';
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
max_date:
|
||||||
|
min_date:
|
||||||
|
|
||||||
|
*/
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.opts_setup();
|
||||||
|
}
|
||||||
|
opts_setup(){
|
||||||
|
var e = this.dom_element;
|
||||||
|
e.type = 'date';
|
||||||
|
if (this.opts.max_date){
|
||||||
|
e.max = this.opts.max_date;
|
||||||
|
}
|
||||||
|
if (this.opts.min_date){
|
||||||
|
e.min = this.opts.min_date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UiText extends UiType {
|
||||||
|
static uitype='text';
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
value:
|
||||||
|
defaultValue:
|
||||||
|
tip:
|
||||||
|
rows:
|
||||||
|
cols:
|
||||||
|
readonly:
|
||||||
|
required:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.build();
|
||||||
|
this.sizable();
|
||||||
|
this.set_fontsize();
|
||||||
|
}
|
||||||
|
create(){
|
||||||
|
this.dom_element = this._create('textarea');
|
||||||
|
}
|
||||||
|
build(){
|
||||||
|
var e = this.dom_element;
|
||||||
|
e.id = e.name = this.opts.name;
|
||||||
|
e.rows = this.opts.rows || 5;
|
||||||
|
e.cols = this.opts.cols || 40;
|
||||||
|
// this.setValue(this.opts.value || this.opts.defaultvalue || '');
|
||||||
|
this.reset();
|
||||||
|
this.bind('input', this.set_value_from_input.bind(this))
|
||||||
|
}
|
||||||
|
set_value_from_input(event){
|
||||||
|
this.value = this.dom_element.innerText;
|
||||||
|
}
|
||||||
|
resultValue(){
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
setValue(v){
|
||||||
|
if (! v) v = '';
|
||||||
|
this.value = v;
|
||||||
|
this.dom_element.innerText = '';
|
||||||
|
this.dom_element.innerText = v;
|
||||||
|
debug('UiText: v=', v);
|
||||||
|
}
|
||||||
|
reset(){
|
||||||
|
var v = this.opts.value || this.opts.defaultvalue||'';
|
||||||
|
this.setValue(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UiCode extends UiType {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
value:
|
||||||
|
valueField:
|
||||||
|
textField:
|
||||||
|
defaultValue:
|
||||||
|
readonly:
|
||||||
|
required:
|
||||||
|
data:
|
||||||
|
dataurl:
|
||||||
|
params:
|
||||||
|
method:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
static uitype='code';
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.data = this.opts.data;
|
||||||
|
this.build();
|
||||||
|
}
|
||||||
|
create(){
|
||||||
|
this.dom_element = this._create('select');
|
||||||
|
}
|
||||||
|
build(){
|
||||||
|
this.dom_element.id = this.opts.name;
|
||||||
|
this.dom_element.name = this.opts.name;
|
||||||
|
if (this.opts.dataurl){
|
||||||
|
schedule_once(this.get_data.bind(this), 0.01);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.build_options(this.opts.data);
|
||||||
|
}
|
||||||
|
async get_data(event){
|
||||||
|
var params = this.opts.params;
|
||||||
|
if(event){
|
||||||
|
extend(params, event.params);
|
||||||
|
}
|
||||||
|
var d = await jcall(this.opts.dataurl,
|
||||||
|
{
|
||||||
|
method:this.opts.method || 'GET',
|
||||||
|
params : params
|
||||||
|
});
|
||||||
|
this.data = d;
|
||||||
|
this.build_options(d);
|
||||||
|
}
|
||||||
|
build_options(data){
|
||||||
|
var e = this.dom_element;
|
||||||
|
e.replaceChildren();
|
||||||
|
var v = this.opts.value || this.opts.defaultvalue;
|
||||||
|
this.value = v;
|
||||||
|
this.option_widgets = {};
|
||||||
|
for (var i=0; i<data.length; i++){
|
||||||
|
var o = document.createElement('option');
|
||||||
|
o.value = data[i][this.opts.valueField||'value'];
|
||||||
|
o.innerText = bricks_app.i18n._(data[i][this.opts.textField||'text']);
|
||||||
|
this.option_widgets[o.value] = o;
|
||||||
|
if (o.value == v){
|
||||||
|
o.selected = true;
|
||||||
|
}
|
||||||
|
e.appendChild(o);
|
||||||
|
this.sizable_elements.push(o);
|
||||||
|
}
|
||||||
|
this.bind('input', this.set_value_from_input.bind(this))
|
||||||
|
this.sizable();
|
||||||
|
this.set_fontsize();
|
||||||
|
}
|
||||||
|
set_value_from_input(event){
|
||||||
|
this.value = this.dom_element.value;
|
||||||
|
this.dispatch('changed', this.getValue());
|
||||||
|
}
|
||||||
|
resultValue(){
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
setValue(v){
|
||||||
|
this.value = v;
|
||||||
|
for (var i=0; i<this.option_widgets.length; i++){
|
||||||
|
if (this.value == this.option_widgets[i].value){
|
||||||
|
this.option_widgets[i].checked = true
|
||||||
|
} else {
|
||||||
|
this.option_widgets[i].checked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reset(){
|
||||||
|
var v = this.opts.value||this.opts.defaultvalue||'';
|
||||||
|
this.setValue(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Input {
|
||||||
|
constructor(){
|
||||||
|
this.uitypes = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
register(name, Klass){
|
||||||
|
if (! Klass){
|
||||||
|
console.log('Klass not defined', name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (! Klass.uitype){
|
||||||
|
console.log('uitype of Klass not defined', name);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
Factory.register(name, Klass);
|
||||||
|
this.uitypes[Klass.uitype] = Klass;
|
||||||
|
}
|
||||||
|
factory(options){
|
||||||
|
var klass = objget(this.uitypes, options.uitype);
|
||||||
|
if (klass){
|
||||||
|
return new klass(options);
|
||||||
|
}
|
||||||
|
console.log('create input for:', options.uitype, 'failed');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UiAudio extends UiStr {
|
||||||
|
static uitype = 'audio';
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.autoplay = opts.autoplay;
|
||||||
|
this.readonly = opts.readonly;
|
||||||
|
this.icon = new Icon({
|
||||||
|
url: bricks_resource('imgs/right_arrow.png')});
|
||||||
|
this.add_widget(this.icon);
|
||||||
|
this.icon.bind('click', this.play_audio.bind(this));
|
||||||
|
this.player = new Audio({
|
||||||
|
url:this.value
|
||||||
|
});
|
||||||
|
if (this.autoplay){
|
||||||
|
schedule_once(this.autoplay_audio.bind(this), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
autoplay_audio(){
|
||||||
|
this.icon.dispatch('click');
|
||||||
|
}
|
||||||
|
play_audio(){
|
||||||
|
this.player.toggle_play();
|
||||||
|
}
|
||||||
|
play_audio(){
|
||||||
|
if(this.value!=this.player.src){
|
||||||
|
this.player.stop();
|
||||||
|
this.player.set_source(this.value);
|
||||||
|
this.player.play();
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.player.toggle_play();
|
||||||
|
this.btn.dispatch('click');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class UiVideo extends UiStr {
|
||||||
|
static uitype = 'video';
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.autoplay = opts.autoplay;
|
||||||
|
this.readonly = opts.readonly;
|
||||||
|
this.icon = new Icon({
|
||||||
|
url: bricks_resource('imgs/right_arrow.png')});
|
||||||
|
this.add_widget(this.icon);
|
||||||
|
this.icon.bind('click', this.play_audio.bind(this));
|
||||||
|
this.player = new VideoPlayer({
|
||||||
|
url:this.value
|
||||||
|
});
|
||||||
|
if (this.autoplay){
|
||||||
|
schedule_once(this.autoplay_audio.bind(this), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
autoplay_audio(){
|
||||||
|
this.icon.dispatch('click');
|
||||||
|
}
|
||||||
|
play_audio(){
|
||||||
|
this.player.toggle_play();
|
||||||
|
}
|
||||||
|
play_audio(){
|
||||||
|
if(this.value!=this.player.src){
|
||||||
|
this.player.stop();
|
||||||
|
this.player.set_source(this.value);
|
||||||
|
this.player.play();
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.player.toggle_play();
|
||||||
|
this.btn.dispatch('click');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var Input = new _Input();
|
||||||
|
Input.register('UiStr', UiStr);
|
||||||
|
Input.register('UiTel', UiTel);
|
||||||
|
Input.register('UiDate', UiDate);
|
||||||
|
Input.register('UiInt', UiInt);
|
||||||
|
Input.register('UiFloat', UiFloat);
|
||||||
|
Input.register('UiCheck', UiCheck);
|
||||||
|
Input.register('UiCheckBox', UiCheckBox);
|
||||||
|
Input.register('UiEmail', UiEmail);
|
||||||
|
Input.register('UiFile', UiFile);
|
||||||
|
Input.register('UiCode', UiCode);
|
||||||
|
Input.register('UiText', UiText);
|
||||||
|
Input.register('UiPassword', UiPassword);
|
||||||
|
Input.register('UiAudio', UiAudio);
|
||||||
|
Input.register('UiVideo', UiVideo);
|
10
bricks/install.bat
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
echo copy ..\dist\*.* e:\gadget\wwwroot\bricks
|
||||||
|
copy ..\dist\*.* e:\gadget\wwwroot\bricks
|
||||||
|
echo copy css\*.* e:\gadget\wwwroot\bricks\css
|
||||||
|
copy css\*.* e:\gadget\wwwroot\bricks\css
|
||||||
|
copy imgs\*.* e:\gadget\wwwroot\bricks\imgs
|
||||||
|
echo copy imgs\*.* e:\gadget\wwwroot\bricks\imgs
|
||||||
|
copy ..\docs\*.* e:\gadget\wwwroot\docs
|
||||||
|
echo copy ..\docs\*.* e:\gadget\wwwroot\docs
|
||||||
|
copy ..\examples\*.* e:\gadget\wwwroot\examples
|
||||||
|
echo copy ..\examples\*.* e:\gadget\wwwroot\examples
|
196
bricks/jsoncall.js
Executable file
@ -0,0 +1,196 @@
|
|||||||
|
function url_params(data) {
|
||||||
|
return Object.keys(data).map(key => `${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<a.length;i++){
|
||||||
|
var b;
|
||||||
|
b = a[i].split('=');
|
||||||
|
this.params[b[0]] = b[1];
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
async get_result_data(resp){
|
||||||
|
return await resp.text();
|
||||||
|
}
|
||||||
|
add_own_params(params){
|
||||||
|
if (! params)
|
||||||
|
params = {};
|
||||||
|
if (params instanceof FormData){
|
||||||
|
for ( const [key, value] of Object.entries(this.params)){
|
||||||
|
params.append(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
params = Object.assign(this.params, params);
|
||||||
|
}
|
||||||
|
var session = bricks_app.get_session();
|
||||||
|
if (session){
|
||||||
|
extend(params,{session:session});
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
add_own_headers(headers){
|
||||||
|
if (! headers){
|
||||||
|
headers = {};
|
||||||
|
}
|
||||||
|
return Object.assign(this.headers, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
async httpcall(url, {method='GET', headers=null, params=null}={}){
|
||||||
|
url = this.url_parse(url);
|
||||||
|
var data = this.add_own_params(params);
|
||||||
|
var header = this.add_own_headers(headers);
|
||||||
|
var _params = {
|
||||||
|
"method":method,
|
||||||
|
}
|
||||||
|
// _params.headers = headers;
|
||||||
|
if (method == 'GET' || method == 'HEAD') {
|
||||||
|
let pstr = url_params(data);
|
||||||
|
url = url + '?' + pstr;
|
||||||
|
} else {
|
||||||
|
if (data instanceof FormData){
|
||||||
|
_params.body = data;
|
||||||
|
} else {
|
||||||
|
_params.body = JSON.stringify(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fetchResult = await fetch(url, _params);
|
||||||
|
var result=null;
|
||||||
|
result = await this.get_result_data(fetchResult);
|
||||||
|
if (fetchResult.ok){
|
||||||
|
var ck = objget(fetchResult.headers, 'Set-Cookie');
|
||||||
|
if (ck){
|
||||||
|
var session = ck.split(';')[0];
|
||||||
|
bricks_app.save_session(session);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (fetchResult.status == 401 && bricks_app.login_url){
|
||||||
|
return await this.withLoginInfo(url, _params);
|
||||||
|
}
|
||||||
|
console.log('method=', method, 'url=', url, 'params=', params);
|
||||||
|
console.log('jsoncall error:');
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
async withLoginInfo(url, params){
|
||||||
|
var get_login_info = function(e){
|
||||||
|
console.log('login info:', e.target.getValue());
|
||||||
|
return e.target.getValue();
|
||||||
|
}
|
||||||
|
var w = await widgetBuild({
|
||||||
|
"id":"login_form",
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":bricks_app.login_url
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var login_info = await new Promise((resolve, reject, w) => {
|
||||||
|
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);
|
||||||
|
|
98
bricks/layout.js
Executable file
@ -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<len; i++){
|
||||||
|
if (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<this.children.length;i++){
|
||||||
|
this.children[i].parent = null;
|
||||||
|
}
|
||||||
|
this.children = [];
|
||||||
|
this.dom_element.replaceChildren();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Body extends Layout {
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
}
|
||||||
|
create(){
|
||||||
|
this.dom_element = document.getElementsByTagName('body')[0];
|
||||||
|
this.set_baseURI(this.dom_element.baseURI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Body = new _Body();
|
||||||
|
|
||||||
|
class VBox extends Layout {
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.set_css('vcontainer');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VFiller extends Layout {
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.set_css('vfiller');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HBox extends Layout {
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.set_css('hcontainer');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HFiller extends Layout {
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.set_css('hfiller');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Factory.register('HBox', HBox);
|
||||||
|
Factory.register('VBox', VBox);
|
||||||
|
Factory.register('HFiller', HFiller);
|
||||||
|
Factory.register('VFiller', VFiller);
|
||||||
|
|
128
bricks/markdown_viewer.js
Executable file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
reply on "https://github.com/markedjs/marked"
|
||||||
|
add following lines before 'bricks.js'
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<links.length; i ++){
|
||||||
|
var url = links[i].href;
|
||||||
|
links[i].href = '#';
|
||||||
|
links[i].onclick=this._build.bind(this, url);
|
||||||
|
}
|
||||||
|
this.dispatch('loaded', {'url':md_url});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class MarkdownViewer extends VBox {
|
||||||
|
/* options
|
||||||
|
{
|
||||||
|
navigator:true
|
||||||
|
recommentable:false
|
||||||
|
md_url:
|
||||||
|
method:"GET",
|
||||||
|
params:{}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.back_stack = [];
|
||||||
|
this.md_url = this.absurl(this.opts.md_url);
|
||||||
|
if (this.opts.navigator){
|
||||||
|
this.createBackButton();
|
||||||
|
}
|
||||||
|
this.mdtext = new MdText({
|
||||||
|
md_url:this.md_url
|
||||||
|
});
|
||||||
|
this.add_widget(this.mdtext);
|
||||||
|
this.mdtext.bind('loaded', this.add_back_stack.bind(this));
|
||||||
|
this.dom_element.style.overflow='auto';
|
||||||
|
this.dom_element.style.height='100%';
|
||||||
|
this.bind('scroll', this.show_scroll.bind(this));
|
||||||
|
}
|
||||||
|
show_scroll(event){
|
||||||
|
console.log('scrollY=', window.scrollY);
|
||||||
|
}
|
||||||
|
createBackButton = async function(){
|
||||||
|
var desc = {
|
||||||
|
"widgettype":"HBox",
|
||||||
|
"options":{},
|
||||||
|
"subwidgets":[
|
||||||
|
{
|
||||||
|
"widgettype":"Text",
|
||||||
|
"options":{
|
||||||
|
"text":"<<<<<<<"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
var w = await widgetBuild(desc);
|
||||||
|
console.log('createBackButton():error, desc=', desc, 'w=', w);
|
||||||
|
var t = w.children[0];
|
||||||
|
console.log('createBackButton():text=',t);
|
||||||
|
t.bind('click',this.go_back.bind(this));
|
||||||
|
this.add_widget(w);
|
||||||
|
console.log('createBackButton():desc=',desc, 'w=', w);
|
||||||
|
}
|
||||||
|
add_back_stack(event){
|
||||||
|
console.log('go_back_stack():event=', event);
|
||||||
|
var url = event.params.url;
|
||||||
|
this.back_stack.push(url);
|
||||||
|
}
|
||||||
|
go_back = async function(event){
|
||||||
|
if (this.back_stack.length < 2){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ignore the current text url
|
||||||
|
this.back_stack.pop();
|
||||||
|
// get the back url
|
||||||
|
var url = this.back_stack.pop();
|
||||||
|
await this.mdtext._build(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
build = async function(){
|
||||||
|
this._build(this.opts.md_url);
|
||||||
|
}
|
||||||
|
_build = async function(md_url){
|
||||||
|
var md_content = await tget(md_url);
|
||||||
|
this.md_el.innerHTML = marked.parse(md_content);
|
||||||
|
// this.md_el.baseURI = md_url;
|
||||||
|
|
||||||
|
/* change links in markdown to a bricks action */
|
||||||
|
var links = this.md_el.getElementsByTagName('a');
|
||||||
|
for (var i=0; i<links.length; i ++){
|
||||||
|
var url = links[i].href;
|
||||||
|
links[i].href = '#';
|
||||||
|
links[i].onclick=this._build.bind(this, url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Factory.register('MarkdownViewer', MarkdownViewer);
|
62
bricks/menu.js
Executable file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
*/
|
||||||
|
class Menu extends VBox {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"items":
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.dom_element.style.display = "";
|
||||||
|
this.dom_element.style.position = "absolute";
|
||||||
|
this.dom_element.style.backgroundColor = options.bgcolor || "white";
|
||||||
|
this.dom_element.style.zIndex = "1000";
|
||||||
|
this.create_children(this.dom_element, this.opts.items);
|
||||||
|
this.bind('click', this.menu_clicked);
|
||||||
|
}
|
||||||
|
create_submenu_container(){
|
||||||
|
let cp = document.createElement('div');
|
||||||
|
cp.style.marginLeft = "15px";
|
||||||
|
cp.style.display = 'none';
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
async menu_clicked(event){
|
||||||
|
let mit = event.target;
|
||||||
|
if (mit.children.length > 0){
|
||||||
|
for (var i=0;i<mit.children.length; i++){
|
||||||
|
if (mit.children[i].style.display == 'none'){
|
||||||
|
mit.children[i].style.display = "";
|
||||||
|
} else {
|
||||||
|
mit.children[i].style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log('item clicked');
|
||||||
|
}
|
||||||
|
create_children(p, items){
|
||||||
|
console.log('create_children():items=', items, 'p=', p);
|
||||||
|
for (let i=0;i<items.length;i++){
|
||||||
|
let item = items[i];
|
||||||
|
let menu_item = this.create_menuitem(item);
|
||||||
|
p.appendChild(menu_item);
|
||||||
|
if (item.hasOwnProperty('items')){
|
||||||
|
let cp = this.create_submenu_container();
|
||||||
|
menu_item.appendChild(cp);
|
||||||
|
this.create_children(cp, item.items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
create_menuitem(item){
|
||||||
|
let i18n = bricks_app.i18n;
|
||||||
|
console.log('i18n=', i18n);
|
||||||
|
let e = document.createElement('div');
|
||||||
|
e.textContent = i18n._(item.label || item.name);
|
||||||
|
// e.description = item
|
||||||
|
console.log('create_menuitem():item=', item, 'obj=', e);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Factory.register('Menu', Menu);
|
109
bricks/message.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
class BPopup extends VBox {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
holder:
|
||||||
|
title:
|
||||||
|
auto_open:
|
||||||
|
auto_dismiss:
|
||||||
|
archor:cc
|
||||||
|
timeout:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.holder = opts.holder;
|
||||||
|
this.task = null;
|
||||||
|
this.title = opts.title|| 'Title';
|
||||||
|
this.archor = opts.archor || 'cc';
|
||||||
|
this.timeout = opts.timeout;
|
||||||
|
this.set_css('message');
|
||||||
|
this.build();
|
||||||
|
archorize(this.dom_element, this.archor);
|
||||||
|
}
|
||||||
|
|
||||||
|
build(){
|
||||||
|
var tb = new HBox({height:'40px'});
|
||||||
|
tb.set_css('title');
|
||||||
|
VBox.prototype.add_widget.bind(this)(tb);
|
||||||
|
var tit = new Text({otext:this.title, i18n:true});
|
||||||
|
this.content = new VBox({});
|
||||||
|
VBox.prototype.add_widget.bind(this)(this.content);
|
||||||
|
tb.add_widget(tit);
|
||||||
|
this.holder = Body;
|
||||||
|
if (this.opts.holder){
|
||||||
|
if (type(this.opts.holder) == 'string'){
|
||||||
|
this.holder = getWidgetById(this.opts.holder, Body);
|
||||||
|
} else {
|
||||||
|
this.holder = this.opts.holder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
open(){
|
||||||
|
this.holder.add_widget(this);
|
||||||
|
if (this.timeout && this.timeout > 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);
|
83
bricks/miniform.js
Normal file
@ -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);
|
4
bricks/minify_tools.txt
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
AJaxMin from Microsoft
|
||||||
|
https://developers.google.com/closure/compiler
|
||||||
|
YUI Compressor
|
||||||
|
Uglify-js
|
121
bricks/modal.js
Executable file
@ -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);
|
||||||
|
|
75
bricks/multiple_state_image.js
Normal file
@ -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;i++){
|
||||||
|
if (states[i] == this.state){
|
||||||
|
var k = i + 1;
|
||||||
|
if (k >= 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;i++){
|
||||||
|
if (states[i] == this.state){
|
||||||
|
var k = i + 1;
|
||||||
|
if (k >= 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);
|
||||||
|
|
13
bricks/myoperator.js
Executable file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
91
bricks/paging.js
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
11
bricks/registerfunction.js
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
class RegisterFunction {
|
||||||
|
constructor(){
|
||||||
|
this.rfs = {};
|
||||||
|
}
|
||||||
|
register(n, f){
|
||||||
|
extend(this.rfs, {n:f});
|
||||||
|
}
|
||||||
|
get(n){
|
||||||
|
return objget(this.rfs, n);
|
||||||
|
}
|
||||||
|
}
|
86
bricks/scroll.js
Normal file
@ -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);
|
||||||
|
|
27
bricks/stdhtml.html
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="/bricks/css/bricks.css" />
|
||||||
|
<link href="https://vjs.zencdn.net/8.3.0/video-js.min.css" rel="stylesheet">
|
||||||
|
<title>Standard Html</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="https://vjs.zencdn.net/8.3.0/video.min.js"></script>
|
||||||
|
<script src="/bricks/bricks.js"></script>
|
||||||
|
<script>
|
||||||
|
const opts = {
|
||||||
|
"widget": {
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"tree.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
125
bricks/tab.js
Executable file
@ -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<items.length;i++){
|
||||||
|
if (tdesc.name == items[i].name){
|
||||||
|
var w = objget(this.content_buffer, tdesc.name);
|
||||||
|
if (w && ! items[i].refresh){
|
||||||
|
this.content_container.clear_widgets();
|
||||||
|
this.content_container.add_widget(w);
|
||||||
|
this.cur_tab_name = name;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w = await widgetBuild(items[i].content);
|
||||||
|
if (! w){
|
||||||
|
console.log('TabPanel():create content error', items[i].content);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.content_buffer[tdesc.name] = w;
|
||||||
|
this.content_container.clear_widgets();
|
||||||
|
this.content_container.add_widget(w);
|
||||||
|
this.cur_tab_name = tdesc.name;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('TabPanel(): click event handled but noting to do', tdesc)
|
||||||
|
}
|
||||||
|
add_tab(desc){
|
||||||
|
var item = this.toolbar.createTool(desc);
|
||||||
|
if (desc.removable){
|
||||||
|
this.add_removeable(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tab_removed(event){
|
||||||
|
var desc = event.params;
|
||||||
|
if (this.content_buffer.hasOwnProperty(desc.name))
|
||||||
|
delete this.content_buffer[desc.name];
|
||||||
|
|
||||||
|
if (desc.name == this.cur_tab_name){
|
||||||
|
this.show_first_tab();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Factory.register('TabPanel', TabPanel);
|
130
bricks/toolbar.js
Executable file
@ -0,0 +1,130 @@
|
|||||||
|
class Toolbar extends Layout {
|
||||||
|
/* toolbar options
|
||||||
|
{
|
||||||
|
orientation:
|
||||||
|
target:
|
||||||
|
interval::
|
||||||
|
tools:
|
||||||
|
}
|
||||||
|
tool options
|
||||||
|
{
|
||||||
|
icon:
|
||||||
|
name:
|
||||||
|
label:
|
||||||
|
css:
|
||||||
|
}
|
||||||
|
|
||||||
|
event:
|
||||||
|
ready: after all the tools built, fire this event
|
||||||
|
command: after user click one of the tool will fire the event with params of the tools[i] object.
|
||||||
|
remove: after user delete a removable tool from the toolbar, will fire the event with its tool description object as params. the params can reach with event.params.
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.toolList = [];
|
||||||
|
if (this.opts.orientation == 'vertical'){
|
||||||
|
this.bar = new VBox(options);
|
||||||
|
this.dom_element.classList.add('vtoolbar')
|
||||||
|
} else {
|
||||||
|
this.bar = new HBox(options);
|
||||||
|
this.dom_element.classList.add('htoolbar')
|
||||||
|
}
|
||||||
|
this.add_widget(this.bar);
|
||||||
|
this.clicked_btn = null;
|
||||||
|
this.preffix_css = this.opts.css || 'toolbar';
|
||||||
|
schedule_once(this.createTools.bind(this), 0.01);
|
||||||
|
}
|
||||||
|
add_interval_box(){
|
||||||
|
if (this.opts.orientation == 'vertical'){
|
||||||
|
this.bar.add_widget(new JsWidget({
|
||||||
|
height:this.opts.interval || '10px'
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this.bar.add_widget(new JsWidget({
|
||||||
|
width:this.opts.interval || '10px'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createTools = async function(){
|
||||||
|
var l = this.opts.tools.length;
|
||||||
|
for (var i=0;i<l; i++){
|
||||||
|
await this.createTool(this.opts.tools[i]);
|
||||||
|
if (i < l -1 ){
|
||||||
|
this.add_interval_box();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.dispatch('ready');
|
||||||
|
}
|
||||||
|
createTool = async function(desc){
|
||||||
|
var options = {
|
||||||
|
"widgettype":"Button",
|
||||||
|
"options":{
|
||||||
|
width:"auto",
|
||||||
|
orientation:"horizontal",
|
||||||
|
icon:desc.icon,
|
||||||
|
label:desc.label,
|
||||||
|
name:desc.name,
|
||||||
|
css:desc.css
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var w = await widgetBuild(options);
|
||||||
|
if (! w){
|
||||||
|
console.log('Toolbar(): build widget failed', options);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.bind('click', this.do_handle.bind(this, w));
|
||||||
|
w.tool_opts = desc;
|
||||||
|
this.add_removable(w);
|
||||||
|
this.toolList.push(w);
|
||||||
|
this.bar.add_widget(w);
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
remove_item(w, event){
|
||||||
|
this.bar.remove_widget(w);
|
||||||
|
this.toolList.remove(w);
|
||||||
|
w.unbind('click',this.do_handle.bind(this, w));
|
||||||
|
this.dispatch('remove', w.tool_opts);
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
do_handle(tool, event){
|
||||||
|
// var tool = event.target;
|
||||||
|
console.log('Toolbar() onclock,target=', event.target, tool);
|
||||||
|
var e = new Event('command');
|
||||||
|
var d = {};
|
||||||
|
extend(d, tool.tool_opts);
|
||||||
|
if (this.opts.target){
|
||||||
|
d.target = this.opts.target;
|
||||||
|
}
|
||||||
|
this.dispatch('command', d);
|
||||||
|
|
||||||
|
if (this.clicked_btn){
|
||||||
|
this.clicked_btn.set_css(this.preffix_css + '-button-active', true);
|
||||||
|
}
|
||||||
|
tool.set_css(this.preffix_css + '-button-active');
|
||||||
|
this.clicked_btn = tool;
|
||||||
|
}
|
||||||
|
add_removable(item){
|
||||||
|
if (! item.tool_opts.removable) return;
|
||||||
|
var img_src = bricks_resource('imgs/delete.png');
|
||||||
|
var image = new Icon({url:img_src});
|
||||||
|
if (image){
|
||||||
|
item.add_widget(image);
|
||||||
|
image.bind('click',this.remove_item.bind(this, item));
|
||||||
|
console.log('Toolbar(): add_removable() for ', img_src);
|
||||||
|
} else {
|
||||||
|
console.log('Toolbar(): Image create error', img_src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
click(name){
|
||||||
|
for (var i=0;i<this.toolList.length;i++){
|
||||||
|
if (name==this.toolList[i].tool_opts.name){
|
||||||
|
this.toolList[i].dom_element.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Factory.register('Toolbar', Toolbar);
|
356
bricks/tree.js
Executable file
@ -0,0 +1,356 @@
|
|||||||
|
class TreeNode extends VBox {
|
||||||
|
constructor(tree, parent, data){
|
||||||
|
var opts = {
|
||||||
|
width:'100%',
|
||||||
|
height:'auto',
|
||||||
|
overflow:'hidden'
|
||||||
|
}
|
||||||
|
super(opts);
|
||||||
|
this.tree = tree;
|
||||||
|
this.parent = parent;
|
||||||
|
this.children_loaded = false;
|
||||||
|
this.data = data;
|
||||||
|
this.is_leaf = this.data.is_leaf;
|
||||||
|
this.params = {id:this.data[this.tree.opts.idField]};
|
||||||
|
if (this.tree.multitype_tree){
|
||||||
|
this.params['type'] = this.data[this.tree.opts.typeField];
|
||||||
|
}
|
||||||
|
var n = new HBox({
|
||||||
|
height:'auto',
|
||||||
|
overflow:'hidden',
|
||||||
|
width:'100%'
|
||||||
|
})
|
||||||
|
n.dom_element.style.margin = bricks_app.charsize * 0.2;
|
||||||
|
this.add_widget(n);
|
||||||
|
n.bind('click', this.tree.node_click_handle.bind(this.tree, this));
|
||||||
|
this.node_widget = n;
|
||||||
|
this.create_node_content(n);
|
||||||
|
if (! this.data.is_leaf) {
|
||||||
|
this.container = new VBox({height:'auto', overflow:'hidden'});
|
||||||
|
this.add_widget(this.container);
|
||||||
|
this.container.dom_element.style.marginLeft = bricks_app.charsize + 'px';
|
||||||
|
if (this.data.children){
|
||||||
|
this.tree.create_node_children(this, this.data.children);
|
||||||
|
}
|
||||||
|
this.container.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selected(flg){
|
||||||
|
if (flg){
|
||||||
|
this.str_w.set_css('selected');
|
||||||
|
} else {
|
||||||
|
this.str_w.set_css('selected',true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async toggleExpandCollapse(event){
|
||||||
|
if (event.params == 'open') {
|
||||||
|
await this.expand();
|
||||||
|
} else {
|
||||||
|
this.collapse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async expand(){
|
||||||
|
if (this.is_leaf){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.tree.opts.dataurl && !this.is_leaf && !this.children_loaded){
|
||||||
|
await this.tree.get_children_data(this)
|
||||||
|
this.children_loaded = true;
|
||||||
|
}
|
||||||
|
this.container.show();
|
||||||
|
}
|
||||||
|
collapse(){
|
||||||
|
if (this.is_leaf){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.container.hide();
|
||||||
|
}
|
||||||
|
create_node_content(widget){
|
||||||
|
var img_size = bricks_app.charsize;
|
||||||
|
if (this.is_leaf){
|
||||||
|
widget.add_widget(new BlankIcon({}));
|
||||||
|
} else {
|
||||||
|
var srcs = this.tree.opts.node_state_imgs || {};
|
||||||
|
var sources = {};
|
||||||
|
sources['open'] = objget(srcs, 'open', bricks_resource('imgs/down_arrow.png'));
|
||||||
|
sources['close'] = objget(srcs, 'close', bricks_resource('imgs/right_arrow.png'));
|
||||||
|
this.trigle = new MultipleStateIcon({
|
||||||
|
state:'close',
|
||||||
|
urls:sources,
|
||||||
|
height:img_size,
|
||||||
|
width:img_size
|
||||||
|
});
|
||||||
|
this.trigle.bind('state_changed', this.toggleExpandCollapse.bind(this));
|
||||||
|
widget.add_widget(this.trigle);
|
||||||
|
}
|
||||||
|
var dtype = this.data[this.tree.opts.typeField];
|
||||||
|
var icon = objget(TypeIcons, dtype);
|
||||||
|
if (!icon && this.tree.opts.default_type){
|
||||||
|
icon = objget(TypeIcons, his.tree.opts.default_type);
|
||||||
|
}
|
||||||
|
if (!icon){
|
||||||
|
icon = bricks_resource('imgs/folder.png');
|
||||||
|
}
|
||||||
|
var img = new Icon({
|
||||||
|
url:icon
|
||||||
|
});
|
||||||
|
widget.add_widget(img);
|
||||||
|
var txt = this.data[this.tree.opts.textField];
|
||||||
|
widget.add_widget(
|
||||||
|
this.str_w = new Text({text:txt}));
|
||||||
|
this.input = new UiStr({name:'text', value:txt});
|
||||||
|
this.input.bind('blur', this.edit_handle.bind(this));
|
||||||
|
widget.add_widget(this.str_w);
|
||||||
|
}
|
||||||
|
edit(){
|
||||||
|
this.node_widget.remove_widget(this.str_w);
|
||||||
|
this.input.setValue(this.str_w.text);
|
||||||
|
this.node_widget.add_widget(this.input);
|
||||||
|
}
|
||||||
|
async edit_handle(){
|
||||||
|
if (this.input.value==this.str_w.text)
|
||||||
|
return;
|
||||||
|
var v = this.input.value;
|
||||||
|
r = await this.syncdata('edit');
|
||||||
|
this.data[this.tree.opts.textField] = v;
|
||||||
|
this.str_w = new Text({text:v});
|
||||||
|
this.node_widget.remove_widget(this.input);
|
||||||
|
this.node_widget.add_widget(this.str_w);
|
||||||
|
}
|
||||||
|
async syncdata(mode){
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Tree extends VBox {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
row_height:
|
||||||
|
multitype_tree:false,
|
||||||
|
idField:
|
||||||
|
textField:
|
||||||
|
type_icons:
|
||||||
|
typeField:
|
||||||
|
default_type:
|
||||||
|
data:
|
||||||
|
dataurl:
|
||||||
|
node_state_imgs:{
|
||||||
|
open:url,
|
||||||
|
close:url
|
||||||
|
},
|
||||||
|
admin:{
|
||||||
|
{
|
||||||
|
addurl:
|
||||||
|
deleteurl:
|
||||||
|
updateurl:
|
||||||
|
othertools:[
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
this.set_height('100%');
|
||||||
|
this.row_height = this.opts.row_height || '35px';
|
||||||
|
this.multitype_tree = this.opts.multitype_tree||false;
|
||||||
|
this.selected_node = null;
|
||||||
|
this.create_toolbar();
|
||||||
|
this.container = new VScrollPanel({});
|
||||||
|
this.add_widget(this.container);
|
||||||
|
this.data_id = null;
|
||||||
|
if (this.opts.dataurl){
|
||||||
|
schedule_once(0.01, this.get_children_data.bind(this, this));
|
||||||
|
}
|
||||||
|
this.create_node_children(this, this.opts.data);
|
||||||
|
}
|
||||||
|
create_toolbar(){
|
||||||
|
}
|
||||||
|
async get_children_data(node){
|
||||||
|
var d = await jcall(this.opts.dataurl,{
|
||||||
|
method : this.opts.method || 'GET',
|
||||||
|
params : node.params
|
||||||
|
})
|
||||||
|
if (d.length == 0){
|
||||||
|
node.is_leaf = true;
|
||||||
|
} else {
|
||||||
|
this.create_tree_nodes(node, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
create_node_children(node, data){
|
||||||
|
for (var i=0; i<data.length; i++){
|
||||||
|
var n = new TreeNode(this, node, data[i]);
|
||||||
|
node.container.add_widget(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node_click_handle(node, event){
|
||||||
|
if (this.selected_node){
|
||||||
|
this.selected_node.selected(false);
|
||||||
|
}
|
||||||
|
this.selected_node = node;
|
||||||
|
node.selected(true);
|
||||||
|
this.dispatch('node_click', node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EditableTree extends Tree {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
...
|
||||||
|
admin:{
|
||||||
|
url:
|
||||||
|
add:{
|
||||||
|
icon:
|
||||||
|
}
|
||||||
|
delete_node:{
|
||||||
|
icon:
|
||||||
|
}
|
||||||
|
move_up:
|
||||||
|
move_down:
|
||||||
|
move_top:
|
||||||
|
move_bottom:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
}
|
||||||
|
create_toolbar(){
|
||||||
|
if (!this.opts.admin){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var desc = {
|
||||||
|
height:'auto',
|
||||||
|
tools:[
|
||||||
|
{
|
||||||
|
name:'add',
|
||||||
|
icon:bricks_resource('imgs/add.png')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name:'edit',
|
||||||
|
icon:bricks_resource('imgs/edit.png')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name:'move_top',
|
||||||
|
icon:bricks_resource('imgs/move_top.png')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name:'move_up',
|
||||||
|
icon:bricks_resource('imgs/move_up.png')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name:'move_down',
|
||||||
|
icon:bricks_resource('imgs/move_down.png')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name:'move_button',
|
||||||
|
icon:bricks_resource('imgs/move_bottom.png')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name:'delete',
|
||||||
|
icon:bricks_resource('imgs/delete_node.png')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
this.toolbar = new Toolbar(desc);
|
||||||
|
this.toolbar.bind('command', this.command_handle.bind(this));
|
||||||
|
this.add_widget(this.toolbar, 0);
|
||||||
|
}
|
||||||
|
command_handle(e){
|
||||||
|
console.log('command event fire ...', e);
|
||||||
|
var name = e.params.name;
|
||||||
|
switch (name) {
|
||||||
|
case 'add':
|
||||||
|
this.add_node();
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
this.delete_node();
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
this.edit_node();
|
||||||
|
break;
|
||||||
|
case 'move_top':
|
||||||
|
this.move_top();
|
||||||
|
break;
|
||||||
|
case 'move_up':
|
||||||
|
this.move_up();
|
||||||
|
break;
|
||||||
|
case 'move_down':
|
||||||
|
this.move_down();
|
||||||
|
break;
|
||||||
|
case 'move_bottom':
|
||||||
|
this.move_bottom();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_node(){
|
||||||
|
var node = this;
|
||||||
|
if (this.selected_node) node = this.selected_node;
|
||||||
|
var data = { };
|
||||||
|
data[this.opts.idField] = 'undefined';
|
||||||
|
data[this.opts.textField] = 'new node';
|
||||||
|
var n = new TreeNode(this, node, data);
|
||||||
|
node.container.add_widget(n);
|
||||||
|
n.edit();
|
||||||
|
console.log('add_node() finished ...');
|
||||||
|
}
|
||||||
|
edit_node(){
|
||||||
|
if (! this.selected_node){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selected_node.edit();
|
||||||
|
}
|
||||||
|
delete_node(){
|
||||||
|
if (! this.selected_node){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selected_node.delete();
|
||||||
|
}
|
||||||
|
move_top(){
|
||||||
|
if (! this.selected_node){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selected_node.move_top();
|
||||||
|
}
|
||||||
|
move_up(){
|
||||||
|
if (! this.selected_node){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selected_node.move_up();
|
||||||
|
}
|
||||||
|
move_down(){
|
||||||
|
if (! this.selected_node){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selected_node.move_down();
|
||||||
|
}
|
||||||
|
move_botton(){
|
||||||
|
if (! this.selected_node){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selected_node.move_botton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class PolymorphyTree extends Tree {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
root:[t1],
|
||||||
|
nodetypes:{
|
||||||
|
t1:{
|
||||||
|
idField:
|
||||||
|
typeField:
|
||||||
|
textField:
|
||||||
|
icon:
|
||||||
|
contextmenu:
|
||||||
|
subtypes:[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data:
|
||||||
|
dataurl:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Factory.register('Tree', Tree);
|
||||||
|
Factory.register('EditableTree', EditableTree);
|
124
bricks/uitypesdef.js
Executable file
@ -0,0 +1,124 @@
|
|||||||
|
class UiTypesDef {
|
||||||
|
constructor(opts){
|
||||||
|
this.opts = opts;
|
||||||
|
this.uitypes = {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set(uitype, viewBuilder, inputBuilder){
|
||||||
|
if (! this.uitypes[uitype]){
|
||||||
|
this.uitypes[uitype] = {};
|
||||||
|
}
|
||||||
|
this.uitypes[uitype].viewBuilder = viewBuilder;
|
||||||
|
this.uitypes[uitype].inputBuilder = inputBuilder;
|
||||||
|
}
|
||||||
|
get(uitype){
|
||||||
|
if (! this.uitypes[uitype]){
|
||||||
|
return (null, null);
|
||||||
|
}
|
||||||
|
return [this.uitypes[uitype].viewBuilder,
|
||||||
|
this.uitypes[uitype].inputBuilder];
|
||||||
|
}
|
||||||
|
getInputBuilder(uitype){
|
||||||
|
if (! this.uitypes[uitype]){
|
||||||
|
return Null;
|
||||||
|
}
|
||||||
|
return this.uitypes[uitype].inputBuilder;
|
||||||
|
}
|
||||||
|
getViewBuilder(uitype){
|
||||||
|
return this.uitypes[uitype].viewBuilder;
|
||||||
|
}
|
||||||
|
setViewBuilder(uitype, Builder){
|
||||||
|
if (! this.uitypes[uitype]){
|
||||||
|
this.uitypes[uitype] = {};
|
||||||
|
}
|
||||||
|
this.uitypes[uitype].viewBuilder = Builder;
|
||||||
|
}
|
||||||
|
setInputBuilder(uitype, Builder){
|
||||||
|
if (! this.uitypes[uitype]){
|
||||||
|
this.uitypes[uitype] = {};
|
||||||
|
}
|
||||||
|
this.uitypes[uitype].inputBuilder = Builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var uitypesdef = new UiTypesDef();
|
||||||
|
|
||||||
|
var viewFactory = function(desc, rec){
|
||||||
|
var uitype = desc.uitype;
|
||||||
|
var builder = uitypesdef.getViewBuilder(uitype) ||
|
||||||
|
uitypesdef.getViewBuilder('str');
|
||||||
|
if (! builder) return Null;
|
||||||
|
var w = builder(desc, rec);
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
var intputFactory = function(desc, rec){
|
||||||
|
var uitype = desc.uitype;
|
||||||
|
var builder = uitypesdef.getInputBuilder(uitype) ||
|
||||||
|
uitypesdef.getInputBuilder('str');
|
||||||
|
if (! builder) return Null;
|
||||||
|
return builder(desc, rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildText = function(text, halign){
|
||||||
|
if (['left', 'right'].indexOf(halign)< 0){
|
||||||
|
halign = 'left';
|
||||||
|
}
|
||||||
|
var w = new Text({
|
||||||
|
text:text || '',
|
||||||
|
overflow:'hidden',
|
||||||
|
wrap:true,
|
||||||
|
halign:'left'
|
||||||
|
});
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
var strViewBuilder = function(desc, rec){
|
||||||
|
var v = rec[desc.name];
|
||||||
|
return buildText(v, 'left');
|
||||||
|
}
|
||||||
|
uitypesdef.setViewBuilder('str', strViewBuilder);
|
||||||
|
|
||||||
|
var strInputBuilder = function(desc, rec) {
|
||||||
|
var v = rec[desc.name];
|
||||||
|
desc[value] = v;
|
||||||
|
return new UiStr(desc);
|
||||||
|
}
|
||||||
|
uitypesdef.setInputBuilder('str', strInputBuilder);
|
||||||
|
|
||||||
|
var passwordViewBuilder = function(desc, rec){
|
||||||
|
return new buildText('******');
|
||||||
|
}
|
||||||
|
uitypesdef.setViewBuilder('password', passwordViewBuilder);
|
||||||
|
|
||||||
|
var intViewBuilder = function(desc, rec){
|
||||||
|
var v = rec[desc.name] + '';
|
||||||
|
return buildText(v, 'right');
|
||||||
|
}
|
||||||
|
uitypesdef.setViewBuilder('int', intViewBuilder);
|
||||||
|
|
||||||
|
var floatViewBuilder = function(desc, rec){
|
||||||
|
var v = rec[desc.name];
|
||||||
|
v = v.toFixed(desc.dec_len||2)
|
||||||
|
v = v + '';
|
||||||
|
return buildText(v, 'right');
|
||||||
|
}
|
||||||
|
uitypesdef.setViewBuilder('float', floatViewBuilder);
|
||||||
|
|
||||||
|
var codeViewBuilder = function(desc, rec){
|
||||||
|
var opts = objcopy(desc)
|
||||||
|
if (opts.uiparams) extend(opts, opts.uiparams);
|
||||||
|
var name = desc.textFeild || 'text';
|
||||||
|
var v = rec[name];
|
||||||
|
if (! v) {
|
||||||
|
name = desc.valueField || 'value';
|
||||||
|
v = rec[name];
|
||||||
|
}
|
||||||
|
return buildText(v, 'left')
|
||||||
|
}
|
||||||
|
uitypesdef.setViewBuilder('code', codeViewBuilder);
|
||||||
|
|
||||||
|
|
||||||
|
var passwordInputBuilder = function(desc, rec){
|
||||||
|
return new UiPassword(desc);
|
||||||
|
}
|
||||||
|
uitypesdef.setInputBuilder('password', passwordInputBuilder);
|
281
bricks/utils.js
Executable file
@ -0,0 +1,281 @@
|
|||||||
|
class _TypeIcons {
|
||||||
|
constructor(){
|
||||||
|
this.kv = {}
|
||||||
|
}
|
||||||
|
get(n, defaultvalue){
|
||||||
|
return objget(this.kv, n, defaultvalue);
|
||||||
|
}
|
||||||
|
register(n, icon){
|
||||||
|
this.kv[n] = icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeIcons = new _TypeIcons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current Script Path
|
||||||
|
*
|
||||||
|
* Get the dir path to the currently executing script file
|
||||||
|
* which is always the last one in the scripts array with
|
||||||
|
* an [src] attr
|
||||||
|
*/
|
||||||
|
var currentScriptPath = function () {
|
||||||
|
var currentScript;
|
||||||
|
if (document.currentScript){
|
||||||
|
currentScript = document.currentScript.src;
|
||||||
|
} else {
|
||||||
|
console.log('has not currentScriot');
|
||||||
|
var scripts = document.querySelectorAll( 'script[src]' );
|
||||||
|
if (scripts.length < 1){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
currentScript = scripts[ scripts.length - 1 ].src;
|
||||||
|
}
|
||||||
|
var currentScriptChunks = currentScript.split( '/' );
|
||||||
|
var currentScriptFile = currentScriptChunks[ currentScriptChunks.length - 1 ];
|
||||||
|
return currentScript.replace( currentScriptFile, '' );
|
||||||
|
}
|
||||||
|
|
||||||
|
var bricks_path = currentScriptPath();
|
||||||
|
|
||||||
|
var bricks_resource = function(name){
|
||||||
|
return bricks_path + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all elements in the entire page matching `selector`, even if they are in shadowRoots.
|
||||||
|
* Just like `querySelectorAll`, but automatically expand on all child `shadowRoot` elements.
|
||||||
|
* @see https://stackoverflow.com/a/71692555/2228771
|
||||||
|
*/
|
||||||
|
function querySelectorAllShadows(selector, el = document.body) {
|
||||||
|
// recurse on childShadows
|
||||||
|
const childShadows = Array.from(el.querySelectorAll('*')).
|
||||||
|
map(el => el.shadowRoot).filter(Boolean);
|
||||||
|
|
||||||
|
console.log('[querySelectorAllShadows]', selector, el, `(${childShadows.length} shadowRoots)`);
|
||||||
|
|
||||||
|
const childResults = childShadows.map(child => querySelectorAllShadows(selector, child));
|
||||||
|
|
||||||
|
// fuse all results into singular, flat array
|
||||||
|
const result = Array.from(el.querySelectorAll(selector));
|
||||||
|
return result.concat(childResults).flat();
|
||||||
|
}
|
||||||
|
|
||||||
|
var schedule_once = function(f, t){
|
||||||
|
/* f: function
|
||||||
|
t:time in second unit
|
||||||
|
*/
|
||||||
|
t = t * 1000
|
||||||
|
window.setTimeout(f, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
var schedule_interval = function(f, t){
|
||||||
|
var mf = function(func, t){
|
||||||
|
func();
|
||||||
|
schedule_once(f, t);
|
||||||
|
}
|
||||||
|
schedule_once(mf.bind(f,t), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
var debug = function(){
|
||||||
|
console.log(...arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
var import_cache = new Map()
|
||||||
|
|
||||||
|
var import_css = async function(url){
|
||||||
|
if (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;
|
||||||
|
}
|
72
bricks/video.js
Executable file
@ -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
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/indigo-player@1/lib/indigo-pla yer.js"></script>
|
||||||
|
options
|
||||||
|
{
|
||||||
|
url:
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(options){
|
||||||
|
super(options);
|
||||||
|
var autoplay = '';
|
||||||
|
if (this.opts.autoplay){
|
||||||
|
autoplay = 'autoplay';
|
||||||
|
}
|
||||||
|
var url = this.opts.url;
|
||||||
|
this.dom_element.innerHTML = `<video width="90%" controls ${autoplay} src="${url}" type="application/vnd.apple.mpegurl" class="media-document mac video" ></video>`;
|
||||||
|
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);
|
49
bricks/views.js
Normal file
@ -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 {
|
||||||
|
|
||||||
|
}
|
310
bricks/widget.js
Executable file
@ -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<okeys.length; k++){
|
||||||
|
if (keys.find( i => i ==okeys[k])){
|
||||||
|
style[okeys[k]] = this.opts[okeys[k]];
|
||||||
|
}
|
||||||
|
if (mkeys.find( i => i ==okeys[k])){
|
||||||
|
var mk = mapping_keys[okeys[k]];
|
||||||
|
style[mk] = this.opts[okeys[k]];
|
||||||
|
}
|
||||||
|
this[okeys[k]] = this.opts[okeys[k]];
|
||||||
|
}
|
||||||
|
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.sizable_elements.length;i++){
|
||||||
|
this.sizable_elements[i].style.fontSize = ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_fontsize(){
|
||||||
|
var fontsize;
|
||||||
|
if (this.opts.fontsize){
|
||||||
|
this.specified_fontsize = true;
|
||||||
|
fontsize = this.opts.fontsize;
|
||||||
|
} else {
|
||||||
|
fontsize = bricks_app.get_textsize(this.ctype);
|
||||||
|
}
|
||||||
|
fontsize = convert2int(fontsize);
|
||||||
|
var rate = this.rate || 1;
|
||||||
|
fontsize = rate * fontsize;
|
||||||
|
fontsize = fontsize + 'px';
|
||||||
|
this.dom_element.style.fontSize = fontsize;
|
||||||
|
for(var i=0;i<this.sizable_elements.length;i++){
|
||||||
|
this.sizable_elements[i].style.fontSize = fontsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h_center(){
|
||||||
|
this.dom_element.style.marginLeft = 'auto';
|
||||||
|
this.dom_element.style.marginRight = 'auto';
|
||||||
|
}
|
||||||
|
h_left(){
|
||||||
|
this.dom_element.style.marginLeft = '0px';
|
||||||
|
this.dom_element.style.marginRight = 'auto';
|
||||||
|
}
|
||||||
|
h_right(){
|
||||||
|
this.dom_element.style.marginLeft = 'auto';
|
||||||
|
this.dom_element.style.marginRight = '0px';
|
||||||
|
}
|
||||||
|
ht_center(){
|
||||||
|
this.dom_element.style.textAlign = 'center';
|
||||||
|
}
|
||||||
|
ht_left(){
|
||||||
|
this.dom_element.style.textAlign = 'left';
|
||||||
|
}
|
||||||
|
ht_right(){
|
||||||
|
this.dom_element.style.textAlign = 'right';
|
||||||
|
}
|
||||||
|
set_width(width){
|
||||||
|
if (typeof(width) == 'number'){
|
||||||
|
width = width + 'px';
|
||||||
|
}
|
||||||
|
this.dom_element.style.width = width;
|
||||||
|
}
|
||||||
|
set_height(height){
|
||||||
|
if (typeof(height) == 'number'){
|
||||||
|
height = height + 'px';
|
||||||
|
}
|
||||||
|
this.dom_element.style.height = height;
|
||||||
|
}
|
||||||
|
set_style(k, v){
|
||||||
|
this.dom_element.style[k] = v;
|
||||||
|
}
|
||||||
|
set_csses(csses, remove_flg){
|
||||||
|
var arr = csses.split(' ');
|
||||||
|
arr.forEach(c =>{
|
||||||
|
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);
|
||||||
|
|
52
bricks/wterm.js
Normal file
@ -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);
|
||||||
|
|
0
dist/README.md
vendored
Normal file
BIN
docs/.DS_Store
vendored
Executable file
21
docs/BoxLayout.md
Executable file
@ -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
|
11
docs/HBox.md
Executable file
@ -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
|
41
docs/README.md
Executable file
@ -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)
|
||||||
|
|
135
docs/cn/bricks.md
Normal file
@ -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
|
||||||
|
```
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/bricks/css/bricks.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="/bricks/bricks.js"></script>
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"tree.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
```
|
||||||
|
这是一个树形控件, 运行[这里](https://github.com/bricks/examples/tree.html)
|
||||||
|
更多的例子请看
|
||||||
|
[bricks控件例子](https://github.com/yumoqing/bricks/examples)
|
||||||
|
|
||||||
|
|
60
docs/cn/bricksapp.md
Normal file
@ -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
|
||||||
|
## 方法
|
||||||
|
|
||||||
|
## 事件
|
||||||
|
|
78
docs/cn/descjson.md
Normal file
@ -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实例的方法
|
||||||
|
|
58
docs/cn/index.md
Normal file
@ -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的目标路径。
|
||||||
|
## 引用
|
||||||
|
```
|
||||||
|
<link rel="stylesheet" href="/bricks/css/bricks.css" />
|
||||||
|
<script src="/bricks/bricks.js"></script>
|
||||||
|
|
||||||
|
```
|
||||||
|
## 例子
|
||||||
|
配置好本地服务器后,可以使用build.sh将bricks项目内容复制到本地网站后台,之后在网站的examples目录中查看bricks提供的例子程序
|
||||||
|
|
102
docs/cn/inherittree.md
Normal file
@ -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
|
||||||
|
```
|
||||||
|
|
25
docs/cn/jswidget.md
Normal file
@ -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()函数调用,用来改变控件的大小
|
||||||
|
## 事件
|
||||||
|
无
|
9
docs/cn/pattern.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# XXX
|
||||||
|
|
||||||
|
## 创建选项
|
||||||
|
|
||||||
|
## 属性
|
||||||
|
|
||||||
|
## 方法
|
||||||
|
|
||||||
|
## 事件
|
45
docs/cn/widgettypes.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# 控件列表
|
||||||
|
Bricks内置许多的显示控件,所有显示控件都继承自JsWidget,容器控件Layout几就继承自JsWidget,其他的容器HBox, VBox继承自Layout
|
||||||
|
|
||||||
|
# 控件继承树
|
||||||
|
|
||||||
|
# 控件清单
|
||||||
|
* [JsWidget](jswidget.md): 祖先控件,对应于<div>元素
|
||||||
|
* [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控件
|
||||||
|
|
||||||
|
#
|
57
docs/image.md
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
# Image
|
||||||
|
Image widget show image
|
||||||
|
## use case
|
||||||
|
```
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="../css/bricks.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="../bricks.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"widgettype":"Image",
|
||||||
|
"options":{
|
||||||
|
"source":"https://cdn.pixabay.com/photo/2018/04/26/16/31/marine-3352341_960_720.jpg",
|
||||||
|
"height":"100%",
|
||||||
|
"width":"100%"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
the result is <br>
|
||||||
|
![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
|
BIN
docs/image.png
Executable file
After Width: | Height: | Size: 974 KiB |
1
docs/index.md
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
README.md
|
16
docs/layout.md
Executable file
@ -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
|
13
docs/markdownviewer.md
Executable file
@ -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
|
||||||
|
|
7
docs/pw.md
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
# Widget Name
|
||||||
|
description of the Widget
|
||||||
|
## use case
|
||||||
|
## inheritance
|
||||||
|
## options
|
||||||
|
## method
|
||||||
|
## event
|
7
docs/text.md
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
# Text
|
||||||
|
Text is a widget to show text
|
||||||
|
## use case
|
||||||
|
## inheritance
|
||||||
|
## options
|
||||||
|
## method
|
||||||
|
## event
|
105
docs/toolbar.md
Executable file
@ -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
|
||||||
|
```
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="../css/bricks.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="../bricks.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"widgettype":"Toolbar",
|
||||||
|
"options":{
|
||||||
|
"target":null,
|
||||||
|
"orientation":"vertical",
|
||||||
|
"tools":[
|
||||||
|
{
|
||||||
|
"name":"c",
|
||||||
|
"Label":"C",
|
||||||
|
"icon":null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"javascript",
|
||||||
|
"Label":"JavaScript",
|
||||||
|
"icon":null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"php",
|
||||||
|
"Label":"PHP",
|
||||||
|
"icon":null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"python",
|
||||||
|
"Label":"Python",
|
||||||
|
"icon":null
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
and the result like this:<br>
|
||||||
|
![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.
|
BIN
docs/toolbar.png
Executable file
After Width: | Height: | Size: 43 KiB |
11
docs/vbox.md
Executable file
@ -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
|
87
docs/videoplayer.md
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
# VideoPlayer
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
### play a mp4 file
|
||||||
|
```
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="../bricks.js"></script>
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"id":"videoplayer",
|
||||||
|
"widgettype":"VideoPlayer",
|
||||||
|
"options":{
|
||||||
|
"autoplay":true,
|
||||||
|
"url":"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
|
||||||
|
"type":"mp4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
### play a m3u8 stream
|
||||||
|
```
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/indigo-player@1/lib/indigo-player.js"></script>
|
||||||
|
<script src="../bricks.js"></script>
|
||||||
|
<script>
|
||||||
|
/*
|
||||||
|
https://abc-iview-mediapackagestreams-2.akamaized.net/out/v1/6e1cc6d25ec0480ea099a5399d73bc4b/index.m3u8
|
||||||
|
https://cbcnewshd-f.akamaihd.net/i/cbcnews_1@8981/index_2500_av-p.m3u8
|
||||||
|
*/
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"id":"videoplayer",
|
||||||
|
"widgettype":"VideoPlayer",
|
||||||
|
"options":{
|
||||||
|
"autoplay":true,
|
||||||
|
"source":"https://abc-iview-mediapackagestreams-2.akamaized.net/out/v1/6e1cc6d25ec0480ea099a5399d73bc4b/index.m3u8",
|
||||||
|
"srctype":"hls"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
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)
|
49
docs/widgets.md
Normal file
@ -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
|
BIN
examples/.DS_Store
vendored
Executable file
52
examples/accordion.html
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/bricks/css/bricks.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="/bricks/bricks.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"widgettype":"Accordion",
|
||||||
|
"options":{
|
||||||
|
"item_size":'28px',
|
||||||
|
"items":[
|
||||||
|
{
|
||||||
|
"name":"test1",
|
||||||
|
"icon":"/imgs/t.png",
|
||||||
|
"text":"accordion 1 test",
|
||||||
|
"content":{
|
||||||
|
"widgettype":"Text",
|
||||||
|
"options":{
|
||||||
|
"text":"text content 1",
|
||||||
|
"i81n":true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"test2",
|
||||||
|
"icon":"/imgs/t.png",
|
||||||
|
"text":"accordion 2 test",
|
||||||
|
"content":{
|
||||||
|
"widgettype":"Text",
|
||||||
|
"options":{
|
||||||
|
"text":"text content 2",
|
||||||
|
"i81n":true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
28
examples/audio.html
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="http://kimird.com/bricks/bricks.js"></script>
|
||||||
|
<script>
|
||||||
|
/*
|
||||||
|
https://abc-iview-mediapackagestreams-2.akamaized.net/out/v1/6e1cc6d25ec0480ea099a5399d73bc4b/index.m3u8
|
||||||
|
https://cbcnewshd-f.akamaihd.net/i/cbcnews_1@8981/index_2500_av-p.m3u8
|
||||||
|
*/
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"id":"audioplayer",
|
||||||
|
"widgettype":"AudioPlayer",
|
||||||
|
"options":{
|
||||||
|
"autoplay":true,
|
||||||
|
"url":"http://kimird.com/songs/sample-mp3-file.mp3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
8
examples/bricks.tmpl
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
{% if not webbricks or webbricks==0 %}
|
||||||
|
{% include "header.html" %}
|
||||||
|
{% endif -%}
|
||||||
|
{% include content %}
|
||||||
|
{% if not webbricks %}
|
||||||
|
{% include "footer.html" %}
|
||||||
|
{% endif -%}
|
||||||
|
|
57
examples/button.html
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/bricks/css/bricks.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="/bricks/bricks.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"widgettype":"HBox",
|
||||||
|
"options":{
|
||||||
|
"height":"auto",
|
||||||
|
"width":"100%"
|
||||||
|
},
|
||||||
|
"subwidgets":[
|
||||||
|
{
|
||||||
|
"widgettype":"Button",
|
||||||
|
"options":{
|
||||||
|
"name":"test",
|
||||||
|
"icon":"/bricks/imgs/submit.png",
|
||||||
|
"label":"test once",
|
||||||
|
"tooltip":"This is a joke too",
|
||||||
|
"nonepack":true,
|
||||||
|
"orientation":"horizontal"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype":"Button",
|
||||||
|
"options":{
|
||||||
|
"name":"test",
|
||||||
|
"icon":"/bricks/imgs/reset.png",
|
||||||
|
"tooltip":"This is a joke",
|
||||||
|
"label":"test twice",
|
||||||
|
"nonepack":true,
|
||||||
|
"orientation":"horizontal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"binds":[
|
||||||
|
{
|
||||||
|
"wid":"self",
|
||||||
|
"event":"click",
|
||||||
|
"actiontype":"script",
|
||||||
|
"script":"alert('HBox clicked');"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
344
examples/config.js
Executable file
@ -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'
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
22
examples/datagrid.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/bricks/css/bricks.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="/bricks/bricks.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"users.bcrud"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
893
examples/datagrid.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
22
examples/datagrid1.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/bricks/css/bricks.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="/bricks/bricks.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"iptvchannels.bcrud"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
24
examples/docs.html
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="/marked.js"></script>
|
||||||
|
<script src="http://kimird.com/bricks/bricks.js"></script>
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"widgettype":"MarkdownViewer",
|
||||||
|
"options":{
|
||||||
|
"navigator":true,
|
||||||
|
"md_url":"../docs/index.md"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
1
examples/echo.ws
Normal file
@ -0,0 +1 @@
|
|||||||
|
return 'resp:' + ws_data
|
24
examples/editabletree.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/bricks/css/bricks.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="/bricks/bricks.js"></script>
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"editabletree.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
84
examples/editabletree.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
105
examples/error.html
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/bricks/css/bricks.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="/bricks/bricks.js"></script>
|
||||||
|
<script>
|
||||||
|
const opts =
|
||||||
|
{
|
||||||
|
"widget": {
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
const app = new BricksApp(opts);
|
||||||
|
app.run();
|
||||||
|
var m = new Error({
|
||||||
|
"title":"TEst Message",
|
||||||
|
"message":"This is a test message",
|
||||||
|
"auto_open":true,
|
||||||
|
"timeout":30
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
2
examples/fileupload.dspy
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
print(params_kw)
|
||||||
|
return params_kw
|