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
|