bugfix
2
3parties/xterm-addon-fit.js
Normal file
@ -0,0 +1,2 @@
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(window,function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(){}return e.prototype.activate=function(e){this._terminal=e},e.prototype.dispose=function(){},e.prototype.fit=function(){var e=this.proposeDimensions();if(e&&this._terminal){var t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}},e.prototype.proposeDimensions=function(){if(this._terminal&&this._terminal.element&&this._terminal.element.parentElement){var e=this._terminal._core,t=window.getComputedStyle(this._terminal.element.parentElement),r=parseInt(t.getPropertyValue("height")),n=Math.max(0,parseInt(t.getPropertyValue("width"))),o=window.getComputedStyle(this._terminal.element),i=r-(parseInt(o.getPropertyValue("padding-top"))+parseInt(o.getPropertyValue("padding-bottom"))),a=n-(parseInt(o.getPropertyValue("padding-right"))+parseInt(o.getPropertyValue("padding-left")))-e.viewport.scrollBarWidth;return{cols:Math.max(2,Math.floor(a/e._renderService.dimensions.actualCellWidth)),rows:Math.max(1,Math.floor(i/e._renderService.dimensions.actualCellHeight))}}},e}();t.FitAddon=n}])});
|
||||
//# sourceMappingURL=xterm-addon-fit.js.map
|
76
bricks/asr.js
Normal file
@ -0,0 +1,76 @@
|
||||
var bricks = window.bricks || {};
|
||||
bricks.ASRClient = class extends bricks.VBox {
|
||||
/*
|
||||
options:
|
||||
{
|
||||
start_icon:record.png,
|
||||
stop_icon:stop.png
|
||||
ws_url:
|
||||
icon_options
|
||||
ws_params:
|
||||
}
|
||||
event:
|
||||
start: start recording, no params
|
||||
stop: stop recording, no params
|
||||
transtext: recognised text, params={
|
||||
"content":
|
||||
"speaker":
|
||||
"start":
|
||||
"end":
|
||||
}
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
var icon_options = this.icon_options || {};
|
||||
icon_options.url = this.start_icon || bricks_resource('imgs/start_recording.png');
|
||||
this.icon = new bricks.Icon(icon_options);
|
||||
this.status = 'stop';
|
||||
this.icon.bind('click', this.toggle_button.bind(this));
|
||||
this.add_widget(this.icon);
|
||||
var sessdata = bricks.app.get_session();
|
||||
this.socket = new WebSocket(this.ws_url, sessdata);
|
||||
this.socket.onmessage = this.response_data.bind(this);
|
||||
this.bind('transtext', this.response_log.bind(this));
|
||||
}
|
||||
response_log(event){
|
||||
console.log('response data=', event.params);
|
||||
}
|
||||
toggle_button(){
|
||||
if (this.status == 'stop'){
|
||||
this.icon.set_url(this.start_icon||bricks_resource('imgs/stop_recording.png'));
|
||||
this.status = 'start';
|
||||
this.start_recording();
|
||||
} else {
|
||||
this.icon.set_url(this.stop_icon||bricks_resource('imgs/start_recording.png'));
|
||||
this.status = 'stop';
|
||||
this.stop_recording();
|
||||
}
|
||||
}
|
||||
async start_recording() {
|
||||
this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
this.mediaRecorder = new MediaRecorder(this.stream);
|
||||
this.mediaRecorder.ondataavailable = (event) => {
|
||||
if (event.data.size > 0) {
|
||||
// 将音频数据通过 WebSocket 发送到服务器
|
||||
blobToBase64(event.data).then((b64str) => {
|
||||
var d = objcopy(this.ws_params);
|
||||
d.type = 'audiobuffer';
|
||||
d.data = b64str;
|
||||
this.socket.send(JSON.stringify(d));
|
||||
}).catch((error) => {
|
||||
console.log('Error', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
this.mediaRecorder.start(1000); // 每 1 秒发送一次数据
|
||||
}
|
||||
stop_recording(){
|
||||
this.mediaRecorder.stop();
|
||||
}
|
||||
response_data(event){
|
||||
var d = JSON.parse(event.data);
|
||||
this.dispatch('transtext', d);
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('ASRClient', bricks.ASRClient);
|
144
bricks/audio.js
@ -26,14 +26,70 @@ bricks.AudioPlayer = class extends bricks.JsWidget {
|
||||
this.audio = this._create('audio');
|
||||
this.audio.controls = true;
|
||||
if (this.opts.autoplay){
|
||||
this.audio.addEventListener('canplay', this.play_audio.bind(this));
|
||||
this.audio.addEventListener('canplay', this.play.bind(this));
|
||||
}
|
||||
this.audio.addEventListener('ended', this.playended.bind(this));
|
||||
this.audio.style.width = "100%"
|
||||
this.dom_element.appendChild(this.audio);
|
||||
if ( this.url ){
|
||||
this.set_source(this.url);
|
||||
}
|
||||
}
|
||||
playended(e){
|
||||
this.dispatch('ended');
|
||||
}
|
||||
set_stream_urls(response){
|
||||
async function* dyn_urls(response) {
|
||||
const reader = response.body.getReader();
|
||||
var value;
|
||||
var done;
|
||||
while (true){
|
||||
done, value = await reader.read();
|
||||
if (value.done){
|
||||
console.log('done=', done, 'value=', value);
|
||||
break;
|
||||
}
|
||||
let result = '';
|
||||
for (let i = 0; i < value.value.length; i++) {
|
||||
result += String.fromCharCode(value.value[i]);
|
||||
}
|
||||
console.log('audio set url=', result);
|
||||
yield result;
|
||||
}
|
||||
}
|
||||
this.url_generator = dyn_urls(response);
|
||||
this.srcList = [];
|
||||
this.notBegin = true;
|
||||
schedule_once(this.load_queue_url.bind(this), 0.1);
|
||||
}
|
||||
async load_queue_url(){
|
||||
while (true){
|
||||
var d = await this.url_generator.next();
|
||||
if (d.done){
|
||||
return;
|
||||
}
|
||||
this.srcList.push({played:false, url:d.value});
|
||||
if (this.srcList.length < 2 ){
|
||||
await this.play_srclist();
|
||||
this.audio.addEventListener('ended',
|
||||
this.play_srclist.bind(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
async play_srclist(evnet){
|
||||
if (event && ! this.audio.ended){
|
||||
return;
|
||||
}
|
||||
for (var i=0;i<this.srcList.length;i++){
|
||||
if (!this.srcList[i].played){
|
||||
console.log('playit', i, this.srcList[i]);
|
||||
this.set_url(this.srcList[i].url);
|
||||
this.srcList[i].played = true;
|
||||
await this.play();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
set_source(url){
|
||||
if (! this.source){
|
||||
this.source = this._create('source');
|
||||
@ -41,7 +97,7 @@ bricks.AudioPlayer = class extends bricks.JsWidget {
|
||||
this.audio.appendChild(this.source);
|
||||
}
|
||||
this.url = this.audio.src = url;
|
||||
bricks.debug(this.audio.src,' new src seted');
|
||||
console.log(this.audio.src,' new src seted');
|
||||
}
|
||||
set_source_from_response(resp){
|
||||
// 将服务器返回的数据设置为音频源
|
||||
@ -49,18 +105,19 @@ bricks.AudioPlayer = class extends bricks.JsWidget {
|
||||
// 播放音频
|
||||
this.audio.play();
|
||||
}
|
||||
play(){
|
||||
this.audio.play();
|
||||
async play(){
|
||||
await this.audio.play();
|
||||
}
|
||||
toggle_play(){
|
||||
async toggle_play(){
|
||||
if (this.audio.paused){
|
||||
this.audio.play();
|
||||
await this.audio.play();
|
||||
} else {
|
||||
this.audio.pause();
|
||||
await this.audio.pause();
|
||||
}
|
||||
}
|
||||
set_url(url){
|
||||
this.set_source(url);
|
||||
this.audio.play();
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,6 +138,7 @@ bricks.AudioRecorder = class extends bricks.HBox {
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.set_css('clickable');
|
||||
this.start_icon = opts.start_icon || bricks_resource('imgs/start_recording.png');
|
||||
this.stop_icon = opts.stop_icon || bricks_resource('imgs/stop_recording.png');
|
||||
this.rec_btn = new bricks.Icon({
|
||||
@ -97,7 +155,7 @@ bricks.AudioRecorder = class extends bricks.HBox {
|
||||
width:'120px'
|
||||
});
|
||||
this.upload_url = opts.upload_url;
|
||||
this.rec_btn.bind('click', this.rec_btn_pressed.bind(this))
|
||||
this.bind('click', this.rec_btn_pressed.bind(this))
|
||||
this.URL = window.URL||webkitURL;
|
||||
this.rec = null;
|
||||
this.wave = null;
|
||||
@ -105,7 +163,9 @@ bricks.AudioRecorder = class extends bricks.HBox {
|
||||
this.add_widget(this.rec_btn);
|
||||
this.add_widget(this.rec_time);
|
||||
this.recordData = null;
|
||||
this.bind('record_ended', this.upload.bind(this));
|
||||
if (this.upload_url){
|
||||
this.bind('record_ended', this.upload.bind(this));
|
||||
}
|
||||
}
|
||||
rec_btn_pressed(){
|
||||
bricks.debug(this.rec_btn.url, ':url:', this.start_icon, this.stop_icon);
|
||||
@ -241,32 +301,58 @@ bricks.AudioRecorder = class extends bricks.HBox {
|
||||
}
|
||||
}
|
||||
|
||||
bricks.SttClient = class extends bricks.VBox {
|
||||
/*
|
||||
{
|
||||
"upload_url"
|
||||
}
|
||||
*/
|
||||
bricks.TextedAudioPlayer = class extends bricks.VBox {
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.recorder = new bricks.AudioRecorder({
|
||||
icon_rate:2,
|
||||
upload_url:opts.upload_url,
|
||||
upload_resp:'json'
|
||||
this.audio = new bricks.AudioPlayer({
|
||||
height:'60px'
|
||||
});
|
||||
this.add_widget(this.recorder);
|
||||
this.result_text = new bricks.Text({
|
||||
text:'',
|
||||
dynsize:true
|
||||
this.audio.bind('ended', this.playnext.bind(this));
|
||||
var filler, panel;
|
||||
filler = new bricks.Filler({});
|
||||
this.add_widget(this.audio);
|
||||
this.add_widget(filler);
|
||||
panel = new bricks.VScrollPanel({
|
||||
height: '100%'
|
||||
});
|
||||
this.add_widget(this.result_text);
|
||||
this.recorder.bind('uploaded', this.set_result_text.bind(this));
|
||||
filler.add_widget(panel);
|
||||
this.textw = new bricks.Text({
|
||||
text: ' ',
|
||||
wrap: true
|
||||
});
|
||||
panel.add_widget(this.textw);
|
||||
this.streaming_buffer = [];
|
||||
this.wait_play = true;
|
||||
}
|
||||
set_result_text(event){
|
||||
var txt = event.params.text;
|
||||
this.result_text.set_text(txt);
|
||||
async playnext(){
|
||||
var json = this.streaming_buffer.shift();
|
||||
console.log('======', json);
|
||||
if (json && ! json.done){
|
||||
var url = base64_to_url(json.audio);
|
||||
this.audio.set_url(url);
|
||||
this.wait_play = false;
|
||||
this.textw.set_text(json.text);
|
||||
await this.audio.play();
|
||||
} else {
|
||||
this.textw.set_text('');
|
||||
this.audio.set_url(null);
|
||||
this.wait_play = true;
|
||||
}
|
||||
}
|
||||
async set_stream_urls(response){
|
||||
this.wait_play = true;
|
||||
await streamResponseJson(response, this.load_stream_data.bind(this));
|
||||
}
|
||||
async load_stream_data(json){
|
||||
console.log('***', json);
|
||||
this.streaming_buffer.push(json);
|
||||
if (this.wait_play) {
|
||||
await this.playnext();
|
||||
}
|
||||
}
|
||||
}
|
||||
bricks.Factory.register('AudioPlayer', bricks.AudioPlayer);
|
||||
bricks.Factory.register('AudioRecorder', bricks.AudioRecorder);
|
||||
bricks.Factory.register('SttClient', bricks.SttClient);
|
||||
bricks.Factory.register('TextedAudioPlayer', bricks.TextedAudioPlayer);
|
||||
|
||||
|
||||
|
@ -33,40 +33,23 @@ bricks.UpStreaming = class extends bricks.JsWidget {
|
||||
}
|
||||
}
|
||||
|
||||
bricks.down_streaming = function(widget, response) {
|
||||
bricks.down_streaming = async function*(response) {
|
||||
if (! response){
|
||||
return;
|
||||
}
|
||||
const reader = response.body.getReader();
|
||||
new ReadableStream({
|
||||
start(controller) {
|
||||
function push() {
|
||||
// 读取下一个数据块
|
||||
reader.read().then(({ done, value }) => {
|
||||
if (done) {
|
||||
// 如果读取完成,关闭流
|
||||
controller.close();
|
||||
return;
|
||||
}
|
||||
// 将数据块放入队列
|
||||
controller.enqueue(value);
|
||||
push();
|
||||
}).catch(error => {
|
||||
console.error('Error reading data', error);
|
||||
controller.error(error);
|
||||
});
|
||||
}
|
||||
push();
|
||||
var value;
|
||||
var t = 0;
|
||||
while (true){
|
||||
done, value = await reader.read();
|
||||
if (value.done){
|
||||
break;
|
||||
}
|
||||
})
|
||||
.then(stream => {
|
||||
// 将ReadableStream转换为Blob
|
||||
return new Response(stream).blob();
|
||||
})
|
||||
.then(blob => {
|
||||
const audioSrc = widget.set_url(URL.createObjectURL(blob));
|
||||
widget.bind('canplay', () => {
|
||||
widget.play();
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fetching audio stream failed', error);
|
||||
});
|
||||
let result = '';
|
||||
for (let i = 0; i < value.value.length; i++) {
|
||||
result += String.fromCharCode(value.value[i]);
|
||||
}
|
||||
console.log('audio set url=', result);
|
||||
yield result;
|
||||
}
|
||||
}
|
||||
|
212
bricks/bricks.js
@ -48,9 +48,20 @@ params:
|
||||
*/
|
||||
|
||||
bricks.uuid = function(){
|
||||
var d = crypto.randomUUID();
|
||||
var lst = d.split('-');
|
||||
return lst.join('');
|
||||
try{
|
||||
var d = crypto.randomUUID();
|
||||
var lst = d.split('-');
|
||||
return lst.join('');
|
||||
} catch(e) {
|
||||
const vv = '1234567890qwertyuiopasdfghjklzxcvbnm';
|
||||
var ret = '';
|
||||
for (var i=0;i<30;i++){
|
||||
var j = parseInt(Math.random() * vv.length);
|
||||
ret = ret + vv[j];
|
||||
}
|
||||
console.log('uuid() return', ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
bricks.deviceid = function(appname){
|
||||
@ -124,6 +135,9 @@ bricks.widgetBuild = async function(desc, widget, data){
|
||||
var klassname = desc.widgettype;
|
||||
var base_url = widget.baseURI;
|
||||
while (klassname == 'urlwidget'){
|
||||
if (data){
|
||||
desc = bricks.apply_data(desc, data);
|
||||
}
|
||||
let url = bricks.absurl(desc.options.url, widget);
|
||||
base_url = url;
|
||||
let method = desc.options.method || 'GET';
|
||||
@ -137,14 +151,24 @@ bricks.widgetBuild = async function(desc, widget, data){
|
||||
if (data){
|
||||
desc = bricks.apply_data(desc, data);
|
||||
}
|
||||
if (!desc.widgettype){
|
||||
console.log('widgettype is null', desc);
|
||||
return null;
|
||||
}
|
||||
let klass = bricks.Factory.get(desc.widgettype);
|
||||
if (! klass){
|
||||
bricks.debug('widgetBuild():',desc.widgettype, 'not registered', bricks.Factory.widgets_kw);
|
||||
console.log('widgetBuild():',
|
||||
desc.widgettype,
|
||||
'not registered',
|
||||
bricks.Factory.widgets_kw);
|
||||
return null;
|
||||
}
|
||||
var options = desc.options || {};
|
||||
options.baseURI = base_url;
|
||||
let w = new klass(options);
|
||||
if (! w){
|
||||
console.log('w is null');
|
||||
}
|
||||
if (desc.id){
|
||||
w.set_id(desc.id);
|
||||
}
|
||||
@ -204,14 +228,34 @@ bricks.universal_handler = async function(from_widget, widget, desc, event){
|
||||
'desc=', desc,
|
||||
event);
|
||||
}
|
||||
bricks.default_popup = function(opts){
|
||||
var popts = bricks.get_popup_default_options();
|
||||
bricks.extend(popts, opts);
|
||||
return new bricks.Popup(popts);
|
||||
}
|
||||
bricks.default_popupwindow = function(opts){
|
||||
var popts = bricks.get_popupwindow_default_options();
|
||||
bricks.extend(popts, opts);
|
||||
return new bricks.PopupWindow(popts);
|
||||
}
|
||||
bricks.buildEventHandler = async function(w, desc, event){
|
||||
var target = bricks.getWidgetById(desc.target, w);
|
||||
var target;
|
||||
if (desc.target == 'Popup'){
|
||||
target = bricks.default_popup(desc.popup_options || {});
|
||||
} else if (desc.target == 'PopupWindow') {
|
||||
target = bricks.default_popupwindow(desc.popup_options || {});
|
||||
} else if ( desc.target instanceof bricks.JsWidget ) {
|
||||
target = desc.target;
|
||||
} else {
|
||||
target = bricks.getWidgetById(desc.target, w);
|
||||
}
|
||||
if (! target){
|
||||
bricks.debug('target miss desc=', desc, 'w=', w);
|
||||
return null
|
||||
}
|
||||
var rtdata = {};
|
||||
|
||||
desc.event_params = event.params || {} ;
|
||||
desc.event = event;
|
||||
if (desc.rtdata) rtdata = desc.rtdata;
|
||||
else if (desc.datawidget){
|
||||
var data_desc = {
|
||||
@ -222,9 +266,6 @@ bricks.buildEventHandler = async function(w, desc, event){
|
||||
}
|
||||
rtdata = await bricks.getRealtimeData(w, data_desc);
|
||||
}
|
||||
if (typeof event.params == typeof {}){
|
||||
rtdata = bricks.extend(rtdata, event.params);
|
||||
}
|
||||
switch (desc.actiontype){
|
||||
case 'urlwidget':
|
||||
return bricks.buildUrlwidgetHandler(w, target, rtdata, desc);
|
||||
@ -270,70 +311,80 @@ bricks.getRealtimeData = async function(w, desc){
|
||||
return null;
|
||||
}
|
||||
|
||||
var _buildWidget = async function(from_widget, target, mode, options){
|
||||
bricks.debug('target=', target, 'mode=', mode, 'options=', options);
|
||||
var w = await (bricks.widgetBuild(options, from_widget));
|
||||
if (!w){
|
||||
bricks.debug('options=', options, 'widgetBuild() failed');
|
||||
return;
|
||||
}
|
||||
var _buildWidget = async function(from_widget, target, mode, options, desc){
|
||||
bricks.debug('target=', target, 'mode=', mode, 'options=', options);
|
||||
var w = await (bricks.widgetBuild(options, from_widget));
|
||||
if (!w){
|
||||
bricks.debug('options=', options, 'widgetBuild() failed');
|
||||
return;
|
||||
}
|
||||
|
||||
if (w.parent) return;
|
||||
|
||||
if (mode == 'replace'){
|
||||
target.clear_widgets();
|
||||
target.add_widget(w);
|
||||
} else if (mode == 'insert'){
|
||||
target.add_widget(w, 0);
|
||||
} else {
|
||||
target.add_widget(w);
|
||||
if (w.parent) {
|
||||
if (target instanceof bricks.Popup || target instanceof bricks.PopupWindow){
|
||||
target.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (target instanceof bricks.Popup || target instanceof bricks.PopupWindow) {
|
||||
if (! target.parent){
|
||||
bricks.app.add_widget(target);
|
||||
}
|
||||
console.log('target=', target);
|
||||
if (desc.popup_options.eventpos){
|
||||
target.bind('opened', bricks.relocate_by_eventpos.bind(null, desc.event, target));
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == 'replace'){
|
||||
target.clear_widgets();
|
||||
target.add_widget(w);
|
||||
} else if (mode == 'insert'){
|
||||
target.add_widget(w, 0);
|
||||
} else {
|
||||
target.add_widget(w);
|
||||
}
|
||||
if (target instanceof bricks.Popup || target instanceof bricks.PopupWindow) {
|
||||
target.open();
|
||||
}
|
||||
}
|
||||
|
||||
bricks.buildUrlwidgetHandler = function(w, target, rtdata, desc){
|
||||
var f = async function(target, mode, options){
|
||||
bricks.debug('target=', target, 'mode=', mode, 'options=', options);
|
||||
var w = await (bricks.widgetBuild(options, w));
|
||||
if (!w){
|
||||
bricks.debug('options=', options, 'widgetBuild() failed');
|
||||
return;
|
||||
}
|
||||
if (mode == 'replace'){
|
||||
target.clear_widgets();
|
||||
target.add_widget(w);
|
||||
} else if (mode == 'insert'){
|
||||
target.add_widget(w, 0);
|
||||
} else {
|
||||
target.add_widget(w);
|
||||
}
|
||||
}
|
||||
var options = objcopy(desc.options||{});
|
||||
var params = options.params || {};
|
||||
options = bricks.apply_data(options, rtdata);
|
||||
options.params = bricks.extend(params, rtdata);
|
||||
if (desc.event_params instanceof FormData){
|
||||
var params = desc.event_params;
|
||||
for ( const [key, value] of Object.entries(rtdata)){
|
||||
params.append(key, value);
|
||||
}
|
||||
options = bricks.apply_data(options, rtdata);
|
||||
for ( const [key, value] of Object.entries(options.params||{})){
|
||||
params.append(key, value);
|
||||
}
|
||||
options.params = params;
|
||||
options.method = "POST";
|
||||
} else {
|
||||
rtdata = bricks.extend(rtdata, desc.event_params);
|
||||
options = bricks.apply_data(options, rtdata);
|
||||
if (desc.params_mapping){
|
||||
rtdata = bricks.map(rtdata, desc.params_mapping.mapping, desc.params_mapping.need_others);
|
||||
}
|
||||
options.params = bricks.extend(params, rtdata);
|
||||
}
|
||||
|
||||
var opts = {
|
||||
"widgettype":"urlwidget",
|
||||
"options":options
|
||||
}
|
||||
return _buildWidget.bind(w, target, target, desc.mode || 'replace', opts);
|
||||
return _buildWidget.bind(null, w, target, desc.mode || 'replace', opts, desc);
|
||||
}
|
||||
bricks.buildBricksHandler = function(w, target, rtdata, desc){
|
||||
var f = async function(target, mode, options){
|
||||
bricks.debug('target=', target, 'mode=', mode, 'options=', options);
|
||||
var w = await (bricks.widgetBuild(options, wa));
|
||||
if (!w){
|
||||
bricks.debug('options=', options, 'widgetBuild() failed');
|
||||
return;
|
||||
}
|
||||
if (mode == 'replace'){
|
||||
target.clear_widgets();
|
||||
}
|
||||
target.add_widget(w);
|
||||
}
|
||||
var options = objcopy(desc.options||{});
|
||||
rtdata = bricks.extend(rtdata, inputdata2dic(desc.event_params));
|
||||
if (desc.params_mapping){
|
||||
rtdata = bricks.map(rtdata, desc.params_mapping.mapping, desc.params_mapping.need_others);
|
||||
}
|
||||
options = bricks.apply_data(options, rtdata);
|
||||
return _buildWidget.bind(w, target, target, desc.mode || 'replace', options);
|
||||
return _buildWidget.bind(w, target, target, desc.mode || 'replace', options, desc);
|
||||
}
|
||||
bricks.buildRegisterFunctionHandler = function(w, target, rtdata, desc){
|
||||
var f = bricks.RF.get(desc.rfname);
|
||||
@ -341,6 +392,9 @@ bricks.buildRegisterFunctionHandler = function(w, target, rtdata, desc){
|
||||
bricks.debug('rfname:', desc.rfname, 'not registed', desc);
|
||||
return null;
|
||||
}
|
||||
if (desc.params_mapping){
|
||||
rtdata = bricks.map(rtdata, desc.params_mapping.mapping, desc.params_mapping.need_others);
|
||||
}
|
||||
var params = {};
|
||||
if (desc.params){
|
||||
bricks.extend(params, desc.params);
|
||||
@ -348,6 +402,7 @@ bricks.buildRegisterFunctionHandler = function(w, target, rtdata, desc){
|
||||
if (rtdata){
|
||||
bricks.extend(params, rtdata);
|
||||
}
|
||||
bricks.extend(params, inputdata2dic(desc.event_params));
|
||||
params = bricks.apply_data(params, rtdata);
|
||||
return f.bind(target, params);
|
||||
}
|
||||
@ -360,6 +415,10 @@ bricks.buildMethodHandler = function(w, target, rtdata, desc){
|
||||
var params = {};
|
||||
bricks.extend(params, desc.params)
|
||||
bricks.extend(params, rtdata);
|
||||
bricks.extend(params, inputdata2dic(desc.event_params));
|
||||
if (desc.params_mapping){
|
||||
rtdata = bricks.map(rtdata, desc.params_mapping.mapping, desc.params_mapping.need_others);
|
||||
}
|
||||
params = bricks.apply_data(params, rtdata);
|
||||
return f.bind(target, params);
|
||||
}
|
||||
@ -367,6 +426,10 @@ bricks.buildScriptHandler = function(w, target, rtdata, desc){
|
||||
var params = {};
|
||||
bricks.extend(params, desc.params)
|
||||
bricks.extend(params, rtdata);
|
||||
bricks.extend(params, inputdata2dic(desc.event_params));
|
||||
if (desc.params_mapping){
|
||||
rtdata = bricks.map(rtdata, desc.params_mapping.mapping, desc.params_mapping.need_others);
|
||||
}
|
||||
params = bricks.apply_data(params, rtdata);
|
||||
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
|
||||
var f = new AsyncFunction('params', 'event', desc.script);
|
||||
@ -380,6 +443,7 @@ bricks.buildDispatchEventHandler = function(w, target, rtdata, desc){
|
||||
var params = {};
|
||||
bricks.extend(params, desc.params)
|
||||
bricks.extend(params, rtdata);
|
||||
bricks.extend(params, inputdata2dic(desc.event_params));
|
||||
params = bricks.apply_data(params, rtdata);
|
||||
return f.bind(target, desc.dispatch_event, params);
|
||||
}
|
||||
@ -406,7 +470,7 @@ bricks.getWidgetById = function(id, from_widget){
|
||||
el = bricks.app.root.dom_element;
|
||||
continue;
|
||||
}
|
||||
if (ids[i]=='app'){
|
||||
if (ids[i]=='app' || ids[i] == 'body'){
|
||||
return bricks.app;
|
||||
}
|
||||
if (ids[i] == 'window'){
|
||||
@ -487,12 +551,38 @@ bricks.App = class extends bricks.Layout {
|
||||
this._Height = this.dom_element.offsetHeight;
|
||||
this.video_stream = null;
|
||||
this.audio_stream = null;
|
||||
this.video_devices = null
|
||||
this.vpos = null;
|
||||
document.addEventListener('keydown', this.key_down_action.bind(this));
|
||||
this.screen_orient = window.screen.orientation.type;
|
||||
window.screen.orientation.addEventListener('change', () => {
|
||||
this.screen_orient = window.screen.orientation.type;
|
||||
this.bind('orient_changed', this.screen_orient);
|
||||
});
|
||||
}
|
||||
async start_camera() {
|
||||
if (this.video_stream) return;
|
||||
async getCameras() {
|
||||
try {
|
||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||
this.video_devices = devices.filter(device => device.kind === 'videoinput');
|
||||
} catch (error) {
|
||||
console.error('获取摄像头数量出错:', error);
|
||||
}
|
||||
}
|
||||
async start_camera(vpos) {
|
||||
if (typeof(vpos) == 'undefined') vpos = 0;
|
||||
if (this.video_devices === null){
|
||||
await this.getCameras();
|
||||
}
|
||||
if (vpos == this.vpos) return;
|
||||
this.vpos = vpos;
|
||||
if (this.video_stream){
|
||||
this.video_stream.getTracks().forEach(track => {
|
||||
track.stop();
|
||||
});
|
||||
}
|
||||
if (navigator.mediaDevices.getUserMedia) {
|
||||
this.video_stream = await navigator.mediaDevices.getUserMedia({ video: true });
|
||||
var x = { deviceId: this.video_devices[vpos].deviceId };
|
||||
this.video_stream = await navigator.mediaDevices.getUserMedia({ video: x });
|
||||
} else {
|
||||
console.log("Webcam access is not supported in this browser.");
|
||||
}
|
||||
|
@ -6,9 +6,11 @@ SOURCES=" page_data_loader.js factory.js uitypesdef.js utils.js uitype.js \
|
||||
tree.js multiple_state_image.js dynamiccolumn.js form.js message.js conform.js \
|
||||
paging.js datagrid.js iframe.js cols.js echartsext.js \
|
||||
floaticonbar.js miniform.js wterm.js dynamicaccordion.js \
|
||||
binstreaming.js streaming_audio.js vadtext.js rtc.js \
|
||||
llm_dialog.js llm.js websocket.js datarow.js tabular.js \
|
||||
line.js pie.js bar.js gobang.js "
|
||||
binstreaming.js streaming_audio.js vadtext.js rtc.js docxviewer.js \
|
||||
llm_dialog.js llm.js websocket.js datarow.js tabular.js continueaudio.js \
|
||||
line.js pie.js bar.js gobang.js period.js iconbarpage.js \
|
||||
keypress.js asr.js webspeech.js countdown.js progressbar.js \
|
||||
qaframe.js svg.js "
|
||||
echo ${SOURCES}
|
||||
cat ${SOURCES} > ../dist/bricks.js
|
||||
# uglifyjs --compress --mangle -- ../dist/bricks.js > ../dist/bricks.min.js
|
||||
@ -38,4 +40,5 @@ cp -a ../examples/* ../dist/examples
|
||||
cp -a ../3parties/* ../dist/3parties
|
||||
cp -a ../docs/* ../dist/docs
|
||||
cp *.tmpl ../dist
|
||||
cp -a ../dist /tmp
|
||||
echo "Finished ..."
|
||||
|
@ -7,42 +7,75 @@ bricks.Camera = class extends bricks.Popup {
|
||||
*/
|
||||
constructor(opts){
|
||||
opts.fps = opts.fps || 60;
|
||||
opts.auto_dismiss = false;
|
||||
super(opts);
|
||||
this.recordedChunks = [];
|
||||
this.mediaRecorder = null;
|
||||
this.stream = null;
|
||||
this.video = document.createElement('video');
|
||||
var filler = new bricks.Filler({});
|
||||
var hbox = new bricks.HBox({
|
||||
cheight:2
|
||||
cheight:3
|
||||
});
|
||||
this.cur_camera_id = 0;
|
||||
this.add_widget(filler);
|
||||
this.add_widget(hbox);
|
||||
var shot_btn = new bricks.Icon({
|
||||
url:bricks_resource('imgs/camera.png'),
|
||||
margin: '10px',
|
||||
tip:'Take a picture',
|
||||
rate:2.5
|
||||
});
|
||||
var switch_btn = new bricks.Icon({
|
||||
url:bricks_resource('imgs/switch-camera.png'),
|
||||
tip:'switch camera',
|
||||
margin: '10px',
|
||||
rate:1.5
|
||||
});
|
||||
var del_btn = new bricks.Icon({
|
||||
url:bricks_resource('imgs/delete.png'),
|
||||
tip:'canel it',
|
||||
margin: '10px',
|
||||
rate:1.5
|
||||
})
|
||||
del_btn.bind('click', this.dismiss.bind(this));
|
||||
shot_btn.bind('click', this.take_picture.bind(this));
|
||||
switch_btn.bind('click', this.switch_camera.bind(this, switch_btn));
|
||||
this.imgw = new bricks.Image({
|
||||
width:'100%'
|
||||
});
|
||||
hbox.add_widget(switch_btn);
|
||||
hbox.add_widget(shot_btn);
|
||||
hbox.add_widget(new bricks.Filler({}));
|
||||
hbox.add_widget(del_btn);
|
||||
filler.add_widget(this.imgw);
|
||||
this.task_period = 1 / this.fps;
|
||||
schedule_once(this.startCamera.bind(this), 0.3);
|
||||
schedule_once(this.startCamera.bind(this), 0.1);
|
||||
}
|
||||
async startCamera() {
|
||||
await bricks.app.start_camera();
|
||||
async switch_camera(btn, event){
|
||||
if (bricks.app.video_devices.length < 2){
|
||||
btn.disabled(true);
|
||||
return;
|
||||
}
|
||||
var vpos = bricks.app.vpos;
|
||||
vpos += 1;
|
||||
if (vpos >= bricks.app.video_devices.length){
|
||||
vpos = 0;
|
||||
}
|
||||
this.startCamera(vpos);
|
||||
}
|
||||
async startCamera(vpos) {
|
||||
await bricks.app.start_camera(vpos);
|
||||
this.stream = bricks.app.video_stream;
|
||||
this.video.srcObject = this.stream;
|
||||
this.video.play();
|
||||
this.show_cnt = 1;
|
||||
this.task = schedule_once(this.show_picture.bind(this), this.task_period);
|
||||
}
|
||||
show_picture(){
|
||||
if (this.task_period == 0){
|
||||
return;
|
||||
}
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.height = this.video.videoHeight;
|
||||
canvas.width = this.video.videoWidth;
|
||||
@ -50,15 +83,51 @@ bricks.Camera = class extends bricks.Popup {
|
||||
context.drawImage(this.video, 0, 0);
|
||||
this.imgw.set_url(canvas.toDataURL('image/jpeg'));
|
||||
this.task = schedule_once(this.show_picture.bind(this), this.task_period);
|
||||
this.show_cnt += 1;
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
take_picture(){
|
||||
if (this.task){
|
||||
this.task.cancel();
|
||||
this.task = null;
|
||||
}
|
||||
=======
|
||||
videorecorder_start(){
|
||||
if (!this.stream) {
|
||||
throw new Error('Media stream is not initialized. Call init() first.');
|
||||
}
|
||||
this.recordedChunks = [];
|
||||
this.mediaRecorder = new MediaRecorder(this.stream);
|
||||
this.mediaRecorder.ondataavailable = (event) => {
|
||||
if (event.data.size > 0) {
|
||||
this.recordedChunks.push(event.data);
|
||||
}
|
||||
};
|
||||
this.mediaRecorder.start();
|
||||
}
|
||||
videorecorder_stop(){
|
||||
return new Promise((resolve) => {
|
||||
this.mediaRecorder.onstop = () => {
|
||||
const blob = new Blob(this.recordedChunks, { type: 'video/webm' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
resolve({ blob, url });
|
||||
};
|
||||
this.mediaRecorder.stop();
|
||||
this.mediaRecorder = null;
|
||||
this.recordedChunks = [];
|
||||
});
|
||||
}
|
||||
take_picture(event){
|
||||
event.stopPropagation();
|
||||
if (this.task){
|
||||
task.cancel();
|
||||
this.task = null;
|
||||
}
|
||||
this.task_period = 0;
|
||||
this.task = null;
|
||||
>>>>>>> 51416a085b5aa99df9f8edf9989fdc1b6306724c
|
||||
var d = this.imgw.base64();
|
||||
this.dispatch('shot', d);
|
||||
// Create a blob from the canvas data URL
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,7 @@ bricks.Cols = class extends bricks.VBox {
|
||||
}
|
||||
|
||||
async handle_click(rw, event){
|
||||
event.stopPropagation();
|
||||
var orev = null;
|
||||
if (this.select_record){
|
||||
orev = this.select_record;
|
||||
@ -64,6 +65,8 @@ bricks.Cols = class extends bricks.VBox {
|
||||
}
|
||||
this.select_record = rw;
|
||||
this.select_record.set_css('selected_record');
|
||||
console.log('record data=', rw.user_data);
|
||||
this.dispatch('record_click', rw.user_data);
|
||||
}
|
||||
async dataHandle(d){
|
||||
var data = d.rows;
|
||||
@ -71,18 +74,20 @@ bricks.Cols = class extends bricks.VBox {
|
||||
if (!data){
|
||||
return;
|
||||
}
|
||||
if (! this.loader.is_max_page(page)){
|
||||
var rev = ! this.loader.is_max_page(page);
|
||||
if (rev){
|
||||
data.reverse();
|
||||
}
|
||||
for (var i=0;i<data.length;i++){
|
||||
var d = data[i];
|
||||
var w = await bricks.widgetBuild(this.record_view, this.main, d);
|
||||
var r = data[i];
|
||||
var w = await bricks.widgetBuild(this.record_view, this.main, r);
|
||||
w.user_data = r;
|
||||
w.bind('click', this.handle_click.bind(this, w));
|
||||
w.set_attribute('data-page', page);
|
||||
if (this.loader.is_max_page(page)){
|
||||
this.main.add_widget(w);
|
||||
} else {
|
||||
if (rev){
|
||||
this.main.add_widget(w, 0);
|
||||
} else {
|
||||
this.main.add_widget(w);
|
||||
}
|
||||
}
|
||||
if (d.delete_page){
|
||||
@ -93,7 +98,7 @@ bricks.Cols = class extends bricks.VBox {
|
||||
var items = this.dom_element.querySelectorAll('[data-page="' + page + '"]');
|
||||
for (var i=0;i<items.length;i++) {
|
||||
var w = items[i].bricks_widget;
|
||||
this.container.remove_widget(w);
|
||||
this.main.remove_widget(w);
|
||||
}
|
||||
}
|
||||
async load_first_page(params){
|
||||
@ -112,14 +117,14 @@ bricks.Cols = class extends bricks.VBox {
|
||||
this.main = new bricks.DynamicColumn({
|
||||
width:"100%",
|
||||
col_cwidth:this.col_cwidth,
|
||||
mobile_cols:this.mobile_cols,
|
||||
mobile_cols:2});
|
||||
mobile_cols:this.mobile_cols || 2
|
||||
});
|
||||
this.container.add_widget(this.main);
|
||||
var d = await this.loader.loadData(p);
|
||||
if (d){
|
||||
this.dataHandle(d);
|
||||
var total = this.container.dom_element.scrollHeight - this.container.dom_element.clientHeight;
|
||||
this.container.dom_element.scrollTop = d.pos_rate * total;
|
||||
// this.container.dom_element.scrollTop = d.pos_rate * total;
|
||||
} else {
|
||||
bricks.debug(this.loader, 'load previous page error');
|
||||
}
|
||||
@ -163,12 +168,12 @@ bricks.Cols = class extends bricks.VBox {
|
||||
if (d){
|
||||
this.dataHandle(d);
|
||||
var total = this.container.dom_element.scrollHeight - this.container.dom_element.clientHeight;
|
||||
this.container.dom_element.scrollTop = d.pos_rate * total;
|
||||
// this.container.dom_element.scrollTop = d.pos_rate * total;
|
||||
} else {
|
||||
bricks.debug(this.loader, 'load next page error');
|
||||
console.log(this.loader, 'load next page error');
|
||||
}
|
||||
} catch (e){
|
||||
bricks.debug('error happened', e);
|
||||
console.log('error happened', e);
|
||||
}
|
||||
this.loading = false;
|
||||
running.dismiss();
|
||||
|
@ -2,6 +2,7 @@ var bricks = window.bricks || {};
|
||||
bricks.Conform = class extends bricks.PopupWindow {
|
||||
constructor(opts){
|
||||
opts.timeout = 0;
|
||||
opts.auto_open = true;
|
||||
super(opts);
|
||||
this.create_conform();
|
||||
}
|
||||
|
133
bricks/continueaudio.js
Normal file
@ -0,0 +1,133 @@
|
||||
var bricks = window.bricks || {};
|
||||
|
||||
bricks.ContinueAudioPlayer = class extends bricks.VBox {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this.ws_url = options.ws_url;
|
||||
this.options = options || {};
|
||||
this.audioContext = null;
|
||||
this.gainNode = null;
|
||||
this.nextStartTime = 0;
|
||||
this.started = false;
|
||||
this.muted = false;
|
||||
this.volume = 1.0;
|
||||
|
||||
this.initAudioContext();
|
||||
}
|
||||
|
||||
initAudioContext() {
|
||||
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
this.gainNode = this.audioContext.createGain();
|
||||
this.gainNode.gain.value = this.volume;
|
||||
this.gainNode.connect(this.audioContext.destination);
|
||||
|
||||
this.nextStartTime = this.audioContext.currentTime;
|
||||
this.started = true;
|
||||
}
|
||||
|
||||
base64ToArrayBuffer(base64) {
|
||||
const binaryStr = atob(base64);
|
||||
const len = binaryStr.length;
|
||||
const bytes = new Uint8Array(len);
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binaryStr.charCodeAt(i);
|
||||
}
|
||||
return bytes.buffer;
|
||||
}
|
||||
|
||||
handleAudioTrack(arrayBuffer) {
|
||||
this.audioContext.decodeAudioData(arrayBuffer).then(decodedBuffer => {
|
||||
const source = this.audioContext.createBufferSource();
|
||||
source.buffer = decodedBuffer;
|
||||
source.connect(this.gainNode);
|
||||
|
||||
const startTime = Math.max(this.audioContext.currentTime, this.nextStartTime);
|
||||
source.start(startTime);
|
||||
|
||||
this.nextStartTime = startTime + decodedBuffer.duration;
|
||||
|
||||
if (typeof this.options.onStart === 'function') {
|
||||
this.options.onStart();
|
||||
}
|
||||
|
||||
source.onended = () => {
|
||||
if (typeof this.options.onEnd === 'function') {
|
||||
this.options.onEnd();
|
||||
}
|
||||
};
|
||||
}).catch(err => {
|
||||
console.error("Error decoding audio data:", err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ⏸ 暂停播放
|
||||
*/
|
||||
pauseAudio() {
|
||||
if (this.audioContext && this.audioContext.state === 'running') {
|
||||
this.audioContext.suspend().then(() => {
|
||||
if (typeof this.options.onPause === 'function') {
|
||||
this.options.onPause();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ▶️ 恢复播放
|
||||
*/
|
||||
resumeAudio() {
|
||||
if (this.audioContext && this.audioContext.state === 'suspended') {
|
||||
this.audioContext.resume().then(() => {
|
||||
if (typeof this.options.onResume === 'function') {
|
||||
this.options.onResume();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔁 重新开始播放
|
||||
*/
|
||||
restart() {
|
||||
console.log("Restarting audio playback...");
|
||||
if (this.audioContext && this.audioContext.state !== 'closed') {
|
||||
this.audioContext.close().then(() => {
|
||||
this.initAudioContext();
|
||||
});
|
||||
} else {
|
||||
this.initAudioContext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔊 设置音量(0.0 - 1.0)
|
||||
*/
|
||||
setVolume(value) {
|
||||
this.volume = Math.max(0, Math.min(1, value));
|
||||
if (this.gainNode) {
|
||||
this.gainNode.gain.value = this.muted ? 0 : this.volume;
|
||||
}
|
||||
this.emit('onVolumeChange', this.volume);
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔇 切换静音
|
||||
*/
|
||||
toggleMute() {
|
||||
this.muted = !this.muted;
|
||||
this.gainNode.gain.value = this.muted ? 0 : this.volume;
|
||||
this.emit('onVolumeChange', this.muted ? 0 : this.volume);
|
||||
}
|
||||
|
||||
/**
|
||||
* 🧩 触发事件回调
|
||||
*/
|
||||
emit(eventName, ...args) {
|
||||
if (typeof this.options[eventName] === 'function') {
|
||||
this.options[eventName](...args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('ContinueAudioPlayer', bricks.ContinueAudioPlayer);
|
103
bricks/countdown.js
Normal file
@ -0,0 +1,103 @@
|
||||
var bricks = window.bricks || {};
|
||||
|
||||
bricks.formatTime = function(seconds) {
|
||||
let hrs = Math.floor(seconds / 3600);
|
||||
let mins = Math.floor((seconds % 3600) / 60);
|
||||
let secs = seconds % 60;
|
||||
|
||||
return [
|
||||
hrs.toString().padStart(2, '0'),
|
||||
mins.toString().padStart(2, '0'),
|
||||
secs.toString().padStart(2, '0')
|
||||
].join(':');
|
||||
}
|
||||
bricks.TimePassed = class extends bricks.VBox {
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.seconds = 0;
|
||||
var t = bricks.formatTime(this.seconds);
|
||||
this.text_w = new bricks.Text({
|
||||
text:this.t,
|
||||
rate:this.text_rate
|
||||
});
|
||||
this.add_widget(this.text_w);
|
||||
}
|
||||
start(){
|
||||
this.task = schedule_once(this.add_one_second.bind(this));
|
||||
}
|
||||
|
||||
add_one_second(){
|
||||
this.seconds += 1;
|
||||
var t = bricks.formatTime(this.seconds);
|
||||
this.text_w.set_text(t);
|
||||
this.task = schedule_once(this.add_one_second.bind(this));
|
||||
}
|
||||
stop(){
|
||||
this.task.cancel();
|
||||
this.task = null;
|
||||
}
|
||||
}
|
||||
bricks.Countdown = class extends bricks.VBox {
|
||||
/*
|
||||
options:
|
||||
limit_time: 01:00:00
|
||||
text_rate:
|
||||
event:
|
||||
timeout
|
||||
timeout event is fired after the countdown time is over.
|
||||
method:
|
||||
start
|
||||
start method is to start the countdown, step is 1 secord
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
var parts = opts.limit_time.split(':');
|
||||
var hours, minutes, seconds;
|
||||
switch(parts.length){
|
||||
case 0:
|
||||
hours = 0;
|
||||
minutes = 0;
|
||||
seconds = 0;
|
||||
break;
|
||||
case 1:
|
||||
hours = 0;
|
||||
minutes = 0;
|
||||
seconds = parseInt(parts[0])
|
||||
break;
|
||||
case 2:
|
||||
hours = 0;
|
||||
minutes = 0;
|
||||
seconds = parseInt(parts[0])
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
hours = parseInt(parts[0]);
|
||||
minutes = parseInt(parts[1]);
|
||||
seconds = parseInt(parts[2])
|
||||
break;
|
||||
}
|
||||
this.seconds = hours * 3600 + minutes * 60 + seconds;
|
||||
this.text_w = new bricks.Text({
|
||||
text:this.limit_time,
|
||||
rate:this.text_rate
|
||||
});
|
||||
this.add_widget(this.text_w);
|
||||
}
|
||||
start(){
|
||||
schedule_once(this.time_down_second.bind(this), 1)
|
||||
}
|
||||
time_down_second(){
|
||||
if (this.seconds < 1){
|
||||
this.dispatch('timeout');
|
||||
return;
|
||||
}
|
||||
var h, m, s;
|
||||
this.seconds -= 1;
|
||||
var ts = bricks.formatTime(this.seconds);
|
||||
this.text_w.set_text(ts);
|
||||
schedule_once(this.time_down_second.bind(this), 1)
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('Countdown', bricks.Countdown);
|
||||
bricks.Factory.register('TimePassed', bricks.TimePassed);
|
@ -7,6 +7,10 @@ body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow-x: auto; /* 允许内容超出容器显示 */
|
||||
background-color: #b5e5e5;
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box!important;
|
||||
}
|
||||
@ -37,7 +41,7 @@ hr {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
.clickable {
|
||||
color: #80ff88;
|
||||
color: #40cc40;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@ -86,6 +90,10 @@ hr {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.titlebar {
|
||||
background-color: #d8d8c8;
|
||||
}
|
||||
|
||||
.toppopup {
|
||||
box-shadow: 10px 5px 10px #000, 0 -5px 5px #fff;
|
||||
}
|
||||
@ -414,6 +422,7 @@ hr {
|
||||
margin-left: 5px;
|
||||
margin-right: auto;
|
||||
margin-bottom: 10px;
|
||||
padding: 3px;
|
||||
background-color:#fefedd;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 0;
|
||||
@ -436,3 +445,19 @@ hr {
|
||||
.llm_title {
|
||||
background-color:#eeeeee;
|
||||
}
|
||||
.progress-container {
|
||||
width: 80%;
|
||||
background-color: #ddd;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.progress-bar {
|
||||
height: 30px;
|
||||
width: 0%;
|
||||
background-color: #4CAF50;
|
||||
text-align: center;
|
||||
color: white;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
|
@ -29,13 +29,17 @@ bricks.DataRow = class extends bricks.HBox {
|
||||
this.render(false);
|
||||
}
|
||||
render(header){
|
||||
this.build_toolbar(header);
|
||||
// this.build_toolbar(header);
|
||||
if (this.checkField){
|
||||
var w;
|
||||
if (header){
|
||||
w = new bricks.BlankIcon({});
|
||||
} else {
|
||||
w = new bricks.UiCheck({name:this.checkField,value:this.user_data[this.checkField]});
|
||||
var v = 0
|
||||
if (this.user_data){
|
||||
v = this.user_data[this.checkField];
|
||||
}
|
||||
w = new bricks.UiCheck({name:this.checkField,value:v});
|
||||
w.bind('changed', this.get_check_state.bind(this));
|
||||
}
|
||||
this.add_widget(w);
|
||||
|
@ -138,7 +138,7 @@ bricks.DataViewer = class extends bricks.VBox {
|
||||
}
|
||||
if (this.toolbar){
|
||||
this.toolbar.tools.forEach(t => {
|
||||
if (! edit_names.incloudes(t.name)){
|
||||
if (! edit_names.includes(t.name)){
|
||||
tbdesc.tools.push(t);
|
||||
}
|
||||
});
|
||||
@ -168,12 +168,13 @@ bricks.DataViewer = class extends bricks.VBox {
|
||||
this.delete_record(this.select_row);
|
||||
return;
|
||||
}
|
||||
var d = {
|
||||
tabular:this,
|
||||
row:this.select_row,
|
||||
data:row.user_data
|
||||
var data = null;
|
||||
if (this.select_row){
|
||||
var r = this.select_row;
|
||||
var data = r.user_data;
|
||||
}
|
||||
this.dispathc(t.name. d);
|
||||
console.log(tdesc.name, 'clicked ==================', tdesc.name, data)
|
||||
this.dispatch(tdesc.name, data);
|
||||
}
|
||||
get_edit_fields(){
|
||||
var fs = this.row_options.fields;
|
||||
@ -193,7 +194,8 @@ bricks.DataViewer = class extends bricks.VBox {
|
||||
this.dispatch('row_check_changed', event.params.user_data);
|
||||
}
|
||||
async renew_record_view(form, row){
|
||||
var d = form.getValue();
|
||||
var d = form._getValue();
|
||||
d = form._getValue();
|
||||
var record = bricks.extend(row.user_data, d);
|
||||
row.renew(record);
|
||||
}
|
||||
@ -324,8 +326,8 @@ bricks.DataViewer = class extends bricks.VBox {
|
||||
var d = await this.loader.loadNextPage();
|
||||
if (d){
|
||||
this.dataHandle(d);
|
||||
var total = this.scrollpanel.dom_element.scrollHeight - this.scrollpanel.dom_element.clientHeight;
|
||||
this.scrollpanel.dom_element.scrollTop = d.pos_rate * total;
|
||||
// var total = this.scrollpanel.dom_element.scrollHeight - this.scrollpanel.dom_element.clientHeight;
|
||||
// this.scrollpanel.dom_element.scrollTop = d.pos_rate * total;
|
||||
} else {
|
||||
bricks.debug(this.loader, 'load next page error');
|
||||
}
|
||||
|
119
bricks/docxviewer.js
Normal file
@ -0,0 +1,119 @@
|
||||
/* need mammoth module
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.4.2/mammoth.browser.min.js"></script>
|
||||
*/
|
||||
var bricks = window.bricks || {};
|
||||
|
||||
bricks.DOCXviewer = class extends bricks.VBox {
|
||||
/*
|
||||
url:
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.bind('on_parent', this.set_url.bind(this));
|
||||
// schedule_once(this.set_url.bind(this, this.url), 0.2);
|
||||
}
|
||||
async set_url(url){
|
||||
var container = this.dom_element
|
||||
var hab = new bricks.HttpArrayBuffer();
|
||||
var ab = await hab.get(this.url);
|
||||
var result = await mammoth.convertToHtml({ arrayBuffer: ab });
|
||||
container.innerHTML = result.value;
|
||||
}
|
||||
}
|
||||
|
||||
function extractBodyContent(htmlString) {
|
||||
// 正则表达式匹配<body>和</body>之间的内容
|
||||
const regex = /<body[^>]*>([\s\S]*?)<\/body>/i;
|
||||
const matches = htmlString.match(regex);
|
||||
return matches ? matches[1] : null; // 如果匹配到,返回匹配的内容,否则返回null
|
||||
}
|
||||
|
||||
bricks.EXCELviewer = class extends bricks.VBox {
|
||||
constructor(opts){
|
||||
opts.height = "100%",
|
||||
super(opts);
|
||||
this.sheets_w = new bricks.HBox({cheight:3, width:'100%'});
|
||||
this.sheets_w.set_css('scroll');
|
||||
this.cur_sheetname = null;
|
||||
this.container = new bricks.Filler({});
|
||||
this.add_widget(this.container);
|
||||
this.add_widget(this.sheets_w);
|
||||
this.bind('on_parent', this.set_url.bind(this));
|
||||
}
|
||||
async set_url(url){
|
||||
this.sheets_w.clear_widgets();
|
||||
var hab = new bricks.HttpArrayBuffer();
|
||||
var ab = await hab.get(this.url);
|
||||
const data = new Uint8Array(ab);
|
||||
this.workbook = XLSX.read(data, {type: 'array'});
|
||||
this.workbook.SheetNames.forEach((sheetname, index) => {
|
||||
var w = new bricks.Text({text:sheetname, wrap:false});
|
||||
w.set_css('clickable');
|
||||
w.set_style('padding', '10px');
|
||||
w.bind('click', this.show_sheet_by_name.bind(this, sheetname, w));
|
||||
this.sheets_w.add_widget(w);
|
||||
if (index==0){
|
||||
this.show_sheet_by_name(this.workbook.SheetNames[0], w);
|
||||
}
|
||||
});
|
||||
}
|
||||
show_sheet_by_name(sheetname, tw){
|
||||
if (this.cur_sheetname == sheetname) return;
|
||||
this.sheets_w.children.forEach(c => c.set_css('selected', true));
|
||||
tw.set_css('selected');
|
||||
const x = new bricks.VScrollPanel({width: '100%', height: '100%'});
|
||||
const sheet = this.workbook.Sheets[sheetname];
|
||||
// const html = extractBodyContent(XLSX.utils.sheet_to_html(sheet));
|
||||
const html = XLSX.utils.sheet_to_html(sheet);
|
||||
x.dom_element.innerHTML = html;
|
||||
this.container.clear_widgets();
|
||||
this.container.add_widget(x);
|
||||
this.cur_sheetname = sheetname;
|
||||
}
|
||||
}
|
||||
|
||||
bricks.PDFviewer = class extends bricks.VBox {
|
||||
/*
|
||||
url:
|
||||
*/
|
||||
constructor(opts){
|
||||
opts.width = '100%';
|
||||
super(opts);
|
||||
this.bind('on_parent', this.set_url.bind(this));
|
||||
}
|
||||
async set_url(url){
|
||||
var container = this.dom_element
|
||||
var hab = new bricks.HttpArrayBuffer();
|
||||
var ab = await hab.get(this.url);
|
||||
const task = pdfjsLib.getDocument({ data: ab });
|
||||
task.promise.then((pdf) => {
|
||||
this.pdf = pdf;
|
||||
for (let i = 1; i <= this.pdf.numPages; i++) {
|
||||
this.pdf.getPage(i).then((page) => {
|
||||
this.add_page_content(page);
|
||||
});
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log('error');
|
||||
})
|
||||
}
|
||||
add_page_content(page){
|
||||
const scale = 1.5;
|
||||
const viewport = page.getViewport({ scale });
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d');
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
page.render({ canvasContext: context, viewport });
|
||||
var w = new bricks.JsWidget();
|
||||
w.dom_element.appendChild(canvas);
|
||||
this.add_widget(w);
|
||||
if (i < this.pdf.numPages){
|
||||
w = new bricks.Splitter();
|
||||
this.add_widget(w)
|
||||
}
|
||||
}
|
||||
}
|
||||
bricks.Factory.register('DOCXviewer', bricks.DOCXviewer);
|
||||
bricks.Factory.register('EXCELviewer', bricks.EXCELviewer);
|
||||
bricks.Factory.register('PDFviewer', bricks.PDFviewer);
|
@ -36,6 +36,7 @@ bricks.DynamicColumn = class extends bricks.Layout {
|
||||
if (bricks.is_mobile() && width < height){
|
||||
cols = this.mobile_cols;
|
||||
cw = (width - (cols - 1) * gap) / cols;
|
||||
console.log('====mobile==cols=', cols, '====');
|
||||
} else {
|
||||
if (this.col_cwidth){
|
||||
cw = bricks.app.charsize * this.col_cwidth;
|
||||
|
@ -80,7 +80,7 @@ bricks.FormBody = class extends bricks.VScrollPanel {
|
||||
this.form = form;
|
||||
this.name_inputs = {};
|
||||
this.fg = new bricks.FieldGroup({});
|
||||
this.fg.build_fields(form, this, form.opts.fields)
|
||||
this.fg.build_fields(form, this, form.nontextfields)
|
||||
}
|
||||
create(){
|
||||
this.dom_element = this._create('form');
|
||||
@ -176,7 +176,7 @@ bricks.FormBase = class extends bricks.Layout {
|
||||
w.reset();
|
||||
}
|
||||
}
|
||||
getValue(){
|
||||
_getValue(){
|
||||
var data = {};
|
||||
for (var name in this.name_inputs){
|
||||
if (! this.name_inputs.hasOwnProperty(name)){
|
||||
@ -195,6 +195,14 @@ bricks.FormBase = class extends bricks.Layout {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
getValue(){
|
||||
if (this.data) {
|
||||
var ret = this.data;
|
||||
this.data = null;
|
||||
return ret;
|
||||
}
|
||||
return this.get_formdata();
|
||||
}
|
||||
get_formdata(){
|
||||
var data = new FormData();
|
||||
for (var name in this.name_inputs){
|
||||
@ -204,37 +212,35 @@ bricks.FormBase = class extends bricks.Layout {
|
||||
var w = this.name_inputs[name];
|
||||
var d = w.getValue();
|
||||
if (w.required && ( d[name] == '' || d[name] === null)){
|
||||
bricks.debug('data=', data, 'd=', d);
|
||||
new bricks.Error({title:'Requirement', message:'required field must input"' + w.label + '"'})
|
||||
w.focus();
|
||||
return;
|
||||
}
|
||||
if (bricks.need_formdata_fields.includes(w.uitype)){
|
||||
var files = w.get_files();
|
||||
for (var i=0;i<files.length;i++){
|
||||
// data.append(name, w.fileContents[i].body, w.fileContents[i].filename);
|
||||
data.append(name, files[i]);
|
||||
}
|
||||
} else {
|
||||
data.append(name, d[name]);
|
||||
if (d[name] === null){
|
||||
continue;
|
||||
}
|
||||
w.set_formdata(data);
|
||||
}
|
||||
this.data = data;
|
||||
return data;
|
||||
}
|
||||
async validation(){
|
||||
var running = new bricks.Running({target:this});
|
||||
try {
|
||||
var data;
|
||||
data = this.get_formdata();
|
||||
/*
|
||||
if (this.need_formdata){
|
||||
data = this.get_formdata();
|
||||
} else {
|
||||
data = this.getValue();
|
||||
}
|
||||
*/
|
||||
if (! data) {
|
||||
running.dismiss();
|
||||
return;
|
||||
}
|
||||
data = bricks.delete_null_values(data);
|
||||
// data = bricks.delete_null_values(data);
|
||||
this.dispatch('submit', data);
|
||||
if (this.submit_url){
|
||||
var rc = new bricks.HttpResponse();
|
||||
@ -302,8 +308,49 @@ bricks.Form = class extends bricks.FormBase {
|
||||
this.set_css('vcontainer');
|
||||
var filler = new bricks.Filler({});
|
||||
this.add_widget(filler);
|
||||
this.nontextfields = [];
|
||||
this.textfields = [];
|
||||
this.fields.forEach((f) => {
|
||||
if (f.uitype == 'text'){
|
||||
this.textfields.push(f);
|
||||
} else {
|
||||
this.nontextfields.push(f);
|
||||
}
|
||||
});
|
||||
this.body = new bricks.FormBody(this, opts);
|
||||
filler.add_widget(this.body);
|
||||
if (this.textfields.length > 0){
|
||||
var tp;
|
||||
var tp_options = {
|
||||
height: "100%",
|
||||
tab_pos: "top",
|
||||
items:[
|
||||
{
|
||||
"name":"form",
|
||||
"label":"Form",
|
||||
"content":this.body
|
||||
}
|
||||
]
|
||||
};
|
||||
this.textfields.forEach((f) => {
|
||||
var txtw = new bricks.UiText({
|
||||
name:f.name,
|
||||
width:"100%",
|
||||
height:"100%",
|
||||
value:f.value
|
||||
});
|
||||
txtw.bind('active', txtw.focus.bind(txtw));
|
||||
tp_options.items.push({
|
||||
name:f.name,
|
||||
label:f.label,
|
||||
content:txtw
|
||||
});
|
||||
this.name_inputs[f.name] = txtw;
|
||||
});
|
||||
tp = new bricks.TabPanel(tp_options);
|
||||
filler.add_widget(tp);
|
||||
} else {
|
||||
filler.add_widget(this.body);
|
||||
}
|
||||
if (! opts.notoolbar)
|
||||
this.build_toolbar(this);
|
||||
}
|
||||
|
@ -4,31 +4,37 @@
|
||||
<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/3parties/xterm.css" />
|
||||
<link href="/bricks/3parties/video-js.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/bricks/css/bricks.css">
|
||||
<link rel="stylesheet", href="/css/myapp.css">
|
||||
<link rel="stylesheet" href="{{entire_url('/bricks/3parties/xterm.css')}}" />
|
||||
<link href="{{entire_url('/bricks/3parties/video-js.css')}}" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="{{entire_url('/bricks/css/bricks.css')}}">
|
||||
<link rel="stylesheet", href="{{entire_url('/css/myapp.css')}}">
|
||||
</head>
|
||||
<body>
|
||||
<!--
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/js-docx-viewer/dist/css/docxviewer.min.css">
|
||||
<script src="//cdn.bootcdn.net/ajax/libs/eruda/2.3.3/eruda.js"></script>
|
||||
<script>eruda.init();</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@ricky0123/vad-web@0.0.7/dist/bundle.min.js"></script>
|
||||
<script src="https://unpkg.com/docx-js@3.2.0/lib/docx.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.14.305/pdf.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.4.2/mammoth.browser.min.js"></script>
|
||||
-->
|
||||
<script type="text/javascript" src="https://registry.npmmirror.com/echarts/5.5.1/files/dist/echarts.min.js"></script>
|
||||
|
||||
<script src="/bricks/3parties/marked.min.js"></script>
|
||||
<script src="/bricks/3parties/xterm.js"></script>
|
||||
<script src="/bricks/3parties/video.min.js"></script>
|
||||
<script src="{{entire_url('/bricks/3parties/marked.min.js')}}"></script>
|
||||
<script src="{{entire_url('/bricks/3parties/xterm.js')}}"></script>
|
||||
<script src="{{entire_url('/bricks/3parties/xterm-addon-fit.js')}}"></script>
|
||||
<script src="{{entire_url('/bricks/3parties/video.min.js')}}"></script>
|
||||
<!---
|
||||
<link href="https://unpkg.com/video.js@6/dist/video-js.css" rel="stylesheet">
|
||||
<script src="https://unpkg.com/video.js@6/dist/video.js"></script></head>
|
||||
--->
|
||||
|
||||
<script src="/bricks/3parties/recorder.wav.min.js"></script>
|
||||
<script src="/bricks/bricks.js"></script>
|
||||
<script src="/js/myapp.js"></script>
|
||||
<script src="{{entire_url('/bricks/3parties/recorder.wav.min.js')}}"></script>
|
||||
<script src="{{entire_url('/bricks/bricks.js')}}"></script>
|
||||
<script src="{{entire_url('/js/myapp.js')}}"></script>
|
||||
<script>
|
||||
const opts = {
|
||||
"widget":
|
||||
|
55
bricks/iconbarpage.js
Normal file
@ -0,0 +1,55 @@
|
||||
var bricks = window.bricks || {};
|
||||
bricks.IconbarPage = class extends bricks.VBox {
|
||||
/*
|
||||
opts={
|
||||
bar_opts:
|
||||
bar_at: top or bottom
|
||||
}
|
||||
bar_opts:{
|
||||
margin:
|
||||
rate:
|
||||
tools:
|
||||
}
|
||||
tools = [
|
||||
tool, ...
|
||||
]
|
||||
tool = {
|
||||
name:
|
||||
icon:
|
||||
label: optional
|
||||
tip,
|
||||
dynsize
|
||||
rate:
|
||||
context:
|
||||
}
|
||||
*/
|
||||
|
||||
constructor(opts){
|
||||
opts.height = '100%'
|
||||
opts.bar_at = opts.bar_at || 'top';
|
||||
super(opts);
|
||||
var bar = new bricks.IconTextBar(this.bar_opts);
|
||||
this.content = new bricks.Filler({});
|
||||
if (this.bar_at == 'top'){
|
||||
this.add_widget(bar);
|
||||
this.add_widget(this.content);
|
||||
} else {
|
||||
this.add_widget(this.content);
|
||||
this.add_widget(bar);
|
||||
}
|
||||
bar.bind('command', this.command_handle.bind(this))
|
||||
schedule_once(this.show_content.bind(this, this.bar_opts.tools[0]), 0.1);
|
||||
}
|
||||
async command_handle(event){
|
||||
var tool = event.params;
|
||||
await this.show_content(tool);
|
||||
}
|
||||
async show_content(tool){
|
||||
var w = await bricks.widgetBuild(tool.content, this);
|
||||
if (w && ! w.parent) {
|
||||
this.content.add_widget(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('IconbarPage', bricks.IconbarPage);
|
@ -1,6 +1,7 @@
|
||||
var bricks = window.bricks || {};
|
||||
bricks.Iframe = class extends bricks.Layout {
|
||||
constructor(opts){
|
||||
opts.height = opts.height || '100%';
|
||||
super(opts);
|
||||
this.dom_element.src = opts.url;
|
||||
}
|
||||
@ -9,4 +10,12 @@ bricks.Iframe = class extends bricks.Layout {
|
||||
}
|
||||
}
|
||||
|
||||
bricks.NewWindow = class extends bricks.JsWidget {
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
window.open(opts.url);
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('NewWindow', bricks.NewWindow);
|
||||
bricks.Factory.register('Iframe', bricks.Iframe);
|
||||
|
@ -46,7 +46,7 @@ bricks.Image = class extends bricks.JsWidget {
|
||||
|
||||
// 获取画布数据并转换为 base64
|
||||
var dataURL = canvas.toDataURL('image/png'); // 可以根据需要修改图像格式
|
||||
dataURL = this.removeBase64Header(dataURL);
|
||||
// dataURL = this.removeBase64Header(dataURL);
|
||||
return dataURL;
|
||||
}
|
||||
set_url(url){
|
||||
|
1
bricks/imgs/add.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748765357426" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="42094" width="100%" height="100%"><path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="${color}" p-id="42095"></path><path d="M739.555556 568.888889H284.444444c-34.133333 0-56.888889-22.755556-56.888888-56.888889s22.755556-56.888889 56.888888-56.888889h455.111112c34.133333 0 56.888889 22.755556 56.888888 56.888889s-22.755556 56.888889-56.888888 56.888889z" fill="#FFFFFF" p-id="42096"></path><path d="M512 796.444444c-34.133333 0-56.888889-22.755556-56.888889-56.888888V284.444444c0-34.133333 22.755556-56.888889 56.888889-56.888888s56.888889 22.755556 56.888889 56.888888v455.111112c0 34.133333-22.755556 56.888889-56.888889 56.888888z" fill="#FFFFFF" p-id="42097"></path></svg>
|
After Width: | Height: | Size: 819 B |
1
bricks/imgs/app_add.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748765357426" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="42094" width="100%" height="100%"><path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="${color}" p-id="42095"></path><path d="M739.555556 568.888889H284.444444c-34.133333 0-56.888889-22.755556-56.888888-56.888889s22.755556-56.888889 56.888888-56.888889h455.111112c34.133333 0 56.888889 22.755556 56.888888 56.888889s-22.755556 56.888889-56.888888 56.888889z" fill="#FFFFFF" p-id="42096"></path><path d="M512 796.444444c-34.133333 0-56.888889-22.755556-56.888889-56.888888V284.444444c0-34.133333 22.755556-56.888889 56.888889-56.888888s56.888889 22.755556 56.888889 56.888888v455.111112c0 34.133333-22.755556 56.888889-56.888889 56.888888z" fill="#FFFFFF" p-id="42097"></path></svg>
|
After Width: | Height: | Size: 819 B |
1
bricks/imgs/app_delete.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748765628728" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="44896" width="100%" height="100%"><path d="M512 1024c-284.444444 0-512-227.555556-512-512s227.555556-512 512-512 512 227.555556 512 512-227.555556 512-512 512zM227.555556 455.111111v113.777778h568.888888V455.111111H227.555556z" fill="${color}" p-id="44897"></path></svg>
|
After Width: | Height: | Size: 386 B |
1
bricks/imgs/app_fullscreen.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748765766687" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="45870" width="100%" height="100%"><path d="M213.333333 213.333333h213.333334V128H170.666667a42.666667 42.666667 0 0 0-42.666667 42.666667v256h85.333333V213.333333zM170.666667 896h256v-85.333333H213.333333v-213.333334H128v256a42.666667 42.666667 0 0 0 42.666667 42.666667z m725.333333-42.666667v-256h-85.333333v213.333334h-213.333334v85.333333h256a42.666667 42.666667 0 0 0 42.666667-42.666667zM597.333333 213.333333h213.333334v213.333334h85.333333V170.666667a42.666667 42.666667 0 0 0-42.666667-42.666667h-256v85.333333z" fill="${color}" p-id="45871"></path></svg>
|
After Width: | Height: | Size: 680 B |
1
bricks/imgs/app_minimize.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748765916398" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="46899" width="100%" height="100%"><path d="M960 544H64a32 32 0 1 1 0-64h896a32 32 0 1 1 0 64" fill="${color}" p-id="46900"></path></svg>
|
After Width: | Height: | Size: 252 B |
1
bricks/imgs/cancel.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748766625752" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="50773" width="100%" height="100%"><path d="M512 922c-55.3 0-109-10.8-159.6-32.2-48.8-20.7-92.7-50.2-130.3-87.9-37.6-37.6-67.2-81.5-87.9-130.3C112.8 621 102 567.3 102 512s10.8-109 32.2-159.6c20.7-48.8 50.2-92.7 87.9-130.3 37.6-37.6 81.5-67.2 130.3-87.9C403 112.8 456.7 102 512 102s109 10.8 159.6 32.2c48.8 20.7 92.7 50.2 130.3 87.9 37.6 37.6 67.2 81.5 87.9 130.3C911.2 403 922 456.7 922 512s-10.8 109-32.2 159.6c-20.7 48.8-50.2 92.7-87.9 130.3-37.6 37.6-81.5 67.2-130.3 87.9C621 911.2 567.3 922 512 922z m0-750c-187.5 0-340 152.5-340 340s152.5 340 340 340 340-152.5 340-340-152.5-340-340-340z" fill="${color}" p-id="50774"></path><path d="M247.9 811.1c-9 0-17.9-3.4-24.7-10.3-13.7-13.7-13.7-35.8 0-49.5l528.2-528.2c13.7-13.7 35.8-13.7 49.5 0 13.7 13.7 13.7 35.8 0 49.5L272.6 800.8c-6.8 6.9-15.7 10.3-24.7 10.3z" fill="#8a8a8a" p-id="50775"></path></svg>
|
After Width: | Height: | Size: 968 B |
1
bricks/imgs/checkbox-checked.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748766061933" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="47910" width="100%" height="100%"><path d="M938.666667 1024 85.333333 1024c-46.933333 0-85.333333-38.4-85.333333-85.333333L0 85.333333c0-46.933333 38.4-85.333333 85.333333-85.333333l853.333333 0c46.933333 0 85.333333 38.4 85.333333 85.333333l0 853.333333C1024 985.6 985.6 1024 938.666667 1024zM938.666667 106.666667c0-12.8-8.533333-21.333333-21.333333-21.333333L106.666667 85.333333C93.866667 85.333333 85.333333 93.866667 85.333333 106.666667l0 810.666667c0 12.8 8.533333 21.333333 21.333333 21.333333l810.666667 0c12.8 0 21.333333-8.533333 21.333333-21.333333L938.666667 106.666667zM456.533333 712.533333C450.133333 721.066667 439.466667 725.333333 426.666667 725.333333s-23.466667-4.266667-29.866667-12.8l-170.666667-170.666667C217.6 535.466667 213.333333 524.8 213.333333 512c0-23.466667 19.2-42.666667 42.666667-42.666667 12.8 0 23.466667 4.266667 29.866667 12.8l140.8 140.8 311.466667-311.466667c8.533333-8.533333 19.2-12.8 29.866667-12.8 23.466667 0 42.666667 19.2 42.666667 42.666667 0 12.8-4.266667 23.466667-12.8 29.866667L456.533333 712.533333z" p-id="47911" fill="#8a8a8a"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
bricks/imgs/checkbox-unchecked.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748766186134" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="48104" width="100%" height="100%"><path d="M938.666667 1024 85.333333 1024c-46.933333 0-85.333333-38.4-85.333333-85.333333L0 85.333333c0-46.933333 38.4-85.333333 85.333333-85.333333l853.333333 0c46.933333 0 85.333333 38.4 85.333333 85.333333l0 853.333333C1024 985.6 985.6 1024 938.666667 1024zM938.666667 106.666667c0-12.8-8.533333-21.333333-21.333333-21.333333L106.666667 85.333333C93.866667 85.333333 85.333333 93.866667 85.333333 106.666667l0 810.666667c0 12.8 8.533333 21.333333 21.333333 21.333333l810.666667 0c12.8 0 21.333333-8.533333 21.333333-21.333333L938.666667 106.666667z" p-id="48105" fill="${color}"></path></svg>
|
After Width: | Height: | Size: 744 B |
1
bricks/imgs/clear.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748765200909" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="40050" width="100%" height="100%"><path d="M558.933333 938.666667c-119.466667-21.333333-226.133333-81.066667-307.2-166.4-85.333333-81.066667-145.066667-192-166.4-307.2l226.133334-98.133334 345.6 345.6-98.133334 226.133334z m-256-482.133334l-128 55.466667c12.8 72.533333 76.8 162.133333 132.266667 217.6 55.466667 55.466667 128 93.866667 204.8 110.933333l51.2-123.733333-260.266667-260.266667z m384 170.666667L396.8 337.066667c25.6-17.066667 55.466667-29.866667 85.333333-25.6 46.933333 0 89.6 17.066667 123.733334 42.666666L874.666667 85.333333c8.533333-8.533333 17.066667-12.8 29.866666-12.8 12.8 0 25.6 4.266667 29.866667 12.8 17.066667 17.066667 21.333333 42.666667 4.266667 64l-264.533334 264.533334c51.2 64 55.466667 149.333333 12.8 213.333333z" p-id="40051" fill="${color}"></path></svg>
|
After Width: | Height: | Size: 909 B |
1
bricks/imgs/condition.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748677809153" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13859" width="200" height="200"><path d="M512 128l512 383.168L512 896 0 512l512-384z" p-id="13860" fill="#8a8a8a"></path></svg>
|
After Width: | Height: | Size: 243 B |
1
bricks/imgs/csv.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748756577974" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="25788" width="100%" height="100%"><path d="M707.2 79.9H238.6c-11.6 0-21 9.4-21 21V923c0 11.6 9.4 21 21 21h704.9V316.3L707.2 79.9" fill="#FFFFFF" p-id="25789"></path><path d="M943.6 960h-705c-20.4 0-37-16.6-37-37V100.9c0-20.4 16.6-37 37-37h468.6c4.2 0 8.3 1.7 11.3 4.7L954.9 305c3 3 4.7 7.1 4.7 11.3V944c0 8.9-7.2 16-16 16z m-705-864.1c-2.7 0-5 2.2-5 5V923c0 2.7 2.2 5 5 5h689V323l-227-227h-462z" fill="${color}" p-id="25790"></path><path d="M943.6 316.3H707.2V79.9z" fill="#FFFFFF" p-id="25791"></path><path d="M943.6 332.3H707.2c-8.8 0-16-7.2-16-16V79.9c0-6.5 3.9-12.3 9.9-14.8s12.9-1.1 17.4 3.5L954.9 305c4.6 4.6 5.9 11.5 3.5 17.4-2.5 6-8.3 9.9-14.8 9.9z m-220.4-32H905L723.2 118.6v181.7z" fill="${color}" p-id="25792"></path><path d="M104.7 414.2h698.8c22.4 0 40.6 19.8 40.6 44.3v301.4c0 24.5-18.2 44.3-40.6 44.3H104.7c-22.4 0-40.6-19.8-40.6-44.3V458.5c-0.1-24.5 18.1-44.3 40.6-44.3z" fill="#34A89F" p-id="25793"></path><path d="M266.1 742.5c13 0 24.7-1.8 35.1-5.3 10.4-3.5 19.2-7.7 26.5-12.6 7.3-4.9 12.9-9.9 16.9-15 4-5.1 6.3-9.2 6.8-12.2 0.5-4.3-0.3-8.4-2.3-12.4-2-4-5.9-7.1-11.6-9.4-6-2.8-12.1-1.9-18.4 2.6-3.3 2.5-6.5 4.9-9.8 7.3-3.3 2.4-6.9 4.6-10.9 6.6s-8.6 3.7-13.9 5.1c-5.3 1.4-11.4 2.2-18.4 2.4-13.5 0.3-25.4-2.3-35.6-7.7s-18.8-12.6-25.7-21.6c-6.9-9-12.1-19.3-15.6-31-3.5-11.6-5.3-23.6-5.3-35.8s1.6-24.1 4.7-35.5c3.1-11.4 7.8-21.5 13.9-30.2 6.1-8.8 13.8-15.8 22.9-21.2 9.1-5.4 19.6-8.1 31.3-8.1 10.5 0 19.3 1.6 26.5 4.7 7.1 3.1 13.3 6.4 18.6 9.8 5.3 3.4 10 6.2 14.3 8.4 4.3 2.3 8.6 2.4 13.1 0.4 2.8-1 5.1-2.4 7.1-4.1 2-1.8 3.4-3.3 4.1-4.5 0.5-1 1.2-2.6 2.1-4.9s1.1-5 0.6-8.3c-0.5-3.8-2.9-8.2-7.1-13.3-4.3-5.1-10.1-10-17.6-14.6-7.5-4.6-16.4-8.5-26.6-11.6-10.3-3.1-21.5-4.7-33.8-4.7-17.3 0-33.3 3.1-48.2 9.4-14.9 6.3-27.8 15.3-38.6 27s-19.5 26.1-25.9 43.2c-6.4 17-9.7 36.4-9.9 58.2-0.3 21.8 2.9 41.2 9.4 58.3 6.5 17.1 15.6 31.7 27.4 43.7 11.8 12 25.7 21.1 41.8 27.4 15.9 6.4 33.3 9.5 52.1 9.5z m157-5.8c9.9 3.1 20.4 4.4 31.7 3.9 30.8-1 53.7-9.1 68.7-24.2s22.8-35.1 23.3-59.8c0.3-9.3-0.8-17.5-3.2-24.8-2.4-7.3-6.3-13.8-11.6-19.5-5.4-5.8-12.2-11.1-20.4-16.1-8.3-5-18-10-29.3-15-4.5-2-9.6-4.1-15.2-6.4s-11-5-16.1-8.3c-5.1-3.3-9.4-7-12.9-11.3s-5.3-9.3-5.3-15c0-3.5 0.8-7.1 2.3-10.7 1.5-3.6 3.6-6.9 6.2-9.8 2.6-2.9 5.8-5.3 9.6-7.1 3.8-1.9 8-2.8 12.8-2.8 4.3 0 8.4 0.6 12.6 1.9 4.1 1.3 8 2.8 11.6 4.5 3.6 1.8 7.1 3.7 10.3 5.8 3.3 2.1 6.1 4.1 8.6 5.8 1.8 1.5 4 2.5 6.8 3s5.6 0.4 8.4-0.2 5.6-1.8 8.3-3.4c2.6-1.6 4.8-3.8 6.6-6.6 3.3-5.5 3.7-11.3 1.3-17.4-2.4-6.1-6.9-11.8-13.5-17.1-6.6-5.3-14.9-9.6-25-13.1-10-3.5-20.9-5.4-32.6-5.6-10.5-0.3-20.8 1.1-31 4.1-10.1 3-19.2 7.5-27.2 13.5s-14.4 13.6-19.3 22.7-7.3 19.7-7.3 31.7c0 11.3 2 21 6 29.3s9.4 15.4 16.1 21.4c6.8 6 14.7 11.2 23.8 15.6 9.1 4.4 18.9 8.4 29.5 12.2 3.8 1.3 7.9 3 12.6 5.3 4.6 2.3 8.9 5.1 12.8 8.4 3.9 3.4 7.2 7.3 9.9 11.8 2.8 4.5 4.1 9.8 4.1 15.8 0 6.3-1.1 11.8-3.4 16.7-2.3 4.9-5.3 8.9-9 12.2-3.8 3.3-8.1 5.8-12.9 7.5-4.9 1.8-9.8 2.6-14.8 2.6-6 0-11.6-0.8-16.7-2.3-5.1-1.5-10-3.4-14.6-5.8s-9-5-13.1-7.9c-4.1-2.9-8.1-5.6-11.8-8.1-4.3-2.8-8.8-3.8-13.7-3.2-4.9 0.6-9.1 3.7-12.6 9.2-2 2.8-3.1 6.1-3.2 10.1-0.1 4 0.7 8.1 2.4 12.4 1.8 4.3 4.6 8.4 8.4 12.6 3.9 4.1 9.1 7.8 15.6 11.1 7 3.9 15.6 7.3 25.4 10.4z m252 2.1c8.5 0 15.4-5.6 20.6-16.9l78.8-224.8c5-14.8 0.9-23.5-12.4-26.3-2.8-0.5-5.7-0.8-8.8-0.9-3.1-0.1-6.1 0.3-9 1.3-2.9 1-5.6 2.6-8.1 4.9-2.5 2.3-4.5 5.4-6 9.4L675 648.3l-55.2-162.5c-1.5-4.8-3.4-8.3-5.8-10.5-2.4-2.3-4.9-3.8-7.7-4.5-2.8-0.8-5.5-1-8.3-0.8-2.8 0.3-5.4 0.6-7.9 1.1-4.3 1-7.6 2.5-9.9 4.5-2.4 2-4.1 4.2-5.1 6.6-1 2.4-1.4 4.9-1.1 7.7 0.3 2.8 0.9 5.5 1.9 8.3l78 222.5c3.3 7.5 6.5 12.4 9.8 14.6 3.4 2.4 7.1 3.5 11.4 3.5z" fill="#FFFFFF" p-id="25794"></path></svg>
|
After Width: | Height: | Size: 3.7 KiB |
1
bricks/imgs/database.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748676392085" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1484" width="100%" height="100%"><path d="M512 1024c-212.032 0-384-85.952-384-192v-108.032C128 830.08 299.968 896 512 896s384-65.92 384-172.032V832c0 106.048-171.968 192-384 192z m0-192c-212.032 0-384-85.952-384-192v-108.032C128 638.08 299.968 704 512 704s384-65.92 384-172.032V640c0 106.048-171.968 192-384 192z m0-192c-212.032 0-384-85.952-384-192v-108.032C128 446.08 299.968 512 512 512s384-65.92 384-172.032V448c0 106.048-171.968 192-384 192z m0-192c-212.032 0-384-85.952-384-192V192c0-106.048 171.968-192 384-192s384 85.952 384 192v64c0 106.048-171.968 192-384 192z" p-id="1485" fill="${color}"></path></svg>
|
After Width: | Height: | Size: 729 B |
1
bricks/imgs/delete.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748765552387" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="44745" width="100%" height="100%"><path d="M512 512m-481.882353 0a481.882353 481.882353 0 1 0 963.764706 0 481.882353 481.882353 0 1 0-963.764706 0Z" fill="${color}" p-id="44746"></path><path d="M597.172706 542.117647l85.202823 85.172706a60.235294 60.235294 0 1 1-85.202823 85.202823L512 627.290353l-85.172706 85.202823a60.235294 60.235294 0 1 1-85.202823-85.202823L426.827294 542.117647l-85.202823-85.172706a60.235294 60.235294 0 1 1 85.202823-85.202823L512 456.944941l85.172706-85.202823a60.235294 60.235294 0 1 1 85.202823 85.202823L597.172706 542.117647z" fill="#FFFFFF" p-id="44747"></path></svg>
|
After Width: | Height: | Size: 717 B |
1
bricks/imgs/dislike.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748764850061" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="38073" width="100%" height="100%"><path d="M725.333333 192c-89.6 0-168.533333 44.8-213.333333 115.2C467.2 236.8 388.266667 192 298.666667 192 157.866667 192 42.666667 307.2 42.666667 448c0 253.866667 469.333333 512 469.333333 512s469.333333-256 469.333333-512c0-140.8-115.2-256-256-256z" fill="${color}" p-id="38074"></path><path d="M76.010667 136.448L136.32 76.117333l809.941333 809.941334-60.330666 60.330666z" fill="#37474F" p-id="38075"></path></svg>
|
After Width: | Height: | Size: 570 B |
1
bricks/imgs/docx.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748754388139" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14695" width="100%" height="100%"><path d="M288 938.666667h618.666667a10.666667 10.666667 0 0 0 10.666666-10.666667V298.666667H736c-17.642667 0-32-14.357333-32-32V85.333333H288a10.666667 10.666667 0 0 0-10.666667 10.666667v832a10.666667 10.666667 0 0 0 10.666667 10.666667z" fill="#FFFFFF" p-id="14696"></path><path d="M912.917333 277.333333L725.333333 89.749333V266.666667a10.666667 10.666667 0 0 0 10.666667 10.666666h176.917333z" fill="#FFFFFF" p-id="14697"></path><path d="M929.290667 263.541333L739.125333 73.376A31.765333 31.765333 0 0 0 716.501333 64H288c-17.642667 0-32 14.357333-32 32v832c0 17.642667 14.357333 32 32 32h618.666667c17.642667 0 32-14.357333 32-32V286.165333c0-8.533333-3.338667-16.576-9.376-22.624zM725.333333 89.749333L912.917333 277.333333H736a10.666667 10.666667 0 0 1-10.666667-10.666666V89.749333zM906.666667 938.666667H288a10.666667 10.666667 0 0 1-10.666667-10.666667V96a10.666667 10.666667 0 0 1 10.666667-10.666667h416v181.333334c0 17.642667 14.357333 32 32 32h181.333333v629.333333a10.666667 10.666667 0 0 1-10.666666 10.666667z" fill="${color}" opacity=".64" p-id="14698"></path><path d="M842.666667 661.333333H544v21.333334h298.666667a10.666667 10.666667 0 0 0 0-21.333334z" fill="#103F91" p-id="14699"></path><path d="M842.666667 597.333333H544v21.333334h298.666667a10.666667 10.666667 0 0 0 0-21.333334z" fill="#185ABD" p-id="14700"></path><path d="M544 554.666667h298.666667a10.666667 10.666667 0 1 0 0-21.333334H544v21.333334z" fill="#2B7CD3" p-id="14701"></path><path d="M842.666667 469.333333H544v21.333334h298.666667a10.666667 10.666667 0 0 0 0-21.333334z" fill="#41A5EE" p-id="14702"></path><path d="M128 789.333333h341.333333a42.666667 42.666667 0 0 0 42.666667-42.666666V405.333333a42.666667 42.666667 0 0 0-42.666667-42.666666H128a42.666667 42.666667 0 0 0-42.666667 42.666666v341.333334a42.666667 42.666667 0 0 0 42.666667 42.666666z" fill="#185ABD" p-id="14703"></path><path d="M230.666667 646.88c0.704 5.568 1.162667 10.421333 1.386666 14.570667h0.8a251.456 251.456 0 0 1 4.554667-28.309334L275.104 469.333333h48.746667l38.997333 161.354667c1.952 7.968 3.584 18.101333 4.874667 30.432h0.650666c0.544-8.501333 1.898667-18.325333 4.064-29.450667L403.637333 469.333333H448l-54.592 234.666667h-51.84l-37.216-155.456c-1.077333-4.48-2.304-10.314667-3.658667-17.514667a204.437333 204.437333 0 0 1-2.517333-15.701333h-0.64c-0.437333 3.818667-1.28 9.493333-2.528 17.013333a434.656 434.656 0 0 1-3.008 16.693334L257.066667 704h-52.650667L149.333333 469.333333h45.173334l33.962666 164.138667c0.757333 3.381333 1.493333 7.850667 2.197334 13.418667z" fill="#F9F7F7" p-id="14704"></path></svg>
|
After Width: | Height: | Size: 2.7 KiB |
1
bricks/imgs/epub.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748756823446" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="27775" width="100%" height="100%"><path d="M908.611 239.293l2.722 711.518a29.557 29.557 0 0 1-29.642 29.642H193.819a29.557 29.557 0 0 1-29.642-29.642V73.027a29.548 29.548 0 0 1 29.642-29.642l522.496-1.104L675.112 0.014H195.274a69.484 69.484 0 0 0-69.564 69.564v884.844a69.484 69.484 0 0 0 69.564 69.565h684.962a69.497 69.497 0 0 0 69.591-69.565V281.573l-41.216-42.294z" fill="${color}" fill-opacity=".4" p-id="27776"></path><path d="M675.126 206.201a75.507 75.507 0 0 0 75.533 75.547h199.343L675.126 0v206.201z" fill="#EF6A63" p-id="27777"></path><path d="M532.345 481.091H109.972a96.499 96.499 0 0 1-96.498-96.512v-63.784a96.499 96.499 0 0 1 96.498-96.525h422.373a96.499 96.499 0 0 1 96.499 96.525v63.784a96.499 96.499 0 0 1-96.499 96.512" fill="#FA4E4E" p-id="27778"></path><path d="M73.149 267.965h100.015v35.57h-62.612v26.476h58.071v33.954h-58.071v32.876h64.417v37.712H73.162z m159.245 71.033h9.149c7.195 0 12.234-1.725 15.158-5.187 2.91-3.45 4.365-7.856 4.365-13.232 0-5.214-1.266-9.674-3.772-13.298-2.56-3.638-7.303-5.457-14.27-5.457h-10.63v37.174z m-37.484-71.033h62.033c13.514 0 23.633 4.446 30.37 13.298 6.71 8.88 10.078 21.477 10.078 37.834 0 16.829-3.665 29.966-10.994 39.451-7.33 9.459-18.513 14.188-33.577 14.188h-20.426v61.817H194.91V267.965z m200.597 0h37.24v99.247c0 9.836-1.104 19.146-3.327 27.89a66.776 66.776 0 0 1-10.47 22.946c-4.755 6.535-9.74 11.13-14.955 13.784-7.235 3.705-15.94 5.578-26.112 5.578-5.875 0-12.302-0.58-19.24-1.711-6.94-1.146-12.747-3.382-17.422-6.764-4.662-3.369-8.933-8.152-12.8-14.363a60.362 60.362 0 0 1-7.95-19.2c-2.317-10.59-3.462-19.982-3.462-28.16v-99.247h37.228v101.618c0 9.082 1.832 16.182 5.483 21.289 3.638 5.12 8.718 7.653 15.185 7.653 6.44 0 11.466-2.52 15.118-7.546 3.665-5.039 5.484-12.153 5.484-21.396V267.965z m99.691 130.802h19.039c6.413 0 10.954-1.576 13.581-4.729 2.627-3.14 3.948-7.357 3.948-12.665 0-4.918-1.307-8.88-3.907-11.884-2.614-2.978-7.168-4.487-13.717-4.487h-18.944v33.765z m0-65.455h16.223c5.82 0 9.876-1.388 12.166-4.15 2.264-2.762 3.41-6.764 3.41-11.991 0-4.85-1.146-8.624-3.41-11.359-2.29-2.721-6.251-4.096-11.91-4.096h-16.479v31.596z m-37.659-65.347H527.4c11.655 0 20.575 3.988 26.827 11.937 6.224 7.963 9.337 17.8 9.337 29.548 0 9.85-2.21 18.284-6.67 25.33-2.964 4.717-7.302 8.408-13.015 11.143 8.677 2.87 15.063 7.829 19.16 14.822 4.082 7.02 6.13 15.818 6.13 26.408 0 8.65-1.455 16.424-4.352 23.31-2.924 6.898-6.912 12.355-11.951 16.37-3.14 2.493-7.869 4.311-14.161 5.443-8.421 1.523-13.986 2.29-16.734 2.29h-64.432V267.966z" fill="#FFFFFF" p-id="27779"></path><path d="M532.157 898.29a23.283 23.283 0 0 1-22.259-16.505L430.08 618.617a23.256 23.256 0 0 1 19.173-29.817l250.435-33.59c10.86-1.617 21.477 4.985 25.088 15.495l36.002 104.461a23.27 23.27 0 0 1-14.74 29.683l-133.834 43.897a23.215 23.215 0 0 1-29.36-14.848 23.242 23.242 0 0 1 14.862-29.359l111.374-36.554-22.097-64.121-204.41 27.419 65.415 215.646 203.776-52.386a23.242 23.242 0 0 1 28.322 16.775 23.27 23.27 0 0 1-16.734 28.335l-225.375 57.91a23.444 23.444 0 0 1-5.82 0.728" fill="#EF6A63" p-id="27780"></path></svg>
|
After Width: | Height: | Size: 3.1 KiB |
1
bricks/imgs/field.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748753432081" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7207" width="100%" height="100%"><path d="M196.923077 393.846154h157.538461V236.307692H196.923077v157.538462zM118.153846 196.923077a39.384615 39.384615 0 0 1 39.384616-39.384615h236.307692a39.384615 39.384615 0 0 1 39.384615 39.384615v236.307692a39.384615 39.384615 0 0 1-39.384615 39.384616H157.538462a39.384615 39.384615 0 0 1-39.384616-39.384616V196.923077z m78.769231 590.769231h157.538461v-157.538462H196.923077v157.538462z m-78.769231-196.923077a39.384615 39.384615 0 0 1 39.384616-39.384616h236.307692a39.384615 39.384615 0 0 1 39.384615 39.384616v236.307692a39.384615 39.384615 0 0 1-39.384615 39.384615H157.538462a39.384615 39.384615 0 0 1-39.384616-39.384615v-236.307692zM551.384615 196.923077a39.384615 39.384615 0 0 1 39.384616-39.384615h315.076923a39.384615 39.384615 0 1 1 0 78.76923h-315.076923a39.384615 39.384615 0 0 1-39.384616-39.384615z m39.384616 393.846154a39.384615 39.384615 0 1 0 0 78.769231h315.076923a39.384615 39.384615 0 1 0 0-78.769231h-315.076923z m-39.384616-196.923077a39.384615 39.384615 0 0 1 39.384616-39.384616h315.076923a39.384615 39.384615 0 1 1 0 78.769231h-315.076923a39.384615 39.384615 0 0 1-39.384616-39.384615z m39.384616 393.846154a39.384615 39.384615 0 1 0 0 78.76923h315.076923a39.384615 39.384615 0 1 0 0-78.76923h-315.076923z" fill="${color}" p-id="7208"></path></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
bricks/imgs/folder.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748754244555" class="icon" viewBox="0 0 1163 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13512" width="100%" height="100%"><path d="M972.334545 209.454545H698.181818v-18.152727A191.301818 191.301818 0 0 0 506.88 0H191.301818A191.301818 191.301818 0 0 0 0 191.301818v641.396364A191.301818 191.301818 0 0 0 191.301818 1024h781.032727A191.301818 191.301818 0 0 0 1163.636364 832.698182V400.756364A191.301818 191.301818 0 0 0 972.334545 209.454545zM1047.272727 832.698182A74.938182 74.938182 0 0 1 972.334545 907.636364H191.301818A74.938182 74.938182 0 0 1 116.363636 832.698182V191.301818A74.938182 74.938182 0 0 1 191.301818 116.363636h315.578182A74.938182 74.938182 0 0 1 581.818182 191.301818V209.454545h-197.818182a58.181818 58.181818 0 0 0 0 116.363637h588.334545A74.938182 74.938182 0 0 1 1047.272727 400.756364z" fill="#8a8a8a" p-id="13513"></path><path d="M325.818182 442.181818m58.181818 0l488.727273 0q58.181818 0 58.181818 58.181818l0 0q0 58.181818-58.181818 58.181819l-488.727273 0q-58.181818 0-58.181818-58.181819l0 0q0-58.181818 58.181818-58.181818Z" fill="${color}" p-id="13514"></path></svg>
|
After Width: | Height: | Size: 1.1 KiB |
1
bricks/imgs/index.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748753930773" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10253" width="100%" height="100%"><path d="M768 556.8a211.2 211.2 0 0 1 162.304 346.304l43.264 43.328-27.136 27.136-43.328-43.264A211.2 211.2 0 1 1 768 556.8zM512 96c204.16 0 374.336 74.752 383.616 182.656l0.32 11.968L895.872 448H896l-0.128 2.176L896 546.24a254.464 254.464 0 0 0-111.744-33.728c27.648-17.92 44.544-38.144 47.36-58.56l0.32-4.8v-52.288c-66.112 49.344-177.024 80.32-302.528 82.944L512 480c-125.248 0-237.696-28.16-308.032-74.752L192 396.8V448c0 63.808 141.248 128 320 128 32.832 0 64.448-2.176 94.08-6.08-23.68 19.2-43.84 42.688-59.328 69.248-11.456 0.64-23.04 0.832-34.752 0.832-132.608 0-250.88-31.488-320-83.2v51.2c0 63.808 141.248 128 320 128h1.92a258.56 258.56 0 0 0 0.064 64H512c-132.608 0-250.88-31.488-320-83.2v51.2c0 63.808 141.248 128 320 128 11.456 0 22.784-0.256 33.92-0.768 12.864 22.592 29.184 43.072 48.192 60.608C567.616 958.592 540.16 960 512 960c-204.16 0-374.336-74.752-383.616-182.656L128 768V288l0.384-9.344C137.664 170.752 307.84 96 512 96z m256 499.2a172.8 172.8 0 1 0 0 345.6 172.8 172.8 0 0 0 0-345.6z m-76.8 166.4v89.6h-38.4v-89.6h38.4z m192-38.4v128h-38.4v-128h38.4z m-96-51.2v179.2h-38.4v-179.2h38.4zM512 160c-178.752 0-320 64.192-320 128 0 63.808 141.248 128 320 128 173.184 0 311.104-60.224 319.616-122.048l0.32-5.952c0.064-63.808-141.184-128-319.936-128z" fill="${color}" p-id="10254"></path></svg>
|
After Width: | Height: | Size: 1.4 KiB |
BIN
bricks/imgs/input.png
Normal file
After Width: | Height: | Size: 12 KiB |
1
bricks/imgs/like.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748764734472" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="37055" width="100%" height="100%"><path d="M780.8 204.8c-83.2-44.8-179.2-19.2-243.2 44.8L512 275.2 486.4 249.6c-64-64-166.4-83.2-243.2-44.8C108.8 275.2 89.6 441.6 185.6 537.6l32 32 153.6 153.6 102.4 102.4c25.6 25.6 57.6 25.6 83.2 0l102.4-102.4 153.6-153.6 32-32C934.4 441.6 915.2 275.2 780.8 204.8z" fill="${color}" p-id="37056"></path></svg>
|
After Width: | Height: | Size: 458 B |
1
bricks/imgs/mobi.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748757181470" class="icon" viewBox="0 0 1396 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="36040" width="100%" height="100%"><path d="M139.636364 0C63.022545 0 0 63.022545 0 139.636364V465.454545h93.090909V139.636364c0-26.158545 20.386909-46.545455 46.545455-46.545455h388.375272c38.818909 0 75.589818 13.405091 95.976728 37.794909l23.645091 34.164364 13.777454 21.131636h73.541818l13.777455-21.131636s22.900364-33.326545 23.645091-34.164364C792.669091 106.682182 829.44 93.090909 868.352 93.090909H1256.727273c26.158545 0 46.545455 20.386909 46.545454 46.545455V465.454545h93.090909V139.636364c0-76.613818-63.022545-139.636364-139.636363-139.636364H868.352c-59.764364 0-124.276364 19.828364-167.284364 71.307636H700.974545c-1.303273 1.489455-1.396364 2.141091-2.699636 3.723637-1.303273-1.582545-1.396364-2.234182-2.792727-3.723637H695.389091C652.194909 19.921455 587.776 0 528.011636 0H139.636364z m0 558.545455C63.022545 558.545455 0 621.568 0 698.181818V1024h93.090909V698.181818c0-26.158545 20.386909-46.545455 46.545455-46.545454s46.545455 20.386909 46.545454 46.545454V1024h93.090909V698.181818c0-26.158545 20.386909-46.545455 46.545455-46.545454s46.545455 20.386909 46.545454 46.545454V1024h93.090909V698.181818C465.454545 621.568 402.432 558.545455 325.818182 558.545455c-35.746909 0-68.235636 14.056727-93.090909 36.584727A138.519273 138.519273 0 0 0 139.636364 558.545455z m558.545454 0C621.568 558.545455 558.545455 621.568 558.545455 698.181818v186.181818c0 76.613818 63.022545 139.636364 139.636363 139.636364S837.818182 960.977455 837.818182 884.363636v-186.181818C837.818182 621.568 774.795636 558.545455 698.181818 558.545455zM930.909091 558.545455v465.454545h139.636364c76.613818 0 139.636364-63.022545 139.636363-139.636364 0-36.119273-15.825455-68.142545-38.725818-93.090909 22.900364-24.948364 38.725818-56.971636 38.725818-93.090909 0-76.613818-63.022545-139.636364-139.636363-139.636363H930.909091z m372.363636 0v465.454545h93.090909V558.545455h-93.090909zM698.181818 651.636364c26.158545 0 46.545455 20.386909 46.545455 46.545454v186.181818c0 26.158545-20.386909 46.545455-46.545455 46.545455a45.893818 45.893818 0 0 1-46.545454-46.545455v-186.181818c0-26.158545 20.386909-46.545455 46.545454-46.545454zM1024 651.636364h46.545455c26.158545 0 46.545455 20.386909 46.545454 46.545454s-20.386909 46.545455-46.545454 46.545455H1024V651.636364z m0 186.181818h46.545455c26.158545 0 46.545455 20.386909 46.545454 46.545454s-20.386909 46.545455-46.545454 46.545455H1024V837.818182z" fill="${color}" p-id="36041"></path></svg>
|
After Width: | Height: | Size: 2.5 KiB |
1
bricks/imgs/pdf.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748755459723" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2638" width="100%" height="100%"><path d="M582.4 864H170.666667c-6.4 0-10.666667-4.266667-10.666667-10.666667V170.666667c0-6.4 4.266667-10.666667 10.666667-10.666667h309.333333V320c0 40.533333 34.133333 74.666667 74.666667 74.666667h160v38.4c0 17.066667 14.933333 32 32 32s32-14.933333 32-32V298.666667c0-8.533333-4.266667-17.066667-8.533334-23.466667l-170.666666-170.666667c-6.4-6.4-14.933333-8.533333-23.466667-8.533333H170.666667C130.133333 96 96 130.133333 96 170.666667v682.666666c0 40.533333 34.133333 74.666667 74.666667 74.666667h411.733333c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32z m132.266667-550.4v17.066667H554.666667c-6.4 0-10.666667-4.266667-10.666667-10.666667V160h19.2l151.466667 153.6z" fill="${color}" p-id="2639"></path><path d="M332.8 533.333333c-12.8 0-19.2 2.133333-25.6 6.4-6.4 4.266667-8.533333 12.8-8.533333 23.466667v206.933333c0 6.4 2.133333 12.8 6.4 19.2 4.266667 4.266667 10.666667 8.533333 21.333333 8.533334s17.066667-4.266667 21.333333-8.533334c4.266667-4.266667 6.4-10.666667 6.4-19.2v-64h32c57.6 0 89.6-29.866667 89.6-87.466666 0-27.733333-8.533333-51.2-23.466666-64-14.933333-14.933333-36.266667-21.333333-66.133334-21.333334h-53.333333z m87.466667 85.333334c0 12.8-2.133333 23.466667-8.533334 27.733333-4.266667 4.266667-14.933333 8.533333-27.733333 8.533333h-32v-70.4H384c12.8 0 21.333333 2.133333 27.733333 8.533334 6.4 4.266667 8.533333 12.8 8.533334 25.6zM667.733333 571.733333c-8.533333-12.8-21.333333-21.333333-34.133333-29.866666-14.933333-4.266667-32-8.533333-51.2-8.533334h-61.866667c-8.533333 0-17.066667 0-23.466666 8.533334-2.133333 4.266667-4.266667 10.666667-4.266667 19.2V768c0 8.533333 2.133333 14.933333 4.266667 19.2 6.4 8.533333 14.933333 8.533333 23.466666 8.533333h64c19.2 0 34.133333-4.266667 49.066667-10.666666 12.8-6.4 25.6-17.066667 34.133333-29.866667 8.533333-12.8 14.933333-25.6 19.2-42.666667 4.266667-14.933333 6.4-32 6.4-49.066666 0-17.066667-2.133333-34.133333-6.4-49.066667-4.266667-14.933333-10.666667-29.866667-19.2-42.666667z m-42.666666 153.6c-8.533333 12.8-21.333333 19.2-38.4 19.2h-38.4v-160H576c21.333333 0 38.4 6.4 46.933333 19.2 10.666667 12.8 14.933333 34.133333 14.933334 59.733334 2.133333 27.733333-4.266667 46.933333-12.8 61.866666zM851.2 533.333333h-106.666667c-8.533333 0-17.066667 2.133333-21.333333 6.4-6.4 4.266667-8.533333 12.8-8.533333 21.333334v209.066666c0 6.4 2.133333 12.8 6.4 17.066667 4.266667 6.4 10.666667 8.533333 21.333333 8.533333 8.533333 0 17.066667-2.133333 21.333333-8.533333 2.133333-4.266667 6.4-8.533333 6.4-19.2v-85.333333h72.533334c12.8 0 23.466667-6.4 25.6-17.066667 2.133333-8.533333 2.133333-14.933333 0-17.066667-2.133333-4.266667-6.4-17.066667-25.6-17.066666H768v-49.066667h81.066667c8.533333 0 14.933333-2.133333 19.2-4.266667 4.266667-2.133333 8.533333-8.533333 8.533333-21.333333 2.133333-12.8-8.533333-23.466667-25.6-23.466667z" fill="#ED6C47" p-id="2640"></path></svg>
|
After Width: | Height: | Size: 2.9 KiB |
1
bricks/imgs/pptx.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748755154061" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1581" width="100%" height="100%"><path d="M288 938.667h618.667A10.667 10.667 0 0 0 917.333 928V298.667H736c-17.643 0-32-14.358-32-32V85.333H288A10.667 10.667 0 0 0 277.333 96v832A10.667 10.667 0 0 0 288 938.667z" fill="#FFFFFF" p-id="1582"></path><path d="M912.917 277.333L725.333 89.75v176.918A10.667 10.667 0 0 0 736 277.333h176.917z" fill="#FFFFFF" p-id="1583"></path><path d="M929.29 263.541L739.126 73.376A31.765 31.765 0 0 0 716.501 64H288c-17.643 0-32 14.357-32 32v832c0 17.643 14.357 32 32 32h618.667c17.642 0 32-14.357 32-32V286.165c0-8.533-3.339-16.576-9.376-22.624zM725.334 89.75l187.584 187.584H736a10.667 10.667 0 0 1-10.667-10.666V89.749z m181.334 848.918H288A10.667 10.667 0 0 1 277.333 928V96A10.667 10.667 0 0 1 288 85.333h416v181.334c0 17.642 14.357 32 32 32h181.333V928a10.667 10.667 0 0 1-10.666 10.667z" fill="${color}" opacity=".64" p-id="1584"></path><path d="M650.667 576L640 565.333h-85.333L544 576v119.019C572.32 720.416 609.632 736 650.667 736c88.362 0 160-71.637 160-160h-160z" fill="#ED6C47" p-id="1585"></path><path d="M544 456.981V576h106.667V416c-41.035 0-78.347 15.573-106.667 40.981z" fill="#FF8F6B" p-id="1586"></path><path d="M682.667 384v160h160c0-88.363-71.638-160-160-160z" fill="#FFC7B5" p-id="1587"></path><path d="M128 789.333h341.333A42.667 42.667 0 0 0 512 746.667V405.333a42.667 42.667 0 0 0-42.667-42.666H128a42.667 42.667 0 0 0-42.667 42.666v341.334A42.667 42.667 0 0 0 128 789.333z" fill="#C43E1C" p-id="1588"></path><path d="M318.443 448c31.52 0 55.68 7.072 72.426 21.173C407.616 483.285 416 503.733 416 530.485c0 17.184-4.15 32.459-12.427 45.835-8.288 13.387-20.074 23.787-35.349 31.21-15.264 7.425-32.97 11.137-53.099 11.137h-48.469v96h-53.323V448h105.11z m-51.776 128h42.314c16.491 0 28.95-3.733 37.387-11.147 8.427-7.434 12.63-18.293 12.63-32.576 0-27.733-16.14-41.61-48.449-41.61h-43.882V576z" fill="#F9F7F7" p-id="1589"></path></svg>
|
After Width: | Height: | Size: 2.0 KiB |
1
bricks/imgs/primarykey.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748754109679" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12235" width="100%" height="100%"><path d="M676.99983406 32H347.00016594c-33.09371625 0-59.99994 26.81247281-59.99994 59.99994v239.99975812c0 33.09371625 26.90622281 59.99994 59.99994 59.99994h71.24992875c2.06249812 0 3.74999625 1.68749813 3.74999625 3.74999625v37.49996157c0 2.06249812 1.68749813 3.74999625 3.74999625 3.74999625h18.74998031c4.12499625 0 7.4999925 3.37499625 7.4999925 7.4999925v486.56201062c0 33.18746625 26.62497281 60.74993906 59.81244 60.93743906 16.68748312 0.09375 31.68746812-6.65624344 42.65620688-17.53123218 10.87498875-10.87498875 17.53123219-25.87497375 17.53123312-42.46870782V444.49958469c0-4.12499625 3.37499625-7.4999925 7.4999925-7.4999925h18.74998031c2.06249812 0 3.74999625-1.68749813 3.74999625-3.74999625v-37.49996157c0-2.06249812 1.68749813-3.74999625 3.74999625-3.74999625h71.24992875c33.09371625 0 59.99994-26.90622281 59.99994-59.99994V91.99994c0-33.18746625-26.90622281-59.99994-59.99994-59.99994zM579.4999325 166.99986406H444.5000675c-12.46873781 0-22.4999775-10.12498969-22.49997656-22.4999775s10.12498969-22.4999775 22.49997656-22.4999775h134.999865c12.46873781 0 22.4999775 10.12498969 22.49997656 22.4999775s-10.03123969 22.4999775-22.49997656 22.4999775z" p-id="12236" fill="${color}"></path></svg>
|
After Width: | Height: | Size: 1.3 KiB |
BIN
bricks/imgs/search.png
Normal file
After Width: | Height: | Size: 12 KiB |
1
bricks/imgs/speak.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748678028121" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16933" width="200" height="200"><path d="M305.283 837.17c-73.9-73.938-119.609-176.055-119.609-288.853 0-112.808 45.715-214.935 119.628-288.873l-0.035-0.035c8.033-7.461 13.064-18.11 13.064-29.938 0-22.567-18.295-40.861-40.863-40.861-11.827 0-22.474 5.031-29.936 13.062l-0.016-0.016c-88.702 88.729-143.564 211.286-143.564 346.66 0 135.427 54.906 258.029 143.67 346.764l0.044-0.044c7.451 7.904 18.01 12.846 29.729 12.846 22.567 0 40.863-18.295 40.863-40.861 0-11.782-4.995-22.394-12.975-29.851z m555.971-145.659h-56.92l60.707-102.74c8.89-10.107 14.512-23.155 15.192-37.506 1.707-22.226-9.409-44.499-30.485-56.389-11.11-6.267-23.391-8.742-35.284-7.849h-92.227l170.277-296.078c16.828-29.258 6.356-66.956-23.387-84.202-29.742-17.247-67.494-7.51-84.32 21.748L561.384 516.977c-6.105 10.616-8.599 22.342-7.899 33.801 1.256 31.765 26.672 57.311 58.388 58.759 2.583 0.184 5.163 0.209 7.726 0.072h91.585l-67.741 114.645c-16.927 28.643-6.881 65.271 22.432 81.807 9.872 5.569 20.67 8.137 31.298 8.017 0.214 0.002 0.425 0.016 0.639 0.016h163.443c33.851 0 61.293-27.442 61.293-61.291-0.001-33.852-27.443-61.292-61.294-61.292z m-454.72 44.661c-48.095-48.068-77.848-114.487-77.848-187.855 0-73.316 29.71-139.69 77.742-187.749l-0.033-0.033c6.714-7.281 10.82-17.003 10.82-27.688 0-22.567-18.295-40.861-40.863-40.861-10.684 0-20.407 4.106-27.688 10.82l-0.023-0.023c-0.254 0.254-0.505 0.513-0.758 0.768-0.377 0.366-0.745 0.741-1.108 1.122-61.721 62.693-99.809 148.718-99.809 243.644 0 94.974 38.128 181.039 99.903 243.74a40.27 40.27 0 0 0 1.496 1.513l0.383 0.387 0.011-0.011c7.305 6.84 17.117 11.035 27.914 11.035 22.567 0 40.863-18.295 40.863-40.861 0-10.797-4.195-20.609-11.035-27.914l0.033-0.034z m128.165-289.641c0-22.567-18.293-40.861-40.859-40.861-11.654 0-22.159 4.886-29.603 12.712l-0.026-0.026c-33.242 33.269-53.803 79.212-53.803 129.961 0 50.802 20.606 96.789 53.912 130.068l0.048-0.048c7.34 7.036 17.293 11.368 28.264 11.368 22.565 0 40.859-18.293 40.859-40.861 0-11.625-4.862-22.107-12.654-29.547-17.766-18.379-28.705-43.398-28.705-70.979 0-28.182 11.414-53.693 29.869-72.174l-0.011-0.011c7.823-7.444 12.709-17.949 12.709-29.602z" fill="#8a8a8a" p-id="16934"></path><path d="M376.352 291.987c22.567 0 40.863 18.293 40.863 40.861 0 22.567-18.295 40.861-40.863 40.861-22.565 0-40.861-18.293-40.861-40.861 0-22.568 18.296-40.861 40.861-40.861zM277.395 826.162c22.567 0 40.863 18.293 40.863 40.861 0 22.565-18.295 40.861-40.863 40.861-22.565 0-40.861-18.295-40.861-40.861 0.001-22.568 18.296-40.861 40.861-40.861zM492.631 607.983c22.565 0 40.859 18.293 40.859 40.861 0 22.567-18.293 40.861-40.859 40.861-22.567 0-40.861-18.293-40.861-40.861 0-22.567 18.294-40.861 40.861-40.861z" fill="#8a8a8a" p-id="16935"></path></svg>
|
After Width: | Height: | Size: 2.8 KiB |
1
bricks/imgs/submit.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748764987368" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="39067" width="100%" height="100%"><path d="M976.21333333 326.9216c-18.2048-21.2384-48.54506667-21.2384-69.78346666-3.03466667L569.64693333 645.49973333 427.0464 512c-18.2048-21.2384-48.54613333-24.27306667-69.78453333-6.06826667-21.23733333 18.2048-24.272 48.54506667-6.06826667 69.78346667l3.03466667 3.03466667 175.97653333 160.80533333C539.30666667 751.69173333 554.4768 757.76 566.61333333 757.76c15.17013333 3.0336 30.34026667 0 42.4768-12.13653333 0 0 0-3.0336 3.03466667-3.0336L973.17973333 396.704c18.20373333-18.2048 21.23733333-48.54506667 3.0336-69.78346667z" fill="${color}" p-id="39068"></path><path d="M827.54346667 742.58986667C803.27146667 742.58986667 785.06666667 760.7936 785.06666667 785.06666667v127.43146666H120.6048v-797.96266666h661.42826667v66.75093333c0 24.272 18.20373333 42.4768 42.4768 42.4768S866.98666667 205.55733333 866.98666667 181.2864V69.024c0-6.06826667 0-12.13653333-3.0336-15.17013333-3.03466667-3.03466667-3.03466667-9.10186667-6.06933334-12.13653334 0 0 0-3.0336-3.0336-3.0336-6.06826667-9.10293333-18.20373333-12.13653333-30.34026666-12.13653333H78.12693333c-12.13546667 0-21.23733333 6.06826667-30.34026666 12.13653333C38.6848 47.78666667 35.65013333 56.88853333 35.65013333 69.024v882.9152c0 24.27306667 18.2048 42.47786667 42.4768 42.47786667h749.41653334c24.27306667 0 42.4768-18.2048 42.4768-42.47786667V785.06666667c0-24.27306667-18.20373333-42.4768-42.4768-42.4768z" fill="${color}" p-id="39069"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
BIN
bricks/imgs/switch-camera.png
Normal file
After Width: | Height: | Size: 14 KiB |
1
bricks/imgs/table.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748753021394" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6063" width="100%" height="100%"><path d="M85.333333 93.866667h853.333334c42.666667 0 76.8 34.133333 76.8 76.8v682.666666c0 42.666667-34.133333 76.8-76.8 76.8H85.333333C42.666667 930.133333 8.533333 896 8.533333 853.333333V170.666667C8.533333 128 42.666667 93.866667 85.333333 93.866667z" fill="#FCFCFC" p-id="6064"></path><path d="M85.333333 93.866667v8.533333h853.333334c34.133333 0 64 29.866667 64 64v682.666667c0 34.133333-29.866667 64-64 64H85.333333c-34.133333 0-64-29.866667-64-64v-682.666667c0-34.133333 29.866667-64 64-64V85.333333C38.4 85.333333 0 123.733333 0 170.666667v682.666666c0 46.933333 38.4 85.333333 85.333333 85.333334h853.333334c46.933333 0 85.333333-38.4 85.333333-85.333334V170.666667c0-46.933333-38.4-85.333333-85.333333-85.333334H85.333333v8.533334z" fill="#DFDFDF" p-id="6065"></path><path d="M8.533333 853.333333V170.666667C8.533333 128 42.666667 93.866667 85.333333 93.866667h247.466667v832H85.333333C42.666667 925.866667 8.533333 891.733333 8.533333 853.333333z" fill="#EEEEEE" p-id="6066"></path><path d="M8.533333 853.333333h8.533334V170.666667c0-34.133333 29.866667-64 64-64h234.666666v810.666666H85.333333c-34.133333 0-64-29.866667-64-64H0c0 46.933333 38.4 85.333333 85.333333 85.333334h256V85.333333H85.333333C38.4 85.333333 0 123.733333 0 170.666667v682.666666h8.533333z" fill="#DFDFDF" p-id="6067"></path><path d="M0 401.066667h1024v-21.333334H0M0 686.933333h1024v-21.333333H0" fill="#DFDFDF" p-id="6068"></path><path d="M85.333333 93.866667h853.333334c42.666667 0 76.8 34.133333 76.8 76.8v221.866666H8.533333V170.666667C8.533333 128 42.666667 93.866667 85.333333 93.866667z" fill="${color}" p-id="6069"></path><path d="M85.333333 93.866667v8.533333h853.333334c34.133333 0 64 29.866667 64 64v209.066667H21.333333V170.666667c0-34.133333 29.866667-64 64-64V85.333333C38.4 85.333333 0 123.733333 0 170.666667v230.4h1024V170.666667c0-46.933333-38.4-85.333333-85.333333-85.333334H85.333333v8.533334z" fill="#DFDFDF" p-id="6070"></path><path d="M341.333333 938.666667V85.333333h-21.333333v853.333334M669.866667 938.666667V85.333333h-21.333334v853.333334" fill="#DFDFDF" p-id="6071"></path></svg>
|
After Width: | Height: | Size: 2.2 KiB |
1
bricks/imgs/txt.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748756184705" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="24679" width="100%" height="100%"><path d="M938.642489 1023.982934H136.522525V0h563.190613v52.069532H187.721671V972.783787h699.721672V225.634639h51.199146V1023.982934z" fill="${color}" p-id="24680"></path><path d="M767.978667 836.252729H85.323378V648.522525h682.655289v187.730204z m-378.464092-121.37611A35.00315 35.00315 0 0 0 353.265579 750.920818a35.361544 35.361544 0 0 0 37.836169 36.027133 34.474092 34.474092 0 0 0 29.746705-14.062699l-16.383727-9.403577a17.834369 17.834369 0 0 1-13.124048 5.119915 15.359744 15.359744 0 0 1-16.366661-9.557174h48.468526a39.457476 39.457476 0 0 0 0.767987-8.123598 34.610623 34.610623 0 0 0-34.695955-36.044199z m122.741421 1.911435v19.660472h10.922484v24.165997c0 17.953834 7.082549 24.968117 25.275312 24.968117A89.922768 89.922768 0 0 0 557.720838 785.053582v-18.568223a74.921418 74.921418 0 0 1-4.556724 0.153597 14.608823 14.608823 0 0 1-7.048416-1.211713 4.949251 4.949251 0 0 1-2.457559-4.81272v-24.165997h14.062699V716.788054h-14.062699v-19.114349l-20.479659 6.143898V716.788054z m-218.159564 0v19.660472h10.922484v24.165997c0 17.953834 7.082549 24.968117 25.275312 24.968117A89.922768 89.922768 0 0 0 339.612473 785.053582v-18.568223c-2.013833 0.119465-3.413276 0.153597-4.556724 0.153597a14.608823 14.608823 0 0 1-7.065482-1.211713 4.949251 4.949251 0 0 1-2.457559-4.81272v-24.165997h14.079765V716.788054h-14.062699v-19.114349l-20.479659 6.143898V716.788054z m173.121381 50.226362L479.898135 785.053582h23.551608l-24.507325-34.678888L502.562291 716.788054h-23.483342l-11.946468 16.946917L455.322545 716.788054H431.770937l23.619873 33.58664L431.020016 785.053582h23.483342l12.680322-18.005033z m-63.350411-23.210279h-29.354177a15.359744 15.359744 0 0 1 29.354177 0z" fill="#D7840F" p-id="24681"></path><path d="M221.854436 170.663822h255.995733v51.199147H221.854436z" fill="#B7B7B7" p-id="24682"></path><path d="M221.854436 273.062116h324.261262v51.199146H221.854436z" fill="#B7B7B7" p-id="24683"></path><path d="M921.576107 273.062116H648.513991V0h51.199147v221.862969h221.862969v51.199147z" fill="${color}" p-id="24684"></path><path d="M699.713138 51.199147l187.730205 170.663822 51.199146 17.066382v-34.132764L716.77952 0h-17.066382z" fill="${color}" p-id="24685"></path></svg>
|
After Width: | Height: | Size: 2.3 KiB |
1
bricks/imgs/version.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748753587532" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8254" width="100%" height="100%"><path d="M928 704c-17.706667 0-32-14.293333-32-32V288c0-17.706667-14.293333-32-32-32H506.453333c-25.6 0-49.706667-10.026667-67.84-28.16l-26.453333-26.453333c-5.973333-5.973333-14.186667-9.386667-22.613333-9.386667H288c-17.706667 0-32-14.293333-32-32s14.293333-32 32-32h101.546667c25.6 0 49.706667 10.026667 67.84 28.16l26.453333 26.453333c5.973333 5.973333 14.186667 9.386667 22.613333 9.386667H864c52.906667 0 96 43.093333 96 96v384c0 17.706667-14.293333 32-32 32z" p-id="8255" fill="#8a8a8a"></path><path d="M736 896H160c-52.906667 0-96-43.093333-96-96V352c0-52.906667 43.093333-96 96-96h101.546667c25.6 0 49.706667 10.026667 67.84 28.16l26.453333 26.453333c5.973333 5.973333 14.186667 9.386667 22.613333 9.386667H736c52.906667 0 96 43.093333 96 96v384c0 52.906667-43.093333 96-96 96zM160 320c-17.706667 0-32 14.293333-32 32v448c0 17.706667 14.293333 32 32 32h576c17.706667 0 32-14.293333 32-32V416c0-17.706667-14.293333-32-32-32H378.453333c-25.6 0-49.706667-10.026667-67.84-28.16l-26.453333-26.453333c-5.973333-5.973333-14.186667-9.386667-22.613333-9.386667H160z" p-id="8256" fill="${color}"></path><path d="M320 704c-11.2 0-21.653333-5.866667-27.413333-15.573333l-96-160c-9.066667-15.146667-4.16-34.773333 10.986666-43.946667 15.146667-9.173333 34.88-4.16 43.946667 10.986667L320 609.813333l68.586667-114.24c9.066667-15.146667 28.8-20.053333 43.946666-10.986666 15.146667 9.066667 20.053333 28.8 10.986667 43.946666l-96 160c-5.866667 9.6-16.32 15.466667-27.52 15.466667zM672 704H480c-17.706667 0-32-14.293333-32-32s14.293333-32 32-32h192c17.706667 0 32 14.293333 32 32s-14.293333 32-32 32zM672 576H544c-17.706667 0-32-14.293333-32-32s14.293333-32 32-32h128c17.706667 0 32 14.293333 32 32s-14.293333 32-32 32z" p-id="8257" fill="#8a8a8a"></path></svg>
|
After Width: | Height: | Size: 1.9 KiB |
1
bricks/imgs/video-record.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748678133532" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18809" width="200" height="200"><path d="M768 384c0-47.061333-38.272-85.333333-85.333333-85.333333h-61.184l-103.168-171.904A85.674667 85.674667 0 0 0 445.184 85.333333H213.333333v85.333334h231.850667l76.8 128H170.666667c-47.061333 0-85.333333 38.272-85.333334 85.333333v384c0 47.061333 38.272 85.333333 85.333334 85.333333h512c47.061333 0 85.333333-38.272 85.333333-85.333333v-128l170.666667 85.333333v-298.666666l-170.666667 85.333333V384z m-85.248 384H170.666667V384h512l0.042666 170.666667H682.666667v42.666666l0.042666 0.042667 0.042667 170.624z" p-id="18810" fill="#8a8a8a"></path><path d="M256 597.333333h256v85.333334H256z" p-id="18811" fill="#8a8a8a"></path></svg>
|
After Width: | Height: | Size: 788 B |
1
bricks/imgs/wf-instance.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748677950218" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15876" width="200" height="200"><path d="M757.04775111 165.06766222H119.92405333c-54.17984 0-98.02183111 44.33578667-98.02183111 99.12661333v644.3008c0 54.68956445 43.84199111 99.11978667 98.02183111 99.11978667h637.12369778c54.08654222 0 98.02069333-44.43022222 98.02069334-99.11978667v-644.3008c0-54.78968889-43.93415111-99.12661333-98.02069334-99.12661333z m0 743.42741333H119.92405333v-625.2999111h637.12369778v625.2999111z" p-id="15877" fill="#8a8a8a"></path><path d="M904.08163555 16.384H266.95224889c-54.17984 0-98.02069333 44.33578667-98.02069334 99.12547555h735.15008V858.9312c54.08199111 0 98.01614222-44.42908445 98.01614223-99.12547555V115.50947555c0-54.78968889-43.93415111-99.12547555-98.01614223-99.12547555z" p-id="15878" fill="#8a8a8a"></path><path d="M435.95434667 649.31271111c11.65880889-10.78272 20.19100445-24.02417778 25.37699555-39.37962666h84.53233778c4.4032 10.70535111 11.95008 19.99189333 21.90563555 26.93006222 11.51772445 8.02702222 25.22794667 12.26979555 39.66179556 12.26865778l0.56888889-0.00227556c37.32138667-0.08874667 67.76263111-28.25671111 67.85934222-62.80419556-0.09671111-34.50652445-30.51633778-62.66538667-67.80700444-62.77006222l-0.6144-0.00227556c-14.41678222 0-28.12472889 4.24277333-39.64131556 12.26979556-9.95783111 6.93930667-17.50357333 16.22471111-21.90677333 26.93006222H461.36888889c-10.72241778-32.04664889-35.93443555-55.54744889-67.95036444-63.35715555v-17.56387556c0-15.27011555 14.48277333-28.66517333 30.99192888-28.66517333h121.45322667c4.4032 10.70762667 11.95008 19.99303111 21.90563555 26.93233778 11.51658667 8.02588445 25.23022222 12.26752 39.66634667 12.26752l0.56433778-0.00227556c37.32138667-0.08988445 67.76263111-28.25784889 67.85934222-62.80419556-0.09671111-34.52131555-30.52885333-62.68017778-67.83431111-62.77006222l-0.58481778-0.00341333c-14.41564445 0-28.12245333 4.24277333-39.64131555 12.27093333-9.95896889 6.93930667-17.50584889 16.22471111-21.90904889 26.92892445H424.48099555c-0.26510222-0.00227555-0.52565333-0.00227555-0.79075555-0.00227556-21.71335111 0-42.12736 7.81880889-57.48394667 22.01827556-15.34065778 14.18695111-24.02304 33.81475555-23.82165333 53.83054222v18.07928889c-16.59562667 4.79687111-30.90773333 12.68508445-42.55857778 23.46325333-11.65653333 10.78272-20.18190222 24.02417778-25.35651555 39.37735111h-47.85265778c-15.01639111 0-25.50442667 9.70069333-25.50442667 23.59068445 0 13.88885333 10.48803555 23.58840889 25.50442667 23.58840889h47.84469333c10.72583111 32.05006222 35.93557333 55.54744889 67.95150223 63.35715555v17.50129778c-0.20366222 20.05902222 8.47644445 39.69934222 23.81141333 53.88174222 15.35658667 14.20515555 35.77173333 22.02737778 57.48394667 22.02737778 0.26055111 0 0.52451555-0.00113778 0.70200888-0.00341333h121.45322667c4.4032 10.70648889 11.95008 19.99189333 21.90677333 26.9312 11.51772445 8.02702222 25.22567111 12.26865778 39.64359112 12.26865778h0.01934222l0.56775111-0.00227556c37.32138667-0.08988445 67.76263111-28.25898667 67.85934222-62.80419556-0.09671111-34.52245333-30.52771555-62.68131555-67.82976-62.76892444l-0.61553778-0.00341334c-14.41792 0-28.12472889 4.24163555-39.64359111 12.26865778-9.95669333 6.94044445-17.50357333 16.22357333-21.90677333 26.93006222h-121.48053333c-16.51029333 0-30.99192889-13.39392-30.9919289-28.66403555v-18.08042667c16.59562667-4.79459555 30.90773333-12.68394667 42.56199112-23.45870222z m-18.97016889-62.98965333c-0.07623111 24.97763555-22.10360889 45.35864889-49.09397333 45.43146667-27.07114667 0-49.09397333-20.36508445-49.09397334-45.39278223 0.07395555-24.97422222 22.09564445-45.35296 49.09397334-45.43032889 26.99491555 0.07736889 49.01660445 20.44359111 49.09397333 45.39164445z m170.13532444 0.02048c0-12.08206222 7.79832889-19.29671111 20.86115556-19.29671111 13.06168889 0 20.86001778 7.21464889 20.86001777 19.29671111 0 12.06613333-7.80856889 19.27168-20.9146311 19.27168l-0.94321778 0.00910222c-12.43818667-0.37319111-19.86332445-7.5776-19.86332445-19.28078222z m-3.98904889-156.76529778c0-13.73297778 9.98741333-22.96035555 24.85134222-22.96035555 14.84572445 0 24.81948445 9.22624 24.81948445 22.96035555 0 13.74663111-9.97489778 22.98197333-24.81948445 22.98197333-14.86392889 0-24.85134222-9.23534222-24.85134222-22.98197333z m3.98904889 313.52945778c0-12.08206222 7.79832889-19.29557333 20.86115556-19.29557333 13.06168889 0 20.86001778 7.21351111 20.86001777 19.29557333s-7.79832889 19.29557333-20.86001777 19.29557333c-13.06282667 0-20.86115555-7.21351111-20.86115556-19.29557333z" p-id="15879" fill="#8a8a8a"></path></svg>
|
After Width: | Height: | Size: 4.5 KiB |
1
bricks/imgs/workflow.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748677519101" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4599" width="200" height="200"><path d="M168.096 349.664c92.704 0 167.84-76.832 167.84-171.616 0-94.72-75.136-171.584-167.84-171.584C75.392 6.464 0.256 83.296 0.256 178.048c0 94.784 75.136 171.616 167.84 171.616z m0-307.232c72.544 0 131.552 60.832 131.552 135.616 0 74.816-59.008 135.648-131.552 135.648-72.544 0-131.584-60.832-131.584-135.648 0-74.784 59.04-135.616 131.584-135.616zM850.752 1001.28c92.704 0 167.84-76.8 167.84-171.584 0-94.752-75.136-171.584-167.84-171.584-92.704 0-167.84 76.8-167.84 171.584 0 94.752 75.136 171.584 167.84 171.584z m0-307.2c72.544 0 131.584 60.832 131.584 135.616 0 74.784-59.04 135.648-131.584 135.648-72.544 0-131.584-60.864-131.584-135.648 0-74.784 59.04-135.616 131.584-135.616zM31.392 648.384h343.168v343.808H31.392V648.384z m39.808 39.84v264.128h263.584v-264.128H71.2zM846.848 1.088L1024 178.24l-176.832 176.8-177.12-177.152L846.848 1.088z m0.032 51.904L721.952 177.92l125.184 125.184 124.928-124.928-125.184-125.184z m-68.48 423.936l62.112-62.016v205.184l21.696 0.512 0.544-205.696 61.984 62.112 15.776-15.776-88.896-88.896-88.864 88.896 15.68 15.68z m-651.616 0l62.08-62.016v205.184l21.696 0.512 0.544-205.696 61.984 62.112 15.776-15.776-88.864-88.896-88.896 88.896 15.68 15.68zM550.88 148.16l61.984 62.112h-205.152l-0.544 21.696 205.696 0.544-62.08 61.984 15.744 15.776 88.896-88.896-88.896-88.864-15.68 15.68z" fill="#8a8a8a" p-id="4600"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
1
bricks/imgs/worknode.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748677626636" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5920" width="200" height="200"><path d="M554.666667 622.805333h327.125333a14.933333 14.933333 0 0 0 14.208-15.104v-149.76a15.104 15.104 0 0 0-15.061333-15.061333H554.666667a15.104 15.104 0 0 0-15.061334 15.061333v44.416H405.504L305.92 402.773333V320.298667A108.928 108.928 0 0 0 276.053333 106.666667a108.928 108.928 0 1 0-29.952 213.632 4.864 4.864 0 0 0 0 1.408v80.426666l-109.226666 109.354667a30.208 30.208 0 0 0 0 42.666667l108.8 109.354666v121.173334a30.037333 30.037333 0 0 0 29.994666 30.165333h263.424v44.714667A15.104 15.104 0 0 0 554.666667 874.666667h327.125333a15.104 15.104 0 0 0 14.208-15.104v-149.76a14.933333 14.933333 0 0 0-15.061333-15.104H554.666667a14.933333 14.933333 0 0 0-15.061334 15.104v44.544h-233.813333v-90.837334L405.333333 562.858667h133.717334v44.842666a14.933333 14.933333 0 0 0 15.616 15.104z" fill="#8a8a8a" p-id="5921"></path><path d="M405.504 502.357333L305.92 402.773333V320.298667A108.928 108.928 0 0 0 276.053333 106.666667a108.928 108.928 0 1 0-29.952 213.632 4.864 4.864 0 0 0 0 1.408v80.426666l-109.226666 109.354667a30.208 30.208 0 0 0 0 42.666667l108.8 109.354666h60.16L405.333333 562.858667l0.170667-60.501334z" fill="#8a8a8a" p-id="5922"></path></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
bricks/imgs/xlsx.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1748754762433" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="19761" width="100%" height="100%"><path d="M288 938.666667h618.666667a10.666667 10.666667 0 0 0 10.666666-10.666667V298.666667H736c-17.642667 0-32-14.357333-32-32V85.333333H288a10.666667 10.666667 0 0 0-10.666667 10.666667v832a10.666667 10.666667 0 0 0 10.666667 10.666667z" fill="#FFFFFF" p-id="19762"></path><path d="M912.917333 277.333333L725.333333 89.749333V266.666667a10.666667 10.666667 0 0 0 10.666667 10.666666h176.917333z" fill="#FFFFFF" p-id="19763"></path><path d="M929.290667 263.541333L739.125333 73.376A31.765333 31.765333 0 0 0 716.501333 64H288c-17.642667 0-32 14.357333-32 32v832c0 17.642667 14.357333 32 32 32h618.666667c17.642667 0 32-14.357333 32-32V286.165333c0-8.533333-3.338667-16.576-9.376-22.624zM725.333333 89.749333L912.917333 277.333333H736a10.666667 10.666667 0 0 1-10.666667-10.666666V89.749333zM906.666667 938.666667H288a10.666667 10.666667 0 0 1-10.666667-10.666667V96a10.666667 10.666667 0 0 1 10.666667-10.666667h416v181.333334c0 17.642667 14.357333 32 32 32h181.333333v629.333333a10.666667 10.666667 0 0 1-10.666666 10.666667z" fill="${color}" opacity=".64" p-id="19764"></path><path d="M842.666667 682.666667H725.333333a10.666667 10.666667 0 0 1-10.666666-10.666667v-21.333333a10.666667 10.666667 0 0 1 10.666666-10.666667h117.333334a10.666667 10.666667 0 0 1 10.666666 10.666667v21.333333a10.666667 10.666667 0 0 1-10.666666 10.666667z" fill="#134A2C" p-id="19765"></path><path d="M672 682.666667H554.666667a10.666667 10.666667 0 0 1-10.666667-10.666667v-21.333333a10.666667 10.666667 0 0 1 10.666667-10.666667h117.333333a10.666667 10.666667 0 0 1 10.666667 10.666667v21.333333a10.666667 10.666667 0 0 1-10.666667 10.666667z" fill="#185C37" p-id="19766"></path><path d="M842.666667 597.333333H725.333333a10.666667 10.666667 0 0 1-10.666666-10.666666v-21.333334a10.666667 10.666667 0 0 1 10.666666-10.666666h117.333334a10.666667 10.666667 0 0 1 10.666666 10.666666v21.333334a10.666667 10.666667 0 0 1-10.666666 10.666666z" fill="#21A366" p-id="19767"></path><path d="M672 597.333333H554.666667a10.666667 10.666667 0 0 1-10.666667-10.666666v-21.333334a10.666667 10.666667 0 0 1 10.666667-10.666666h117.333333a10.666667 10.666667 0 0 1 10.666667 10.666666v21.333334a10.666667 10.666667 0 0 1-10.666667 10.666666z" fill="#107C41" p-id="19768"></path><path d="M842.666667 512H725.333333a10.666667 10.666667 0 0 1-10.666666-10.666667v-21.333333a10.666667 10.666667 0 0 1 10.666666-10.666667h117.333334a10.666667 10.666667 0 0 1 10.666666 10.666667v21.333333a10.666667 10.666667 0 0 1-10.666666 10.666667z" fill="#33C481" p-id="19769"></path><path d="M672 512H554.666667a10.666667 10.666667 0 0 1-10.666667-10.666667v-21.333333a10.666667 10.666667 0 0 1 10.666667-10.666667h117.333333a10.666667 10.666667 0 0 1 10.666667 10.666667v21.333333a10.666667 10.666667 0 0 1-10.666667 10.666667z" fill="#21A366" p-id="19770"></path><path d="M128 789.333333h341.333333a42.666667 42.666667 0 0 0 42.666667-42.666666V405.333333a42.666667 42.666667 0 0 0-42.666667-42.666666H128a42.666667 42.666667 0 0 0-42.666667 42.666666v341.333334a42.666667 42.666667 0 0 0 42.666667 42.666666z" fill="#107C41" p-id="19771"></path><path d="M180.8 704l84.096-128.362667L187.861333 448h61.994667l42.048 81.589333c3.861333 7.733333 6.517333 13.504 7.968 17.312h0.544c2.794667-6.186667 5.685333-12.192 8.704-18.026666L354.069333 448h56.906667l-79.018667 126.933333L412.981333 704H352.426667l-48.576-89.621333a74.122667 74.122667 0 0 1-5.802667-11.957334h-0.714667c-0.853333 2.858667-2.72 6.72-5.610666 11.605334L241.706667 704h-60.906667z" fill="#F9F7F7" p-id="19772"></path></svg>
|
After Width: | Height: | Size: 3.6 KiB |
259
bricks/input.js
@ -17,6 +17,9 @@ bricks.UiType =class extends bricks.Layout {
|
||||
}
|
||||
return o;
|
||||
}
|
||||
set_formdata(formdata){
|
||||
formdata.append(this.name, this.resultValue());
|
||||
}
|
||||
resultValue(){
|
||||
return this.value;
|
||||
}
|
||||
@ -46,6 +49,47 @@ bricks.UiType =class extends bricks.Layout {
|
||||
}
|
||||
}
|
||||
|
||||
bricks.UiAudioRecorder = class extends bricks.AudioRecorder {
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.uitype = 'audiorecorder';
|
||||
this.name = this.opts.name;
|
||||
this.required = opts.required || false;
|
||||
this.value = opts.value || opts.defaultvalue||'';
|
||||
this.bind('record_ended', this.getValue.bind(this));
|
||||
}
|
||||
|
||||
getValue(){
|
||||
var o = {}
|
||||
this.value = this.recordData.data;
|
||||
o[this.name] = this.value;
|
||||
return o;
|
||||
}
|
||||
set_formdata(formdata){
|
||||
formdata.append(this.name, this.value, 'record.wav');
|
||||
}
|
||||
resultValue(){
|
||||
return this.value;
|
||||
}
|
||||
focus(){
|
||||
this.dom_element.focus();
|
||||
}
|
||||
reset(){
|
||||
}
|
||||
setValue(v){
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
bricks.UiAudioText = class extends bricks.UiType {
|
||||
/*
|
||||
{
|
||||
@ -70,10 +114,12 @@ bricks.UiAudioText = class extends bricks.UiType {
|
||||
clear_text(){
|
||||
this.text_w.setValue('');
|
||||
}
|
||||
getValue(){
|
||||
return this.text_w.getValue();
|
||||
resultValue(){
|
||||
this.value = this.text_w.resultValue();
|
||||
return this.value;
|
||||
}
|
||||
setValue(v){
|
||||
this.value = v;
|
||||
this.text_w.setValue(v);
|
||||
}
|
||||
set_result_text(event){
|
||||
@ -164,7 +210,8 @@ bricks.UiStr =class extends bricks.UiType {
|
||||
}
|
||||
onkeydown(event){
|
||||
if(event.key == 'Enter'){
|
||||
this.dispatch('blur', )
|
||||
var v = this.getValue();
|
||||
this.dispatch('blur', v)
|
||||
}
|
||||
}
|
||||
check_pattern(value){
|
||||
@ -203,6 +250,105 @@ bricks.UiStr =class extends bricks.UiType {
|
||||
}
|
||||
}
|
||||
|
||||
bricks.UiSearch = class extends bricks.HBox {
|
||||
/*
|
||||
search_url:
|
||||
valueField
|
||||
textField
|
||||
select_event
|
||||
popup_options
|
||||
value,
|
||||
text
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.uitype = 'search';
|
||||
var inputdesc = {
|
||||
name:this.name,
|
||||
value:this.text,
|
||||
readonly:true
|
||||
}
|
||||
this.str_in = new bricks.UiStr(inputdesc);
|
||||
this.search_icon = new bricks.Icon({
|
||||
url:bricks_resource('imgs/search.png'),
|
||||
rate:1.5
|
||||
});
|
||||
this.str_in.set_css('filler');
|
||||
this.search_icon.set_css('clickable');
|
||||
this.search_icon.bind('click', this.open_search_window.bind(this));
|
||||
this.add_widget(this.str_in);
|
||||
this.add_widget(this.search_icon);
|
||||
}
|
||||
async open_search_window(event){
|
||||
var desc = {
|
||||
"widgettype":"urlwidget",
|
||||
"options":{
|
||||
"url":this.search_url
|
||||
}
|
||||
}
|
||||
var w = await bricks.widgetBuild(desc, this);
|
||||
var tabular = null;
|
||||
for (var i=0;i<w.children.length;i++){
|
||||
if (w.children[i] instanceof bricks.Tabular){
|
||||
tabular = w.children[i];
|
||||
}
|
||||
}
|
||||
if (!tabular){
|
||||
console.log('tubular not found is w');
|
||||
return;
|
||||
}
|
||||
var win = bricks.default_popupwindow(this.popup_options||{});
|
||||
win.add_widget(w);
|
||||
win.open();
|
||||
tabular.bind(this.search_event, this.set_data.bind(this));
|
||||
tabular.bind(this.search_event, win.dismiss.bind(win));
|
||||
}
|
||||
set_data(event){
|
||||
var d = event.params;
|
||||
this.value = d[this.valueField];
|
||||
this.str_in.setValue(d[this.textField])
|
||||
}
|
||||
getValue(){
|
||||
var o = {}
|
||||
o[this.name] = this.resultValue();
|
||||
var d = this.getUserData();
|
||||
if (d){
|
||||
o = bricks.extend(o, d);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
set_formdata(formdata){
|
||||
formdata.append(this.name, this.resultValue());
|
||||
}
|
||||
resultValue(){
|
||||
return this.value;
|
||||
}
|
||||
focus(){
|
||||
this.str_in.dom_element.focus();
|
||||
}
|
||||
reset(){
|
||||
var v = this.opts.value||this.opts.defaultvalue|| '';
|
||||
this.setValue(v);
|
||||
this.str_in.setValue(this.opts.text||'');
|
||||
}
|
||||
setValue(v, t){
|
||||
if (! v)
|
||||
v = '';
|
||||
this.vlaue = v;
|
||||
this.str_in.setValue(t);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
bricks.UiPassword =class extends bricks.UiStr {
|
||||
/*
|
||||
{
|
||||
@ -265,6 +411,7 @@ bricks.UiFloat =class extends bricks.UiInt {
|
||||
this.dom_element.step = step;
|
||||
}
|
||||
resultValue(){
|
||||
super.resultValue();
|
||||
return parseFloat(this.value);
|
||||
}
|
||||
setValue(v){
|
||||
@ -331,7 +478,7 @@ bricks.UiFile =class extends bricks.UiStr {
|
||||
return this.dom_element.files;
|
||||
}
|
||||
resultValue(){
|
||||
return this.get_files();
|
||||
return this.get_files()[0];
|
||||
}
|
||||
setValue(v){
|
||||
return;
|
||||
@ -346,7 +493,8 @@ bricks.UiImage =class extends bricks.VBox {
|
||||
this.uitype='image';
|
||||
this.camera_w = new bricks.Icon({
|
||||
url:bricks_resource('imgs/camera.png'),
|
||||
rate:1.5});
|
||||
tip:'use cemera to take a picture',
|
||||
rate:2});
|
||||
this.add_widget(this.camera_w);
|
||||
this.camera_w.bind('click', this.take_photo.bind(this));
|
||||
this.bind('drop', this.dropHandle.bind(this));
|
||||
@ -359,7 +507,8 @@ bricks.UiImage =class extends bricks.VBox {
|
||||
this.dom_element.appendChild(this.input);
|
||||
this.imgw = null;
|
||||
}
|
||||
take_photo(){
|
||||
take_photo(event){
|
||||
event.stopPropagation();
|
||||
var camera = new bricks.Camera({
|
||||
"archor":"cc",
|
||||
"auto_open":true,
|
||||
@ -369,12 +518,13 @@ bricks.UiImage =class extends bricks.VBox {
|
||||
camera.bring_to_top();
|
||||
camera.bind('shot', this.accept_photo.bind(this));
|
||||
}
|
||||
accept_photo(url){
|
||||
accept_photo(camera, event){
|
||||
camera.dismiss();
|
||||
if (this.imgw){
|
||||
this.remove_widget(this.imgw);
|
||||
}
|
||||
this.imgw = new bricks.Image({
|
||||
url:d,
|
||||
url:event.params,
|
||||
width:'100%'
|
||||
});
|
||||
this.add_widget(this.imgw);
|
||||
@ -395,6 +545,8 @@ bricks.UiImage =class extends bricks.VBox {
|
||||
if (this.imgw){
|
||||
this.remove_widget(this.imgw);
|
||||
}
|
||||
this.value = e.target.result;
|
||||
console.log('this.value=', this.value);
|
||||
this.imgw = new bricks.Image({
|
||||
url:e.target.result,
|
||||
width:'100%'
|
||||
@ -403,10 +555,22 @@ bricks.UiImage =class extends bricks.VBox {
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
set_formdata(fd){
|
||||
// fd.append(this.name, this.resultValue(), 'test.png');
|
||||
fd.append(this.name, this.resultValue());
|
||||
}
|
||||
resultValue(){
|
||||
if (this.imgw){
|
||||
this.value = this.imgw.base64();
|
||||
return this.value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
getValue(){
|
||||
var ret = {}
|
||||
if (this.imgw){
|
||||
ret[this.name] = this.imgw.base64()
|
||||
// ret[this.name] = this.imgw.base64()
|
||||
ret[this.name] = this.value;
|
||||
} else {
|
||||
ret[this.name] = null;
|
||||
}
|
||||
@ -653,6 +817,7 @@ bricks.UiText =class extends bricks.UiType {
|
||||
this.uitype='text';
|
||||
this.build();
|
||||
this.charsize_sizing();
|
||||
this.bind('keydown', this.key_handle.bind(this))
|
||||
}
|
||||
create(){
|
||||
this.dom_element = this._create('textarea');
|
||||
@ -683,6 +848,78 @@ bricks.UiText =class extends bricks.UiType {
|
||||
var v = this.opts.value || this.opts.defaultvalue||'';
|
||||
this.setValue(v);
|
||||
}
|
||||
key_handle(e){
|
||||
switch(e.key){
|
||||
case 'Tab':
|
||||
e.preventDefault(); // 阻止默认Tab行为
|
||||
var erase = false
|
||||
if (e.shiftKey) erase = true;
|
||||
this.handle_tab_indent(erase);
|
||||
break;
|
||||
case 'Enter':
|
||||
e.preventDefault(); // 阻止默认行为
|
||||
this.handle_enter();
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
case 'ArrowDown':
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
set_editor_focus(editor, pos){
|
||||
editor.selectionStart = editor.selectionEnd = pos;
|
||||
editor.focus();
|
||||
}
|
||||
handle_enter(){
|
||||
var editor = this.dom_element;
|
||||
const cursorPos = editor.selectionStart;
|
||||
const value = editor.value;
|
||||
const before = value.substring(0, cursorPos);
|
||||
const after = value.substring(cursorPos);
|
||||
editor.value = before + '\n' + after;
|
||||
editor.selectionStart = editor.selectionEnd = cursorPos + 1;
|
||||
editor.focus();
|
||||
schedule_once(this.set_editor_focus.bind(this, editor, cursorPos+1), 0.5);
|
||||
}
|
||||
handle_tab_indent(erase){
|
||||
/* erase == true : delete tabspace
|
||||
else
|
||||
add tabspace
|
||||
*/
|
||||
var editor = this.dom_element;
|
||||
var indent_cnt;
|
||||
const cursorPos = editor.selectionStart;
|
||||
const value = editor.value;
|
||||
|
||||
// 获取光标所在行的开始位置
|
||||
const beforeCursor = value.substring(0, cursorPos);
|
||||
const lastLineStart = beforeCursor.lastIndexOf("\n") + 1; // 上一行的结束位置
|
||||
const currentLineStart = lastLineStart; // 当前行的开始位置
|
||||
const cur_col = cursorPos - currentLineStart;
|
||||
var pos;
|
||||
if (!erase){
|
||||
indent_cnt = 4 - cur_col % 4;
|
||||
if (indent_cnt == 0) indent_cnt = 4;
|
||||
// 根据光标前的空格数动态插入合适数量的空格
|
||||
const before = value.substring(0, cursorPos);
|
||||
const after = value.substring(cursorPos);
|
||||
const indentation = ' '.repeat(indent_cnt); // 生成合适数量的空格
|
||||
editor.value = before + indentation + after;
|
||||
// 更新光标位置(将光标移到插入的缩进后面)
|
||||
pos = cursorPos + indent_cnt;
|
||||
editor.selectionStart = editor.selectionEnd = cursorPos + indent_cnt;
|
||||
} else {
|
||||
indent_cnt = cur_col % 4;
|
||||
if (indent_cnt == 0) indent_cnt = 4;
|
||||
const before = value.substring(0, cursorPos - indent_cnt);
|
||||
const after = value.substring(cursorPos);
|
||||
editor.value = before + after;
|
||||
pos = cursorPos - indent_cnt;
|
||||
editor.selectionStart = editor.selectionEnd = cursorPos - indent_cnt;
|
||||
}
|
||||
editor.focus();
|
||||
schedule_once(this.set_editor_focus.bind(this, editor, pos), 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
bricks.UiCode =class extends bricks.UiType {
|
||||
@ -745,7 +982,7 @@ bricks.UiCode =class extends bricks.UiType {
|
||||
e.removeChild(e.firstChild);
|
||||
}
|
||||
var v = this.opts.value || this.opts.defaultvalue || null;
|
||||
if (!v && ! this.opts.nullable){
|
||||
if (!v && ! this.opts.nullable && data.length > 0){
|
||||
v = data[0][this.opts.valueField]
|
||||
}
|
||||
if (this.opts.nullable){
|
||||
@ -888,6 +1125,7 @@ bricks.UiVideo =class extends bricks.UiStr {
|
||||
}
|
||||
}
|
||||
var Input = new bricks._Input();
|
||||
Input.register('UiAudioRecorder', 'audiorecorder', bricks.UiAudioRecorder);
|
||||
Input.register('UiStr', 'str', bricks.UiStr);
|
||||
Input.register('UiHide', 'hide', bricks.UiHide);
|
||||
Input.register('UiTel', 'tel', bricks.UiTel);
|
||||
@ -905,3 +1143,4 @@ Input.register('UiPassword', 'password', bricks.UiPassword);
|
||||
Input.register('UiAudio', 'audio', bricks.UiAudio);
|
||||
Input.register('UiVideo', 'video', bricks.UiVideo);
|
||||
Input.register('UiAudioText', 'audiotext', bricks.UiAudioText);
|
||||
Input.register('UiSearch', 'search', bricks.UiSearch);
|
||||
|
@ -44,9 +44,9 @@ bricks.HttpText = class {
|
||||
};
|
||||
bricks.extend(this.headers, headers);
|
||||
var width=0, height=0;
|
||||
var is_mobile = 0
|
||||
var is_mobile = '0'
|
||||
if (bricks.is_mobile()){
|
||||
is_mobile = 1;
|
||||
is_mobile = '1';
|
||||
}
|
||||
if (bricks.app) {
|
||||
width = bricks.app.screenWidth();
|
||||
@ -77,8 +77,6 @@ bricks.HttpText = class {
|
||||
return await resp.text();
|
||||
}
|
||||
add_own_params(params){
|
||||
if (! params)
|
||||
params = {};
|
||||
var session = bricks.app.get_session();
|
||||
if (params instanceof FormData){
|
||||
for ( const [key, value] of Object.entries(this.params)){
|
||||
@ -89,6 +87,8 @@ bricks.HttpText = class {
|
||||
}
|
||||
return params;
|
||||
}
|
||||
if (! params)
|
||||
params = {};
|
||||
var p = bricks.extend({}, this.params);
|
||||
p = bricks.extend(p, params);
|
||||
if (session){
|
||||
@ -102,26 +102,31 @@ bricks.HttpText = class {
|
||||
}
|
||||
return Object.assign(this.headers, headers);
|
||||
}
|
||||
async httpcall(url, {method='GET', headers=null, params=null}={}){
|
||||
async bricks_fetch(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;
|
||||
if (data instanceof FormData){
|
||||
method = 'POST';
|
||||
_params.body = data;
|
||||
} else {
|
||||
if (data instanceof FormData){
|
||||
_params.body = data;
|
||||
if (method == 'GET' || method == 'HEAD') {
|
||||
let pstr = url_params(data);
|
||||
url = url + '?' + pstr;
|
||||
} else {
|
||||
_params.body = JSON.stringify(data);
|
||||
}
|
||||
}
|
||||
const fetchResult = await fetch(url, _params);
|
||||
// console.log('fetchResult.status=', fetchResult.status, url, 'login url=', bricks.app.login_url);
|
||||
return await fetch(url, _params);
|
||||
}
|
||||
async httpcall(url, opts){
|
||||
const fetchResult = await this.bricks_fetch(url, {
|
||||
method: opts.method,
|
||||
headers: opts.headers,
|
||||
params: opts.params});
|
||||
if (fetchResult.status == 401 && bricks.app.login_url){
|
||||
console.log('go to login')
|
||||
return await this.withLoginInfo(url, _params);
|
||||
@ -187,6 +192,18 @@ bricks.HttpText = class {
|
||||
}
|
||||
}
|
||||
|
||||
bricks.HttpArrayBuffer = class extends bricks.HttpText {
|
||||
async get_result_data(resp){
|
||||
return await resp.arrayBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
bricks.HttpBin = class extends bricks.HttpText {
|
||||
async get_result_data(resp){
|
||||
return await resp.blob();
|
||||
}
|
||||
}
|
||||
|
||||
bricks.HttpResponse = class extends bricks.HttpText {
|
||||
async get_result_data(resp){
|
||||
return resp;
|
||||
|
18
bricks/keypress.js
Normal file
@ -0,0 +1,18 @@
|
||||
var bricks = window.bricks || {};
|
||||
|
||||
bricks.KeyPress = class extends bricks.VBox {
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
bricks.app.bind('keydown', this.key_handler.bind(this));
|
||||
}
|
||||
key_handler(event){
|
||||
var key = event.key;
|
||||
if (!key) return;
|
||||
this.clear_widgets();
|
||||
var w = new bricks.Text({text:'key press is:' + key});
|
||||
this.add_widget(w)
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('KeyPress', bricks.KeyPress);
|
||||
|
@ -4,9 +4,30 @@ bricks.key_selectable_stack = [];
|
||||
|
||||
bricks.Layout = class extends bricks.JsWidget {
|
||||
constructor(options){
|
||||
if (! options){
|
||||
options = {};
|
||||
}
|
||||
super(options);
|
||||
this._container = true;
|
||||
this.keyselectable = options.keyselectable || false;
|
||||
this.children = [];
|
||||
if (this.use_key_select){
|
||||
this.enable_key_select();
|
||||
}
|
||||
}
|
||||
build_title(){
|
||||
if (this.title){
|
||||
this.title_w = new bricks.Title3({otext:this.title, i18n:true, dynsize:true});
|
||||
this.add_widget(this.title_w);
|
||||
}
|
||||
}
|
||||
build_description(){
|
||||
if (this.description){
|
||||
this.description_w = new bricks.Text({otext:this.description,
|
||||
i18n:true, dynsize:true
|
||||
});
|
||||
this.add_widget(this.description_w);
|
||||
}
|
||||
}
|
||||
set_key_select_items(){
|
||||
this.key_select_items = this.children;
|
||||
@ -14,7 +35,6 @@ bricks.Layout = class extends bricks.JsWidget {
|
||||
enable_key_select(){
|
||||
this.keyselectable = true;
|
||||
this.set_key_select_items();
|
||||
this.selected_children = null;
|
||||
bricks.app.bind('keydown', this.key_handler.bind(this));
|
||||
bricks.key_selectable_stack.push(this)
|
||||
this.select_default_item();
|
||||
@ -87,25 +107,31 @@ bricks.Layout = class extends bricks.JsWidget {
|
||||
}
|
||||
down_level(){
|
||||
this.set_key_select_items();
|
||||
for (var i=0;i<this.key_select_items.length;i++){
|
||||
var w = this.key_select_items[i];
|
||||
if(w.keyselectable){
|
||||
w.enable_key_select();
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
if (w.down_level()){
|
||||
return true;
|
||||
}
|
||||
} catch (e){
|
||||
;
|
||||
}
|
||||
var w = this.selected_item;
|
||||
if (! w) return;
|
||||
if (! w.keyselectable){
|
||||
w = w.find_first_keyselectable_child();
|
||||
if (! w) return;
|
||||
}
|
||||
return false;
|
||||
bricks.key_selectable_stack.push(this);
|
||||
this.disable_key_select();
|
||||
w.enable_key_select();
|
||||
}
|
||||
find_first_keyselectable_child(){
|
||||
for (var i=0;i<this.children;i++){
|
||||
if (this.children[i].keyselectable){
|
||||
return this.children[i];
|
||||
}
|
||||
var sw = this.children[i].find_first_keyselectable_child();
|
||||
if (sw) return sw;
|
||||
}
|
||||
return null
|
||||
}
|
||||
enter_handler(){
|
||||
if (! this.selected_item) {
|
||||
return;
|
||||
}
|
||||
this.selected_item.dispatch('click');
|
||||
this.down_level();
|
||||
}
|
||||
key_handler(event){
|
||||
if (!this.is_currkeyselectable()){
|
||||
|
266
bricks/llm.js
@ -41,7 +41,7 @@ bricks.LlmMsgAudio = class extends bricks.UpStreaming {
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
bricks.ModelOutput = class extends bricks.HBox {
|
||||
bricks.ModelOutput = class extends bricks.VBox {
|
||||
/* {
|
||||
icon:
|
||||
output_view:
|
||||
@ -53,16 +53,29 @@ bricks.ModelOutput = class extends bricks.HBox {
|
||||
opts = {};
|
||||
}
|
||||
opts.width = '100%';
|
||||
opts.height = 'auto';
|
||||
super(opts);
|
||||
var hb = new bricks.HBox({width:'100%', cheight:2});
|
||||
this.img = new bricks.Icon({
|
||||
rate:2,
|
||||
tip:this.opts.model,
|
||||
url:this.icon||bricks_resource('imgs/llm.png')
|
||||
});
|
||||
hb.add_widget(this.img);
|
||||
var mname = new bricks.Text({text:this.opts.model});
|
||||
hb.add_widget(mname);
|
||||
this.add_widget(hb);
|
||||
|
||||
this.content = new bricks.HBox({width:'100%'});
|
||||
this.add_widget(this.content);
|
||||
this.logid = null;
|
||||
this.img = new bricks.Icon({rate:2,url:this.icon||bricks_resource('imgs/llm.png')});
|
||||
this.run = new bricks.BaseRunning({target:this});
|
||||
this.add_widget(this.img);
|
||||
this.add_widget(this.run);
|
||||
this.content.add_widget(this.run);
|
||||
this.filler = new bricks.VBox({});
|
||||
this.filler.set_css('filler');
|
||||
this.add_widget(this.filler);
|
||||
this.add_widget(new bricks.BlankIcon({rate:2, flexShrink:0}));
|
||||
this.content.add_widget(new bricks.BlankIcon({rate:2, flexShrink:0}));
|
||||
this.content.add_widget(this.filler);
|
||||
this.content.add_widget(new bricks.BlankIcon({rate:2, flexShrink:0}));
|
||||
this.build_estimate_widgets();
|
||||
}
|
||||
build_estimate_widgets(){
|
||||
@ -104,7 +117,7 @@ bricks.ModelOutput = class extends bricks.HBox {
|
||||
async update_data(data){
|
||||
if (this.run) {
|
||||
this.run.stop_timepass();
|
||||
this.remove_widget(this.run);
|
||||
this.content.remove_widget(this.run);
|
||||
if(this.textvoice){
|
||||
this.upstreaming = new bricks.UpStreaming({
|
||||
url:this.tts_url
|
||||
@ -116,9 +129,18 @@ bricks.ModelOutput = class extends bricks.HBox {
|
||||
this.upstreaming.send(data.content);
|
||||
}
|
||||
this.run = null;
|
||||
var w = await bricks.widgetBuild(this.output_view, this.llmio, data);
|
||||
w.set_css('llm_msg');
|
||||
this.filler.clear_widgets();
|
||||
if (typeof this.output_view === 'string'){
|
||||
this.output_view = JSON.parse(this.output_view);
|
||||
}
|
||||
var desc = bricks.apply_data(this.output_view, data);
|
||||
var w = await bricks.widgetBuild(desc, this.llmio);
|
||||
if (! w){
|
||||
console.log('widgetBuild() return null, desc=', this.output_view, desc, 'data=', data);
|
||||
return;
|
||||
}
|
||||
w.set_css('llm_msg');
|
||||
w.set_style('width', '100%');
|
||||
this.filler.add_widget(w);
|
||||
this.filler.add_widget(this.estimate_w);
|
||||
if (data.logid){
|
||||
@ -140,7 +162,6 @@ bricks.LlmModel = class extends bricks.JsWidget {
|
||||
{
|
||||
icon:
|
||||
model:
|
||||
mapi:
|
||||
url:
|
||||
output_view:
|
||||
params:
|
||||
@ -160,16 +181,45 @@ bricks.LlmModel = class extends bricks.JsWidget {
|
||||
this.messages = [];
|
||||
}
|
||||
render_title(){
|
||||
var w = new bricks.HBox({});
|
||||
var w = new bricks.HBox({padding:'15px'});
|
||||
w.bind('click', this.show_setup_panel.bind(this))
|
||||
var img = new bricks.Icon({rate:2,url:this.opts.icon||bricks_resource('imgs/llm.png')});
|
||||
var txt = new bricks.Text({text:this.opts.model});
|
||||
var img = new bricks.Icon({
|
||||
rate:2,
|
||||
tip:this.opts.model,
|
||||
url:this.opts.icon||bricks_resource('imgs/llm.png')
|
||||
});
|
||||
// var txt = new bricks.Text({text:this.opts.model});
|
||||
w.add_widget(img);
|
||||
w.add_widget(txt);
|
||||
// w.add_widget(txt);
|
||||
return w;
|
||||
}
|
||||
show_setup_panel(event){
|
||||
|
||||
}
|
||||
inputdata2uploaddata(data){
|
||||
var d;
|
||||
if (data instanceof FormData){
|
||||
d = bricks.formdata_copy(data);
|
||||
} else {
|
||||
d = objcopy(data);
|
||||
}
|
||||
var fmt = this.opts.user_message_format;
|
||||
if (fmt){
|
||||
var umsg = bricks.apply_data(fmt, inputdata2dic(data));
|
||||
this.messages.push(umsg);
|
||||
}
|
||||
if (data instanceof FormData){
|
||||
d.append('model', this.opts.model)
|
||||
d.append('modelinstanceid', this.opts.modelinstanceid)
|
||||
d.append('modeltypeid', this.opts.modeltypeid)
|
||||
d.append('messages', JSON.stringify(this.messages));
|
||||
} else {
|
||||
d.messages = JSON.stringify(this.messages);
|
||||
d.model = this.opts.model;
|
||||
d.modelinstanceid = this.opts.modelinstanceid;
|
||||
d.modeltypeid = this.opts.modeltypeid;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
async model_inputed(data){
|
||||
if (!opts.use_session){
|
||||
@ -178,29 +228,24 @@ bricks.LlmModel = class extends bricks.JsWidget {
|
||||
var mout = new bricks.ModelOutput({
|
||||
textvoice:this.textvoice,
|
||||
tts_url:this.tts_url,
|
||||
icon:this.opts.icon,
|
||||
icon:this.opts.icon,
|
||||
model:this.opts.model,
|
||||
estimate_url:this.llmio.estimate_url,
|
||||
output_view:this.opts.output_view});
|
||||
this.llmio.o_w.add_widget(mout);
|
||||
var fmt = this.opts.user_message_format || { role:'user', content:'${prompt}'};
|
||||
var umsg = bricks.apply_data(fmt, data);
|
||||
var d = data;
|
||||
this.messages.push(umsg);
|
||||
d = {};
|
||||
d.messages = this.messages;
|
||||
d.model = this.opts.model;
|
||||
d.modelinstanceid = this.opts.modelinstanceid;
|
||||
d.modeltypeid = this.opts.modeltypeid;
|
||||
console.log('upload data=', d, this.options);
|
||||
if (this.response_mode == 'stream' || this.response_mode == 'async') {
|
||||
var d = this.inputdata2uploaddata(data);
|
||||
console.log('data_inouted=', data, 'upload_data=', d);
|
||||
var hr = new bricks.HttpResponseStream();
|
||||
var resp = await hr.post(this.opts.url, {params:d});
|
||||
await hr.handle_chunk(resp, this.chunk_response.bind(this, mout));
|
||||
this.chunk_ended();
|
||||
} else {
|
||||
var d = this.inputdata2uploaddata(data);
|
||||
var hj = new bricks.HttpJson()
|
||||
var resp = await hj.post(this.opts.url, {params:d});
|
||||
if (this.response_mode == 'sync'){
|
||||
resp.content = bricks.escapeSpecialChars(resp.content)
|
||||
mout.update_data(resp);
|
||||
if (this.messages){
|
||||
var msg = this.llm_msg_format();
|
||||
@ -229,7 +274,7 @@ bricks.LlmModel = class extends bricks.JsWidget {
|
||||
d.content = bricks.escapeSpecialChars(d.content);
|
||||
this.resp_data = d;
|
||||
mout.update_data(d);
|
||||
console.log('stream data=', d);
|
||||
// console.log('stream data=', d);
|
||||
}
|
||||
chunk_ended(){
|
||||
if (! this.messages) {
|
||||
@ -248,6 +293,7 @@ bricks.LlmIO = class extends bricks.VBox {
|
||||
options:
|
||||
{
|
||||
user_icon:
|
||||
list_models_url:
|
||||
input_fields:
|
||||
input_view:
|
||||
output_view:
|
||||
@ -257,7 +303,6 @@ bricks.LlmIO = class extends bricks.VBox {
|
||||
{
|
||||
icon:
|
||||
model:
|
||||
mapi:
|
||||
url:
|
||||
params:
|
||||
use_session:
|
||||
@ -271,31 +316,158 @@ bricks.LlmIO = class extends bricks.VBox {
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.llmmodels = [];
|
||||
this.title_w = new bricks.HBox({cheight:2});
|
||||
this.i_w = new bricks.VBox({cheight:5});
|
||||
this.title_w = new bricks.HBox({cheight:3});
|
||||
var bottom_box = new bricks.HBox({cheight:3});
|
||||
this.i_w = new bricks.Icon({
|
||||
rate:2,
|
||||
url:bricks_resource('imgs/input.png'),
|
||||
margin:'14px',
|
||||
tip:'input data',
|
||||
css:'clickable'
|
||||
});
|
||||
this.nm_w = new bricks.Icon({
|
||||
rate:2,
|
||||
url:bricks_resource('imgs/add.png'),
|
||||
margin:'14px',
|
||||
tip:'add new model',
|
||||
css:'clickable'
|
||||
});
|
||||
bottom_box.add_widget(this.i_w);
|
||||
bottom_box.add_widget(this.nm_w);
|
||||
|
||||
this.nm_w.bind('click', this.open_search_models.bind(this));
|
||||
this.i_w.bind('click', this.open_input_widget.bind(this));
|
||||
this.o_w = new bricks.Filler({overflow:'auto'});
|
||||
this.add_widget(this.title_w);
|
||||
this.add_widget(this.o_w);
|
||||
if (this.models.length < 2 && this.tts_url){
|
||||
this.textvoice = true;
|
||||
}
|
||||
this.add_widget(this.i_w);
|
||||
this.add_widget(bottom_box);
|
||||
this.models.forEach( m =>{
|
||||
if (this.textvoice){
|
||||
m.textvoice = true;
|
||||
m.tts_url = this.tts_url;
|
||||
}
|
||||
var lm = new bricks.LlmModel(this, m);
|
||||
this.llmmodels.push(lm);
|
||||
var tw = lm.render_title();
|
||||
this.title_w.add_widget(tw);
|
||||
this.show_added_model(m);
|
||||
});
|
||||
this.build_input();
|
||||
}
|
||||
show_added_model(m){
|
||||
if (this.textvoice){
|
||||
m.textvoice = true;
|
||||
m.tts_url = this.tts_url;
|
||||
}
|
||||
var lm = new bricks.LlmModel(this, m);
|
||||
this.llmmodels.push(lm);
|
||||
var tw = lm.render_title();
|
||||
this.title_w.add_widget(tw);
|
||||
}
|
||||
async open_search_models(event){
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
var rect = this.showRectage();
|
||||
var opts = {
|
||||
title:"select model",
|
||||
icon:bricks_resource('imgs/search.png'),
|
||||
auto_destroy:true,
|
||||
auto_open:true,
|
||||
auto_dismiss:false,
|
||||
movable:true,
|
||||
top:rect.top + 'px',
|
||||
left:rect.left + 'px',
|
||||
width: rect.right - rect.left + 'px',
|
||||
height: rect.bottom - rect.top + 'px'
|
||||
}
|
||||
var w = new bricks.PopupWindow(opts);
|
||||
var sopts = {
|
||||
data_url:this.list_models_url,
|
||||
data_params:{
|
||||
mii:this.models[0].modelinstanceid,
|
||||
mti:this.models[0].modeltypeid
|
||||
},
|
||||
data_method:'POST',
|
||||
col_cwidth: 24,
|
||||
record_view:{
|
||||
widgettype:"VBox",
|
||||
options:{
|
||||
cheight:20,
|
||||
css:"card"
|
||||
},
|
||||
subwidgets:[
|
||||
{
|
||||
widgettype:"Title4",
|
||||
options:{
|
||||
text:"${name}"
|
||||
}
|
||||
},
|
||||
{
|
||||
widgettype:"Filler",
|
||||
options:{
|
||||
css:"scroll"
|
||||
},
|
||||
subwidgets:[
|
||||
{
|
||||
widgettype:"VBox",
|
||||
options:{
|
||||
css:"subcard"
|
||||
},
|
||||
subwidgets:[
|
||||
{
|
||||
widgettype:"Text",
|
||||
options:{
|
||||
text:"模型描述:${description}",
|
||||
wrap:true
|
||||
}
|
||||
},
|
||||
{
|
||||
widgettype:"Text",
|
||||
options:{
|
||||
text:"启用日期:${enable_date}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
var cols = new bricks.Cols(sopts);
|
||||
cols.bind('record_click', this.add_new_model.bind(this));
|
||||
cols.bind('record_click', w.dismiss.bind(w));
|
||||
w.add_widget(cols);
|
||||
w.open();
|
||||
}
|
||||
async add_new_model(event){
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.models.push(event.params);
|
||||
this.show_added_model(event.params);
|
||||
}
|
||||
async open_input_widget(event){
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
var rect = this.showRectage();
|
||||
var opts = {
|
||||
title:"input data",
|
||||
icon:bricks_resource('imgs/input.png'),
|
||||
auto_destroy:true,
|
||||
auto_open:true,
|
||||
auto_dismiss:false,
|
||||
movable:true,
|
||||
top:rect.top + 'px',
|
||||
left:rect.left + 'px',
|
||||
width: rect.right - rect.left + 'px',
|
||||
height: rect.bottom - rect.top + 'px'
|
||||
}
|
||||
var w = new bricks.PopupWindow(opts);
|
||||
var fopts = {
|
||||
fields:this.input_fields
|
||||
}
|
||||
var fw = new bricks.Form(fopts);
|
||||
fw.bind('submit', this.handle_input.bind(this));
|
||||
fw.bind('submit', w.destroy.bind(w));
|
||||
w.add_widget(fw);
|
||||
w.open();
|
||||
}
|
||||
async handle_input(event){
|
||||
var params = event.params;
|
||||
if (params.prompt)
|
||||
params.prompt = bricks.escapeSpecialChars(params.prompt);
|
||||
await this.show_input(params);
|
||||
for(var i=0;i<this.llmmodels.length;i++){
|
||||
var lm = this.llmmodels[i];
|
||||
@ -307,7 +479,9 @@ bricks.LlmIO = class extends bricks.VBox {
|
||||
}
|
||||
async show_input(params){
|
||||
var box = new bricks.HBox({width:'100%'});
|
||||
var w = await bricks.widgetBuild(this.input_view, this.o_w, params);
|
||||
var data = inputdata2dic(params);
|
||||
console.log('data=', data, 'input_view=', this.input_view);
|
||||
var w = await bricks.widgetBuild(this.input_view, this.o_w, data);
|
||||
w.set_css(this.msg_css||'user_msg');
|
||||
w.set_css('filler');
|
||||
var img = new bricks.Icon({rate:2,url:this.user_icon||bricks_resource('imgs/user.png')});
|
||||
@ -316,14 +490,6 @@ bricks.LlmIO = class extends bricks.VBox {
|
||||
box.add_widget(img);
|
||||
this.o_w.add_widget(box);
|
||||
}
|
||||
build_input(){
|
||||
var fopts = {
|
||||
fields:this.input_fields
|
||||
};
|
||||
var fw = new bricks.InlineForm(fopts);
|
||||
fw.bind('submit', this.handle_input.bind(this));
|
||||
this.i_w.add_widget(fw);
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('LlmIO', bricks.LlmIO);
|
||||
|
@ -11,6 +11,8 @@ bricks.Menu = class extends bricks.VBox {
|
||||
super(options);
|
||||
this.dom_element.style.display = "";
|
||||
this.dom_element.style.backgroundColor = options.bgcolor || "white";
|
||||
this.build_title();
|
||||
this.build_description();
|
||||
this.create_children(this, this.opts.items);
|
||||
this.bind('item_click', this.menu_clicked.bind(this));
|
||||
}
|
||||
@ -24,7 +26,19 @@ bricks.Menu = class extends bricks.VBox {
|
||||
console.log(event);
|
||||
let e = event.target;
|
||||
let opts = event.params;
|
||||
var t = bricks.getWidgetById(this.target);
|
||||
var t;
|
||||
var popts;
|
||||
if (this.target == 'PopupWindow'){
|
||||
popts = bricks.get_popupwindow_default_options();
|
||||
bricks.extend(popts, this.popup_options || {});
|
||||
t = new bricks.PopupWindow(popts);
|
||||
} else if (this.target == 'Popup'){
|
||||
popts = bricks.get_popup_default_options();
|
||||
bricks.extend(popts, this.popup_options || {});
|
||||
t = new bricks.Popup(popts);
|
||||
} else {
|
||||
t = bricks.getWidgetById(this.target);
|
||||
}
|
||||
if (t){
|
||||
var desc = {
|
||||
"widgettype":"urlwidget",
|
||||
@ -55,13 +69,17 @@ bricks.Menu = class extends bricks.VBox {
|
||||
itw.add_widget(subw);
|
||||
itw.add_widget(w1);
|
||||
this.create_children(w1, item.items);
|
||||
subw.bind('click', w1.toggle_hide.bind(w1));
|
||||
subw.bind('click', this.items_toggle_hide.bind(this, w1));
|
||||
} else {
|
||||
subw.bind('click', this.regen_menuitem_event.bind(this, item))
|
||||
w.add_widget(subw);
|
||||
}
|
||||
}
|
||||
}
|
||||
items_toggle_hide(w, event){
|
||||
w.toggle_hide();
|
||||
event.stopPropagation();
|
||||
}
|
||||
create_menuitem(item){
|
||||
var w = new bricks.HBox({cheight:this.item_cheight||2});
|
||||
var iw, tw;
|
||||
|
@ -189,6 +189,9 @@ bricks.ModalForm = class extends bricks.PopupWindow {
|
||||
super(opts);
|
||||
this.build_form();
|
||||
}
|
||||
_getValue(){
|
||||
return this.form._getValue();
|
||||
}
|
||||
getValue(){
|
||||
return this.form.getValue();
|
||||
}
|
||||
|
99
bricks/period.js
Normal file
@ -0,0 +1,99 @@
|
||||
var bricks = window.bricks || {};
|
||||
bricks.str2date = function(sdate){
|
||||
let [year, month, day] = sdate.split("-");
|
||||
var dateObj = new Date(year, month - 1, day);
|
||||
return dateObj;
|
||||
}
|
||||
bricks.date2str = function(date){
|
||||
let year = date.getFullYear();
|
||||
let month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
let day = String(date.getDate()).padStart(2, '0');
|
||||
let formattedDate = `${year}-${month}-${day}`;
|
||||
return formattedDate;
|
||||
}
|
||||
bricks.addMonths = function(dateObj, months){
|
||||
var newDate = new Date(dateObj);
|
||||
newDate.setMonth(newDate.getMonth() + months);
|
||||
return newDate;
|
||||
}
|
||||
bricks.addYears = function(dateObj, years){
|
||||
const newDate = new Date(dateObj);
|
||||
newDate.setYear(newDate.getYear() + years);
|
||||
return newDate;
|
||||
}
|
||||
bricks.addDays = function(dateObj, days){
|
||||
var newdate = new Date(dateObj);
|
||||
newdate.setDate(newdate.getDate() + days);
|
||||
return newdate;
|
||||
}
|
||||
|
||||
bricks.PeriodDays = class extends bricks.HBox {
|
||||
/*
|
||||
{
|
||||
start_date:
|
||||
end_date:
|
||||
step_type: 'days', 'months', 'years'
|
||||
step_cnt:
|
||||
title:'',
|
||||
splitter:' -- '
|
||||
}
|
||||
event: 'changed';
|
||||
*/
|
||||
constructor(opts){
|
||||
opts.splitter = opts.splitter || ' 至 ';
|
||||
opts.step_cnt = opts.step_cnt || 1;
|
||||
super(opts);
|
||||
this.start_w = new bricks.Text({
|
||||
text:opts.start_date
|
||||
});
|
||||
this.end_w = new bricks.Text({
|
||||
text:opts.end_date
|
||||
});
|
||||
this.start_w.set_css('clickable');
|
||||
this.end_w.set_css('clickable');
|
||||
this.start_w.bind('click', this.step_back.bind(this));
|
||||
this.end_w.bind('click', this.step_forward.bind(this));
|
||||
if (this.title){
|
||||
this.add_widget(new bricks.Text({otext:this.title, i18n:true}));
|
||||
}
|
||||
this.add_widget(this.start_w);
|
||||
this.add_widget(new bricks.Text({
|
||||
otext:this.splitter,
|
||||
i18n:true
|
||||
}));
|
||||
this.add_widget(this.end_w);
|
||||
}
|
||||
date_add(strdate, step_cnt, step_type){
|
||||
var date = bricks.str2date(strdate);
|
||||
switch(step_type){
|
||||
case 'years':
|
||||
var nd = bricks.addYears(date, step_cnt);
|
||||
return bricks.date2str(nd);
|
||||
break;
|
||||
case 'months':
|
||||
var nd = bricks.addMonths(date, step_cnt);
|
||||
return bricks.date2str(nd);
|
||||
break;
|
||||
default:
|
||||
var nd = bricks.addDays(date, step_cnt);
|
||||
return bricks.date2str(nd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
step_back(){
|
||||
this.start_date = this.date_add(this.start_date, -this.step_cnt, this.step_type);
|
||||
this.end_date = this.date_add(this.end_date, -this.step_cnt, this.step_type);
|
||||
this.start_w.set_text(this.start_date);
|
||||
this.end_w.set_text(this.end_date);
|
||||
this.dispatch('changed', {start_date:this.start_date, end_date:this.end_date});
|
||||
}
|
||||
step_forward(){
|
||||
this.start_date = this.date_add(this.start_date, this.step_cnt, this.step_type);
|
||||
this.end_date = this.date_add(this.end_date, this.step_cnt, this.step_type);
|
||||
this.start_w.set_text(this.start_date);
|
||||
this.end_w.set_text(this.end_date);
|
||||
this.dispatch('changed', {start_date:this.start_date, end_date:this.end_date});
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('PeriodDays', bricks.PeriodDays);
|
158
bricks/popup.js
@ -1,5 +1,17 @@
|
||||
var bricks = window.bricks || {};
|
||||
|
||||
bricks.get_popup_default_options = function(){
|
||||
return {
|
||||
timeout:0,
|
||||
archor:'cc',
|
||||
auto_open:true,
|
||||
auto_dismiss:true,
|
||||
auto_destroy:true,
|
||||
movable:true,
|
||||
resizable:false,
|
||||
modal:true
|
||||
}
|
||||
}
|
||||
bricks.Popup = class extends bricks.VBox {
|
||||
/*
|
||||
{
|
||||
@ -10,8 +22,10 @@ bricks.Popup = class extends bricks.VBox {
|
||||
auto_dismiss:boolean
|
||||
auto_destroy:boolean
|
||||
movable:boolean
|
||||
dismiss_event:
|
||||
resizable:boolean
|
||||
modal:boolean
|
||||
content:{}
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
@ -21,11 +35,10 @@ bricks.Popup = class extends bricks.VBox {
|
||||
this.opened = false;
|
||||
this.set_css('popup');
|
||||
this.bring_to_top();
|
||||
this.moving_w = this;
|
||||
this.content_box = new bricks.VBox({width:'100%', height:'100%'});
|
||||
this.content_box.set_style('display', 'flex');
|
||||
this.content_box.set_style('overflow', 'auto');
|
||||
this.content_box = new bricks.VBox({height:'100%',width:'100%'});
|
||||
super.add_widget(this.content_box);
|
||||
this.content_w = this.content_box;
|
||||
this.moving_w = this;
|
||||
if (this.auto_dismiss){
|
||||
bricks.Body.bind('click', this.click_outside.bind(this));
|
||||
}
|
||||
@ -41,6 +54,26 @@ bricks.Popup = class extends bricks.VBox {
|
||||
this.set_style('display', 'none');
|
||||
bricks.Body.add_widget(this);
|
||||
this.bind('click', this.bring_to_top.bind(this));
|
||||
if (this.auto_open){
|
||||
this.open();
|
||||
}
|
||||
if (this.content){
|
||||
this.bind('opened', this.load_content.bind(this))
|
||||
}
|
||||
}
|
||||
async load_content(){
|
||||
var w = await bricks.widgetBuild(this.content, this);
|
||||
if (w){
|
||||
this.set_dismiss_events(w);
|
||||
this.content_w.clear_widgets();
|
||||
this.content_w.add_widget(w);
|
||||
}
|
||||
}
|
||||
set_dismiss_events(w){
|
||||
if (!this.dismiss_events) return;
|
||||
this.dismiss_events.forEach(ename => {
|
||||
w.bind(ename, this.destroy.bind(this));
|
||||
});
|
||||
}
|
||||
bring_to_top(){
|
||||
if (this == bricks.app.toppopup){
|
||||
@ -50,10 +83,38 @@ bricks.Popup = class extends bricks.VBox {
|
||||
bricks.app.toppopup.set_css('toppopup', true);
|
||||
this.zindex = bricks.app.new_zindex();
|
||||
this.set_style('zIndex', this.zindex);
|
||||
console.log('this.zindex=', this.zindex, 'app.zindex=', bricks.app.zindex);
|
||||
this.set_css('toppopup');
|
||||
bricks.app.toppopup = this;
|
||||
}
|
||||
|
||||
popup_from_widget(from_w){
|
||||
var myrect = this.showRectage();
|
||||
var rect = from_w.showRectage();
|
||||
var x,y;
|
||||
var ox, oy;
|
||||
ox = (rect.right - rect.left) / 2 + rect.left;
|
||||
oy = (rect.bottom - rect.top) / 2 + rect.top;
|
||||
if (ox < bricks.app.screenWidth() / 2) {
|
||||
x = rect.right + 3;
|
||||
if (x + (myrect.right - myrect.left) > bricks.app.screenWidth()){
|
||||
x = bricks.app.screenWidth() - (myrect.right - myrect.left);
|
||||
}
|
||||
} else {
|
||||
x = rect.left - (myrect.right - myrect.left) - 3
|
||||
if (x < 0) x = 0;
|
||||
}
|
||||
if (oy < bricks.app.screenHeight() / 2){
|
||||
y = rect.bottom + 3;
|
||||
if (y + (myrect.bottom - myrect.top) > bricks.app.screenHeight()){
|
||||
y = bricks.app.screenHeight() - (myrect.bottom - myrect.top);
|
||||
}
|
||||
} else {
|
||||
y = rect.bottom - (myrect.bottom - myrect.top) - 3
|
||||
if (y < 0) y = 0;
|
||||
}
|
||||
this.set_style('top', y + 'px');
|
||||
this.set_style('left', x + 'px');
|
||||
}
|
||||
setup_resizable(){
|
||||
this.resizable_w = new bricks.Icon({rate:1.5, url:bricks_resource('imgs/right-bottom-triangle.png')});
|
||||
super.add_widget(this.resizable_w);
|
||||
@ -222,15 +283,10 @@ bricks.Popup = class extends bricks.VBox {
|
||||
this.dismiss();
|
||||
}
|
||||
}
|
||||
add_widget(w, index){
|
||||
this.content_box.add_widget(w, index);
|
||||
if (this.auto_open){
|
||||
this.open();
|
||||
} else {
|
||||
// console.log('auto_open is ', this.auto_open, ' so not auto open it', this.opts, w);
|
||||
}
|
||||
}
|
||||
open(){
|
||||
if (!this.parent){
|
||||
bricks.app.add_widget(this);
|
||||
}
|
||||
var rect, w, h;
|
||||
if (this.opened) {
|
||||
return;
|
||||
@ -258,9 +314,10 @@ bricks.Popup = class extends bricks.VBox {
|
||||
if (this.opts.modal && this.opts.widget){
|
||||
this.target_w.disabled(true);
|
||||
}
|
||||
this.content_box.disabled(false);
|
||||
this.bring_to_top();
|
||||
}
|
||||
dismiss(){
|
||||
if (! this.opened) return;
|
||||
if (this.opts.modal){
|
||||
this.target_w.disabled(false);
|
||||
}
|
||||
@ -285,47 +342,62 @@ bricks.Popup = class extends bricks.VBox {
|
||||
this.parent = null;
|
||||
}
|
||||
}
|
||||
add_widget(w, i){
|
||||
this.set_dismiss_events(w);
|
||||
this.content_w.add_widget(w, i);
|
||||
if (this.auto_open){
|
||||
this.open();
|
||||
}
|
||||
}
|
||||
remove_widget(w){
|
||||
return this.content_w.remove_widget(w);
|
||||
}
|
||||
clear_widgets(){
|
||||
return this.content_w.clear_widgets();
|
||||
}
|
||||
}
|
||||
|
||||
bricks.get_popupwindow_default_options = function(){
|
||||
return {
|
||||
timeout:0,
|
||||
archor:'cc',
|
||||
auto_open:true,
|
||||
auto_dismiss:true,
|
||||
auto_destroy:true,
|
||||
movable:true,
|
||||
resizable:true,
|
||||
modal:true
|
||||
}
|
||||
}
|
||||
bricks.PopupWindow = class extends bricks.Popup {
|
||||
/*
|
||||
{
|
||||
title:
|
||||
icon:
|
||||
params:
|
||||
url:
|
||||
}
|
||||
*/
|
||||
constructor(opts){
|
||||
opts.moviable = true;
|
||||
opts.movable = true;
|
||||
opts.resizable = true;
|
||||
opts.auto_open = true;
|
||||
var ao = opts.auto_open;
|
||||
opts.auto_open = false
|
||||
opts.auto_dismiss = false;
|
||||
opts.auto_destroy = false;
|
||||
super(opts);
|
||||
this.title_bar = new bricks.HBox({cheight:1.5, width:'100%'});
|
||||
this.title_bar.set_css('titlebar')
|
||||
this.auto_open = ao;
|
||||
this.title_bar = new bricks.HBox({css:'titlebar', cheight:2, width:'100%'});
|
||||
this.moving_w = this.title_bar;
|
||||
this.parent_add_widget(this.title_bar);
|
||||
this.add_widget(this.title_bar);
|
||||
this.build_title_bar();
|
||||
var filler = new bricks.Filler({});
|
||||
this.parent_add_widget(filler)
|
||||
this.content_w = new bricks.Layout({});
|
||||
this.add_widget(filler)
|
||||
|
||||
this.content_w = new bricks.Layout({height:'100%', width:'100%'});
|
||||
this.content_w.set_css('flexbox');
|
||||
this.auto_open = true;
|
||||
filler.add_widget(this.content_w);
|
||||
// console.log(this.auto_open, 'opts=', opts);
|
||||
}
|
||||
async load_content(){
|
||||
var dic = {
|
||||
"widgettype":"urlwidget",
|
||||
"options":{
|
||||
"params":this.params,
|
||||
"url":this.url
|
||||
}
|
||||
if (this.auto_open){
|
||||
this.open();
|
||||
}
|
||||
var w = bricks.widgetBuild(dic, bricks.Body);
|
||||
this.add_widget(w);
|
||||
}
|
||||
build_title_bar(){
|
||||
var icon = new bricks.Icon({
|
||||
@ -372,22 +444,6 @@ bricks.PopupWindow = class extends bricks.Popup {
|
||||
this.title_w.set_text(txt);
|
||||
}
|
||||
}
|
||||
parent_add_widget(w, index){
|
||||
var ao = this.autho_open;
|
||||
this.auto_open = false;
|
||||
super.add_widget(w, index);
|
||||
this.auto_open = ao;
|
||||
}
|
||||
add_widget(w, index){
|
||||
// console.log('auto_open=', this.auto_open);
|
||||
this.content_w.add_widget(w, index);
|
||||
if (this.auto_open){
|
||||
this.open();
|
||||
} else {
|
||||
this.open();
|
||||
// console.log('auto_open is false, not auto open');
|
||||
}
|
||||
}
|
||||
open(){
|
||||
var f = bricks.app.docks.find(o => {
|
||||
if (o == this){
|
||||
|
24
bricks/progressbar.js
Normal file
@ -0,0 +1,24 @@
|
||||
var bricks = window.bricks || {};
|
||||
|
||||
bricks.ProgressBar = class extends bricks.HBox {
|
||||
/*
|
||||
options:
|
||||
total_value
|
||||
bar_cwidth
|
||||
event:
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.set_css('progress-container');
|
||||
this.text_w = new bricks.Text({text:'0%', cheight:this.bar_cwidth||2});
|
||||
this.text_w.set_css('progress-bar')
|
||||
this.add_widget(this.text_w);
|
||||
}
|
||||
set_value(v){
|
||||
var pzt = (current / total) * 100;
|
||||
pzt = Math.max(0, Math.min(100, percentage));
|
||||
this.text_w.set_style('width', pzt + '%')
|
||||
}
|
||||
}
|
||||
bricks.Factory.register('ProgressBar', bricks.ProgressBar);
|
||||
|
250
bricks/qaframe.js
Normal file
@ -0,0 +1,250 @@
|
||||
bricks = window.bricks || {};
|
||||
|
||||
bricks.QAFrame = class extends bricks.VBox {
|
||||
/*
|
||||
{
|
||||
ws_url:
|
||||
ws_params:
|
||||
title:
|
||||
description:
|
||||
courseware:{
|
||||
type: "audio" or "video", "image", "markdown"
|
||||
url:
|
||||
timeout:
|
||||
}
|
||||
timeout:0 no timeout, number in seconds
|
||||
"accept data type"
|
||||
1:
|
||||
type:courseware:
|
||||
data:{
|
||||
type:
|
||||
url:
|
||||
}
|
||||
2:
|
||||
type:askready
|
||||
data:{
|
||||
total_q
|
||||
cur_q
|
||||
}
|
||||
3:
|
||||
type:question
|
||||
data: {
|
||||
q_desc:
|
||||
total_q:
|
||||
cur_q
|
||||
}
|
||||
4:
|
||||
type:result
|
||||
data: {
|
||||
total_q:
|
||||
correct_cnt:
|
||||
error_cnt
|
||||
}
|
||||
5:
|
||||
type:error_list,
|
||||
data: {
|
||||
error_cnt,
|
||||
rows:[
|
||||
{
|
||||
pos:
|
||||
q_desc:
|
||||
your_a:
|
||||
corrent_a:
|
||||
error_desc:
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
send message:
|
||||
1:
|
||||
type: qa_start
|
||||
data:null
|
||||
|
||||
2:
|
||||
}
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.top_w = new bricks.HBox({
|
||||
cheight:2
|
||||
});
|
||||
this.bottom_w = new bricks.HBox({
|
||||
cheight:2
|
||||
});
|
||||
this.main_w = new bricks.Filler({});
|
||||
this.add_widget(this.top_w);
|
||||
this.add_widget(this.main_w);
|
||||
this.add_widget(this.bottom_w);
|
||||
var url = this.ws_url;
|
||||
if (this.ws_params){
|
||||
url += '?' + new URLSearchParams(this.ws_params).toString();
|
||||
}
|
||||
this.ws = new bricks.WebSocket({
|
||||
ws_url:url
|
||||
});
|
||||
this.ws.bind('onopen', this.start_question_answer.bind(this));
|
||||
this.ws.bind('onquestion', this.show_question.bind(this));
|
||||
this.ws.bind('oncourseware', this.show_courseware.bind(this));
|
||||
this.ws.bind('onaskstart', this.show_conform.bind(this));
|
||||
this.ws.bind('oncourseware', this.show_courseware.bind(this));
|
||||
this.ws.bind('oncourseware', this.show_courseware.bind(this));
|
||||
}
|
||||
show_question(d){
|
||||
console.log('show_question(), d=', d);
|
||||
this.qtotal_w.set_text(str(d.total_q));
|
||||
this.qcur_w.set_text(str(d.cur_q));
|
||||
var w = bricks.widgetBuild(d.q_desc, this);
|
||||
this.main_w.clear_widgets();
|
||||
if (w){
|
||||
this.main_w.add_widget(w);
|
||||
}
|
||||
}
|
||||
show_courseware(d){
|
||||
var w;
|
||||
this.main_w.clear_widgets();
|
||||
console.log('show_courseware(), d=', d);
|
||||
switch(d.type){
|
||||
case 'video':
|
||||
w = new bricks.VideoPlayer({
|
||||
width:'100%',
|
||||
height:'100%',
|
||||
url:d.url,
|
||||
autoplay:true
|
||||
});
|
||||
break;
|
||||
case 'audio':
|
||||
w = new bricks.AudioPlayer({
|
||||
width:'100%',
|
||||
height:'100%',
|
||||
url:d.url,
|
||||
autoplay:true
|
||||
});
|
||||
break;
|
||||
case 'image':
|
||||
w = new bricks.Image({
|
||||
width:'100%',
|
||||
height:'100%',
|
||||
url:d.url,
|
||||
});
|
||||
break;
|
||||
case 'markdown':
|
||||
w = new bricks.MdWidget({
|
||||
height:'100%',
|
||||
width:'100%',
|
||||
md_url: d.url
|
||||
});
|
||||
break;
|
||||
}
|
||||
this.main_w.add_widget(w);
|
||||
}
|
||||
show_conform(d){
|
||||
this.main_w.clear_widgets();
|
||||
var btn = new bricks.Button({
|
||||
label: 'Start ?'
|
||||
});
|
||||
btn.bind('click', this.start_question_answer.bind(this));
|
||||
this.main_w.clear_widgets();
|
||||
this.main_w.add_widget(btn);
|
||||
}
|
||||
build_startbtn(){
|
||||
var btn = new bricks.Button({
|
||||
label:'press to start'
|
||||
});
|
||||
btn.bind('click', this.conform_start.bind(this));
|
||||
this.bottom_w.add_widget(btn);
|
||||
}
|
||||
conform_start(){
|
||||
var d = {
|
||||
type: 'conform_start',
|
||||
data: null
|
||||
}
|
||||
this.ws.send(d);
|
||||
}
|
||||
start_question_answer(){
|
||||
this.main_w.clear_widgets();
|
||||
var d = {
|
||||
'type': 'qa_start',
|
||||
'data': {
|
||||
d: 'test data',
|
||||
v: 100
|
||||
}
|
||||
};
|
||||
this.ws.send(d);
|
||||
}
|
||||
async send_audio_answer(e){
|
||||
var audio = e.data;
|
||||
var b64audio = blobToBase64(audio.audio);
|
||||
this.ws.send({
|
||||
type: 'audio_answer',
|
||||
data: b64audio
|
||||
})
|
||||
}
|
||||
send_text_answer(e){
|
||||
var answer = e.data;
|
||||
console.log('answer=', answer);
|
||||
this.ws.send({
|
||||
type: 'text_answer',
|
||||
data: answer.texta
|
||||
});
|
||||
}
|
||||
build_input_widgets(){
|
||||
var hw = StrInput({
|
||||
name:texta,
|
||||
css:'filler'
|
||||
});
|
||||
var speakw = new bricks.AudioRecorder({
|
||||
icon_rate:1.7,
|
||||
padding: '6px'
|
||||
});
|
||||
/*
|
||||
var imagew = new bricks.Icon({
|
||||
rate:1.7,
|
||||
padding: '6px',
|
||||
url: bricks_resource('imgs/camera.png')
|
||||
});
|
||||
var videow = new bricks.Icon({
|
||||
rate: 1.7,
|
||||
padding: '6px',
|
||||
url: bricks_resource('imgs/recorder.png')
|
||||
});
|
||||
this.bottom_w.add_widget(imagew);
|
||||
this.bottom_w.add_widget(videow);
|
||||
*/
|
||||
hw.bind('blur', this.send_text_answer.bind(this));
|
||||
speakw.bind('record_ended', this.send_audio_data.bind(this));
|
||||
|
||||
this.bottom_w.add_widget(speakw);
|
||||
this.bottom_w.add_widget(hw);
|
||||
}
|
||||
play_course(){
|
||||
switch(this.courseware.type){
|
||||
case 'video':
|
||||
this.cw = new bricks.VideoPlayer({
|
||||
url:this.courseware.url,
|
||||
autoplay:true
|
||||
});
|
||||
break;
|
||||
case 'audio':
|
||||
this.cw = new bricks.AudioPlayer({
|
||||
url:this.courseware.url,
|
||||
autoplay:true
|
||||
});
|
||||
break;
|
||||
case 'image':
|
||||
this.cw = new bricks.Image({
|
||||
url:this.courseware.url
|
||||
});
|
||||
break;
|
||||
case 'markdown':
|
||||
this.cw = new bricks.MdWidget({
|
||||
md_url:this.courseware.url
|
||||
});
|
||||
break;
|
||||
default:
|
||||
return
|
||||
}
|
||||
this.main_w.add_widget(this.cw);
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('QAFrame', bricks.QAFrame);
|
@ -45,7 +45,8 @@ bricks.Signaling = class {
|
||||
}
|
||||
|
||||
init_websocket(){
|
||||
this.socket = new WebSocket(this.signaling_url);
|
||||
var sessdata = bricks.app.get_session();
|
||||
this.socket = new WebSocket(this.signaling_url, sessdata);
|
||||
this.socket.onmessage = this.signaling_recvdata.bind(this);
|
||||
this.socket.onopen = this.login.bind(this);
|
||||
this.socket.onclose = this.reconnect.bind(this);
|
||||
|
70
bricks/svg.js
Normal file
@ -0,0 +1,70 @@
|
||||
var bricks = window.bricks || {};
|
||||
bricks.Svg = class extends bricks.VBox {
|
||||
/*
|
||||
options:{
|
||||
rate:
|
||||
url:
|
||||
color:*
|
||||
blinkcolor:*
|
||||
blinktime:*
|
||||
}
|
||||
*/
|
||||
constructor(opts){
|
||||
opts.rate = opts.rate || 1;
|
||||
opts.cwidth = opts.cwidth || 1;
|
||||
opts.cheight = opts.cheight || 1;
|
||||
opts.dynsize = true;
|
||||
super(opts);
|
||||
if (opts.url){
|
||||
this.set_url(opts.url);
|
||||
}
|
||||
}
|
||||
set_url(url){
|
||||
fetch(url)
|
||||
.then(response => response.text())
|
||||
.then(svgText => {
|
||||
this.svgText = svgText;
|
||||
this.set_colored_svg(this.color);
|
||||
this.blink();
|
||||
});
|
||||
}
|
||||
set_ancent_color(e){
|
||||
var pstyle = getComputedStyle(this.parent);
|
||||
this.set_color(pstyle.color);
|
||||
}
|
||||
set_color(color){
|
||||
this.color = color;
|
||||
this.set_colored_svg(color);
|
||||
}
|
||||
set_blinkcolor(color){
|
||||
this.blinkcolor = color;
|
||||
this.blinktime = this.blinktime || 0.5;
|
||||
}
|
||||
set_colored_svg(color){
|
||||
this.cur_color = color;
|
||||
var svgText = bricks.obj_fmtstr({color: color}, this.svgText);
|
||||
this.dom_element.innerHTML = svgText;
|
||||
}
|
||||
blink(){
|
||||
if (this.blinktime && this.blinkcolor) {
|
||||
if (this.cur_color == this.color){
|
||||
this.set_colored_svg(this.blinkcolor);
|
||||
} else {
|
||||
this.set_colored_svg(this.color);
|
||||
}
|
||||
this.blink_task = schedule_once(this.blink.bind(this),
|
||||
this.blinktime);
|
||||
}
|
||||
}
|
||||
start_blink(){
|
||||
if (!this.blink_task){
|
||||
blink();
|
||||
}
|
||||
}
|
||||
end_blink(){
|
||||
this.blink_task = null;
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('Svg', bricks.Svg);
|
||||
|
@ -25,6 +25,13 @@ bricks.TabPanel = class extends bricks.Layout {
|
||||
tab-button-active
|
||||
tab-button-hover
|
||||
tab-content
|
||||
|
||||
events:
|
||||
switch: fired when switch content
|
||||
event data: actived content widget
|
||||
|
||||
content wedget event:
|
||||
active: fired when the content event is switch to show
|
||||
*/
|
||||
constructor(options){
|
||||
super(options);
|
||||
@ -87,21 +94,23 @@ bricks.TabPanel = class extends bricks.Layout {
|
||||
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;
|
||||
this.switch_content(w);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
w = await bricks.widgetBuild(items[i].content, this, {});
|
||||
if (items[i].content instanceof bricks.JsWidget){
|
||||
w = items[i].content;
|
||||
} else {
|
||||
w = await bricks.widgetBuild(items[i].content, this, {});
|
||||
}
|
||||
if (! w){
|
||||
bricks.debug('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;
|
||||
this.switch_content(w);
|
||||
return;
|
||||
}
|
||||
catch (e) {
|
||||
@ -111,6 +120,12 @@ bricks.TabPanel = class extends bricks.Layout {
|
||||
}
|
||||
bricks.debug('TabPanel(): click event handled but noting to do', tdesc)
|
||||
}
|
||||
switch_content(w){
|
||||
this.content_container.clear_widgets();
|
||||
this.content_container.add_widget(w);
|
||||
this.dispatch('switch', w);
|
||||
w.dispatch('active');
|
||||
}
|
||||
add_tab(desc){
|
||||
var item = this.toolbar.createTool(desc);
|
||||
if (desc.removable){
|
||||
|
@ -59,13 +59,16 @@ bricks.Tabular = class extends bricks.DataViewer {
|
||||
} else {
|
||||
row.set_css('tabular-row-selected');
|
||||
}
|
||||
this.dispatch('row_selected', row.user_data);
|
||||
}
|
||||
}
|
||||
async toggle_content(row, flag){
|
||||
if (flag){
|
||||
row.content_widget.show();
|
||||
row.content_widget.clear_widgets();
|
||||
var w = await bricks.widgetBuild(this.content_view, row.content_widget, row.user_data);
|
||||
var desc = objcopy(this.content_view);
|
||||
desc = bricks.apply_data(desc, row.user_data);
|
||||
var w = await bricks.widgetBuild(desc, row.content_widget);
|
||||
if (w){
|
||||
row.content_widget.add_widget(w);
|
||||
}
|
||||
@ -98,9 +101,11 @@ bricks.Tabular = class extends bricks.DataViewer {
|
||||
var dr = new bricks.DataRow(options);
|
||||
dr.set_css('tabular-row');
|
||||
dr.render(header);
|
||||
/*
|
||||
dr.event_names.forEach(e => {
|
||||
dr.toolbar_w.bind(e, this.record_event_handle.bind(this, e, record, dr));
|
||||
});
|
||||
*/
|
||||
dr.bind('check_changed', this.record_check_changed.bind(this));
|
||||
return dr;
|
||||
}
|
||||
@ -109,7 +114,7 @@ bricks.Tabular = class extends bricks.DataViewer {
|
||||
this.dispatch('row_check_changed', event.params.user_data);
|
||||
}
|
||||
async renew_record_view(form, row){
|
||||
var d = form.getValue();
|
||||
var d = form._getValue();
|
||||
var record = bricks.extend(row.user_data, d);
|
||||
if (this.content_view){
|
||||
row.rec_widget.renew(record);
|
||||
|
@ -133,9 +133,8 @@ bricks.TreeNode = class extends bricks.VBox {
|
||||
if (this.view_w){
|
||||
widget.add_widget(this.view_w);
|
||||
}
|
||||
} else {
|
||||
this.str_w.set_text(this.user_data[this.tree.opts.textField]);
|
||||
}
|
||||
this.str_w.set_text(this.user_data[this.tree.opts.textField]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,6 +170,8 @@ bricks.Tree = class extends bricks.VScrollPanel {
|
||||
this.row_height = this.opts.row_height || '35px';
|
||||
this.multitype_tree = this.opts.multitype_tree||false;
|
||||
this.selected_node = null;
|
||||
this.build_title();
|
||||
this.build_description();
|
||||
this.create_toolbar();
|
||||
this.checked_data = [];
|
||||
this.container = new bricks.VBox({
|
||||
@ -209,14 +210,14 @@ bricks.Tree = class extends bricks.VScrollPanel {
|
||||
create_toolbar(){
|
||||
var toolbar = bricks.extend({}, this.toolbar);
|
||||
var tools = [];
|
||||
if (toolbar.tools){
|
||||
toolbar.tools.forEach(f => tools.push(f));
|
||||
}
|
||||
if (this.editable){
|
||||
tools.push({icon:bricks_resource('imgs/add.png'), name:'add'});
|
||||
tools.push({icon:bricks_resource('imgs/update.png'), name:'update'});
|
||||
tools.push({icon:bricks_resource('imgs/delete.png'), name:'delete'});
|
||||
}
|
||||
if (toolbar.tools){
|
||||
toolbar.tools.forEach(f => tools.push(f));
|
||||
}
|
||||
if (tools.length == 0){
|
||||
return;
|
||||
}
|
||||
@ -230,7 +231,7 @@ bricks.Tree = class extends bricks.VScrollPanel {
|
||||
switch (opts.name){
|
||||
case 'add':
|
||||
this.add_new_node();
|
||||
breaks;
|
||||
break;
|
||||
case 'delete':
|
||||
this.delete_node();
|
||||
break;
|
||||
@ -238,16 +239,17 @@ bricks.Tree = class extends bricks.VScrollPanel {
|
||||
this.update_node();
|
||||
break;
|
||||
default:
|
||||
if ((opts.selected_data || opts.checked_data) && ! this.selected_node){
|
||||
w = new bricks.Error({title:'Error', message:'No selected node found'});
|
||||
w.open();
|
||||
return;
|
||||
}
|
||||
console.log('opts=', opts);
|
||||
var d = null;
|
||||
if (opts.checked_data){
|
||||
d = {
|
||||
checked_data:JSON.stringify(this.checked_data)
|
||||
}
|
||||
} else if (opts.selected_node){
|
||||
d = {
|
||||
selected_data:JSON.stringify(this.selected_node.user_data)
|
||||
}
|
||||
d = this.checked_data
|
||||
} else if (opts.selected_data){
|
||||
d = this.selected_node.user_data
|
||||
}
|
||||
this.dispatch(opts.name, d);
|
||||
break;
|
||||
@ -269,7 +271,11 @@ bricks.Tree = class extends bricks.VScrollPanel {
|
||||
var node = this;
|
||||
if (this.selected_node){
|
||||
node = this.selected_node;
|
||||
d[this.parentField] = node.get_id();
|
||||
if (d instanceof FormData){
|
||||
d.append(this.parentField, node.get_id());
|
||||
} else {
|
||||
d[this.parentField] = node.get_id();
|
||||
}
|
||||
}
|
||||
if (this.editable.add_url){
|
||||
var jc = new bricks.HttpJson()
|
||||
@ -385,24 +391,34 @@ bricks.Tree = class extends bricks.VScrollPanel {
|
||||
async update_node_inputed(event){
|
||||
var d = event.params;
|
||||
var node = this.selected_node;
|
||||
d[this.idField] = node.get_id();
|
||||
if (d instanceof FormData){
|
||||
d.append(this.idField, node.get_id());
|
||||
} else {
|
||||
d[this.idField] = node.get_id();
|
||||
}
|
||||
if(this.editable.update_url){
|
||||
var jc = new bricks.HttpJson()
|
||||
var desc = await jc.post(this.editable.update_url, {params:d});
|
||||
if (desc.widgettype == 'Message'){
|
||||
await this.update_node_data(node, d);
|
||||
var o = formdata2object(d);
|
||||
await this.update_node_data(node, o);
|
||||
}
|
||||
var w = await bricks.widgetBuild(desc, this);
|
||||
w.open();
|
||||
} else {
|
||||
await this.update_node_data(node, d);
|
||||
var o = formdata2object(d);
|
||||
await this.update_node_data(node, o);
|
||||
}
|
||||
}
|
||||
|
||||
async update_node_data(node, data){
|
||||
for (var name in Object.keys(data)){
|
||||
node.user_data[name] = data[name];
|
||||
}
|
||||
var data_keys = Object.keys(node.user_data);
|
||||
Object.keys(data).forEach(k => {
|
||||
if (data_keys.includes(k)){
|
||||
console.log(node.user_data[k], ':', k, ':', data[k]);
|
||||
node.user_data[k] = data[k];
|
||||
}
|
||||
});
|
||||
await node.update_content();
|
||||
}
|
||||
|
||||
|
339
bricks/utils.js
@ -1,12 +1,142 @@
|
||||
var bricks = window.bricks || {};
|
||||
bricks.bug = false;
|
||||
|
||||
async function streamResponseJson(response, onJson) {
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
let buffer = "";
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) break;
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
// 按换行切分 NDJSON
|
||||
let lines = buffer.split("\n");
|
||||
buffer = lines.pop(); // 可能是不完整的一行,留到下一轮
|
||||
for (const line of lines) {
|
||||
if (line.trim()) {
|
||||
try {
|
||||
const json = JSON.parse(line);
|
||||
onJson(json); // 👈 回调处理每个 JSON 对象
|
||||
} catch (err) {
|
||||
console.warn("Failed to parse JSON line:", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理最后残留的一行
|
||||
if (buffer.trim()) {
|
||||
try {
|
||||
const json = JSON.parse(buffer);
|
||||
onJson(json);
|
||||
} catch (err) {
|
||||
console.warn("Failed to parse trailing JSON line:", buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function base64_to_url(base64, mimeType = "audio/wav") {
|
||||
const binary = atob(base64); // 解码 Base64 成 binary 字符串
|
||||
const len = binary.length;
|
||||
const bytes = new Uint8Array(len);
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
|
||||
const blob = new Blob([bytes], { type: mimeType });
|
||||
const url = URL.createObjectURL(blob);
|
||||
return url;
|
||||
}
|
||||
|
||||
function blobToBase64(blob) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onloadend = () => {
|
||||
resolve(reader.result); // This will be a base64 string prefixed with "data:*/*;base64,"
|
||||
};
|
||||
|
||||
reader.onerror = reject;
|
||||
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
bricks.formdata_copy = function(fd){
|
||||
var cfd = new FormData();
|
||||
|
||||
// 遍历 originalFormData 中的所有条目并添加到 clonedFormData 中
|
||||
for (var pair of fd.entries()) {
|
||||
cfd.append(pair[0], pair[1]);
|
||||
}
|
||||
return cfd;
|
||||
}
|
||||
|
||||
bricks.map = function(data_source, mapping, need_others){
|
||||
ret = {};
|
||||
Object.entries(data_source).forEach(([key, value]) => {
|
||||
if (mapping.hasOwnProperty(key)){
|
||||
ret[mapping[key]] = data_source[key];
|
||||
} else if (need_others){
|
||||
ret[key] = data_source[key];
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
bricks.relocate_by_eventpos = function(event, widget){
|
||||
var ex,ey;
|
||||
var x,y;
|
||||
var xsize = bricks.Body.dom_element.clientWidth;
|
||||
var ysize = bricks.Body.dom_element.clientHeight;
|
||||
ex = event.clientX;
|
||||
ey = event.clientY;
|
||||
var mxs = widget.dom_element.offsetWidth;
|
||||
var mys = widget.dom_element.offsetHeight;
|
||||
if (ex < (xsize / 2)) {
|
||||
x = ex + bricks.app.charsize;
|
||||
} else {
|
||||
x = ex - mxs - bricks.app.charsize;
|
||||
}
|
||||
if (ey < (ysize / 2)) {
|
||||
y = ey + bricks.app.charsize;
|
||||
} else {
|
||||
y = ey - mys - bricks.app.charsize;
|
||||
}
|
||||
widget.set_style('left', x + 'px');
|
||||
widget.set_style('top', y + 'px');
|
||||
}
|
||||
|
||||
var formdata2object = function(formdata){
|
||||
let result = {};
|
||||
formdata.forEach((value, key) => {
|
||||
result[key] = value;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
var inputdata2dic = function(data){
|
||||
try {
|
||||
var d = {}
|
||||
for (let k of data.keys()){
|
||||
var x = data.get(k);
|
||||
if (k == 'prompt'){
|
||||
x = bricks.escapeSpecialChars(x);
|
||||
}
|
||||
d[k] = x;
|
||||
}
|
||||
return d;
|
||||
} catch (e){
|
||||
return data;
|
||||
}
|
||||
}
|
||||
bricks.delete_null_values = function(obj) {
|
||||
for (let key in obj) {
|
||||
if (obj[key] === null) {
|
||||
delete obj[key];
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
for (let key in obj) {
|
||||
if (obj[key] === null) {
|
||||
delete obj[key];
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
bricks.is_empty = function(obj){
|
||||
@ -44,7 +174,7 @@ bricks.debug = function(...args){
|
||||
}
|
||||
|
||||
bricks.is_mobile = function(){
|
||||
var userAgent = navigator.userAgent;
|
||||
var userAgent = navigator.userAgent;
|
||||
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent)) {
|
||||
return true;
|
||||
}
|
||||
@ -90,9 +220,9 @@ var currentScriptPath = function () {
|
||||
}
|
||||
currentScript = scripts[ scripts.length - 1 ].src;
|
||||
}
|
||||
var currentScriptChunks = currentScript.split( '/' );
|
||||
var currentScriptFile = currentScriptChunks[ currentScriptChunks.length - 1 ];
|
||||
return currentScript.replace( currentScriptFile, '' );
|
||||
var currentScriptChunks = currentScript.split( '/' );
|
||||
var currentScriptFile = currentScriptChunks[ currentScriptChunks.length - 1 ];
|
||||
return currentScript.replace( currentScriptFile, '' );
|
||||
}
|
||||
|
||||
bricks.path = currentScriptPath();
|
||||
@ -107,17 +237,17 @@ var bricks_resource = function(name){
|
||||
* @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);
|
||||
// recurse on childShadows
|
||||
const childShadows = Array.from(el.querySelectorAll('*')).
|
||||
map(el => el.shadowRoot).filter(Boolean);
|
||||
|
||||
bricks.debug('[querySelectorAllShadows]', selector, el, `(${childShadows.length} shadowRoots)`);
|
||||
bricks.debug('[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();
|
||||
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){
|
||||
@ -195,7 +325,7 @@ bricks.obj_fmtstr = function(obj, fmt){
|
||||
'${name:}, ${age=}'
|
||||
*/
|
||||
var s = fmt;
|
||||
s = s.replace(/\${(\w+)([:=]*)}/g, (k, key, op) => {
|
||||
s = s.replace(/\${(\w+)([:=]*)}/g, (k, key, op) => {
|
||||
if (obj.hasOwnProperty(key)){
|
||||
if (op == ''){
|
||||
return obj[key];
|
||||
@ -270,7 +400,7 @@ var archorize = function(ele,archor){
|
||||
}
|
||||
|
||||
Array.prototype.insert = function ( index, ...items ) {
|
||||
this.splice( index, 0, ...items );
|
||||
this.splice( index, 0, ...items );
|
||||
};
|
||||
|
||||
Array.prototype.remove = function(item){
|
||||
@ -310,26 +440,26 @@ var convert2int = function(s){
|
||||
}
|
||||
|
||||
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=/";
|
||||
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;
|
||||
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;';
|
||||
function eraseCookie(name) {
|
||||
document.cookie = name +'=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
||||
}
|
||||
|
||||
var set_max_height = function(w1, w2){
|
||||
@ -343,13 +473,48 @@ var set_max_height = function(w1, w2){
|
||||
}
|
||||
}
|
||||
var objcopy = function(obj){
|
||||
var o = {}
|
||||
for ( k in obj){
|
||||
if (obj.hasOwnProperty(k)){
|
||||
o[k] = obj[k];
|
||||
}
|
||||
}
|
||||
return o;
|
||||
var s = JSON.stringify(obj);
|
||||
return JSON.parse(s);
|
||||
}
|
||||
|
||||
bricks.set_stream_source = async function(target, url, params){
|
||||
var widget;
|
||||
if (typeof target == typeof ''){
|
||||
widget = bricks.getWidgetById(target);
|
||||
} else if (target instanceof bricks.JsWidget){
|
||||
widget = target;
|
||||
} else {
|
||||
widget = await bricks.widgetBuild(target);
|
||||
}
|
||||
if (! widget){
|
||||
bricks.debug('playResponseAudio():', target, 'can not found or build a widget');
|
||||
return;
|
||||
}
|
||||
const mediaSource = new MediaSource();
|
||||
mediaSource.addEventListener('sourceopen', handleSourceOpen);
|
||||
widget.set_url(URL.createObjectURL(mediaSource));
|
||||
function handleSourceOpen(){
|
||||
const sourceBuffer = mediaSource.addSourceBuffer('audio/wav; codecs=1');
|
||||
var ht = new bricks.HttpText();
|
||||
ht.bricks_fetch(url, {params:params})
|
||||
.then(response => response.body)
|
||||
.then(body => {
|
||||
const reader = body.getReader();
|
||||
const read = () => {
|
||||
reader.read().then(({ done, value }) => {
|
||||
if (done) {
|
||||
mediaSource.endOfStream();
|
||||
return;
|
||||
}
|
||||
sourceBuffer.appendBuffer(value);
|
||||
read();
|
||||
}).catch(error => {
|
||||
console.error('Error reading audio stream:', error);
|
||||
});
|
||||
};
|
||||
read();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bricks.playResponseAudio = async function(response, target){
|
||||
@ -367,8 +532,8 @@ bricks.playResponseAudio = async function(response, target){
|
||||
bricks.debug('playResponseAudio():', target, 'can not found or build a widget');
|
||||
return;
|
||||
}
|
||||
const blob = await response.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
const blob = await response.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
widget.set_url(url);
|
||||
widget.play();
|
||||
}
|
||||
@ -395,12 +560,88 @@ bricks.Observable = class {
|
||||
this.value = v;
|
||||
}
|
||||
set(v){
|
||||
if (this.value != v){
|
||||
var ov = this.value;
|
||||
this.value = v;
|
||||
if (this.value != ov){
|
||||
this.owner.dispatch(this.name, v);
|
||||
}
|
||||
this.value = v;
|
||||
}
|
||||
get(){
|
||||
return this.v;
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Queue = class {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this._done = false;
|
||||
}
|
||||
|
||||
// 添加元素到队列尾部
|
||||
enqueue(element) {
|
||||
this.items.push(element);
|
||||
}
|
||||
done(){
|
||||
this._done = true;
|
||||
}
|
||||
is_done(){
|
||||
return this._done;
|
||||
}
|
||||
|
||||
// 移除队列的第一个元素并返回
|
||||
dequeue() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return this.items.shift();
|
||||
}
|
||||
|
||||
// 查看队列的第一个元素
|
||||
peek() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return this.items[0];
|
||||
}
|
||||
|
||||
// 检查队列是否为空
|
||||
isEmpty() {
|
||||
return this.items.length === 0;
|
||||
}
|
||||
|
||||
// 获取队列的大小
|
||||
size() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
// 清空队列
|
||||
clear() {
|
||||
this.items = [];
|
||||
}
|
||||
|
||||
// 打印队列元素
|
||||
print() {
|
||||
console.log(this.items.toString());
|
||||
}
|
||||
}
|
||||
|
||||
function blobToBase64(blob) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = function() {
|
||||
resolve(reader.result);
|
||||
};
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
/*
|
||||
// 使用队列
|
||||
const queue = new Queue();
|
||||
queue.enqueue(1);
|
||||
queue.enqueue(2);
|
||||
queue.enqueue(3);
|
||||
queue.print(); // 输出: 1,2,3
|
||||
console.log(queue.dequeue()); // 输出: 1
|
||||
queue.print(); // 输出: 2,3
|
||||
*/
|
||||
|
220
bricks/video.js
@ -26,6 +26,7 @@ bricks.VideoBody = class extends bricks.Layout {
|
||||
bricks.Video = class extends bricks.Layout {
|
||||
/*
|
||||
{
|
||||
title:
|
||||
vtype:
|
||||
url:
|
||||
fullscreen:
|
||||
@ -34,13 +35,22 @@ bricks.Video = class extends bricks.Layout {
|
||||
*/
|
||||
constructor(options){
|
||||
super(options);
|
||||
this.video_body = new bricks.VideoBody(options);
|
||||
this.add_widget(this.video_body);
|
||||
// this.video_body = new bricks.VideoBody(options);
|
||||
this.set_css('video-js');
|
||||
this.set_css('vjs-big-play-centered');
|
||||
this.set_css('vjs-fluid');
|
||||
this.set_style('width', '100%');
|
||||
this.set_style('height', '100%');
|
||||
this.set_style('object-fit', 'contain');
|
||||
this.cur_url = opts.url;
|
||||
this.cur_vtype = opts.type;
|
||||
schedule_once(this.create_player.bind(this), 0.1);
|
||||
this.hidedbtn = new bricks.Button({label:'click me'});
|
||||
this.hidedbtn.bind('click', this.play.bind(this));
|
||||
this.hidedbtn.hide();
|
||||
this.add_widget(this.hidedbtn);
|
||||
}
|
||||
create(){
|
||||
var e;
|
||||
e = document.createElement('video');
|
||||
this.dom_element = e;
|
||||
e.controls = true;
|
||||
}
|
||||
|
||||
destroy_resource(params, event){
|
||||
@ -62,18 +72,51 @@ bricks.Video = class extends bricks.Layout {
|
||||
}
|
||||
}
|
||||
}
|
||||
findVideoButtonByClass(cls){
|
||||
var e = this.dom_element;
|
||||
return e.querySelector('.' + cls);
|
||||
}
|
||||
|
||||
auto_play(){
|
||||
<<<<<<< HEAD
|
||||
return;
|
||||
schedule_once(this._auto_play.bind(this), 0.5);
|
||||
=======
|
||||
schedule_once(this._auto_play.bind(this), 0.8);
|
||||
>>>>>>> 51416a085b5aa99df9f8edf9989fdc1b6306724c
|
||||
}
|
||||
_auto_play(){
|
||||
this.set_url(this.opts.url);
|
||||
return;
|
||||
var play_btn = this.findVideoButtonByClass('vjs-big-play-button');
|
||||
if (!play_btn){
|
||||
console.log('vjs-big-play-button not found');
|
||||
return;
|
||||
}
|
||||
if (play_btn.style.display == 'none'){
|
||||
console.log('playing .............already');
|
||||
return;
|
||||
}
|
||||
console.log('video ready, auto_playing ....');
|
||||
schedule_once(this.disable_captions.bind(this), 2);
|
||||
this.hidedbtn.dispatch('click');
|
||||
var clickevent = new MouseEvent('click', {
|
||||
'bubbles': true, // 事件是否冒泡
|
||||
'cancelable': true // 事件是否可取消
|
||||
});
|
||||
play_btn.dispatchEvent(clickevent);
|
||||
/*
|
||||
if (this.autounmute && this.player.muted){
|
||||
schedule_once(this.dispatch_mute.bind(this), 1);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
play(){
|
||||
console.log('Video:play() called....');
|
||||
this.player.play();
|
||||
// this.player.muted(false);
|
||||
}
|
||||
unmuted(){
|
||||
this.player.muted(false);
|
||||
}
|
||||
set_fullscreen(){
|
||||
if (this.fullscreen){
|
||||
@ -86,9 +129,31 @@ bricks.Video = class extends bricks.Layout {
|
||||
}
|
||||
}
|
||||
}
|
||||
dispatch_mute(){
|
||||
var mute_btn = this.findVideoButtonByClass("vjs-mute-control.vjs-control.vjs-button");
|
||||
if (!mute_btn){
|
||||
var isMute = this.player.muted();
|
||||
if (isMuted){
|
||||
this.player.muted(False);
|
||||
}
|
||||
bricks.test_element = this;
|
||||
console.log(this, 'there is not mute button found, isMuted=', isMuted);
|
||||
return;
|
||||
}
|
||||
var clickevent = new MouseEvent('click', {
|
||||
'bubbles': true, // 事件是否冒泡
|
||||
'cancelable': true // 事件是否可取消
|
||||
});
|
||||
var isMuted = this.player.muted();
|
||||
if (isMuted){
|
||||
mute_btn.dispatchEvent(clickevent);
|
||||
}
|
||||
}
|
||||
|
||||
create_player(){
|
||||
if(this.url){
|
||||
this.player = videojs(this.video_body.dom_element, {
|
||||
// this.player = videojs(this.video_body.dom_element, {
|
||||
this.player = videojs(this.dom_element, {
|
||||
controls:true,
|
||||
autoplay:this.autoplay,
|
||||
muted:true,
|
||||
@ -99,37 +164,49 @@ bricks.Video = class extends bricks.Layout {
|
||||
this.player.on('error',this.report_error.bind(this));
|
||||
this.player.on('play', this.report_playok.bind(this));
|
||||
this.player.on('ended', this.report_ended.bind(this));
|
||||
this._set_source();
|
||||
this.set_url(this.opts.url);
|
||||
this.player.ready(this.set_fullscreen.bind(this));
|
||||
/*
|
||||
if (this.autoplay){
|
||||
this.player.autoplay = true;
|
||||
this.player.muted = true;
|
||||
this.player.ready(this.auto_play.bind(this));
|
||||
} else {
|
||||
console.log('autoplay=', this.autoplay, this.auto_play);
|
||||
// this.player.ready(this.auto_play.bind(this));
|
||||
this.auto_play();
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
report_ended(){
|
||||
this.dispatch('play_end',{src:this.video_body.cur_url,type:this.video_body.cur_vtype});
|
||||
if (this.play_status != 'playok'){
|
||||
returnl
|
||||
}
|
||||
this.play_status = 'playend';
|
||||
this.dispatch('play_end',{src:this.cur_url,type:this.cur_vtype});
|
||||
}
|
||||
report_playok(){
|
||||
console.log(this.video_body.cur_url, 'play ok');
|
||||
this.dispatch('play_ok', {src:this.video_body.cur_url,type:this.video_body.cur_vtype});
|
||||
if (this.play_status != ''){
|
||||
return;
|
||||
}
|
||||
this.play_status = 'playok';
|
||||
console.log(this.cur_url, 'play ok');
|
||||
if (this.autounmute && this.player.muted()){
|
||||
schedule_once(this.dispatch_mute.bind(this), 2.5);
|
||||
console.log('mute btn clicked');
|
||||
} else {
|
||||
console.log(this.autounmute, 'player.muted=', this.player.muted);
|
||||
}
|
||||
this.dispatch('play_ok', {src:this.cur_url,type:this.cur_vtype});
|
||||
}
|
||||
report_error(){
|
||||
console.log(this.video_body.cur_url, 'play failed', this.err_cnt, 'times');
|
||||
this.dispatch('play_failed', {'src':this.video_body.cur_url, type:this.video_body.cur_vtype});
|
||||
if (this.play_status != ''){
|
||||
return;
|
||||
}
|
||||
this.play_status = 'playfailed';
|
||||
console.log(this.cur_url, 'play failed', this.err_cnt, 'times');
|
||||
this.dispatch('play_failed', {'src':this.cur_url, type:this.cur_vtype});
|
||||
}
|
||||
_set_source(){
|
||||
if (this.player){
|
||||
this.player.src({
|
||||
src:this.video_body.cur_url,
|
||||
type:this.video_body.cur_vtype
|
||||
src:this.cur_url,
|
||||
type:this.cur_vtype
|
||||
});
|
||||
this.play_status = '';
|
||||
}
|
||||
}
|
||||
set_source(url, vtype){
|
||||
@ -138,17 +215,106 @@ bricks.Video = class extends bricks.Layout {
|
||||
vtype = 'application/x-mpegURL';
|
||||
} else if (t.endsWith('.mp4')){
|
||||
vtype = 'video/mp4';
|
||||
} else if (t.endsWith('.avi')){
|
||||
vtype = 'video/avi';
|
||||
} else if (t.endsWith('.webm')){
|
||||
vtype = 'video/webm';
|
||||
} else {
|
||||
vtype = 'application/x-mpegURL';
|
||||
}
|
||||
if(this.player){
|
||||
this.video_body.cur_url = url;
|
||||
this.video_body.cur_vtype = vtype;
|
||||
this.cur_url = url;
|
||||
this.cur_vtype = vtype;
|
||||
this._set_source();
|
||||
this.play();
|
||||
}
|
||||
}
|
||||
set_url(url){
|
||||
this.set_source(url);
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Iptv = class extends bricks.VBox {
|
||||
/*
|
||||
{
|
||||
iptv_data_url:
|
||||
playok_url:
|
||||
playfailed_url:
|
||||
}
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
schedule_once(this.build_subwidgets.bind(this), 0.1);
|
||||
}
|
||||
async build_subwidgets(){
|
||||
console.log('build_subwidgets called');
|
||||
var jc = new bricks.HttpJson();
|
||||
this.deviceid = bricks.deviceid('iptv')
|
||||
this.user_data = await jc.httpcall(this.iptv_data_url, {
|
||||
params:{
|
||||
deviceid:this.deviceid
|
||||
},
|
||||
method:'GET'
|
||||
});
|
||||
console.log('this.user_data =', this.user_data);
|
||||
this.video = new bricks.Video({
|
||||
autoplay:true,
|
||||
autounmute:this.autounmute,
|
||||
url:this.user_data.url
|
||||
});
|
||||
this.title_w = new bricks.Text({text:this.user_data.tv_name, wrap:false});
|
||||
this.add_widget(this.title_w);
|
||||
this.add_widget(this.video);
|
||||
this.video.bind('play_ok', this.report_play_ok.bind(this));
|
||||
this.video.bind('play_failed', this.report_play_failed.bind(this));
|
||||
}
|
||||
async report_play_ok(){
|
||||
console.log(this.user_data, 'channel playing ...', this.playok_url);
|
||||
if (this.playok_url){
|
||||
var ht = new bricks.HttpText();
|
||||
var resp = ht.httpcall(this.playok_url,{
|
||||
params:{
|
||||
deviceid:this.deviceid,
|
||||
channelid:this.user_data.id
|
||||
},
|
||||
method:"GET"
|
||||
});
|
||||
if (resp != 'Error'){
|
||||
console.log('report playok ok');
|
||||
} else {
|
||||
console.log('report playok failed');
|
||||
}
|
||||
} else {
|
||||
console.log('this.playok_url not defined', this.playok_url);
|
||||
}
|
||||
}
|
||||
async report_play_failed(){
|
||||
console.log(this.user_data, 'channel play failed ...');
|
||||
if (this.playfailed_url){
|
||||
var ht = new bricks.HttpText();
|
||||
var resp = ht.httpcall(this.playfailed_url,{
|
||||
params:{
|
||||
deviceid:this.deviceid,
|
||||
channelid:this.user_data.id
|
||||
},
|
||||
method:"GET"
|
||||
});
|
||||
if (resp != 'Error'){
|
||||
console.log('report playfailed ok');
|
||||
} else {
|
||||
console.log('report playfailed failed');
|
||||
}
|
||||
} else {
|
||||
console.log('this.playfailed_url not defined', this.playfailed_url);
|
||||
}
|
||||
}
|
||||
setValue(data){
|
||||
this.user_data = data;
|
||||
this.title_w.set_text(data.tv_name);
|
||||
this.video.set_url(data.url);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
bricks.Factory.register('Video', bricks.Video);
|
||||
bricks.Factory.register('Iptv', bricks.Iptv);
|
||||
|
@ -1,52 +1,86 @@
|
||||
var bricks = window.bricks || {}
|
||||
bricks.WebSocket = class extends bricks.VBox {
|
||||
/*
|
||||
options = {
|
||||
ws_url:
|
||||
with_session:
|
||||
}
|
||||
event:
|
||||
onopen:
|
||||
onmessage:
|
||||
onerror:
|
||||
onclose:
|
||||
ontext:
|
||||
onbase64audio
|
||||
onbase64video
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.dialog = new bricks.VScrollPanel({})
|
||||
this.dialog.set_css('filler')
|
||||
this.input = new bricks.UiStr({
|
||||
name:'prompt',
|
||||
label:'Say something'
|
||||
});
|
||||
this.add_widget(this.dialog);
|
||||
this.add_widget(this.input);
|
||||
this.input.bind('keypress', this.check_keypress.bind(this));
|
||||
this.ws = new WebSocket(this.ws_url);
|
||||
this.ws.onopen = function(){
|
||||
console.log("open");
|
||||
if (opts.with_session){
|
||||
var session = bricks.app.get_session();
|
||||
this.ws = new WebSocket(this.ws_url, sessopn);
|
||||
} else {
|
||||
this.ws = new WebSocket(this.ws_url);
|
||||
}
|
||||
this.ws.onclose = function(e){
|
||||
//当客户端收到服务端发送的关闭连接请求时,触发onclose事件
|
||||
console.log("close");
|
||||
}
|
||||
this.ws.onerror = function(e){
|
||||
//如果出现连接、处理、接收、发送数据失败的时候触发onerror事件
|
||||
console.log(error);
|
||||
}
|
||||
this.ws.onmessage = this.show_response.bind(this);
|
||||
this.ws.onopen = this.on_open.bind(this);
|
||||
this.ws.onmessage = this.on_message.bind(this);
|
||||
this.ws.onclose = this.on_close.bind(this);
|
||||
this.ws.onerror = this.on_error.bind(this);
|
||||
}
|
||||
check_keypress(e){
|
||||
if (e.key == 'Enter'){
|
||||
var v = this.input.getValue();
|
||||
var s = v.prompt;
|
||||
console.log('check_keypress()', v, s);
|
||||
if (s != ''){
|
||||
this.show_input(s);
|
||||
}
|
||||
}
|
||||
on_open(e){
|
||||
this.dispatch('onopen');
|
||||
console.log("open");
|
||||
}
|
||||
show_input(s){
|
||||
var w = new bricks.MdWidget({mdtext:s});
|
||||
w.set_css('user_msg');
|
||||
this.dialog.add_widget(w);
|
||||
this.ws.send(s);
|
||||
on_close(e){
|
||||
this.dispatch('onclose');
|
||||
console.log("close");
|
||||
}
|
||||
show_response(e){
|
||||
on_error(e){
|
||||
this.dispatch('onerror');
|
||||
console.log(error);
|
||||
}
|
||||
on_message(e){
|
||||
var d = JSON.parse(e.data);
|
||||
console.log(e.data, d.type, d.data, d);
|
||||
var w = new bricks.MdWidget({mdtext:d.data});
|
||||
w.set_css('llm_msg');
|
||||
this.dialog.add_widget(w);
|
||||
var eventname = 'on' + d.type;
|
||||
this.dispatch(eventname, d.data);
|
||||
}
|
||||
send_text(text){
|
||||
var d = {
|
||||
type: "text",
|
||||
data: text
|
||||
}
|
||||
this.send(d);
|
||||
}
|
||||
send_base64_video(b64video){
|
||||
var d = {
|
||||
type: "base64video",
|
||||
data: b64video
|
||||
}
|
||||
this.send(d);
|
||||
}
|
||||
send_base64_audio(b64audio){
|
||||
var d = {
|
||||
type: "base64audio",
|
||||
data: b64audio
|
||||
}
|
||||
this.send(d);
|
||||
}
|
||||
send_typedata(type, data){
|
||||
var d = {
|
||||
type:type,
|
||||
data:data
|
||||
}
|
||||
return send(d);
|
||||
}
|
||||
send(d){
|
||||
/* d is a object:
|
||||
{
|
||||
type:
|
||||
data:
|
||||
}
|
||||
*/
|
||||
var s = JSON.stringify(d);
|
||||
this.ws.send(s);
|
||||
}
|
||||
}
|
||||
bricks.Factory.register('WebSocket', bricks.WebSocket);
|
||||
|
73
bricks/webspeech.js
Normal file
@ -0,0 +1,73 @@
|
||||
var bricks = window.bricks || {};
|
||||
|
||||
bricks.WebTTS = class extends bricks.VBox {
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
}
|
||||
speak(text){
|
||||
// 检查浏览器是否支持SpeechSynthesis
|
||||
if ('speechSynthesis' in window) {
|
||||
var utterance = new SpeechSynthesisUtterance(text);
|
||||
// 设置语音属性,例如语言
|
||||
utterance.lang = bricks.app.lang;
|
||||
utterance.pitch = 1;
|
||||
utterance.rate = 1;
|
||||
utterance.onstart = function(event) {
|
||||
console.log('语音合成开始');
|
||||
};
|
||||
// 当语音合成结束时触发
|
||||
utterance.onend = function(event) {
|
||||
console.log('语音合成结束');
|
||||
};
|
||||
// 当语音合成出错时触发
|
||||
utterance.onerror = function(event) {
|
||||
console.error('语音合成出错:', event.error);
|
||||
};
|
||||
// 将utterance添加到语音合成队列
|
||||
window.speechSynthesis.speak(utterance);
|
||||
} else {
|
||||
console.error('浏览器不支持SpeechSynthesis');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bricks.WebASR = class extends bricks.VBox {
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.reognition = None;
|
||||
}
|
||||
start_recording(){
|
||||
// 检查浏览器是否支持SpeechRecognition
|
||||
if ('SpeechRecognition' in window) {
|
||||
// 创建SpeechRecognition实例
|
||||
this.recognition = new SpeechRecognition();
|
||||
// 处理识别错误
|
||||
this.recognition.onerror = function(event) {
|
||||
console.error('识别错误:', event.error);
|
||||
};
|
||||
// 处理语音识别结束事件
|
||||
this.recognition.onend = function() {
|
||||
console.log('语音识别已结束');
|
||||
};
|
||||
// 处理识别结果
|
||||
this.recognition.onresult = function(event) {
|
||||
var transcript = event.results[0][0].transcript;
|
||||
this.dispatch('asr_result', {
|
||||
content:transcript
|
||||
});
|
||||
console.log('识别结果:', transcript);
|
||||
};
|
||||
this.recognition.lang = bricks.app.lang;
|
||||
this.recognition.start();
|
||||
} else {
|
||||
console.log('browser has not SpeechRecognition');
|
||||
}
|
||||
}
|
||||
stop_recording(){
|
||||
this.recognition.stop();
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('WebTTS', bricks.WebTTS);
|
||||
bricks.Factory.register('WebASR', bricks.WebASR);
|
||||
|
@ -15,6 +15,13 @@ bricks.resize_observer = new ResizeObserver(entries => {
|
||||
});
|
||||
|
||||
bricks.JsWidget = class {
|
||||
/*
|
||||
popup:{
|
||||
popup_event:
|
||||
popup_desc:
|
||||
popupwindow:false or true
|
||||
}
|
||||
*/
|
||||
constructor(options){
|
||||
if (!options){
|
||||
options = {}
|
||||
@ -38,9 +45,36 @@ bricks.JsWidget = class {
|
||||
var w = bricks.app.tooltip;
|
||||
this.bind('mousemove', w.show.bind(w, this.opts.tip));
|
||||
this.bind('mouseout', w.hide.bind(w));
|
||||
this.bind('click', w.hide.bind(w));
|
||||
}
|
||||
if (this.popup){
|
||||
this.bind(this.popup.popup_event, this.popup_action.bind(this));
|
||||
}
|
||||
bricks.resize_observer.observe(this.dom_element);
|
||||
}
|
||||
destroy_popup(){
|
||||
this.popup_widget.destroy();
|
||||
this.popup_widget = null;
|
||||
}
|
||||
async popup_action(){
|
||||
if (this.popup_widget){
|
||||
this.popup_widget.destroy();
|
||||
this.popup_widget = null;
|
||||
} else {
|
||||
if (this.popup.popupwindow){
|
||||
this.popup_widget = new bricks.PopupWindow(this.popup.optiosn);
|
||||
} else {
|
||||
this.popup_widget = new bricks.Popup(this.popup.options);
|
||||
}
|
||||
this.popup_widget.bind('dismissed', this.destroy_popup.bind(this));
|
||||
var w = await bricks.widgetBuild(this.popup.popup_desc, this, this.user_data);
|
||||
if (w){
|
||||
this.popup_widget.add_widget(w);
|
||||
this.popup_widget.open();
|
||||
this.popup_widget.popup_from_widget(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
showRectage(){
|
||||
return this.dom_element.getBoundingClientRect();
|
||||
}
|
||||
@ -477,36 +511,22 @@ bricks.Tooltip = class extends bricks.Text {
|
||||
this.set_otext(otext);
|
||||
this.set_style('zIndex', 999999999);
|
||||
this.set_style('display', 'block');
|
||||
var ex,ey;
|
||||
var x,y;
|
||||
var xsize = bricks.Body.dom_element.clientWidth;
|
||||
var ysize = bricks.Body.dom_element.clientHeight;
|
||||
ex = event.clientX;
|
||||
ey = event.clientY;
|
||||
var mxs = this.dom_element.offsetWidth;
|
||||
var mys = this.dom_element.offsetHeight;
|
||||
if (ex < (xsize / 2)) {
|
||||
x = ex + bricks.app.charsize;
|
||||
} else {
|
||||
x = ex - mxs - bricks.app.charsize;
|
||||
}
|
||||
if (ey < (ysize / 2)) {
|
||||
y = ey + bricks.app.charsize;
|
||||
} else {
|
||||
y = ey - mys - bricks.app.charsize;
|
||||
}
|
||||
this.set_style('left', x + 'px');
|
||||
this.set_style('top', y + 'px');
|
||||
if (this.auto_task){
|
||||
this.auto_task.cancel();
|
||||
}
|
||||
this.auto_task = schedule_once(this.hide.bind(this), 30);
|
||||
}
|
||||
hide(){
|
||||
bricks.relocate_by_eventpos(event, this);
|
||||
if (this.auto_task){
|
||||
this.auto_task.cancel();
|
||||
this.auto_task = null;
|
||||
}
|
||||
this.auto_task = schedule_once(this.hide.bind(this), 6);
|
||||
}
|
||||
hide(){
|
||||
try {
|
||||
if (this.auto_task){
|
||||
this.auto_task.cancel();
|
||||
this.auto_task = null;
|
||||
}
|
||||
} catch(e){
|
||||
console.log('Exception:', e);
|
||||
}
|
||||
this.set_style('display', 'none');
|
||||
}
|
||||
}
|
||||
|
471
bricks/wsllm.js
Normal file
@ -0,0 +1,471 @@
|
||||
bricks = window.bricks || {}
|
||||
|
||||
bricks.ModelOutput = class extends bricks.VBox {
|
||||
bricks.RoleOutput = class extends bricks.VBox {
|
||||
/*
|
||||
{
|
||||
icon:
|
||||
role:'user' or 'llm',
|
||||
output_view:
|
||||
}
|
||||
完成模型输出的控件的初始化以及获得数据后的更新, 更新是的数据在流模式下,需要使用累积数据
|
||||
*/
|
||||
constructor(opts){
|
||||
if(! opts){
|
||||
opts = {};
|
||||
}
|
||||
opts.width = '100%';
|
||||
opts.height = 'auto';
|
||||
super(opts);
|
||||
var hb = new bricks.HBox({width:'100%', cheight:2});
|
||||
var default_icon;
|
||||
if (this.role == 'llm'){
|
||||
default_icon = bricks_resource('imgs/llm.png')
|
||||
} else {
|
||||
defautl_icon = bricks_resource('imgs/user.png')
|
||||
}
|
||||
this.img = new bricks.Icon({
|
||||
rate:2,
|
||||
tip:this.opts.model,
|
||||
url:this.icon || default_icon
|
||||
});
|
||||
hb.add_widget(this.img);
|
||||
var mname = new bricks.Text({text:this.opts.model});
|
||||
hb.add_widget(mname);
|
||||
this.add_widget(hb);
|
||||
|
||||
this.content = new bricks.HBox({width:'100%'});
|
||||
this.add_widget(this.content);
|
||||
this.logid = null;
|
||||
this.run = new bricks.BaseRunning({target:this});
|
||||
this.content.add_widget(this.run);
|
||||
this.filler = new bricks.VBox({});
|
||||
this.filler.set_css('filler');
|
||||
if (this.role == 'llm'){
|
||||
this.content.add_widget(new bricks.BlankIcon({rate:2, flexShrink:0}));
|
||||
}
|
||||
this.content.add_widget(this.filler);
|
||||
if (this.role != 'llm'){
|
||||
this.content.add_widget(new bricks.BlankIcon({rate:2, flexShrink:0}));
|
||||
}
|
||||
if (this.role == 'llm'){
|
||||
this.build_estimate_widgets();
|
||||
}
|
||||
}
|
||||
build_estimate_widgets(){
|
||||
if (!this.estimate_url) return;
|
||||
this.estimate_w = new bricks.HBox({width:'100%', cheight:2});
|
||||
var txtw = new bricks.Text({
|
||||
otext:'结果满意吗?',
|
||||
i18n:true,
|
||||
});
|
||||
var likew = new bricks.Icon({rate:2, url:bricks_resource('imgs/like.png')});
|
||||
var unlikew = new bricks.Icon({rate:2, url:bricks_resource('imgs/unlike.png')});
|
||||
likew.bind('click', this.estimate_llm.bind(this, 1));
|
||||
unlikew.bind('click', this.estimate_llm.bind(this, -1))
|
||||
this.estimate_w.add_widget(txtw);
|
||||
this.estimate_w.add_widget(likew);
|
||||
this.estimate_w.add_widget(new bricks.BlankIcon({rate:1, flexShrink:0}));
|
||||
this.estimate_w.add_widget(unlikew);
|
||||
likew.set_style('cursor', 'pointer');
|
||||
unlikew.set_style('cursor', 'pointer');
|
||||
this.estimate_w.hide();
|
||||
}
|
||||
async estimate_llm(val, event){
|
||||
var desc = {
|
||||
"widgettype":"urlwidget",
|
||||
"options":{
|
||||
"params":{
|
||||
"logid":this.logid,
|
||||
"value":val
|
||||
},
|
||||
"url":this.estimate_url
|
||||
}
|
||||
};
|
||||
var icon = event.target.bricks_widget;
|
||||
icon.rate = 2;
|
||||
icon.charsize_sizing();
|
||||
var w = await bricks.widgetBuild(desc, this);
|
||||
this.estimate_w.disabled(true);
|
||||
}
|
||||
async update_data(data){
|
||||
if (this.run) {
|
||||
this.run.stop_timepass();
|
||||
this.content.remove_widget(this.run);
|
||||
if(this.textvoice){
|
||||
this.upstreaming = new bricks.UpStreaming({
|
||||
url:this.tts_url
|
||||
});
|
||||
this.upstreaming.go();
|
||||
}
|
||||
}
|
||||
if (this.upstreaming){
|
||||
this.upstreaming.send(data.content);
|
||||
}
|
||||
this.run = null;
|
||||
this.filler.clear_widgets();
|
||||
if (typeof this.output_view === 'string'){
|
||||
this.output_view = JSON.parse(this.output_view);
|
||||
}
|
||||
var desc = bricks.apply_data(this.output_view, data);
|
||||
var w = await bricks.widgetBuild(desc, this.llmio);
|
||||
if (! w){
|
||||
console.log('widgetBuild() return null, desc=', this.output_view, desc, 'data=', data);
|
||||
return;
|
||||
}
|
||||
w.set_css('llm_msg');
|
||||
w.set_style('width', '100%');
|
||||
this.filler.add_widget(w);
|
||||
this.filler.add_widget(this.estimate_w);
|
||||
if (data.logid){
|
||||
this.logid = data.logid;
|
||||
if (this.estimate_url){
|
||||
this.estimate_w.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
finish(){
|
||||
if (this.upstreaming){
|
||||
this.upstreaming.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bricks.LlmModel = class extends bricks.JsWidget {
|
||||
/*
|
||||
{
|
||||
icon:
|
||||
model:
|
||||
url:
|
||||
output_view:
|
||||
params:
|
||||
user_message_format:
|
||||
system_message_format:
|
||||
llm_message_format:
|
||||
use_session:
|
||||
input_from:
|
||||
textvoice:
|
||||
tts_url:
|
||||
response_mode:stream, sync or async
|
||||
}
|
||||
*/
|
||||
constructor(llmio, opts){
|
||||
super(opts);
|
||||
this.llmio = llmio;
|
||||
this.messages = [];
|
||||
}
|
||||
render_title(){
|
||||
var w = new bricks.HBox({padding:'15px'});
|
||||
w.bind('click', this.show_setup_panel.bind(this))
|
||||
var img = new bricks.Icon({
|
||||
rate:2,
|
||||
tip:this.opts.model,
|
||||
url:this.opts.icon||bricks_resource('imgs/llm.png')
|
||||
});
|
||||
// var txt = new bricks.Text({text:this.opts.model});
|
||||
w.add_widget(img);
|
||||
// w.add_widget(txt);
|
||||
return w;
|
||||
}
|
||||
show_setup_panel(event){
|
||||
|
||||
}
|
||||
inputdata2uploaddata(data){
|
||||
var d;
|
||||
if (data instanceof FormData){
|
||||
d = bricks.formdata_copy(data);
|
||||
} else {
|
||||
d = objcopy(data);
|
||||
}
|
||||
var fmt = this.opts.user_message_format;
|
||||
if (fmt){
|
||||
var umsg = bricks.apply_data(fmt, inputdata2dic(data));
|
||||
this.messages.push(umsg);
|
||||
}
|
||||
if (data instanceof FormData){
|
||||
d.append('model', this.opts.model)
|
||||
d.append('modelinstanceid', this.opts.modelinstanceid)
|
||||
d.append('modeltypeid', this.opts.modeltypeid)
|
||||
d.append('messages', JSON.stringify(this.messages));
|
||||
} else {
|
||||
d.messages = JSON.stringify(this.messages);
|
||||
d.model = this.opts.model;
|
||||
d.modelinstanceid = this.opts.modelinstanceid;
|
||||
d.modeltypeid = this.opts.modeltypeid;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
async model_inputed(data){
|
||||
if (!opts.use_session){
|
||||
this.messages = [];
|
||||
}
|
||||
var mout = new bricks.ModelOutput({
|
||||
textvoice:this.textvoice,
|
||||
tts_url:this.tts_url,
|
||||
icon:this.opts.icon,
|
||||
model:this.opts.model,
|
||||
estimate_url:this.llmio.estimate_url,
|
||||
output_view:this.opts.output_view});
|
||||
this.llmio.o_w.add_widget(mout);
|
||||
if (this.response_mode == 'stream' || this.response_mode == 'async') {
|
||||
var d = this.inputdata2uploaddata(data);
|
||||
console.log('data_inouted=', data, 'upload_data=', d);
|
||||
var hr = new bricks.HttpResponseStream();
|
||||
var resp = await hr.post(this.opts.url, {params:d});
|
||||
await hr.handle_chunk(resp, this.chunk_response.bind(this, mout));
|
||||
this.chunk_ended();
|
||||
} else {
|
||||
var d = this.inputdata2uploaddata(data);
|
||||
var hj = new bricks.HttpJson()
|
||||
var resp = await hj.post(this.opts.url, {params:d});
|
||||
if (this.response_mode == 'sync'){
|
||||
resp.content = bricks.escapeSpecialChars(resp.content)
|
||||
mout.update_data(resp);
|
||||
if (this.messages){
|
||||
var msg = this.llm_msg_format();
|
||||
var lmsg = bricks.apply_data(msg, resp);
|
||||
this.messages.push(lmsg)
|
||||
}
|
||||
} else {
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
is_accept_source(source){
|
||||
if (this.opts.input_from == source){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
llm_msg_format(){
|
||||
return this.llm_message_format || {role:'assistant', content:"${content}"}
|
||||
}
|
||||
chunk_response(mout, l){
|
||||
var d = JSON.parse(l);
|
||||
if (! d.content || d.content == ''){
|
||||
return;
|
||||
}
|
||||
d.content = bricks.escapeSpecialChars(d.content);
|
||||
this.resp_data = d;
|
||||
mout.update_data(d);
|
||||
// console.log('stream data=', d);
|
||||
}
|
||||
chunk_ended(){
|
||||
if (! this.messages) {
|
||||
console.log('this.messages is null !!!!!!!!!');
|
||||
return;
|
||||
}
|
||||
var msg = this.llm_msg_format();
|
||||
var txt = bricks.escapeSpecialChars(this.resp_data.content)
|
||||
this.resp_data.content = txt;
|
||||
var lmsg = bricks.apply_data(msg, this.resp_data);
|
||||
this.messages.push(lmsg);
|
||||
}
|
||||
}
|
||||
bricks.LlmIO = class extends bricks.VBox {
|
||||
/*
|
||||
options:
|
||||
{
|
||||
ws_url:
|
||||
user_icon:
|
||||
list_models_url:
|
||||
input_fields:
|
||||
input_view:
|
||||
output_view:
|
||||
models:
|
||||
}
|
||||
models:[
|
||||
{
|
||||
icon:
|
||||
model:
|
||||
url:
|
||||
params:
|
||||
use_session:
|
||||
system_prompt:
|
||||
user_parmpt:
|
||||
input_from:
|
||||
io_mode:stream, sync or async
|
||||
}
|
||||
]
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.ws = new bricks.WebSocket(this.ws_url);
|
||||
this.llmmodels = [];
|
||||
this.title_w = new bricks.HBox({cheight:3});
|
||||
var bottom_box = new bricks.HBox({cheight:3});
|
||||
this.i_w = new bricks.Icon({
|
||||
rate:2,
|
||||
url:bricks_resource('imgs/input.png'),
|
||||
margin:'14px',
|
||||
tip:'input data',
|
||||
css:'clickable'
|
||||
});
|
||||
this.nm_w = new bricks.Icon({
|
||||
rate:2,
|
||||
url:bricks_resource('imgs/add.png'),
|
||||
margin:'14px',
|
||||
tip:'add new model',
|
||||
css:'clickable'
|
||||
});
|
||||
bottom_box.add_widget(this.i_w);
|
||||
bottom_box.add_widget(this.nm_w);
|
||||
|
||||
this.nm_w.bind('click', this.open_search_models.bind(this));
|
||||
this.i_w.bind('click', this.open_input_widget.bind(this));
|
||||
this.o_w = new bricks.Filler({overflow:'auto'});
|
||||
this.add_widget(this.title_w);
|
||||
this.add_widget(this.o_w);
|
||||
if (this.models.length < 2 && this.tts_url){
|
||||
this.textvoice = true;
|
||||
}
|
||||
this.add_widget(bottom_box);
|
||||
this.models.forEach( m =>{
|
||||
this.show_added_model(m);
|
||||
});
|
||||
}
|
||||
show_added_model(m){
|
||||
if (this.textvoice){
|
||||
m.textvoice = true;
|
||||
m.tts_url = this.tts_url;
|
||||
}
|
||||
var lm = new bricks.LlmModel(this, m);
|
||||
this.llmmodels.push(lm);
|
||||
var tw = lm.render_title();
|
||||
this.title_w.add_widget(tw);
|
||||
}
|
||||
async open_search_models(event){
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
var rect = this.showRectage();
|
||||
var opts = {
|
||||
title:"select model",
|
||||
icon:bricks_resource('imgs/search.png'),
|
||||
auto_destroy:true,
|
||||
auto_open:true,
|
||||
auto_dismiss:false,
|
||||
movable:true,
|
||||
top:rect.top + 'px',
|
||||
left:rect.left + 'px',
|
||||
width: rect.right - rect.left + 'px',
|
||||
height: rect.bottom - rect.top + 'px'
|
||||
}
|
||||
var w = new bricks.PopupWindow(opts);
|
||||
var sopts = {
|
||||
data_url:this.list_models_url,
|
||||
data_params:{
|
||||
mii:this.models[0].modelinstanceid,
|
||||
mti:this.models[0].modeltypeid
|
||||
},
|
||||
data_method:'POST',
|
||||
col_cwidth: 24,
|
||||
record_view:{
|
||||
widgettype:"VBox",
|
||||
options:{
|
||||
cheight:20,
|
||||
css:"card"
|
||||
},
|
||||
subwidgets:[
|
||||
{
|
||||
widgettype:"Title4",
|
||||
options:{
|
||||
text:"${name}"
|
||||
}
|
||||
},
|
||||
{
|
||||
widgettype:"Filler",
|
||||
options:{
|
||||
css:"scroll"
|
||||
},
|
||||
subwidgets:[
|
||||
{
|
||||
widgettype:"VBox",
|
||||
options:{
|
||||
css:"subcard"
|
||||
},
|
||||
subwidgets:[
|
||||
{
|
||||
widgettype:"Text",
|
||||
options:{
|
||||
text:"模型描述:${description}",
|
||||
wrap:true
|
||||
}
|
||||
},
|
||||
{
|
||||
widgettype:"Text",
|
||||
options:{
|
||||
text:"启用日期:${enable_date}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
var cols = new bricks.Cols(sopts);
|
||||
cols.bind('record_click', this.add_new_model.bind(this));
|
||||
cols.bind('record_click', w.dismiss.bind(w));
|
||||
w.add_widget(cols);
|
||||
w.open();
|
||||
}
|
||||
async add_new_model(event){
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.models.push(event.params);
|
||||
this.show_added_model(event.params);
|
||||
}
|
||||
async open_input_widget(event){
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
var rect = this.showRectage();
|
||||
var opts = {
|
||||
title:"input data",
|
||||
icon:bricks_resource('imgs/input.png'),
|
||||
auto_destroy:true,
|
||||
auto_open:true,
|
||||
auto_dismiss:false,
|
||||
movable:true,
|
||||
top:rect.top + 'px',
|
||||
left:rect.left + 'px',
|
||||
width: rect.right - rect.left + 'px',
|
||||
height: rect.bottom - rect.top + 'px'
|
||||
}
|
||||
var w = new bricks.PopupWindow(opts);
|
||||
var fopts = {
|
||||
fields:this.input_fields
|
||||
}
|
||||
var fw = new bricks.Form(fopts);
|
||||
fw.bind('submit', this.handle_input.bind(this));
|
||||
fw.bind('submit', w.destroy.bind(w));
|
||||
w.add_widget(fw);
|
||||
w.open();
|
||||
}
|
||||
async handle_input(event){
|
||||
var params = event.params;
|
||||
await this.show_input(params);
|
||||
for(var i=0;i<this.llmmodels.length;i++){
|
||||
var lm = this.llmmodels[i];
|
||||
if (lm.is_accept_source('userinput')){
|
||||
schedule_once(lm.model_inputed.bind(lm, params), 0.01);
|
||||
// await lm.model_inputed(params);
|
||||
}
|
||||
};
|
||||
}
|
||||
async show_input(params){
|
||||
var box = new bricks.HBox({width:'100%'});
|
||||
var data = inputdata2dic(params);
|
||||
console.log('data=', data, 'input_view=', this.input_view);
|
||||
var w = await bricks.widgetBuild(this.input_view, this.o_w, data);
|
||||
w.set_css(this.msg_css||'user_msg');
|
||||
w.set_css('filler');
|
||||
var img = new bricks.Icon({rate:2,url:this.user_icon||bricks_resource('imgs/user.png')});
|
||||
box.add_widget(new bricks.BlankIcon({rate:2, flexShrink:0}));
|
||||
box.add_widget(w);
|
||||
box.add_widget(img);
|
||||
this.o_w.add_widget(box);
|
||||
}
|
||||
}
|
||||
|
||||
bricks.Factory.register('LlmIO', bricks.LlmIO);
|
@ -6,29 +6,59 @@ bricks.Wterm = class extends bricks.JsWidget {
|
||||
/*
|
||||
{
|
||||
ws_url:
|
||||
host:
|
||||
ssh_port:
|
||||
user:
|
||||
ping_timeout:19
|
||||
}
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.socket = null;
|
||||
this.ping_timeout = opts.ping_timeout || 19;
|
||||
schedule_once(this.open.bind(this), 0.5);
|
||||
}
|
||||
charsize_sizing(){
|
||||
var cs = bricks.app.charsize;
|
||||
this.term.setOption('fontSize', cs);
|
||||
}
|
||||
heartbeat(){
|
||||
if (this.socket.readyState != 1) return;
|
||||
this.socket.send('_#_heartbeat_#_');
|
||||
this.heartbeat_task = schedule_once(this.heartbeat.bind(this),
|
||||
this.ping_timeout);
|
||||
}
|
||||
async open(){
|
||||
var term = new Terminal();
|
||||
var term_options = this.term_options || {};
|
||||
var term = new Terminal(term_options);
|
||||
this.term = term;
|
||||
term.open(this.dom_element);
|
||||
var ws = new WebSocket(this.opts.ws_url);
|
||||
bricks.debug('FitAddon=', FitAddon);
|
||||
var sessdata = bricks.app.get_session();
|
||||
var ws = new WebSocket(this.opts.ws_url, sessdata);
|
||||
this.socket = ws;
|
||||
|
||||
this.fitAddon = new FitAddon.FitAddon()
|
||||
term.loadAddon(this.fitAddon)
|
||||
// this.fitAddon.fit()
|
||||
this.fitAddon.fit();
|
||||
this.charsize_sizing();
|
||||
this.bind('resize', this.term_resize.bind(this))
|
||||
ws.onmessage = msg => {
|
||||
term.write(JSON.parse(msg.data).data);
|
||||
ws.onmessage = event => {
|
||||
var msg = JSON.parse(event.data);
|
||||
console.log('ws msg=', msg);
|
||||
if (msg.data == '_#_heartbeat_#_'){
|
||||
console.log('connection alive');
|
||||
} else {
|
||||
term.write(msg.data);
|
||||
}
|
||||
};
|
||||
ws.onclose = (event) => {
|
||||
console.log('websocket closed:', event.code, '--', event.reason);
|
||||
if (this.heartbeat_task) {
|
||||
this.heartbeat_task.cancel();
|
||||
this.heartbeat_task = null;
|
||||
}
|
||||
};
|
||||
ws.onopen = () => {
|
||||
this.heartbeat_task = schedule_once(this.heartbeat.bind(this),
|
||||
this.ping_timeout);
|
||||
};
|
||||
|
||||
term.onData(function(key) {
|
||||
//Enter
|
||||
let msg = {
|
||||
@ -38,13 +68,12 @@ bricks.Wterm = class extends bricks.JsWidget {
|
||||
ws.send(key);
|
||||
});
|
||||
term.focus();
|
||||
term.paste("ls -l\n");
|
||||
}
|
||||
term_resize(){
|
||||
try {
|
||||
this.fitAddon.fit();
|
||||
} catch(e){
|
||||
bricks.debug('resize error', e);
|
||||
console.log('resize error', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,14 @@ bricks的事件处理是在控件描述文件的binds区域中添加事件处理
|
||||
### dataparams
|
||||
获取动态参数时需给定的参数, 可选,对象类型,k,v形式给定参数
|
||||
|
||||
### popup_options
|
||||
当target为“Popup“或“PopupWindow”时,定义Popup或PopupWindow的参数
|
||||
|
||||
#### dismiss_events
|
||||
字符串数组,每个字符串定义一个Popup, PopupWindow的子控件的事件,这些事件发生时将导致Popup, PopupWindow关闭
|
||||
|
||||
#### eventpos
|
||||
Popup, PopupWindow窗体移动到鼠标位置
|
||||
|
||||
### 获取动态参数说明
|
||||
绑定任务获取实时数据作为参数,需要给定以下属性:
|
||||
@ -50,7 +58,15 @@ bricks的事件处理是在控件描述文件的binds区域中添加事件处理
|
||||
datamethod 优先datascript,从datawidget控件中通过datamethod
|
||||
|
||||
### target
|
||||
字符串或控件实例,目标控件实例,如果是字符串,使用”getWidgetById“函数获得目标控件实例,关于target规则请查看[控件id](widgetid.md)
|
||||
支持一下形式的target定义:
|
||||
* 目标控件实例对象
|
||||
* 字符串,且等于“Popup“
|
||||
* 字符串,且等于”PopupWindow“
|
||||
* 其他字符串(控件对象的id)
|
||||
当actiontype为"urlwidget"时,target应该是一个容器控件,所生成的控件将插入或替代到“target”所代表的对象中,如果actiontype是其他类型,则在此对象中执行方法,脚本,定义函数,或定义事件
|
||||
|
||||
|
||||
|
||||
|
||||
### conform
|
||||
如果一个事件处理需要用户确认,可以在事件处理中指定一个conform属性来引发,当此事件发生时,会弹出一个确认窗口,用户确认后才会处理此事件,否则不处理
|
||||
|
6
examples/alipay_recharge.ui
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"widgettype":"VBox",
|
||||
"options":{
|
||||
"height":"100%"
|
||||
}
|
||||
}
|
14
examples/asr.ui
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"widgettype":"ASRClient",
|
||||
"options":
|
||||
{
|
||||
"ws_url":"{{entire_url('/wss/ws/test.ws')}}?userid={{get_user()}}",
|
||||
"icon_options":{
|
||||
"rate":3
|
||||
},
|
||||
"ws_params":{
|
||||
"kkk":1,
|
||||
"brade":"123"
|
||||
}
|
||||
}
|
||||
}
|
36
examples/recharge.ui
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"widgettype":"IconbarPage",
|
||||
"options":{
|
||||
"bar_at":"top",
|
||||
"bar_opts":{
|
||||
"margin":"10px",
|
||||
"rate":1.6,
|
||||
"tools":[
|
||||
{
|
||||
"name":"wechat",
|
||||
"icon":"{{entire_url('/imgs/weixinzhifu.png')}}",
|
||||
"label":"微信充值",
|
||||
"tip":"使用微信为账户充值",
|
||||
"content":{
|
||||
"widgettype":"urlwidget",
|
||||
"options":{
|
||||
"url":"{{entire_url('wechat_recharge.ui')}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"alipay",
|
||||
"icon":"{{entire_url('/imgs/zhifubao.png')}}",
|
||||
"label":"支付宝充值",
|
||||
"tip":"使用支付宝为账户充值",
|
||||
"content":{
|
||||
"widgettype":"urlwidget",
|
||||
"options":{
|
||||
"url":"{{entire_url('alipay_recharge.ui')}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
6
examples/wechat_recharge.ui
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"widgettype":"VBox",
|
||||
"options":{
|
||||
"height":"100%"
|
||||
}
|
||||
}
|