first commit

This commit is contained in:
yumoqing 2025-07-16 14:28:55 +08:00
commit 86d1672251
482 changed files with 59798 additions and 0 deletions

12
3parties/README.md Normal file
View File

@ -0,0 +1,12 @@
https://cdn.jsdelivr.net/npm/xterm@4.19.0/css/xterm.css
https://vjs.zencdn.net/8.10.0/video-js.css
https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js
https://cdn.jsdelivr.net/npm/xterm@4.19.0/lib/xterm.js
https://vjs.zencdn.net/8.10.0/video.min.js
# webrtc_adapter.js
come from https://github.com/googlecodelabs/webrtc-web
# peerjs
come from https://github.com/peers/peerjs
https://cdnjs.cloudflare.com/ajax/libs/peerjs/1.5.2/peerjs.min.js

45
3parties/echarts.min.js vendored Normal file

File diff suppressed because one or more lines are too long

12
3parties/fingerprintjs-4.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2864
3parties/marked.js Executable file

File diff suppressed because it is too large Load Diff

14
3parties/marked.min.js vendored Executable file

File diff suppressed because one or more lines are too long

27427
3parties/ort.js Normal file

File diff suppressed because one or more lines are too long

8
3parties/peerjs.min.js vendored Normal file

File diff suppressed because one or more lines are too long

6
3parties/recorder.wav.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
3parties/vad.0.0.7.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1930
3parties/video-js.css Normal file

File diff suppressed because one or more lines are too long

46
3parties/video.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
3parties/videojs-ie8.min.js vendored Normal file

File diff suppressed because one or more lines are too long

3
3parties/videojs.record.min.css vendored Normal file

File diff suppressed because one or more lines are too long

8
3parties/videojs.record.min.js vendored Normal file

File diff suppressed because one or more lines are too long

215
3parties/webrtc_adapter.js Normal file
View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
'use strict';
var RTCPeerConnection = null;
var getUserMedia = null;
var attachMediaStream = null;
var reattachMediaStream = null;
var webrtcDetectedBrowser = null;
var webrtcDetectedVersion = null;
function maybeFixConfiguration(pcConfig) {
if (!pcConfig) {
return;
}
for (var i = 0; i < pcConfig.iceServers.length; i++) {
if (pcConfig.iceServers[i].hasOwnProperty('urls')) {
pcConfig.iceServers[i].url = pcConfig.iceServers[i].urls;
delete pcConfig.iceServers[i].urls;
}
}
}
if (navigator.mozGetUserMedia) {
console.log('This appears to be Firefox');
window.webrtcDetectedBrowser = 'firefox';
window.webrtcDetectedVersion =
parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
// The RTCPeerConnection object.
RTCPeerConnection = function(pcConfig, pcConstraints) {
// .urls is not supported in FF yet.
maybeFixConfiguration(pcConfig);
return new mozRTCPeerConnection(pcConfig, pcConstraints);
};
// The RTCSessionDescription object.
RTCSessionDescription = mozRTCSessionDescription;
// The RTCIceCandidate object.
RTCIceCandidate = mozRTCIceCandidate;
// Get UserMedia (only difference is the prefix).
// Code from Adam Barth.
window.getUserMedia = navigator.mozGetUserMedia.bind(navigator);
navigator.getUserMedia = getUserMedia;
// Creates iceServer from the url for FF.
window.createIceServer = function(url, username, password) {
var iceServer = null;
var urlParts = url.split(':');
if (urlParts[0].indexOf('stun') === 0) {
// Create iceServer with stun url.
iceServer = {
'url': url
};
} else if (urlParts[0].indexOf('turn') === 0) {
if (webrtcDetectedVersion < 27) {
// Create iceServer with turn url.
// Ignore the transport parameter from TURN url for FF version <=27.
var turnUrlParts = url.split('?');
// Return null for createIceServer if transport=tcp.
if (turnUrlParts.length === 1 ||
turnUrlParts[1].indexOf('transport=udp') === 0) {
iceServer = {
'url': turnUrlParts[0],
'credential': password,
'username': username
};
}
} else {
// FF 27 and above supports transport parameters in TURN url,
// So passing in the full url to create iceServer.
iceServer = {
'url': url,
'credential': password,
'username': username
};
}
}
return iceServer;
};
window.createIceServers = function(urls, username, password) {
var iceServers = [];
// Use .url for FireFox.
for (var i = 0; i < urls.length; i++) {
var iceServer = createIceServer(urls[i],
username,
password);
if (iceServer !== null) {
iceServers.push(iceServer);
}
}
return iceServers;
};
// Attach a media stream to an element.
window.attachMediaStream = function(element, stream) {
console.log('Attaching media stream');
element.mozSrcObject = stream;
element.play();
};
window.reattachMediaStream = function(to, from) {
console.log('Reattaching media stream');
to.mozSrcObject = from.mozSrcObject;
to.play();
};
} else if (navigator.webkitGetUserMedia) {
console.log('This appears to be Chrome');
window.webrtcDetectedBrowser = 'chrome';
// Temporary fix until crbug/374263 is fixed.
// Setting Chrome version to 999, if version is unavailable.
var result = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
if (result !== null) {
window.webrtcDetectedVersion = parseInt(result[2], 10);
} else {
window.webrtcDetectedVersion = 999;
}
// Creates iceServer from the url for Chrome M33 and earlier.
window.createIceServer = function(url, username, password) {
var iceServer = null;
var urlParts = url.split(':');
if (urlParts[0].indexOf('stun') === 0) {
// Create iceServer with stun url.
iceServer = {
'url': url
};
} else if (urlParts[0].indexOf('turn') === 0) {
// Chrome M28 & above uses below TURN format.
iceServer = {
'url': url,
'credential': password,
'username': username
};
}
return iceServer;
};
// Creates iceServers from the urls for Chrome M34 and above.
window.createIceServers = function(urls, username, password) {
var iceServers = [];
if (webrtcDetectedVersion >= 34) {
// .urls is supported since Chrome M34.
iceServers = {
'urls': urls,
'credential': password,
'username': username
};
} else {
for (var i = 0; i < urls.length; i++) {
var iceServer = createIceServer(urls[i],
username,
password);
if (iceServer !== null) {
iceServers.push(iceServer);
}
}
}
return iceServers;
};
// The RTCPeerConnection object.
RTCPeerConnection = function(pcConfig, pcConstraints) {
// .urls is supported since Chrome M34.
if (webrtcDetectedVersion < 34) {
maybeFixConfiguration(pcConfig);
}
return new webkitRTCPeerConnection(pcConfig, pcConstraints);
};
// Get UserMedia (only difference is the prefix).
// Code from Adam Barth.
window.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
navigator.getUserMedia = getUserMedia;
// Attach a media stream to an element.
window.attachMediaStream = function(element, stream) {
if (typeof element.srcObject !== 'undefined') {
element.srcObject = stream;
} else if (typeof element.mozSrcObject !== 'undefined') {
element.mozSrcObject = stream;
} else if (typeof element.src !== 'undefined') {
element.src = URL.createObjectURL(stream);
} else {
console.log('Error attaching stream to element.');
}
};
window.reattachMediaStream = function(to, from) {
to.src = from.src;
};
} else {
console.log('Browser does not appear to be WebRTC-capable');
}

View 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

190
3parties/xterm.css Normal file
View File

@ -0,0 +1,190 @@
/**
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
* https://github.com/chjj/term.js
* @license MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Originally forked from (with the author's permission):
* Fabrice Bellard's javascript vt100 for jslinux:
* http://bellard.org/jslinux/
* Copyright (c) 2011 Fabrice Bellard
* The original design remains. The terminal itself
* has been extended to include xterm CSI codes, among
* other features.
*/
/**
* Default styles for xterm.js
*/
.xterm {
cursor: text;
position: relative;
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
}
.xterm.focus,
.xterm:focus {
outline: none;
}
.xterm .xterm-helpers {
position: absolute;
top: 0;
/**
* The z-index of the helpers must be higher than the canvases in order for
* IMEs to appear on top.
*/
z-index: 5;
}
.xterm .xterm-helper-textarea {
padding: 0;
border: 0;
margin: 0;
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
position: absolute;
opacity: 0;
left: -9999em;
top: 0;
width: 0;
height: 0;
z-index: -5;
/** Prevent wrapping so the IME appears against the textarea at the correct position */
white-space: nowrap;
overflow: hidden;
resize: none;
}
.xterm .composition-view {
/* TODO: Composition position got messed up somewhere */
background: #000;
color: #FFF;
display: none;
position: absolute;
white-space: nowrap;
z-index: 1;
}
.xterm .composition-view.active {
display: block;
}
.xterm .xterm-viewport {
/* On OS X this is required in order for the scroll bar to appear fully opaque */
background-color: #000;
overflow-y: scroll;
cursor: default;
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 0;
}
.xterm .xterm-screen {
position: relative;
}
.xterm .xterm-screen canvas {
position: absolute;
left: 0;
top: 0;
}
.xterm .xterm-scroll-area {
visibility: hidden;
}
.xterm-char-measure-element {
display: inline-block;
visibility: hidden;
position: absolute;
top: 0;
left: -9999em;
line-height: normal;
}
.xterm.enable-mouse-events {
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
cursor: default;
}
.xterm.xterm-cursor-pointer,
.xterm .xterm-cursor-pointer {
cursor: pointer;
}
.xterm.column-select.focus {
/* Column selection mode */
cursor: crosshair;
}
.xterm .xterm-accessibility,
.xterm .xterm-message {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 10;
color: transparent;
}
.xterm .live-region {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
.xterm-dim {
opacity: 0.5;
}
.xterm-underline {
text-decoration: underline;
}
.xterm-strikethrough {
text-decoration: line-through;
}
.xterm-screen .xterm-decoration-container .xterm-decoration {
z-index: 6;
position: absolute;
}
.xterm-decoration-overview-ruler {
z-index: 7;
position: absolute;
top: 0;
right: 0;
pointer-events: none;
}
.xterm-decoration-top {
z-index: 2;
position: relative;
}

2
3parties/xterm.js Normal file

File diff suppressed because one or more lines are too long

22
README.md Executable file
View File

@ -0,0 +1,22 @@
# Bricks
A new web application development framework to make web application development more easier like play bricks
## Documentation
We have English and Chinese versions documents,
Documents in English, please read from [docs](docs/README.md), 中文资料看[这里](docs/cn/README.md)
## Development base on components
We built web development components which use a options objects as API.
third party can develops their component suply the standard of components API
Most front-end development tools only help user to build the front-end UI, and use script to build the app's logic.
Bricks not only build the UI but also the front-end logic.
Bricks provide a new mathiciam to description the event fire, and event handler, Bricks use json data to descripts event and it handler, when event fire, according the json data, Bricks dynamicly constructs the event handler.
## Dependanance
[Marked](https://github.com/yumoqing/marked) is a tool for markdown text parser, extends from [MarkedJs marked](https://github.com/markedjs/marked), we extends audio and video link, user can directly use `!v[text](url)` pattern to show a video player, and `!a[text](url)` pattern to show a audio player

BIN
bricks/.DS_Store vendored Executable file

Binary file not shown.

85
bricks/accordion.js Normal file
View File

@ -0,0 +1,85 @@
var bricks = window.bricks || {};
bricks.Accordion = class extends bricks.VBox {
/*
{
item_size:
items:[
{
icon:
text:
content:{
widgettype:
...
}
}
]
}
*/
constructor(opts){
super(opts);
this.keyselectable = true;
var item_size = this.opts.item_size || '25px';
this.set_height('100%');
var items = this.opts.items;
this.w_items = [];
this.subcontents = {};
var item_css = this.opts.item_css || 'accordion' + '-button';
var content_css = this.opts.content_css || 'accordion' + '-content';
for (var i=0; i< items.length; i++){
var opts = {
name:items[i].name,
icon:items[i].icon,
label:items[i].label,
height:'auto',
orientation:'horizontal'
}
var b = new bricks.Button(opts);
b.bind('click', this.change_content.bind(this));
this.w_items.push(b);
this.add_widget(b);
}
this.key_select_items = this.w_items;
this.content = new bricks.Filler({});
this.sub_container = new bricks.VScrollPanel({height:'100%'});
this.content.add_widget(this.sub_container);
this.w_items[0].dispatch('click');
}
async change_content(event){
var refresh = false;
var b = event.target.bricks_widget;
var name = b.opts.name;
this.select_item(b);
bricks.debug('accordion: button=', b, 'name=', name);
var pos = -1;
for (var i=0; i< this.opts.items.length; i++){
if (name == this.opts.items[i].name){
pos = i;
if (this.opts.items[i].refresh) refresh = true;
break
}
}
if (pos==-1){
debug('Accordion():name=',name, 'not found in items',this.opts.items);
}
var c = objget(this.subcontents,name);
if (refresh || ! c ){
if (!this.opts.items[pos].content){
console.log('***', pos, 'item dont has content');
return;
}
c = await bricks.widgetBuild(this.opts.items[pos].content);
this.subcontents[name] = c;
}
this.sub_container.clear_widgets();
this.sub_container.add_widget(c);
try {
this.remove_widget(this.content);
}
catch(e){
;
}
this.add_widget(this.content, pos+1);
}
}
bricks.Factory.register('Accordion', bricks.Accordion);

46
bricks/aggrid.js Normal file
View File

@ -0,0 +1,46 @@
var bricks = window.bricks || {};
bricks.AG_Grid = class extends bricks.JsWidget {
/*
{
dataurl:
fields:
}
*/
constructor(opts){
super(opts);
ag_opts = {}
}
init(){
this.datasource = {
getRows:this.getRows,
startRow
this.ag_opts.columnDefs = [];
this.ag_opts.rowModelType = 'infinite';
this.ag_opts.maxConcurrentDatasourceRequests: 1,
this.ag_opts.datasource = this.datasource;
for (var i=0; i< this.opts.fields.length; i++){
var f = {
width:this.opts.fields[i].width | 100,
headerName:this.opts.fields[i].label|this.opts.fields[i].name,
field:this.opts.fields[i].name
},
this.ag_opts.columnDefs.push(f)
}
this.ag_opts.defaultColDef = {sortable: true, filter: true};
this.ag_opts.rowSelection = 'multiple';
this.ag_opts.animateRows = true;
this.ag_opts.onCellClicked = this.cell_clicked.bind(this);
this.aggrid = new agGrid.Grid(this.dom_element, this.ag_opts);
fetch(this.opts.dataurl)
.then(response => response.json())
.then(data => {
// load fetched data into grid
this.ag_opts.api.setRowData(data);
});
}
cell_clicked(params){
bricks.debug('clicked, params=', params);
}
}

76
bricks/asr.js Normal file
View 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.svg');
this.icon = new bricks.Svg(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.svg'));
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);

355
bricks/audio.js Normal file
View File

@ -0,0 +1,355 @@
var bricks = window.bricks || {};
bricks.formatMs=function(ms,all){
var ss=ms%1000;ms=(ms-ss)/1000;
var s=ms%60;ms=(ms-s)/60;
var m=ms%60;ms=(ms-m)/60;
var h=ms;
var t=(h?h+":":"")
+(all||h+m?("0"+m).substr(-2)+":":"")
+(all||h+m+s?("0"+s).substr(-2)+"″":"")
+("00"+ss).substr(-3);
return t;
};
bricks.AudioPlayer = class extends bricks.JsWidget {
/*
{
url:
autoplay:
}
*/
constructor(options){
super(options);
this.url = options.url;
this.audio = this._create('audio');
this.audio.controls = true;
if (this.opts.autoplay){
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');
this.source.src = url;
this.audio.appendChild(this.source);
}
this.url = this.audio.src = url;
console.log(this.audio.src,' new src seted');
}
set_source_from_response(resp){
// 将服务器返回的数据设置为音频源
this.audio.src = URL.createObjectURL(new Blob([response.body]));
// 播放音频
this.audio.play();
}
async play(){
await this.audio.play();
}
async toggle_play(){
if (this.audio.paused){
await this.audio.play();
} else {
await this.audio.pause();
}
}
set_url(url){
this.set_source(url);
this.audio.play();
}
}
bricks.AudioRecorder = class extends bricks.HBox {
/*
{
"upload_url":
"icon_rate":
}
we need this module:
https://gitee.com/xiangyuecn/Recorder
events:
record_started
record_ended
realtime record wave show need a another package
we only use the wav file format
*/
constructor(opts){
super(opts);
this.set_css('clickable');
this.start_icon = opts.start_icon || bricks_resource('imgs/start_recording.svg');
this.stop_icon = opts.stop_icon || bricks_resource('imgs/stop_recording.svg');
this.rec_btn = new bricks.Svg({
url:this.start_icon,
rate:this.icon_rate
});
// this.player = new bricks.AudioPlayer({url:"",width:'80px'});
this.rec_time = new bricks.Text({
text:" record time",
i18n:false,
dynsize:true,
wrap:false,
width:'120px'
});
this.upload_url = opts.upload_url;
this.bind('click', this.rec_btn_pressed.bind(this))
this.URL = window.URL||webkitURL;
this.rec = null;
this.wave = null;
this.mic_opened = false;
this.add_widget(this.rec_btn);
this.add_widget(this.rec_time);
this.recordData = null;
if (this.upload_url){
this.bind('record_ended', this.upload.bind(this));
}
}
rec_btn_pressed(){
if(this.rec_btn.url == this.start_icon){
console.log('start recording .......');
this.rec_btn.set_url(this.stop_icon);
this.start_recording();
} else {
console.log('stop recording ....');
this.rec_btn.set_url(this.start_icon);
this.stop_recording();
}
}
on_process(buffers,powerLevel,
bufferDuration,bufferSampleRate,
newBufferIdx,asyncEnd){
//录音实时回调大约1秒调用12次本回调
// document.querySelector(".recpowerx").style.width=powerLevel+"%";
//可视化图形绘制
// wave.input(buffers[buffers.length-1],powerLevel,bufferSampleRate);
this.rec_time.set_text(' ' + bricks.formatMs(bufferDuration,1));
}
recOpen(){
this.rec=null;
this.wave=null;
var newRec = Recorder({
type:"wav",sampleRate:16000,bitRate:16
,onProcess:this.on_process.bind(this)
});
newRec.open(function(){//打开麦克风授权获得相关资源
this.mic_opened = true;
this.rec=newRec;
this.rec.start();
this.dispatch('record_started');
//此处创建这些音频可视化图形绘制浏览器支持妥妥的
//this.wave=Recorder.FrequencyHistogramView({elem:".recwave"});
}.bind(this),function(msg,isUserNotAllow){//用户拒绝未授权或不支持
bricks.debug('open recorder failed');
});
}
recClose(){
if(this.rec){
this.rec.close();
this.rec = null;
this.mic_opened = false;
}else{
bricks.debug('close recorder error');
};
}
start_recording(){
this.recordData = null;
if (this.mic_opened){
this.rec.start();
this.dispatch('record_started');
}
this.recOpen();
}
pause_recording(){
if(this.rec&&Recorder.IsOpen()){
this.rec.pause();
}else{
bricks.debug("gCAR::未打开录音");
};
}
resume_recording(){
if(this.rec&&Recorder.IsOpen()){
this.rec.resume();
}else{
bricks.debug("Ob6S::未打开录音");
};
}
stop_recording(){
if(!(this.rec&&Recorder.IsOpen())){
bricks.debug("5JuL::未打开录音");
return;
};
this.rec.stop(function(blob,duration){
var localURL = this.URL.createObjectURL(blob);
var d = {
data:blob,
url:localURL,
duration:duration
}
this.recordData = d;
this.dispatch('record_ended', d);
}.bind(this),function(msg){
bricks.debug("kGZO::录音失败:");
});
this.recClose();
}
async upload(){
var running = new bricks.Running({target:this});
if(!this.recordData){
bricks.debug("DUTn::请先录音,然后停止后再上传");
return;
};
if(!this.upload_url){
return;
}
var blob=this.recordData.data;
bricks.debug('blob=', blob, this.recordData);
var form=new FormData();
form.append("audiofile",blob,"recorder.wav");
var jpost = bricks.jpost
var ret = await jpost(this.upload_url,{
params:form
});
bricks.debug('ret=', ret);
this.dispatch('uploaded', ret)
running.dismiss();
}
download(){
if(!this.recordData){
bricks.debug('recorder not opened');
return;
};
var fileName="recorder-"+Date.now()+".wav";
var downA=document.createElement("A");
downA.innerHTML="下载"+fileName;
downA.href=this.recordData.url;
downA.download=fileName;
// document.querySelector("."+cls).appendChild(downA);
if(bricks.is_mobile()){
bricks.debug('mobile device');
}
downA.click();
//不用了时需要revokeObjectURL否则霸占内存
(window.URL||webkitURL).revokeObjectURL(downA.href);
}
}
bricks.TextedAudioPlayer = class extends bricks.VBox {
constructor(opts){
super(opts);
this.audio = new bricks.AudioPlayer({
height:'60px'
});
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%'
});
filler.add_widget(panel);
this.textw = new bricks.Text({
text: ' ',
wrap: true
});
panel.add_widget(this.textw);
this.streaming_buffer = [];
this.wait_play = true;
}
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('TextedAudioPlayer', bricks.TextedAudioPlayer);

58
bricks/bar.js Normal file
View File

@ -0,0 +1,58 @@
var bricks = window.bricks || {};
bricks.ChartBar = class extends bricks.EchartsExt {
/*
{
data_url,
data_params,
method,
data,
nameField,
valueFields
}
*/
values_from_data(data, name){
var d = [];
data.forEach(x => {
d.push(x[name]);
});
return d;
}
lineinfo_from_data(data, name){
return {
name:name,
type:'bar',
data:this.values_from_data(data, name)
}
}
setup_options(data){
var n_data = [];
var series = [];
this.valueFields.forEach(v => {
series.push(this.lineinfo_from_data(data, v));
});
data.forEach(d => {
n_data.push(d[this.nameField]);
});
var opts = {
tooltip:{
trigger:'axis'
},
legend:{
data:n_data
},
xAxis:{
type:'category',
data: n_data
},
yAxis:{
type: 'value'
},
series:series
}
return opts;
}
}
bricks.Factory.register('ChartBar', bricks.ChartBar);

10
bricks/baseKnowledge.txt Normal file
View File

@ -0,0 +1,10 @@
css 子元素按照父元素位置定位
```
#parentDiv { position:relative; }
#childDiv { position:absolute; left:50px; top:20px; }
```
css 子元素按照window位置定位( use top:, left:, right:, and bottom: to position as you see fit.)
```
#yourDiv { position:fixed; bottom:40px; right:40px; }
```

55
bricks/binstreaming.js Normal file
View File

@ -0,0 +1,55 @@
bricks = window.bricks || {};
bricks.UpStreaming = class extends bricks.JsWidget {
/*
{
"url":
}
*/
constructor(opts){
super(opts);
}
async go(){
this.body = new ReadableStream(this);
this.headers = new Headers();
this.headers.append('Content-Type',
'application/octet-stream');
var resp = await fetch(this.url, {
method: 'POST',
headers: this.headers,
duplex: 'full',
body: this.body
});
return resp
}
send(data){
this.stream_ctlr.enqueue(data);
}
finish(){
this.stream_ctlr.close();
}
start(controller){
this.stream_ctlr = controller;
}
}
bricks.down_streaming = async function*(response) {
if (! response){
return;
}
const reader = response.body.getReader();
var value;
var t = 0;
while (true){
done, value = await reader.read();
if (value.done){
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;
}
}

720
bricks/bricks.js Normal file
View File

@ -0,0 +1,720 @@
var bricks = window.bricks || {};
bricks.app = null;
/*
all type of bind action's desc has the following attributes:
actiontype:'bricks',
wid:
event:
target:
datawidget:
datascript:
datamethod:
datakwargs:
rtdata:
conform:
and each type of binds specified attributes list following
urlwidget action:
mode:,
options:{
method:
params:{},
url:
}
bricks action:
mode:,
options:{
"widgettype":"gg",
...
}
method action:
method:
params: for methods kwargs
script action:
script:
params:
registerfunction action:
rfname:
params:
event action:
dispatch_event:
params:
*/
bricks.uuid = function(){
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){
var deviceid = appname + 'deviceid';
var id = localStorage.getItem(deviceid);
if (!id){
id = bricks.uuid();
localStorage.setItem(deviceid, id);
}
return id;
}
bricks.str2data = function(s, d){
/* fmt like
'my name is ${name}, ${age:type}'
type can be:
int, str, json
*/
funcs = {
'json':JSON.stringify
}
var regex = /\${(\w+)(?::(int|str|json))?}/;
var match = s.match(regex)
if (match){
var key = match[1];
var typ = match[2];
var ss = '${' + key;
if (typ != ''){
ss += ':' + typ;
}
ss += '}';
if (s == ss){
if (!d.hasOwnProperty(key)){
return null;
}
if (typ == ''){
return d[key];
}
var f = funcs[typ];
if (f){
return f(d[key]);
}
return d[key];
}
return s.replace(regex, (k, key, typ) => {
if (d.hasOwnProperty(key)){
var f = funcs[typ];
if (f){
return f(d[key]);
}
return d[key];
}
return '';
});
}
return s;
}
bricks.apply_data = function(desc, data){
if (bricks.is_empty(data)){
return desc;
}
var tmpl = JSON.stringify(desc);
var s = bricks.obj_fmtstr(data, tmpl);
return JSON.parse(s);
}
bricks.widgetBuild = async function(desc, widget, data){
if (! widget){
widget = bricks.Body;
}
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';
let opts = desc.options.params || {};
var jc = new bricks.HttpJson();
var desc1 = await jc.httpcall(url, { "method":method, "params":opts});
if (!desc1) return;
desc = desc1;
klassname = desc.widgettype;
}
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){
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);
}
if (w.is_container() && desc.subwidgets){
for (let i=0; i<desc.subwidgets.length; i++){
let sdesc = desc.subwidgets[i];
let sw = await (bricks.widgetBuild(sdesc, w, data));
if ( sw ){
w.add_widget(sw);
} else {
bricks.debug('widgetBuild() error: sdesc=', sdesc);
}
}
}
if (desc.hasOwnProperty('binds')){
for (var i=0;i<desc.binds.length; i++){
await bricks.buildBind(w, desc.binds[i]);
}
}
return w;
}
bricks.buildBind = async function(w, desc){
var widget = bricks.getWidgetById(desc.wid, w);
if (!widget){
console.log('desc wid not find', desc);
return;
}
var event = desc.event;
await bricks.buildEventBind(w, widget, event, desc);
}
bricks.buildEventBind = async function(from_widget, widget, event, desc){
var handler = bricks.universal_handler.bind(null,from_widget, widget, desc);
widget.bind(event, handler);
}
bricks.universal_handler = async function(from_widget, widget, desc, event){
var f = await bricks.buildEventHandler(from_widget, desc, event);
if (f){
if (desc.conform){
var c_desc = {
"widgettype":"Conform",
"options":desc.conform
}
var conform_widget = await bricks.widgetBuild(c_desc, widget);
conform_widget.bind('conformed', f);
// handler = conform_widget.open.bind(conform_widget);
} else {
return await f(event);
}
}
bricks.debug('universal_handler() error', 'from_widget=',
from_widget,
'widget=', widget,
'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;
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 = {
widget:desc.datawidget,
method:desc.datamethod || 'getValue',
params:desc.dataparams,
script:desc.datascript
}
rtdata = await bricks.getRealtimeData(w, data_desc);
}
switch (desc.actiontype){
case 'urlwidget':
return bricks.buildUrlwidgetHandler(w, target, rtdata, desc);
break;
case 'bricks':
return bricks.buildBricksHandler(w, target, rtdata, desc);
break;
case 'registerfunction':
return bricks.buildRegisterFunctionHandler(w, target, rtdata, desc);
break;
case 'method':
return bricks.buildMethodHandler(w, target, rtdata, desc);
break;
case 'script':
var f = bricks.buildScriptHandler(w, target, rtdata, desc);
return f;
break;
case 'event':
return bricks.buildDispatchEventHandler(w, target, rtdata, desc);
break;
default:
bricks.debug('invalid actiontype', target, desc);
break;
}
}
bricks.getRealtimeData = async function(w, desc){
var target = bricks.getWidgetById(desc.widget, w);
var f;
bricks.debug('getRealtimeData() calling ...');
if (! target){
bricks.debug('target miss', desc);
return null
}
if (desc.method){
f = bricks.buildMethodHandler(null, target, null, desc)
return f();
}
if (desc.script){
f = bricks.buildScriptHandler(null, target, null, desc)
return await f();
}
debug('getRealtimeData():desc=', desc, 'f=', f);
return null;
}
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) {
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 options = objcopy(desc.options||{});
var params = options.params || {};
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(null, w, target, desc.mode || 'replace', opts, desc);
}
bricks.buildBricksHandler = function(w, target, rtdata, desc){
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, desc);
}
bricks.buildRegisterFunctionHandler = function(w, target, rtdata, desc){
var f = bricks.RF.get(desc.rfname);
if( ! f){
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);
}
if (rtdata){
bricks.extend(params, rtdata);
}
bricks.extend(params, inputdata2dic(desc.event_params));
params = bricks.apply_data(params, rtdata);
return f.bind(target, params);
}
bricks.buildMethodHandler = function(w, target, rtdata, desc){
var f = target[desc.method];
if (! f){
bricks.debug('desc:', desc, 'not exists in', target, 'w=', w);
return null;
}
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);
}
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);
return f.bind(target, params);
}
bricks.buildDispatchEventHandler = function(w, target, rtdata, desc){
var f = function(event_name, params, event){
// console.log('target=', target, 'event_name=', event_name, 'params=', params, 'Arguments=', arguments);
this.dispatch(event_name, params);
}
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);
}
bricks.getWidgetById = function(id, from_widget){
if (!from_widget){
from_widget = bricks.Body;
}
if (! id){
return from_widget;
}
if (typeof(id) != 'string') return id;
var ids = id.split('.');
var el = from_widget.dom_element;
var new_el = null;
var j = 0;
for (var i=0; i< ids.length; i++){
if (i == 0){
if (ids[i] == 'self'){
el = from_widget.dom_element;
continue;
}
if (ids[i]=='root'){
el = bricks.app.root.dom_element;
continue;
}
if (ids[i]=='app' || ids[i] == 'body'){
return bricks.app;
}
if (ids[i] == 'window'){
el = bricks.Body.dom_element;
continue;
}
}
try {
if (ids[i][0] == '-'){
var wid = substr(1, ids[i].length - 1)
new_el = el.closest('#' + wid);
} else {
new_el = el.querySelector('#' + ids[i]);
}
}
catch(err){
bricks.debug('getWidgetById():i=', ids[i], id, 'not found', err);
return null;
}
if ( new_el == null ){
bricks.debug('getWidgetById():', id, from_widget, 'el=', el, 'id=', ids[i]);
return null;
}
el = new_el;
}
if (typeof(el.bricks_widget) !== 'undefined'){
return el.bricks_widget;
}
bricks.debug('********', id, 'el=', el, 'found, but not a bricks class with dom element');
return el;
}
bricks.App = class extends bricks.Layout {
constructor(opts){
/*
opts = {
appname:
debug:false, true, 'server'
login_url:
"charsize:
"language":
"i18n":{
"url":'rrr',
"default_lang":'en'
},
"widget":{
"widgettype":"Text",
"options":{
}
}
}
*/
super(opts);
bricks.app = this;
this.docks = [];
bricks.bug = opts.debug || false;
bricks.Body = this;
this.deviceid = bricks.deviceid(opts.appname || 'appname');
this.login_url = opts.login_url || '/rbac/userpassword_login.ui';
this.charsize = this.opts.charsize || 20;
this.keyevent_blocked = false;
this.char_size = this.observable('charsize', this.charsize);
if (this.opts.language){
this.lang = this.opts.language;
}
else {
this.lang = navigator.language;
}
this.lang_x = this.observable('lang', this.lang);
this.zindex = 10000;
this.textList = [];
this.i18n = new bricks.I18n(objget(opts, 'i18n', {}));
this.session_id = null;
this.tooltip = new bricks.Tooltip({otext:'test',i18n:true, wrap:true});
this.add_widget(this.tooltip);
this._Width = this.dom_element.offsetWidth;
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);
});
this.mwins = [];
this.wins_panel = null;
}
show_windows_panel(event){
console.log('event=', event);
event.preventDefault();
event.stopPropagation()
this.wins_panel = new bricks.WindowsPanel({})
}
get_color(){
return getComputedStyle(this.dom_element).color;
return parseRGB(colorStr);
}
get_bgcolor(){
return getComputedStyle(this.dom_element).backgroundColor;
return parseRGB(colorStr);
}
get_blinkcolor(){
var color, bgcolor, blinkcolor;
color = parseRGB(this.get_color());
bgcolor = parseRGB(this.get_bgcolor());
console.log('color=', color, 'bgcolor=', bgcolor);
function short1of3(x, y){
if (x < y) {
return x + (y - x) / 3;
} else {
return x - (x - y) / 3;
}
}
var r = short1of3(color.r, bgcolor.r);
var g = short1of3(color.g, bgcolor.g);
var b = short1of3(color.b, bgcolor.b);
var bc = bricks.obj_fmtstr({r:r, g:g, b:b}, "rgb(${r}, ${g}, ${b})");
console.log('color=', color, 'bgcolor=', bgcolor, 'bc=', bc);
return bc;
}
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) {
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.");
}
}
async start_mic() {
if (this.audio_stream) return;
if (navigator.mediaDevices.getUserMedia) {
this.audio_stream = navigator.mediaDevices.getUserMedia({ audio: true });
} else {
console.log("mic access is not supported in this browser.");
this.stream = null;
}
}
new_zindex(){
const v = this.zindex;
this.zindex = v + 1;
return v;
}
screenHeight(){
return this.dom_element.clientHeight;
}
screenWidth(){
return this.dom_element.clientWidth;
}
create(){
this.dom_element = document.getElementsByTagName('body')[0];
this.set_baseURI(this.dom_element.baseURI);
}
save_session(session){
this.session_id = session;
}
get_session(){
return this.session_id;
}
async setup_i18n(){
let params = {'lang':this.lang};
var jc = new bricks.HttpJson();
d = await jc.httpcall(desc.url, {
"method":desc.method||'GET', params:params});
this.i18n.setup_dict(d);
}
async build(){
var opts = bricks.extend({}, this.opts.widget);
var w = await bricks.widgetBuild(opts, bricks.Body);
if (!w){
bricks.debug('w=', w, 'Body=', bricks.Body, 'Factory=', bricks.Factory)
}
return w;
}
async run(){
await (this.change_language(this));
var w = await this.build();
this.root = w;
if (!w){
bricks.debug('w=', w, 'Body=', bricks.Body, 'Factory=', bricks.Factory)
return null;
}
bricks.Body.add_widget(w);
bricks.Body.down_level();
}
textsize_bigger(){
this.charsize = this.charsize * 1.05;
this.char_size.set(this.charsize);
}
textsize_smaller(){
this.charsize = this.charsize * 0.95;
this.char_size.set(this.charsize);
}
text_resize(){
for (var i=0;i<this.textList.length;i++){
if(this.textList[i].deref()){
var w = this.textList[i].deref();
var ts = this.get_textsize(w.ctype);
w.change_fontsize(ts);
}
}
}
async change_language(lang){
this.lang = lang;
await (this.i18n.change_lang(lang));
this.lang_x.set(this.lang);
}
async key_down_action(event){
if (this.keyevent_blocked){
return;
}
var d = {
key:event.key,
repeat:event.repeat,
altkey:event.altKey,
ctrlkey:event.ctrlKey,
shiftkey:event.shiftKey,
metakey:event.metaKey,
code:event.code
}
this.dispatch('keydown', d);
}
}

9
bricks/build.cmd Normal file
View File

@ -0,0 +1,9 @@
set SOURCES=utils.js i18n.js factory.js widget.js bricks.js image.js jsoncall.js myoperator.js layout.js menu.js modal.js markdown_viewer.js video.js audio.js toolbar.js tab.js input.js registerfunction.js button.js accordion.js tree.js multiple_state_image.js form.js message.js paging.js scroll.js datagrid.js miniform.js terminal.js
del ..\dist\bricks.js
echo %SOURCES%
type %SOURCES% > ..\dist\bricks.js
copy css\*.* ..\dist\css
copy imgs/*.* ..\dist\imgs
copy ..\examples\*.* ..\dist\examples
copy ..\docs\*.* ..\dist\docs
rem uglifyjs --compress --mangle %SOURCES% > ..\dist\bricks.min.js

44
bricks/build.sh Executable file
View File

@ -0,0 +1,44 @@
SOURCES=" page_data_loader.js factory.js uitypesdef.js utils.js uitype.js \
i18n.js widget.js layout.js bricks.js image.js html.js splitter.js \
jsoncall.js myoperator.js scroll.js menu.js popup.js camera.js modal.js running.js \
markdown_viewer.js video.js audio.js toolbar.js tab.js \
input.js registerfunction.js button.js accordion.js dataviewer.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 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
if [ ! -d ../dist/css ];then
rm -rf ../dist/css
mkdir ../dist/css
fi
if [ ! -d ../dist/3parties ];then
rm -rf ../dist/3parties
mkdir ../dist/3parties
fi
if [ ! -d ../dist/examples ];then
rm -rf ../dist/examples
mkdir ../dist/examples
fi
if [ ! -d ../dist/docs ];then
rm -rf ../dist/docs
mkdir ../dist/docs
fi
if [ ! -d ../dist/imgs ];then
rm -rf ../dist/imgs
mkdir ../dist/imgs
fi
cp -a css/* ../dist/css
cp -a imgs/* ../dist/imgs
cp -a ../examples/* ../dist/examples
cp -a ../3parties/* ../dist/3parties
cp -a ../docs/* ../dist/docs
cp *.tmpl ../dist
cp -a ../dist /tmp
echo "Finished ..."

93
bricks/button.js Normal file
View File

@ -0,0 +1,93 @@
bricks.Button = class extends bricks.Layout {
/*
orientation:
height:100%,
width:100%,
item_rate:
tooltip:
color:
nonepack:
name:
icon:
label:
css:
action:{
target:
datawidget:
datamethod:
datascript:
dataparams:
rtdata:
actiontype:
...
}
*/
constructor(opts){
super(opts);
var style = {
display:"flex",
justifyContent:"center",
textAlign:"center",
alignItem:"center",
width:"auto",
height:"auto",
};
if (opts.nonepack){
style.padding = '0px';
style.border = '0';
} else {
style.padding = '0.5rem';
}
if (this.opts.orientation == 'horizontal'){
style.flexDirection = 'rows';
this.orient = 'h';
} else {
style.flexDirection = 'column';
this.orient = 'v';
}
this.item_rate = opts.item_rate || 1;
this.set_id(this.opts.name);
this.opts_setup();
bricks.extend(this.dom_element.style, style);
}
create(){
this.dom_element = document.createElement('button');
}
opts_setup(){
var item_size = this.opts.item_size || bricks.app.charsize;
if (this.opts.icon){
var icon = new bricks.Icon({
rate:this.item_rate,
url:this.opts.icon
})
this.add_widget(icon);
icon.bind('click', this.target_clicked.bind(this));
}
if (this.opts.label){
var opts = {
rate:this.item_rate,
color:this.opts.color,
bgcolor:this.opts.bgcolor,
otext:this.opts.label,
i18n:true};
var txt = new bricks.Text(opts);
this.add_widget(txt);
txt.bind('click', this.target_clicked.bind(this));
this.text_w = txt;
}
}
target_clicked(event){
bricks.debug('target_clicked() .... called ');
event.stopPropagation();
this.dispatch('click', this.opts);
if (this.opts.action){
if (this.opts.debug){
bricks.debug('debug:opts=', this.opts);
}
}
}
}
bricks.Factory.register('Button', bricks.Button);

126
bricks/camera.js Normal file
View File

@ -0,0 +1,126 @@
var bricks = window.bricks || {}
bricks.Camera = class extends bricks.Popup {
/*
{
fps:60
}
*/
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:3
});
this.cur_camera_id = 0;
this.add_widget(filler);
this.add_widget(hbox);
var shot_btn = new bricks.Svg({
url:bricks_resource('imgs/camera.svg'),
margin: '10px',
tip:'Take a picture',
rate:2.5
});
var switch_btn = new bricks.Svg({
url:bricks_resource('imgs/switch-camera.svg'),
tip:'switch camera',
margin: '10px',
rate:1.5
});
var del_btn = new bricks.Svg({
url:bricks_resource('imgs/delete.Svg'),
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.1);
}
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;
const context = canvas.getContext('2d');
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;
}
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;
var d = this.imgw.base64();
this.dispatch('shot', d);
}
}
bricks.Factory.register('Camera', bricks.Camera);

204
bricks/cols.js Normal file
View File

@ -0,0 +1,204 @@
bricks = window.bricks || {}
bricks.Cols = class extends bricks.VBox {
/*
{
data_url:
data_params:
data_method:
col_width:
col_cwidth:
record_view:{
}
}
event:
record_click
*/
constructor(opts){
super(opts);
this.loading = false;
this.loader = new bricks.PageDataLoader({
url:this.opts.data_url,
params:this.opts.data_params,
pagerows:this.opts.page_rows,
method:this.opts.data_method,
cache_pages:this.opts.cache_limit
});
this.select_record = null;
this.container = new bricks.VScrollPanel({width:"100%"});
this.container.set_css('filler');
this.container.bind('min_threshold', this.load_previous_page.bind(this));
this.container.bind('max_threshold', this.load_next_page.bind(this));
if (this.title){
this.title_w = new bricks.Title4({
i18n:true,
otext:this.title,
dynsize:true
});
this.add_widget(this.title_w);
}
if (this.description){
this.desc_w = new bricks.MdWidget({mdtext:this.description});
this.add_widget(this.desc_w);
}
if (this.toolbar){
this.toolbar_w = new bricks.Toolbar(this.toolbar);
this.add_widget(this.toolbar_w);
this.toolbar_w.bind('command', this.command_handle.bind(this));
}
this.add_widget(this.container);
this.create_main_widget();
schedule_once(this.load_first_page.bind(this), 0.5);
}
command_handle(event){
var params = event.params;
this.dispatch(params.name);
}
async handle_click(rw, event){
event.stopPropagation();
var orev = null;
if (this.select_record){
orev = this.select_record;
this.select_record.set_css('selected_record', true);
this.select_record = null;
if (rw == orev) return;
}
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;
var page = d.add_page;
if (!data){
return;
}
var rev = ! this.loader.is_max_page(page);
if (rev){
data.reverse();
}
for (var i=0;i<data.length;i++){
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 (rev){
this.main.add_widget(w, 0);
} else {
this.main.add_widget(w);
}
}
if (d.delete_page){
this.delete_page(d.delete_page);
}
}
delete_page(page){
var items = this.dom_element.querySelectorAll('[data-page="' + page + '"]');
for (var i=0;i<items.length;i++) {
var w = items[i].bricks_widget;
this.main.remove_widget(w);
}
}
create_main_widget(){
this.container.clear_widgets();
this.main = new bricks.DynamicColumn({
width:"100%",
col_cwidth:this.col_cwidth,
mobile_cols:this.mobile_cols || 2
});
this.container.add_widget(this.main);
}
async show_with_data(data){
this.data = data;
this.data_url = null;
await load_first_page(params);
}
async load_first_page(params){
var running = null;
try {
var d;
running = new bricks.Running({target:this});
if (this.data_url){
if (this.loading){
bricks.debug('this.loading is set, do not thing');
throw 't';
}
this.loading = true;
var p = bricks.extend({}, this.data_params);
if (params){
p = bricks.extend(p, params);
}
var d = await this.loader.loadData(p);
} else {
if (this.data) {
d = this.data;
}
}
if (d){
this.main.clear_widgets();
this.dataHandle(d);
var total = this.container.dom_element.scrollHeight - this.container.dom_element.clientHeight;
// this.container.dom_element.scrollTop = d.pos_rate * total;
} else {
bricks.debug(this.loader, 'data is null');
}
} catch (e) {
bricks.debug('e=', e);
}
this.loading = false;
if (running) running.dismiss();
}
async load_previous_page(){
if(! this.data_url) return;
if (this.loading){
bricks.debug('this.loading is set, do not thing');
return;
}
var running = new bricks.Running({target:this});
this.loading = true;
try {
var d = await this.loader.loadPreviousPage();
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;
} else {
bricks.debug(this.loader, 'load previous page error');
}
} catch (e) {
bricks.debug('e=', e);
}
this.loading = false;
running.dismiss();
}
async load_next_page(){
if(! this.data_url) return;
if (this.loading){
bricks.debug('this.loading is set, do not thing');
return;
}
var running = new bricks.Running({target:this});
this.loading = true;
try {
var d = await this.loader.loadNextPage();
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;
} else {
console.log(this.loader, 'load next page error');
}
} catch (e){
console.log('error happened', e);
}
this.loading = false;
running.dismiss();
bricks.debug('load_next_page() finished');
}
}
bricks.Factory.register('Cols', bricks.Cols);

58
bricks/conform.js Normal file
View File

@ -0,0 +1,58 @@
var bricks = window.bricks || {};
bricks.Conform = class extends bricks.PopupWindow {
constructor(opts){
opts.timeout = 0;
opts.auto_open = true;
super(opts);
this.create_conform();
}
create_conform(){
var w = new bricks.VBox({width:'100%', height: '100%'});
this.create_message(w);
this.create_toolbar(w);
this.add_widget(w);
}
create_message(widget){
var w = new bricks.Filler();
widget.add_widget(w);
var w1 = new bricks.VScrollPanel({});
w.add_widget(w1);
var t = new bricks.Text({otext:this.opts.message,
wrap:true,
halign:'middle',
i18n:true});
w1.add_widget(t);
}
create_toolbar(widget){
var desc = {
tools:[
bricks.extend({
"name":"conform",
"icon":bricks_resource('imgs/conform.svg'),
"label":'Conform'
}, this.opts.conform||{}),
bricks.extend({
"name":"discard",
"icon":bricks_resource('imgs/cancel.svg'),
"label":"Discard"
}, this.opts.discard||{})
]
}
var w = new bricks.IconTextBar(desc);
w.bind('conform', this.conform_hndl.bind(this));
w.bind('discard', this.discard_hndl.bind(this));
if (!w) return;
widget.add_widget(w);
}
conform_hndl(event){
this.dismiss();
this.dispatch('conformed');
}
discard_hndl(event){
this.dismiss();
this.dispatch('cancelled');
}
}
bricks.Factory.register('Conform', bricks.Conform);

133
bricks/continueaudio.js Normal file
View 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
View 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
bricks/css.js Normal file
View File

@ -0,0 +1,7 @@
var css = {
multicolumns:{
columnWidth:'350px',
colummGap:'10px'
}
}

494
bricks/css/bricks.css Executable file
View File

@ -0,0 +1,494 @@
html,
body {
height: 100%;
width: 100%;
margin: 0;
color: #8a8a8a;
background-color: #fafafa;
overflow: auto;
display: flex;
}
pre {
overflow-x: auto; /* 允许内容超出容器显示 */
background-color: #b5e5e5;
}
* {
box-sizing: border-box!important;
}
hr {
height: 1px;
background-color: #8a8a8a;
width: 80%;
}
.flexbox {
height: 100%;
width: 100%;
display: flex;
}
.curpos {
border-radius: 30%;
background-color: #f5f5f5;
}
.card {
border-radius: 8px;
padding: 5px;
margin: 5px;
background-color: #f5f5f5;
border: 1px solid #888888;
}
.subcard {
background-color: #eeeeee;
}
.clickable {
color: #40cc40;
cursor: pointer;
}
.video-in-video {
position: relative;
}
.bigvideo {
position: absolute;
width: 100%;
height: 100%;
z-index: 0;
}
.smallvideo {
position: absolute;
bottom: 10px;
right: 30px;
width: 30%;
height: 30%;
z-index: 2;
}
.griddata {
display: grid;
grid-gap: 1px;
}
.resizebox {
width: 10px;
height: 10px;
background-color: darkblue;
position: absolute;
bottom: 0;
right: 0;
cursor: se-resize; /* 改变鼠标指针样式 */
}
.popup {
display: none;
position: absolute;
box-sizing: border-box; /* 包括边框在内计算宽度和高度 */
color: #111111;
background-color: #f1f1f1;
border: 1px solid #c1c1c1;
border-radius: 5px;
padding: 4px;
}
.titlebar {
background-color: #d8d8c8;
}
.toppopup {
box-shadow: 10px 5px 10px #000, 0 -5px 5px #fff;
}
.modal {
display:none;
position: absolute;
padding: 10px;
color: #111111;
background-color: #dddddd;
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: 10px;
}
.menuitem {
backgroud-color: #eeeeee;
align-items: center;
border: 1px solid #ccc;
cursor: pointer;
}
.modal>.title {
background-color: #a0a0a0;
}
.message {
padding: 10px;
width: 30%;
height: 30%;
background-color: #f0f0f0;
color:#222222;
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: 10px;
}
.error {
padding: 10px;
width: 30%;
height: 30%;
background-color: #f0f0f0;
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: 10px;
}
.message>.title {
background-color: #3030f0;
color: #e8e8e8;
}
.error>.title {
background-color: #f03030;
color: #e8e8e8;
}
.vscroll {
overflow-x: scroll;
}
.hscroll {
overflow-y: scroll;
}
.scroll {
overflow: auto;
}
.vcontainer {
display: flex;
flex-direction: column;
}
.vbox {
display: flex;
flex-direction: column;
}
.hcontainer {
display: flex;
flex-direction: row;
}
.hbox {
display: flex;
flex-direction: row;
}
.fixitem {
flex:none;
}
.filler, .hfiller, .vfiller {
flex: auto;
flex-grow: 1;
overflow:hidden;
}
.vfiller .vbox:last-child {
overflow-x: overlay;
}
.vline {
width:1px;
height:100%;
background-colir:#999;
}
.hline {
height:1px;
width:100%;
background-colir:#999;
}
.hfiller::-webkit-scrollbar {
display: none;
}
.flc {
width: 203px;
overflow-y: scroll;
overflow-x: visible;
}
.vtoolbar {
heigth: 100%;
background-color: #f1f1f1;
border: 1px solid #ccc;
}
.selected {
background-color: #d4d4d4;
}
.htoolbar {
width: 100%;
height: 40px;
background-color: #f1f1f1;
border: 1px solid #ccc;
}
.toolbar-button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
border: 1px solid #888;
}
.toolbar-button-active {
background-color: #ddd;
}
.tabpanel {
background-color: #ededed;
border: 3px solid #888;
}
.tabpanel-content {
background-color: #f8f8f8;
border: 2px solid #888;
}
.multicolumns {
column-width: 340px;
colomn-gap: 10px;
overflow-x: none;
}
.selected_record {
border-radius: 8px;
border: 1px solid #f00;
}
.inputbox {
background-color: #f8f8f8;
color: #111111;
border: 1px solid #ccc;
padding: 10px;
margin: 0 0 1em 0;
}
.datagrid {
display:flex;
flex-direction:column;
width:100%;
height:100%;
}
.datagrid-grid {
width: 100%;
flex: 1;
overflow: auto;
display: flex;
flex-direction: row;
}
.datagrid-left {
height:100%;
display: flex;
flex-direction: column;
overflow: auto;
}
.datagrid-left>.scrollbar {
width:0px;
opacity:0;
}
.datagrid-right {
flex:1 0 ;
height:100%;
overflow: auto;
display: flex;
flex-direction: column;
}
.grid_header, .grid_footer {
height: 50px;
background-color: blue;
}
.childrensize {
display: flex;
flex-wrap: nowrap;
flex-shrink: 0;
}
.datagrid-row {
flex:0 0 150px;
display: flex;
flex-direction: row;
}
.datagrid-body {
width: 100%;
flex: 1;
overflow: auto;
display: flex;
flex-direction: column;
}
/* Flex 布局 */
.accordion {
display: flex;
flex-direction: column;
}
.accordion-item {
border: 1px solid #ccc;
width: auto;
margin-bottom: 5px;
}
.accordion-item:nth-child(odd) {
background-color: #fdfdfd;
width: auto;
}
.accordion-item:nth-child(even) {
background-color: #f9f9f9;
width: auto;
}
.accordion-item-selected {
background-color: #efefef;
}
.accordion-item-header {
padding: 10px;
background-color: #f0f0f0;
}
.accordion-item-info {
padding: 10px;
background-color: #fbfbfb;
cursor: pointer;
width: auto;
height: 50px;
}
.test_box {
height: 100px;
background-color: #e6e6e6;
border-radius: 5px;
flex-shrink:0;
border: 1px solid #c00;
}
.accordion-item-info-selected {
background-color: #e6e6e6;
}
.scrollpanel
.tabular-table {
width: 100%;
height: 100%;
overflow: auto;
}
.tabular-header-row {
display: flex;
top: 0;
position: sticky;
background-color: #dddddd;
min-width: 0;
min-width: fit-content;
flex-wrap: nowrap;
flex-shrink: 0;
}
.tabular-row {
display: flex;
margin-bottom: 5px;
min-width: 0;
min-width: fit-content;
flex-wrap: nowrap;
flex-shrink: 0;
}
.tabular-row:nth-child(odd) {
background-color: #5dfdfd;
}
.tabular-row:nth-child(even) {
background-color: #f9f9f9;
}
.tabular-row-selected {
color: #ef0000;
}
.tabular-row-content {
padding: 2;
}
.tabular-cell {
border: 1px solid #ccc;
overflow: hidden;
text-overflow: ellipsis;
}
.llm_msg {
margin-left: 5px;
margin-right: auto;
margin-bottom: 10px;
padding: 3px;
background-color:#fefedd;
border-top-left-radius: 10px;
border-top-right-radius: 0;
border-bottom-right-radius: 10px;
border-bottom-left-radius: 0;
box-shadow: 5px 5px 10px rgba(0, 0, 0.2, 0.5);
}
.user_msg {
margin-left: auto;
margin-right: 5px;
margin-bottom: 10px;
background-color:#ddfefe;
border-top-right-radius: 10px;
border-top-left-radius: 0;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 0;
box-shadow: 5px 5px 10px rgba(0.2, 0, 0, 0.5);
}
.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;
}
.left {
justify-content: flex-start;
}
/* 居右 */
.right {
justify-content: flex-end;
}
/* 居中 */
.hcenter {
justify-content: center;
}
/* 居上 */
.top {
align-self: flex-start;
}
/* 居下 */
.bottom {
align-self: flex-end;
}
/* 居中 */
.vcenter {
align-self: center;
}

385
bricks/datagrid.js Normal file
View File

@ -0,0 +1,385 @@
var bricks = window.bricks || {};
bricks.Row = class {
constructor(dg, rec) {
this.dg = dg;
this.data = objcopy(rec);
this.freeze_cols = [];
this.normal_cols = [];
this.name_widgets = {};
this.click_handler = this.dg.click_handler.bind(this.dg, this);
this.freeze_row = this.create_col_widgets(this.dg.freeze_fields, this.freeze_cols);
if (this.freeze_row){
// this.freeze_row.set_css('datagrid-row');
this.freeze_row.set_style('width', this.freeze_width + 'px');
}
this.normal_row = this.create_col_widgets(this.dg.normal_fields, this.normal_cols);
if (this.normal_row){
// this.normal_row.set_css('datagrid-row');
this.normal_row.set_style('width', this.normal_width + 'px');
}
}
create_col_widgets(fields, cols) {
for (var i = 0; i < fields.length; i++) {
var f = fields[i];
var opts = f.uioptions || {};
var w;
bricks.extend(opts, {
name: f.name,
label: f.label,
uitype: f.uitype,
width: f.width,
required: true,
row_data: objcopy(this.data),
readonly: true
});
if (opts.uitype == 'button') {
opts.icon = f.icon;
opts.action = f.action;
opts.action.params = objcopy(this.data);
opts.action.params.row = this;
w = new bricks.Button(opts);
w.bind('click', this.button_click.bind(w))
} else {
w = bricks.viewFactory(opts, this.data);
w.bind('click', this.click_handler);
}
w.desc_dic = opts;
w.rowObj = this;
w.dom_element.style['min-width'] = w.width + 'px';
w.set_style('flex', '0 0 ' + convert2int(f.width) + 'px');
cols.push(w);
this.name_widgets[f.name] = w;
}
if (cols.length > 0) {
var row = new bricks.HBox({ height: 'auto' })
for (var i = 0; i < cols.length; i++) {
row.add_widget(cols[i]);
}
return row;
}
return null;
}
button_click(event){
this.getValue=function(){
return this.desc_dic.row_data;
}
var desc = this.desc_dic.action;
desc.datawidget = this;
desc.datamethod = 'getValue';
var f = universal_handler(this, this.rowObj, desc);
}
selected() {
if (this.freeze_row) {
this.freeze_cols.forEach(w => { w.set_css('selected', false) })
}
if (this.normal_row) {
this.normal_cols.forEach(w => { w.set_css('selected', false) })
}
}
unselected() {
if (this.freeze_row) {
this.freeze_cols.forEach(w => { w.set_css('selected', true) })
}
if (this.normal_row) {
this.normal_cols.forEach(w => { w.set_css('selected', true) })
}
}
toogle_select(e, f) {
if (f) e.classList.add('selected');
else e.classList.remove('selected');
}
}
bricks.DataGrid = class extends bricks.VBox {
/*
{
data:
dataurl:
method:
params:
title:
description:
show_info:
miniform:
toolbar:
tailer:
row_height:
header_css:
body_css:
fields:[
{
name:
label:
datatype:
uitype:
uioptions:
freeze:
width:
}
]
}
*/
constructor(opts) {
super(opts);
this.loading = false;
this.select_row = null;
this.set_css('datagrid');
this.dataurl = opts.dataurl;
this.method = opts.method;
this.params = opts.params;
this.title = opts.title;
this.check = opts.check || false;
this.lineno = opts.lineno || false;
this.description = opts.description;
this.show_info = opts.show_info;
this.admin = opts.admin;
this.row_height = opts.row_height;
this.fields = opts.fields;
this.header_css = opts.header_css || 'grid_header';
this.body_css = opts.body_css || 'grid_body';
if (this.title) {
this.title_bar = new bricks.HBox({ height: 'auto' });
this.add_widget(this.title_bar);
var tw = new bricks.Title1({ otext: this.title, i18n: true });
this.title_bar.add_widget(tw);
}
if (this.description) {
this.descbar = new bricks.HBox({ height: 'auto' });
this.add_widget(this.descbar);
var dw = new bricks.Text({ otext: this.description, i18n: true });
this.descbar.add_widget(dw);
}
if (this.opts.miniform || this.opts.toolbar){
this.admin_bar = new bricks.HBox({height:'auto'});
}
if (this.opts.miniform){
this.miniform = new bricks.MiniForm(this.opts.miniform);
this.miniform.bind('input', this.miniform_input.bind(this));
this.admin_bar.add_widget(this.miniform);
}
if (this.opts.toolbar) {
this.admin_bar.add_widget(new bricks.Filler({}));
self.toolbar = new bricks.Toolbar(this.opts.toolbar);
self.toolbar.bind('command', this.command_handle.bind(this));
this.admin_bar.add_widget(this.toolbar);
}
this.create_parts();
if (this.show_info) {
this.infow = new bricks.HBox({ height: '40px' });
this.add_widget(this.infow);
}
if (this.dataurl) {
this.loader = new bricks.BufferedDataLoader(this, {
pagerows: 80,
buffer_pages: 5,
url: bricks.absurl(this.dataurl, this),
method: this.method,
params: this.params
})
schedule_once(this.loader.loadData.bind(this.loader), 0.01);
if (this.freeze_body) {
this.freeze_body.bind('min_threshold', this.loader.previousPage.bind(this.loader));
this.freeze_body.bind('max_threshold', this.loader.nextPage.bind(this.loader));
}
this.normal_body.bind('min_threshold', this.loader.previousPage.bind(this.loader));
this.normal_body.bind('max_threshold', this.loader.nextPage.bind(this.loader));
} else {
if (this.data) {
this.add_rows(this.data);
}
}
}
clear_data(){
if (this.normal_body)
this.normal_body.clear_widgets();
if (this.freeze_body)
this.freeze_body.clear_widgets()
this.selected_row = null;
}
miniform_input(event){
var params = this.miniform.getValue();
this.loadData(params);
}
loadData(params){
this.loader.loadData(params)
}
command_handle(event){
}
del_old_rows(cnt, direction) {
if (this.freeze_body) {
if (direction == 'down') {
this.freeze_body.remove_widgets_at_begin(cnt);
} else {
this.freeze_body.remove_widgets_at_end(cnt);
}
}
if (direction == 'down') {
this.normal_body.remove_widgets_at_begin(cnt);
} else {
this.normal_body.remove_widgets_at_end(cnt);
}
}
add_rows(records, direction) {
if (! direction) direction = 'down';
var index = null;
if (direction == 'down') {
index = 0
}
for (var i = 0; i < records.length; i++) {
this.add_row(records[i], index);
}
}
add_row(data, index) {
var row = new bricks.Row(this, data);
if (this.freeze_body)
this.freeze_body.add_widget(row.freeze_row, index);
if (this.normal_body)
this.normal_body.add_widget(row.normal_row, index);
}
check_desc() {
return {
freeze:true,
uitype: 'check',
name: '_check',
width: '20px'
}
}
lineno_desc() {
return {
freeze:true,
uitype: 'int',
name: '_lineno',
label: '#',
width: '100px'
}
}
create_parts() {
this.freeze_width = 0;
this.normal_width = 0;
var hbox = new bricks.HBox({});
hbox.set_css('datagrid-grid');
this.add_widget(hbox);
this.freeze_fields = [];
this.normal_fields = [];
if (this.check) {
this.fields.push(this.check_desc());
}
if (this.lineno) {
this.fields.push(this.lineno_desc());
}
for (var i = 0; i < this.fields.length; i++) {
var f = this.fields[i];
if (!f.width || f.width <= 0 ) f.width = 100;
if (f.freeze) {
this.freeze_fields.push(f);
this.freeze_width += convert2int(f.width);
} else {
this.normal_fields.push(f);
this.normal_width += convert2int(f.width);
}
}
this.freeze_part = null;
this.normal_part = null;
bricks.debug('width=', this.freeze_width, '-', this.normal_width, '...');
if (this.freeze_fields.length > 0) {
this.freeze_part = new bricks.VBox({});
this.freeze_part.set_css('datagrid-left');
this.freeze_part.set_style('width', this.freeze_width + 'px');
this.freeze_header = new bricks.HBox({ height: this.row_height + 'px', width: this.freeze_width + 'px'});
this.freeze_body = new bricks.VScrollPanel({ height: "100%",
width: this.freeze_width + 'px' })
this.freeze_body.set_css('datagrid-body');
this.freeze_body.bind('scroll', this.coscroll.bind(this));
}
if (this.normal_fields.length > 0) {
this.normal_part = new bricks.VBox({
width: this.normal_width + 'px',
height:'100%',
csses:"hscroll"
});
this.normal_part.set_css('datagrid-right');
this.normal_header = new bricks.HBox({ height: this.row_height + 'px', width: this.normal_width + 'px'});
// this.normal_header.set_css('datagrid-row');
this.normal_body = new bricks.VScrollPanel({
height:"100%",
width: this.normal_width + 'px'
});
this.normal_body.set_css('datagrid-body')
}
this.create_header();
if (this.freeze_fields.length > 0) {
this.freeze_part.add_widget(this.freeze_header);
this.freeze_part.add_widget(this.freeze_body);
hbox.add_widget(this.freeze_part);
}
if (this.normal_fields.length > 0) {
this.normal_part.add_widget(this.normal_header);
this.normal_part.add_widget(this.normal_body);
this.normal_body.bind('scroll', this.coscroll.bind(this));
this.normal_body.bind('min_threshold', this.load_previous_data.bind(this));
this.normal_body.bind('max_threshold', this.load_next_data.bind(this));
hbox.add_widget(this.normal_part);
}
}
load_previous_data() {
bricks.debug('event min_threshold fired ........');
this.loader.previousPage();
}
load_next_data() {
bricks.debug('event max_threshold fired ........');
this.loader.nextPage();
}
coscroll(event) {
var w = event.target.bricks_widget;
if (w == this.freeze_body) {
this.normal_body.dom_element.scrollTop = w.dom_element.scrollTop;
} else if (w == this.normal_body && this.freeze_body) {
this.freeze_body.dom_element.scrollTop = w.dom_element.scrollTop;
}
}
create_header() {
for (var i = 0; i < this.freeze_fields.length; i++) {
var f = this.freeze_fields[i];
var t = new bricks.Text({
otext: f.label || f.name,
i18n: true,
});
if (f.width) {
t.set_style('flex','0 0 ' + convert2int(f.width) + 'px');
} else {
t.set_style('flex','0 0 100px');
}
this.freeze_header.add_widget(t);
t.dom_element.column_no = 'f' + i;
}
for (var i = 0; i < this.normal_fields.length; i++) {
var f = this.normal_fields[i];
var t = new bricks.Text({
otext: f.label || f.name,
i18n: true,
});
if (f.width) {
t.set_style('flex','0 0 ' + convert2int(f.width) + 'px');
} else {
t.set_style('flex','0 0 100px');
}
this.normal_header.add_widget(t);
t.dom_element.column_no = 'n' + i;
}
}
click_handler(row, event) {
if (this.selected_row) {
this.selected_row.unselected();
}
this.selected_row = row;
this.selected_row.selected();
this.dispatch('row_click', row);
bricks.debug('DataGrid():click_handler, row=', row, 'event=', event);
}
}
bricks.Factory.register('DataGrid', bricks.DataGrid);

133
bricks/datarow.js Normal file
View File

@ -0,0 +1,133 @@
var bricks = window.bricks || {};
bricks.DataRow = class extends bricks.HBox {
/*
{
toolbar:[
]
fields:[]
css
browserfields{
exclouded:[],
cwidth:{
field:10,
field2:11
}
}
editexclouded:[],
header_css
}
*/
constructor(opts){
super(opts);
this.record_w = null;
}
render_header(){
this.render(true);
}
render_data(){
this.render(false);
}
render(header){
// this.build_toolbar(header);
if (this.checkField){
var w;
if (header){
w = new bricks.BlankIcon({});
} else {
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);
}
this.build_fields(header);
}
renew(record){
this.user_data = record;
this.record_w.clear_widgets();
this._build_fields(false, this.record_w);
}
get_check_state(e){
var d = e.target.bricks_widget.getValue()
this.user_data[this.checkField] = d[this.checkField];
this.dispatch('check_changed', this);
}
build_toolbar(header){
var tools = [];
if (header){
if (this.toolbar){
this.toolbar.tools.forEach(t => {
tools.push({name:'blankicon'});
});
}
} else {
if (this.toolbar){
this.toolbar.tools.forEach(t => {
tools.push(t);
});
}
}
var toolbar = bricks.extend({cwidth:2.5}, this.toolbar || {});
toolbar.tools = tools;
var w = new bricks.IconBar(toolbar);
this.add_widget(w);
this.toolbar_w = w;
this.event_names = []
for(var i=0;i<tools.length;i++){
if (tools[i].name != 'blankicon'){
this.event_names.push(tools[i].name);
w.bind(tools[i].name, this.my_dispatch(tools[i].name));
}
}
}
my_dispatch(e){
this.dispatch(e);
}
build_fields(header, cw){
this.record_w = new bricks.HBox({height:'auto'});
this.record_w.set_css('childrensize');
this.add_widget(this.record_w);
this._build_fields(header, this.record_w);
}
_build_fields(header, cw){
var exclouded = [];
var cwidths = {};
if (this.browserfields && this.browserfields.exclouded){
exclouded = this.browserfields.exclouded;
}
if (this.browserfields && this.browserfields.cwidths){
cwidths = this.browserfields.cwidths;
}
if (this.checkField){
exclouded.push(this.checkField);
}
for (var i=0;i<this.fields.length;i++){
var f = this.fields[i]
if (exclouded.includes(f.name)){
continue;
}
var opts = bricks.extend({
margin:'1px'
}, f);
if (header || ! this.user_data){
opts.value = f.label || f.name;
} else {
opts.user_data = this.user_data;
opts.value = opts.tip = this.user_data[f.name];
}
opts.cwidth = cwidths[f.name] ||f.cwidth || 10;
var f = bricks.get_ViewBuilder(f.uitype);
if (!f) f = bricks.get_ViewBuilder('str');
var w = f(opts);
w.set_css('tabular-cell');
cw.add_widget(w)
}
}
}
bricks.Factory.register('DataRow', bricks.DataRow);

365
bricks/dataviewer.js Normal file
View File

@ -0,0 +1,365 @@
var bricks = window.bricks || {};
bricks.DataViewer = class extends bricks.VBox {
constructor(opts){
opts.width = '100%';
opts.height = '100%';
opts.overflow = 'hidden';
super(opts);
this.loader = new bricks.PageDataLoader({
url:this.opts.data_url,
params:this.opts.data_params,
pagerows:this.opts.page_rows,
method:this.opts.data_method,
cache_pages:this.opts.cache_limit
});
this.old_params = null;
this.select_row = null;
this.active_item = null;
this.loading = false;
this.data_offset = 0;
this.keyselectable = true;
this.bind('row_check_changed', this.show_check_event_data.bind(this));
schedule_once(this.build_all.bind(this), 0.1);
}
set_key_select_items(){
if (!this.scrollpanel) return;
var items = this.scrollpanel.children;
this.key_select_items = items.filter(i => i != items[0]);
}
async build_all(){
this.build_title_widget();
this.build_description_widget();
this.build_toolbar_widget();
this.build_records_area();
await this.build_other();
this.check_changed_row = null;
this.scrollpanel.bind('min_threshold', this.load_previous_page.bind(this));
this.scrollpanel.bind('max_threshold', this.load_next_page.bind(this));
await this.render();
this.set_key_select_items();
bricks.debug_obj = this.scrollpanel;
}
async build_other(){
}
async render(params) {
params = params || {};
if (params == this.old_params){
return;
}
this.old_params = params;
bricks.debug('params=', params, 'render() called');
var d = await this.loader.loadData(params);
if (d){
this.scrollpanel.clear_widgets();
await this.before_data_handle();
await this.dataHandle(d);
} else {
bricks.debug(params, 'load data return null');
}
}
async before_data_handle(){
}
async dataHandle(d){
var data = d.rows;
var page = d.add_page;
if (!data){
return;
}
await this.renderPageData(data, page);
if (d.delete_page){
this.delete_page(d.delete_page);
}
}
build_records_area(){
this.filler_widget = new bricks.Filler({});
this.add_widget(this.filler_widget)
this.scrollpanel = new bricks.VScrollPanel({});
this.filler_widget.add_widget(this.scrollpanel);
}
async renderPageData(data, page){
var pos;
if (! this.loader.is_max_page(page)){
data.reverse();
pos = this.data_offset;
} else {
pos = null;
}
for(var i=0; i<data.length;i++){
var rec = data[i];
await this.build_row(rec, page, pos);
}
}
async build_record_view(record){
/* will be overwrite by subclass */
var w = new bricks.VBox({width: '100px',height:'100px'});
w.set_css('test_box');
return w;
}
async build_row(record, page, pos){
var r = await this.build_record_view(record);
r.set_attribute('data-page', page);
this.scrollpanel.add_widget(r, pos);
}
show_check_event_data(event){
var d = event.params;
console.log('row_check_changed event data=', d);
}
build_toolbar_widget(){
var edit_names = [];
var tbdesc = {
width:'auto',
tools:[]
}
if (this.editable){
tbdesc.tools = [
{
name:'add',
tip:'add new record',
icon:this.editable.add_icon || bricks_resource('imgs/add.svg')
},
{
name:'update',
tip:'update selected record',
selected_row:true,
icon:this.editable.update_icon || bricks_resource('imgs/edit.svg')
},
{
name:'delete',
tip:'delete selected record',
selected_row:true,
icon:this.editable.delete_icon || bricks_resource('imgs/delete.svg')
}
];
tbdesc.tools.forEach(t => {
edit_names.push(t.name);
});
}
if (this.toolbar){
this.toolbar.tools.forEach(t => {
if (! edit_names.includes(t.name)){
tbdesc.tools.push(t);
}
});
}
if (tbdesc.tools.length == 0){
return;
}
this.toolbar_w = new bricks.IconTextBar(tbdesc);
this.add_widget(this.toolbar_w);
this.toolbar_w.bind('command', this.command_event_handle.bind(this));
}
async command_event_handle(event){
var tdesc = event.params;
if (tdesc.selected_row && ! this.select_row){
bricks.show_error({title:'Error', message:'need select a row'});
return;
}
if (tdesc.name == 'add'){
await this.add_record();
return;
}
if (tdesc.name == 'update'){
await this.update_record(this.select_row);
return;
}
if (tdesc.name == 'delete'){
this.delete_record(this.select_row);
return;
}
var data = null;
if (this.select_row){
var r = this.select_row;
var data = r.user_data;
}
console.log(tdesc.name, 'clicked ==================', tdesc.name, data)
this.dispatch(tdesc.name, data);
}
get_edit_fields(){
var fs = this.row_options.fields;
this.fields = [];
var exclouded = [];
if (this.row_options.editexclouded){
exclouded = this.row_options.editexclouded;
}
fs.forEach(f => {
if (!exclouded.includes(f.name)){
this.fields.push(f);
}
});
}
record_check_changed(event){
this.check_changed_row = event.params;
this.dispatch('row_check_changed', event.params.user_data);
}
async renew_record_view(form, row){
var d = form._getValue();
d = form._getValue();
var record = bricks.extend(row.user_data, d);
row.renew(record);
}
get_hidefields(){
var fs = [];
var params = this.data_params || {};
for (var k in params){
fs.push({name:k, value:params[k], uitype:'hide'});
}
return fs;
}
async build_editform(data){
var hidefields = [];
if (!this.data_params){
this.data_params = {}
}
var opts = this.opts.editor || {};
opts.widgettype = 'Form';
var submit_url = this.editable.new_data_url;
if (data) {
submit_url = this.editable.update_data_url;
}
opts.options = {
submit_url: submit_url,
width: '100%',
height: '100%'
};
var fs = this.get_hidefields();
for (var i=0;i<this.fields.length;i++){
var f = bricks.extend({}, this.fields[i]);
if (data){
f.value = data[f.name];
}
fs.push(f);
}
if (data){
fs.push({name:'id', value:data.id, uitype:'hide'})
}
opts.options.fields = fs
var title = "Add record";
if (data){
title = "Edit record";
}
var f = new bricks.PopupWindow({
"title": title,
"widget":this,
"archor":"cc",
"movable":true,
"resizable":true,
"archor":"cc",
"width":"90%",
"height":"70%"
});
var form = await bricks.widgetBuild(opts, this);
form.bind('cancel', f.dismiss.bind(f));
f.add_widget(form);
f.open();
return {
win: f,
form:form
}
}
async add_record(){
var widgets = await this.build_editform(null);
widgets.form.bind('submited', this.add_record_finish.bind(this, widgets.win));
}
async add_record_finish(f, event){
f.dismiss();
this.render();
var resp = event.params;
var desc = await resp.json();
var w = await bricks.widgetBuild(desc);
}
async update_record(){
var record = this.select_row.user_data;
var widgets = await this.build_editform(record);
widgets.form.bind('submited', this.update_record_finish.bind(this, widgets.win, widgets.form));
}
async update_record_finish(win, form, event){
await this.renew_record_view(form, this.select_row);
var resp = event.params;
var desc = await resp.json();
var w = await bricks.widgetBuild(desc);
w.open();
win.dismiss();
}
delete_record(row, record){
var conform_w = new bricks.Conform({
cwidth:16,
cheight:9,
target:this,
title:'Delete conform',
message:'Are you sure to delete is record?'
});
conform_w.bind('conformed', this.delete_record_act.bind(this, row, record));
conform_w.bind('discard', conform_w.dismiss.bind(conform_w));
}
async delete_record_act(){
var id = this.select_row.user_data.id;
var url = this.editable.delete_data_url + '?id=' + id;
var hc = new bricks.HttpJson();
var desc = await hc.get(url);
var w = await bricks.widgetBuild(desc);
if (desc.widgettype == 'Message'){
this.scrollpanel.remove_widget(this.select_row);
this.select_row = null;
this.render();
}
}
async load_previous_page(){
// console.log('tabular:load_previous_page() called');
if (this.loading){
bricks.debug('this.loading is set, do not thing');
return;
}
var running = new bricks.Running({target:this});
this.loading = true;
try {
var d = await this.loader.loadPreviousPage();
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;
} else {
bricks.debug(this.loader, 'load previous page error');
}
} catch (e) {
bricks.debug('e=', e);
}
this.loading = false;
running.dismiss();
}
async load_next_page(){
// console.log('tabular:load_next_page() called');
if (this.loading){
bricks.debug('this.loading is set, do not thing');
return;
}
var running = new bricks.Running({target:this});
this.loading = true;
try {
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;
} else {
bricks.debug(this.loader, 'load next page error');
}
} catch (e){
bricks.debug('error happened', e);
}
this.loading = false;
running.dismiss();
bricks.debug('load_next_page() finished');
}
delete_page(page){
var items = this.dom_element.querySelectorAll('[data-page="' + page + '"]');
for (var i=0;i<items.length;i++) {
var w = items[i].bricks_widget;
this.scrollpanel.remove_widget(w);
}
}
}
bricks.Factory.register('DataViewer', bricks.DataViewer);

119
bricks/docxviewer.js Normal file
View 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);

512
bricks/dynamicaccordion.js Normal file
View File

@ -0,0 +1,512 @@
var bricks = window.bricks || {};
bricks.AccordionItem = class extends bricks.VBox {
constructor(opts){
super(opts);
this.set_css('accordion-item');
}
}
bricks.AccordionInfo = class extends bricks.FHBox {
constructor(opts){
super(opts);
this.set_css('accordion-item-info');
}
}
bricks.DynamicAccordion = class extends bricks.VScrollPanel {
/*
{
"data_url",
"data_method",
"cache_limit",
"page_rows",
"row_cheight":1.5
"record_view"
"content_rely_on"
"content_rely_value"
"editable"
"fields":
"record_toolbar",
"record_toolbar_collapsable"
"header"
"content_view"
}
*/
constructor(opts){
super(opts);
this.row_cheight = opts.row_cheight || 1.5;
// this.set_style('overflow', 'auto');
this.loader = new bricks.PageDataLoader({
url:this.opts.data_url,
params:this.opts.data_params,
pagerows:this.opts.page_rows,
method:this.opts.data_method,
cache_pages:this.opts.cache_limit
});
this.old_params = null;
this.active_item = null;
this.active_content = null;
this.loading = false;
schedule_once(this.build_all.bind(this), 0.1);
}
async build_all(){
if (this.title){
this.build_title();
}
if (this.description){
this.build_description();
}
await this.build_toolbar();
await this.build_header();
var filler = new bricks.Filler();
this.container = new bricks.VScrollPanel({ });
filler.add_widget(this.container);
this.add_widget(filler);
this.container.bind('min_threshold', this.load_previous_page.bind(this));
this.container.bind('max_threshold', this.load_next_page.bind(this));
await this.render();
}
build_title(){
var w = new bricks.Title3({
otext:this.title,
i18n:true,
wrap:true,
dynsize:true,
halign:'left'
});
this.add_widget(w);
}
build_description(){
var w = new bricks.Text({
otext:this.description,
i18n:true,
wrap:true,
dynsize:true,
halign:'left'
});
this.add_widget(w);
}
build_toolbar(){
this.toolbar_w = new bricks.IconTextBar(this.toolbar);
this.add_widget(this.toolbar_w);
}
async build_header(){
this.header_w = await this.build_item();
this.add_widget(this.header_w);
/*
var w = await this.build_item();
w.set_style('position', 'sticky');
w.set_style('top', 0);
return w;
*/
}
async build_item(record){
var item = new bricks.AccordionItem({});
var info = await this.build_info(item, record);
var content = new bricks.VBox({
height:'auto',
display:'none'
});
var build_content = true;
if (!record){
build_content = false;
} else {
if (this.content_rely_on){
var v = this.content_rely_value || true;
if(record[this.content_rely_on] != v){
build_content = false;
}
}
}
content.set_css('accordion-item-content');
content.hide();
if (record){
info.bind('click',
this.line_clicked.bind(this, info, content, record));
}
item.add_widget(content);
return item;
}
async build_info(item, record){
if (! this.fields && !record){
return;
}
var w;
var tb = null;
var info = new bricks.AccordionInfo({cheight:this.cheight});
info.user_data = record;
item.add_widget(info);
tb = this.build_record_toolbar(info, record);
if (! record){
record = {};
for (var i=0;i<this.fields.length;i++){
var f = this.fields[i];
record[f.name] = f.label || f.name;
}
}
w = await bricks.widgetBuild(this.record_view, info, record);
if (w){
if (tb){
w.add_widget(tb, 0);
}
info.add_widget(w);
} else {
bricks.debug('bricks.widgetBuild(), tmpl=', this.record_view, 'record=', record);
}
return info;
}
add_record(info){
var w = info.parent;
var hided;
var content = w.children[1];
content.clear_widgets();
var hided = content.is_hide();
var fields = this.fields;
if (this.data_params){
for (var k in this.data_params){
fields.push({
name:k,
value:this.data_params[k],
uitype:'hide'
});
}
}
var f = new bricks.Form({
"cheight":this.editable.form_cheight||7,
"submit_url":this.editable.new_data_url,
"fields":fields
});
f.bind('cancel', this.add_record_abort.bind(this, info));
content.add_widget(f, 0);
content.show();
f.bind('submited', this.add_record_finish.bind(this, info));
}
async add_record_abort(info, event){
var content = info.parent.children[1];
content.hide();
content.clear_widgets();
}
async add_record_finish(info, event){
var resp = event.params;
var desc = await resp.json();
var w = await bricks.widgetBuild(desc);
console.log(resp, desc, w);
var content = info.parent.children[1];
content.hide();
this.render();
}
update_record(info, record){
console.log('update_record():info=', info)
var w = info.parent;
var hided;
var content = w.children[1];
content.clear_widgets();
var fields = [];
for (var i=0; i< this.fields.length; i++){
var f = bricks.extend({}, this.fields[i]);
f.value = record[f.name];
fields.push(f);
}
var f = new bricks.Form({
"cheight":this.editable.form_cheight||7,
"submit_url":this.editable.update_data_url+'?id=' + record.id,
"fields":fields
});
content.add_widget(f, 0);
f.bind('submited', this.update_record_finish.bind(this, info, content, f));
f.bind('cancel', this.update_cancel.bind(this, info, content));
content.show();
}
update_cancel(info, content){
content.clear_widgets();
content.hide();
}
async update_record_finish(info, content, form, event){
content.remove_widget(form);
content.hide();
var resp = event.params;
var desc = await resp.json();
var w = await bricks.widgetBuild(desc);
if (desc.widgettype == 'Message'){
await this.renew_record_view(form, info);
}
}
async renew_record_view(form, info){
var d = form.getValue();
var record = bricks.extend(info.user_data, d);
var w = info.children[0];
info.clear_widgets();
var rtb = w.children[0];
var w = await bricks.widgetBuild(this.record_view, info, record);
w.add_widget(rtb, 0);
info.add_widget(w);
}
delete_record(info, record){
var conform_w = new bricks.Conform({
target:this,
title:'Delete conform',
message:'Are you sure to delete is record?'
});
conform_w.bind('conformed', this.delete_record_act.bind(this, info, record));
conform_w.bind('discard', conform_w.dismiss.bind(conform_w));
}
async delete_record_act(info, record){
var url = this.editable.delete_data_url + '?id=' + record.id;
var hc = new bricks.HttpJson();
var desc = await hc.get(url);
var w = await bricks.widgetBuild(desc);
if (desc.widgettype == 'Message'){
this.container.remove_widget(info.parent);
}
}
async build_new_form(){
var desc = {
"widgettype":"VBox",
"options":{
"height":"auto",
},
"subwidgets":[
{
"id":"new",
"widgettype":"IconBar",
"options":{
"tools":[
{
"name":"add",
"tip":"add a new record",
"icon":this.editable.add_icon || bricks_resource('imgs/add.svg')
}
]
}
},
{
"widgettype":"Form",
"options":{
"cheight":this.editable.form_cheight||7,
"submit_url":this.editable.new_data_url,
"fields":this.fields
}
}
]
};
var w = await bricks.widgetBuild(desc, this);
w.children[1].hide();
w.children[0].bind('add',function(){ w.children[1].toggle_hide()})
this.new_form = w.children[1];
this.new_form.bind('submited', this.render.bind(this));
this.add_widget(w);
}
async render(params) {
params = params || {};
if (params == this.old_params){
return;
}
this.old_params = params;
bricks.debug('params=', params, 'render() called');
var d = await this.loader.loadData(params);
if (d){
this.container.clear_widgets();
await this.dataHandle(d);
} else {
bricks.debug(params, 'load data return null');
}
}
async dataHandle(d){
var data = d.rows;
var page = d.add_page;
if (!data){
return;
}
await this.renderAccordionItems(data, page);
if (d.delete_page){
this.delete_page(d.delete_page);
}
}
build_record_toolbar(info, record){
var c = new bricks.Layout({cwidth:2.5, height:'auto'})
var desc;
var edit_tools = [];
if (this.record_toolbar){
desc = bricks.extend({}, this.record_toolbar);
} else {
desc = {
cwidth:2.5,
tools:[]
}
}
var event_names = [];
for (var i=0;i<desc.tools.length;i++){
event_names.push(desc.tools[i].name);
}
if (! record){
var mytools = [];
for (var i=0;i<desc.tools.length;i++){
mytools.push({ name:'blankicon'});
}
if (this.editable){
edit_tools = [
{
name:'add',
tip:'add new record',
icon:this.editable.add_icon || bricks_resource('imgs/add.svg')
},
{
name:'blankicon'
}
];
desc.tools = edit_tools.concat(mytools);
} else {
desc.tools = mytools;
}
var w = new bricks.IconBar(desc);
if (this.editable){
w.bind('add', this.add_record.bind(this, info, record));
}
c.add_widget(w);
return c;
}
if (this.editable){
var edit_tools = [
{
name:"update",
tip:"update record in this line",
icon:this.editable.update_icon || bricks_resource('imgs/update.svg')
},
{
name:'delete',
tip:"delete record in this line",
icon:this.editable.delete_icon || bricks_resource('imgs/delete.svg')
}
]
desc.tools = edit_tools.concat(desc.tools);
}
var w = new bricks.IconBar(desc);
if (this.editable){
w.bind('update', this.update_record.bind(this, info, record));
w.bind('delete', this.delete_record.bind(this, info, record));
}
for (var i=0;i<event_names.length;i++){
w.bind(event_names[i], this.fire_event.bind(this, event_names[i], record));
}
c.add_widget(w);
return c;
}
fire_event(event_name, data){
this.dispatch(event_name, data);
}
async renderAccordionItems(data, page) {
var pos;
for (var i=0;i<data.length;i++){
if (this.loader.is_max_page(page)){
pos = -1;
} else {
pos = i;
}
var record = data[i];
var item = await this.build_item(record);
item.set_attribute('data-page', page);
this.container.add_widget(item, pos);
};
}
delete_page(page){
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);
}
}
select_line(info){
if (this.select_row){
this.select_row.unset_css('accordion-item-info-selected');
}
this.select_row = info;
this.select_row.set_css('accordion-item-info-selected');
this.dispatch('row_selected', info);
}
async line_clicked(info, content, record, event){
this.select_line(info);
if(! this.content_view){
return;
}
this.toggle_content(info, content, record, event);
}
async toggle_content(info, content, record, event){
if(! this.content_view){
return;
}
var h = this.container.dom_element.offsetHeight - 3 * info.dom_element.offsetHeight;
content.set_style('height', h + 'px');
if (this.active_content){
if (this.active_content != content){
this.active_content.clear_widgets();
this.active_content.hide();
this.active_content = null;
}
}
content.toggle_hide();
if (content.dom_element.style.display == 'none'){
bricks.debug('content just collapsed');
content.clear_widgets();
this.active_content = null;
return;
}
var w;
w = await bricks.widgetBuild(this.content_view, content, record);
if (w){
content.add_widget(w);
this.active_content = content;
} else {
this.active_content = null;
content.hide();
}
}
async load_previous_page(){
if (this.loading){
bricks.debug('this.loading is set, do not thing');
return;
}
var running = new bricks.Running({target:this});
this.loading = true;
try {
var d = await this.loader.loadPreviousPage();
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;
} else {
bricks.debug(this.loader, 'load previous page error');
}
} catch (e) {
bricks.debug('e=', e);
}
this.loading = false;
running.dismiss();
}
async load_next_page(){
if (this.loading){
bricks.debug('this.loading is set, do not thing');
return;
}
var running = new bricks.Running({target:this});
this.loading = true;
try {
var d = await this.loader.loadNextPage();
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;
} else {
bricks.debug(this.loader, 'load next page error');
}
} catch (e){
bricks.debug('error happened', e);
}
this.loading = false;
running.dismiss();
bricks.debug('load_next_page() finished');
}
}
bricks.Factory.register('DynamicAccordion', bricks.DynamicAccordion);

52
bricks/dynamiccolumn.js Normal file
View File

@ -0,0 +1,52 @@
var bricks = window.bricks || {};
bricks.DynamicColumn = class extends bricks.Layout {
/*
{
mobile_cols:
col_cwidth:
col_cgap:
col_width:
}
*/
constructor(opts){
if (! opts.col_cwidth){
if(! opts.col_width){
opts.col_cwidth = 20;
}
}
opts.col_cgap = opts.col_cgap || 0.5;
opts.mobile_cols = opts.mobile_cols|| 1;
super(opts);
this.set_style('display', 'grid');
// this.set_column_width();
this.bind('on_parent', this.set_column_width.bind(this));
this.bind('resize', this.set_column_width.bind(this));
if (this.cwidth){
bricks.app.bind('charsize', this.set_column_width.bind(this));
}
}
set_column_width(){
var cw;
var cols;
var gap;
gap = bricks.app.charsize * (this.col_cgap || 0.1);
var width = bricks.app.screenWidth();
var height = bricks.app.screenHeight();
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;
} else {
cw = this.col_width;
}
}
this.dom_element.style.gridTemplateColumns = "repeat(auto-fill, minmax(" + cw + "px, 1fr))";
this.set_style('gap', gap + 'px');
}
}
bricks.Factory.register('DynamicColumn', bricks.DynamicColumn);

117
bricks/echartsext.js Normal file
View File

@ -0,0 +1,117 @@
var bricks = window.bricks || {};
bricks.bug = true;
bricks.EchartsExt = class extends bricks.VBox {
/*
{
title:
description:
pie_optiosn:
data_url:
nameField:
valueField:
serieField:
valueFields:
data_params:
data:[]
}
event:element_click
*/
constructor(opts){
super(opts);
if(!this.idField) this.idField = 'id';
if(!this.nameField) this.nameField = 'name';
if(!this.valueFields) this.valueFields = ['value'];
this.build_title_widget();
this.build_description_widget();
this.holder = new bricks.Filler({});
this.add_widget(this.holder);
this.chart = echarts.init(this.holder.dom_element);
if (this.user_data){
this.render_data(this.user_data)
} else if (this.data_url) {
schedule_once(this.render_urldata.bind(this), 0.1);
}
this.bind('element_resize', this.chart.resize.bind(this.chart));
}
pivotify(data){
var series = [];
data.forEach(x => {
if (series.indexOf(x[this.serieField]) == -1){
series.push(x[this.serieField]);
}
});
data.sort( (x, y) => {
if(x[this.nameField] > y[this.nameField]) return 1;
if(x[this.nameField] < y[this.nameField]) return -1;
return 0;
});
var ndic = {}
for (var i=0;i<data.length;i++){
var k = data[i][this.nameField];
if( !ndic[k] ){
ndic[k] = {
};
ndic[k][this.nameField] = data[i][this.nameField];
}
ndic[k][data[i][this.serieField]] = data[i][this.valueField];
}
var nd = Object.values(ndic);
nd.sort( (x, y) => {
if(x[this.nameField] > y[this.nameField]) return 1;
if(x[this.nameField] < y[this.nameField]) return -1;
return 0;
});
return nd;
}
get_series(data){
if (!this.serieField){
return null;
}
var series = [];
data.forEach(x => {
if (series.indexOf(x[this.serieField]) == -1){
series.push(x[this.serieField]);
}
});
return series;
}
render_data(){
var data = this.user_data;
if (this.serieField){
if (!this.valueField) this.valueFields[0];
this.valueFields = this.get_series(data);
data = this.pivotify(data);
}
this.chart = echarts.init(this.holder.dom_element);
var opts = this.setup_options(data);
opts.grid = {
left: '3%',
right: '3%',
bottom: '3%',
containLabel: true
};
if (this.valueFields.length>1 && opts.legend ){
opts.legend.data = this.valueFields;
}
console.log('opts=', opts);
this.chart.setOption(opts);
this.chart.on('click', this.click_handle.bind(this));
}
click_handle(params){
console.log('params=', params);
this.dispatch('element_click', this.user_data[params.dataIndex]);
}
async render_urldata(params){
if (! params) params = {};
var _params = bricks.extend({}, this.data_params);
_params = bricks.extend(_params, params);
var jc = new bricks.HttpJson();
var d = await jc.httpcall(this.data_url, {method:this.method || 'GET', params:_params});
if (d){
this.user_data = d;
this.render_data();
}
}
}

18
bricks/factory.js Normal file
View File

@ -0,0 +1,18 @@
var bricks = window.bricks || {};
class Factory_ {
constructor(){
this.widgets_kv = new Object();
this.widgets_kv['_t_'] = 1;
}
register(name, widget){
this.widgets_kv[name] = widget;
}
get(name){
if (this.widgets_kv.hasOwnProperty(name)){
return this.widgets_kv[name];
}
return null;
}
}
bricks.Factory = new Factory_();

150
bricks/floaticonbar.js Normal file
View File

@ -0,0 +1,150 @@
var bricks = window.bricks || {};
bricks.IconBar = class extends bricks.HBox {
/*
{
margin:
rate:
tools:[
{
name:
icon:
rate:
dynsize:
tip
}
]
}
*/
constructor(opts){
if (! opts.cheight){
opts.cheight = 2;
}
if (! opts.rate){
opts.rate = 1;
}
super(opts);
this.set_css('childrensize');
this.height_int = 0;
var tools = this.opts.tools;
for (var i=0;i<tools.length;i++){
var opts_i = bricks.extend({}, tools[i]);
if (!opts_i.rate){
opts_i.rate = this.rate;
}
opts_i.cheight = opts.cheight;
opts_i.cwidth = opts.cheight;
opts_i.dynsize = true;
var w = this.build_item(opts_i);
w.set_style('margin-left', this.opts.margin || '10px');
w.set_style('margin-right', this.opts.margin || '10px');
if (tools[i].name){
w.set_id(tools[i].name);
}
w.set_style('cursor', 'pointer');
this.add_widget(w);
}
this.set_style('alignItems', 'center');
// this.set_style('justifyContent', 'center');
}
build_item(opts){
var rate = opts.rate || this.opts.rate || 1;
var h = bricks.app.charsize * rate * opts.cheight;
if (this.height_int < h){
this.height_int = h;
}
if (opts.name == 'blankicon'){
return new bricks.BlankIcon({
rate:rate,
cheight:opts.cheight,
cwidth:opts.cwidth,
dynsize:opts.dynsize||true
});
}
opts.url = opts.icon;
var w = new bricks.Svg(opts);
w.bind('click', this.regen_event.bind(this, opts));
return w;
}
regen_event(desc, event){
this.dispatch(desc.name, desc);
this.dispatch('command', desc);
event.preventDefault();
event.stopPropagation();
}
}
bricks.IconTextBar = class extends bricks.IconBar {
build_item(opts){
var rate = opts.rate || this.opts.rate || 1;
var o = {
width:'auto',
height:'auto',
cheight:1.3 * rate
};
if (opts.tip){
o.tip = opts.tip;
}
var box = new bricks.HBox(o);
if (opts.icon){
var desc = {
url:opts.icon,
rate:opts.rate || rate,
dynsize:opts.dynsize||true
};
var w = new bricks.Svg(desc);
box.add_widget(w);
}
if (opts.label){
var desc = {
otext:opts.label,
i18n:true,
wrap:true,
haligh:'left',
rate:opts.rate || rate,
dynsize:opts.dynsize||true
};
var w = new bricks.Text(desc);
box.add_widget(w);
}
var h = bricks.app.charsize * rate;
if (this.height_int < h){
this.height_int = h;
}
box.bind('click', this.regen_event.bind(this,opts));
return box;
}
}
bricks.FloatIconBar = class extends bricks.HBox {
constructor(opts){
super(opts);
this.float_w = new bricks.Svg({url:bricks_resource('imgs/float-out.png')});
this.float_w.bind('mousemove', this.show_icons.bind(this));
this.add_widget(this.float_w);
this.icons_box = this.build_bar(opts);
this.add_widget(this.icons_box);
this.hide_icons()
this.set_style('height', this.icons_box.height_int + 'px')
bricks.Body.bind('click', this.hide_icons.bind(this));
}
build_bar(opts){
return new bricks.IconBar(opts);
}
show_icons(){
this.icons_box.set_style('display', 'flex');
}
hide_icons(){
this.icons_box.set_style('display', 'none');
}
}
bricks.FloatIconTextBar = class extends bricks.FloatIconBar {
build_bar(opts){
return new bricks.IconTextBar(opts);
}
}
bricks.Factory.register('IconBar', bricks.IconBar);
bricks.Factory.register('IconTextBar', bricks.IconTextBar);
bricks.Factory.register('FloatIconBar', bricks.FloatIconBar);
bricks.Factory.register('FloatIconTextBar', bricks.FloatIconTextBar);

6
bricks/footer.tmpl Normal file
View File

@ -0,0 +1,6 @@
};
const app = new bricks.App(opts);
app.run();
</script>
</body>
</html>

361
bricks/form.js Normal file
View File

@ -0,0 +1,361 @@
var bricks = window.bricks || {};
bricks.need_formdata_fields = ['file', 'video', 'audio'];
bricks.show_resp_message_or_error = async function(resp){
var desc = await resp.json();
await bricks.widgetBuild(desc, bricks.Body);
}
bricks.FieldGroup = class {
constructor(opts){
this.opts = opts
}
build_fields(form, parent, fields){
var dc = new bricks.DynamicColumn({mobile_cols:2});
for (var i=0;i<fields.length;i++){
if (fields[i].uitype == 'group'){
if (dc.children.length>0){
parent.add_widget(dc);
dc = new bricks.DynamicColumn({mobile_cols:2});
}
this.build_fields(form, dc, fields[i].fields);
parent.add_widget(dc);
dc = new bricks.DynamicColumn({mobile_cols:2});
} else {
var box;
if (! form.opts.input_layout || form.opts.input_layout == 'VBox'){
box = new bricks.VBox({height:'auto',overflow:'none'});
} else {
box = new bricks.HBox({height:'auto',overflow:'none'});
}
box.set_css('inputbox');
if (fields[i].uitype !== 'hide'){
dc.add_widget(box);
}
if(bricks.need_formdata_fields.includes(fields[i].uitype)){
form.need_formdata = true;
}
var txt = new bricks.Text({
otext:fields[i].label||fields[i].name,
dynsize:true,
height:'auto',
i18n:true});
box.add_widget(txt);
var w = Input.factory(fields[i]);
if (w){
box.add_widget(w);
form.name_inputs[fields[i].name] = w;
w.set_id(fields[i].name);
} else {
bricks.debug(fields[i], 'createInput failed');
}
}
}
if (dc.children.length > 0){
parent.add_widget(dc);
}
}
}
bricks.FormBody = class extends bricks.VScrollPanel {
/*
{
title:
description:
fields: [
{
"name":,
"label":,
"removable":
"icon":
"content":
},
...
]
}
*/
constructor(form, opts){
opts.width = '100%';
opts.height = '100%';
super(opts);
this.form = form;
this.name_inputs = {};
this.fg = new bricks.FieldGroup({});
this.fg.build_fields(form, this, form.nontextfields)
}
create(){
this.dom_element = this._create('form');
}
}
bricks.FormBase = class extends bricks.Layout {
constructor(opts){
super(opts);
this.name_inputs = {};
}
build_toolbar(widget){
var box = new bricks.HBox({height:'auto', width:'100%'});
widget.add_widget(box);
var tools = [
{
icon:bricks_resource('imgs/submit.svg'),
name:'submit',
css:'submit_btn',
label:'Submit'
},
{
icon:bricks_resource('imgs/reset.svg'),
name:'reset',
css:'reset_btn',
label:'Reset'
},
{
icon:bricks_resource('imgs/cancel.svg'),
name:'cancel',
css:'clear_btn',
label:'Cancel'
}
]
var tb_desc={};
var names = [ 'submit', 'reset', 'cancel' ];
if (this.toolbar){
tb_desc = bricks.extend(tb_desc, this.toolbar);
tb_desc.tools = tools;
tools.forEach(t => {
if (! names.includes(t.name)) {
tb_desc.tools.push(t);
}
});
this.toolbar.tools.forEach(t => {
if (! names.includes(t.name)) {
tb_desc.tools.push(t);
}
});
} else {
tb_desc = {
width:"auto",
tools:tools
};
}
var tbw = new bricks.IconTextBar(tb_desc);
tbw.bind('command', this.command_handle.bind(this));
box.add_widget(new bricks.Filler());
box.add_widget(tbw);
box.add_widget(new bricks.Filler());
}
command_handle(event){
var params = event.params;
bricks.debug('Form(): click_handle() params=', params);
if (!params){
error('click_handle() get a null params');
return
}
if (params.name == 'submit'){
this.validation();
} else if (params.name == 'cancel'){
this.cancel();
} else if (params.name == 'reset'){
this.reset_data();
} else {
if (params.action){
f = bricks.buildEventHandler(this, params);
if (f) f(event);
} else {
this.dispatch(params.name);
}
}
}
cancel(){
this.dispatch('cancel');
}
reset_data(){
for (var name in this.name_inputs){
if (! this.name_inputs.hasOwnProperty(name)){
continue;
}
var w = this.name_inputs[name];
w.reset();
}
}
_getValue(){
var data = {};
for (var name in this.name_inputs){
if (! this.name_inputs.hasOwnProperty(name)){
continue;
}
var w = this.name_inputs[name];
var d = w.getValue();
if (w.required && ( d[name] == '' || d[name] === null)){
bricks.debug('data=', data, 'd=', d);
new bricks.Error({title:'Requirement', message:'required field must input"' + w.label + '"'})
w.focus();
return;
}
bricks.extend(data, d);
}
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){
if (! this.name_inputs.hasOwnProperty(name)){
continue;
}
var w = this.name_inputs[name];
var d = w.getValue();
if (w.required && ( d[name] == '' || d[name] === null)){
new bricks.Error({title:'Requirement', message:'required field must input"' + w.label + '"'})
w.focus();
return;
}
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);
this.dispatch('submit', data);
if (this.submit_url){
var rc = new bricks.HttpResponse();
var resp = await rc.httpcall(this.submit_url,
{
method:this.method || 'POST',
params:data
});
this.dispatch('submited', resp);
}
} catch (e){
console.log('form submit error', e);
}
running.dismiss();
}
}
bricks.InlineForm = class extends bricks.FormBase {
constructor(opts){
opts.height = "100%";
opts.width = "100%";
opts.overflow = "auto";
super(opts);
this.fg = new bricks.FieldGroup({});
this.fg.build_fields(this, this, this.opts.fields)
this.build_toolbar(this.children[0]);
}
}
bricks.Form = class extends bricks.FormBase {
/*
{
title:
description:
notoolbar:False,
input_layout:"VBox" or "HBox", default is "VBox",
cols:
dataurl:
toolbar:
submit_url:
method:
fields
}
*/
constructor(opts){
opts.height = "100%";
opts.width = "100%";
opts.overflow = "auto";
super(opts);
this.need_formdata = false;
if (this.opts.title){
var t = new bricks.Title3({
otext:this.opts.title,
height:'auto',
i18n:true});
this.add_widget(t, 0);
}
if (this.opts.description){
var d = new bricks.Text({
otext:this.opts.description,
height:'auto',
i18n:true});
this.add_widget(d);
}
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);
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);
}
}
bricks.Factory.register('InlineForm', bricks.InlineForm);
bricks.Factory.register('Form', bricks.Form);

129
bricks/gobang.js Normal file
View File

@ -0,0 +1,129 @@
var bricks = window.bricks || {}
bricks.GobangPoint = class extends bricks.Image {
/*
p_status: 0:empty, 1:black, 2:white
p_x: horontical position from 1 to 15
p_y: verical position, from 1 to 15
*/
constructor(opts){
super(opts);
var url = this.calc_url();
this.set_url(url);
this.bind('mouseover', this.set_current_position.bind(this, true));
this.bind('mouseout', this.set_current_position.bind(this, false));
}
set_current_position(flg, event){
this.set_css('curpos', !flg);
}
calc_url(){
var one, two, st;
switch(this.p_status){
case 0:
st = 'empty';
break;
case 1:
st = 'black';
break;
case 2:
st = 'white';
break;
}
switch(this.p_y){
case 1:
one = "t";
break;
case 15:
one = "b";
break;
default:
one = "c"
}
switch(this.p_x){
case 1:
two = "l";
break;
case 15:
two = "r";
break;
default:
two = "c"
}
var name = 'imgs/' + one + two + '_' + st + '.png';
// console.log(name, this.p_x, this.p_y, one, two);
return bricks_resource(name);
}
getValue(){
return {
status:this.p_status,
x:this.p_x,
y:this.p_y
}
}
str(){
return '(' + this.p_status + ',' + this.p_x + ',' + this.p_y + ')';
}
}
bricks.Gobang = class extends bricks.VBox {
/*
player:{
"name":"ttt",
"type":"user", "llm"
"url":
"delay":seconds
"params":
}
{
black_player:{}
white_player:{}
}
*/
constructor(opts){
super(opts);
this.filler = new bricks.Filler({});
this.add_widget(this.filler);
this.render_empty_area()
this.inform_go('black')
this.filler.bind('element_resize', this.resize_area.bind(this));
}
resize_area(){
var ele = this.filler.dom_element;
var siz = Math.min(ele.clientWidth,
ele.clientHeight)/ 15;
console.log(siz, ele.clientWidth, ele.clientHeight);
for(var i=0;i<15;i++){
for(var j=0;j<15;j++){
var w = this.area[i][j];
w.set_style('width', siz+'px');
w.set_style('height', siz+'px');
}
}
}
inform_go(party){
}
render_empty_area(){
this.area = [];
var vbox = new bricks.VBox({});
vbox.h_center();
for (var i=1; i<=15; i++){
var hbox = new bricks.HBox({})
vbox.add_widget(hbox);
var l = [];
for (var j=1; j<=15; j++){
var w = new bricks.GobangPoint({
p_status:0,
tip: '(' + i + ',' + j + ')',
p_x: j,
p_y: i
});
hbox.add_widget(w);
l.push(w);
}
this.area.push(l);
}
this.filler.add_widget(vbox);
}
}
bricks.Factory.register('Gobang', bricks.Gobang);

40
bricks/header.tmpl Normal file
View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="{{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="{{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="{{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":

15
bricks/html.js Normal file
View File

@ -0,0 +1,15 @@
var bricks = window.bricks || {};
bricks.Html = class extends bricks.JsWidget {
/*
{
html:
}
*/
constructor(opts){
super(opts);
this.dom_element.innerHTML = opts.html;
}
}
bricks.Factory.register('Html', bricks.Html);

53
bricks/i18n.js Normal file
View File

@ -0,0 +1,53 @@
var bricks = window.bricks || {};
bricks.I18n = class {
constructor(url, default_lang){
/*
{
url:
method:
default_lang
}
*/
this.url = opts.url;
this.default_lang = opts.default_lang||'en';
this.method = opts.method || 'GET';
this.lang_msgs = {};
this.msgs = {};
}
_(txt, obj){
if (this.msgs.hasOwnProperty(txt)){
itxt = this.msgs[txt];
}
if (obj instanceof Object){
return obj_fmtstr(obj, itxt);
}
return txt;
}
is_loaded(lang){
if (objget(this.lang_msgs, lang)) return true;
return false;
}
setup_dict(dic, lang){
this.cur_lang = lang;
bricks.extend(this.lang_msgs, {lang:dic});
this.msgs = dic;
}
async change_lang(lang){
if (objget(this.lang_msgs, lang)){
this.msgs = objget(this.lang_msgs, lang);
return;
}
if (! this.url) return;
let params = {'lang':lang};
var jc = new bricks.HttpJson();
d = await jc.httpcall(desc.url, {
"method":this.method || 'GET',
params:params
});
this.setup_dict(d, lang);
}
}

55
bricks/iconbarpage.js Normal file
View 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);

21
bricks/iframe.js Normal file
View File

@ -0,0 +1,21 @@
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;
}
create(){
this.dom_element = document.createElement('iframe');
}
}
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);

115
bricks/image.js Normal file
View File

@ -0,0 +1,115 @@
var bricks = window.bricks || {};
bricks.Image = class extends bricks.JsWidget {
/*
{
url:
height:
width:
}
*/
constructor(opts){
super(opts);
this.opts = opts;
this.options_parse();
}
create(){
this.dom_element = document.createElement('img');
}
options_parse(){
if (this.opts.hasOwnProperty('url')){
this.set_url(this.opts.url);
}
if (this.opts.hasOwnProperty('width')){
this.width = this.opts.width;
this.dom_element.style.width = this.width;
}
if (this.opts.hasOwnProperty('height')){
this.height = this.opts.height;
this.dom_element.style.height = this.height;
}
}
removeBase64Header(base64String) {
return base64String.replace(/^data:[^;]*;base64,/, '');
}
base64(){
const image = this.dom_element;
// 创建一个画布来绘制图像
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置画布大小与图像相同
canvas.width = image.width;
canvas.height = image.height;
// 将图像绘制到画布上
ctx.drawImage(image, 0, 0);
// 获取画布数据并转换为 base64
var dataURL = canvas.toDataURL('image/png'); // 可以根据需要修改图像格式
// dataURL = this.removeBase64Header(dataURL);
return dataURL;
}
set_url(url){
this.url = url;
this.dom_element.src = url;
}
}
bricks.Icon = class extends bricks.Image {
constructor(opts){
super(opts);
}
options_parse(){
this.rate = this.rate || 1;
var siz = bricks.app.charsize * this.rate + 'px';
this.set_url(this.url)
this.cwidth = this.opts.cwidth || 1;
this.cheight = this.opts.cheight || 1;
this.dynsize = this.opts.dynsize || true;
this.charsize_sizing();
}
}
bricks.StatedIcon = class extends bricks.Icon {
/*
states:[{state:aaa,url:} ,,]
state:aaa,
*/
constructor(opts){
super(opts);
}
options_parse(){
if (! this.states){
return;
}
if (! this.state){
this.state = this.states[0].state;
}
this.set_state(this.state);
}
set_state(state){
this.state = state;
this.states.forEach(s => {
if(s.state == this.state){
this.url = s.url
super.options_parse();
}
});
}
}
bricks.BlankIcon = class extends bricks.JsWidget {
constructor(opts){
super(opts);
this.rate = opts.rate || 1;
this.cwidth = this.opts.cwidth || 1;
this.cheight = this.opts.cheight || 1;
this.dynsize = this.opts.dynsize || true;
this.charsize_sizing();
}
}
bricks.Factory.register('Image', bricks.Image);
bricks.Factory.register('StatedIcon', bricks.StatedIcon);
bricks.Factory.register('Icon', bricks.Icon);
bricks.Factory.register('BlankIcon', bricks.BlankIcon);

BIN
bricks/imgs/.DS_Store vendored Normal file

Binary file not shown.

1
bricks/imgs/9cycles.svg Normal file
View File

@ -0,0 +1 @@
<svg t="1749698260805" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="45734" width="100%" height="100%"><path d="M512 725.328A85.328 85.328 0 1 1 512 896a85.328 85.328 0 0 1 0-170.672z m298.672 0a85.328 85.328 0 1 1 0 170.672 85.328 85.328 0 0 1 0-170.672z m-597.344 0a85.328 85.328 0 1 1 0 170.672 85.328 85.328 0 0 1 0-170.672z" fill="${color}" p-id="45735"></path><path d="M512 426.672a85.328 85.328 0 1 1 0 170.656 85.328 85.328 0 0 1 0-170.656z m298.672 0a85.328 85.328 0 1 1 0 170.656 85.328 85.328 0 0 1 0-170.656z m-597.344 0a85.328 85.328 0 1 1 0 170.656 85.328 85.328 0 0 1 0-170.656z" fill="${color}" p-id="45736"></path><path d="M512 128a85.328 85.328 0 1 1 0 170.672A85.328 85.328 0 0 1 512 128z m298.672 0a85.328 85.328 0 1 1 0 170.672 85.328 85.328 0 0 1 0-170.672z" fill="${color}" p-id="45737"></path><path d="M213.328 128a85.328 85.328 0 1 1 0 170.672 85.328 85.328 0 0 1 0-170.672z" fill="#417AE7" p-id="45738"></path></svg>

After

Width:  |  Height:  |  Size: 989 B

BIN
bricks/imgs/add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

1
bricks/imgs/add.svg Normal file
View 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

11
bricks/imgs/app-dock.svg Normal file
View File

@ -0,0 +1,11 @@
<svg t="1749637984292" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17580" width="100%" height="100%">
<path d="M187.072 160h137.856c14.944 0 27.072 12.128 27.072 27.072v137.856a27.072 27.072 0 0 1-27.072 27.072H187.072A27.072 27.072 0 0 1 160 324.928V187.072C160 172.128 172.128 160 187.072 160z" fill="green" p-id="17581"></path>
<path d="M443.072 160h137.856c14.944 0 27.072 12.128 27.072 27.072v137.856a27.072 27.072 0 0 1-27.072 27.072h-137.856a27.072 27.072 0 0 1-27.072-27.072V187.072c0-14.944 12.128-27.072 27.072-27.072z" fill="${color}" p-id="17582"></path>
<path d="M699.072 160h137.856c14.944 0 27.072 12.128 27.072 27.072v137.856a27.072 27.072 0 0 1-27.072 27.072h-137.856a27.072 27.072 0 0 1-27.072-27.072V187.072c0-14.944 12.128-27.072 27.072-27.072z" fill="${color}" p-id="17583"></path>
<path d="M187.072 416h137.856c14.944 0 27.072 12.128 27.072 27.072v137.856a27.072 27.072 0 0 1-27.072 27.072H187.072A27.072 27.072 0 0 1 160 580.928v-137.856c0-14.944 12.128-27.072 27.072-27.072z" fill="${color}" p-id="17584"></path>
<path d="M443.072 416h137.856c14.944 0 27.072 12.128 27.072 27.072v137.856a27.072 27.072 0 0 1-27.072 27.072h-137.856a27.072 27.072 0 0 1-27.072-27.072v-137.856c0-14.944 12.128-27.072 27.072-27.072z" fill="yellow" p-id="17585"></path>
<path d="M699.072 416h137.856c14.944 0 27.072 12.128 27.072 27.072v137.856a27.072 27.072 0 0 1-27.072 27.072h-137.856a27.072 27.072 0 0 1-27.072-27.072v-137.856c0-14.944 12.128-27.072 27.072-27.072z" fill="${color}" p-id="17586"></path>
<path d="M187.072 672h137.856c14.944 0 27.072 12.128 27.072 27.072v137.856a27.072 27.072 0 0 1-27.072 27.072H187.072A27.072 27.072 0 0 1 160 836.928v-137.856c0-14.944 12.128-27.072 27.072-27.072z" fill="${color}" p-id="17587"></path>
<path d="M443.072 672h137.856c14.944 0 27.072 12.128 27.072 27.072v137.856a27.072 27.072 0 0 1-27.072 27.072h-137.856a27.072 27.072 0 0 1-27.072-27.072v-137.856c0-14.944 12.128-27.072 27.072-27.072z" fill="${color}" p-id="17588"></path>
<path d="M699.072 672h137.856c14.944 0 27.072 12.128 27.072 27.072v137.856a27.072 27.072 0 0 1-27.072 27.072h-137.856a27.072 27.072 0 0 1-27.072-27.072v-137.856c0-14.944 12.128-27.072 27.072-27.072z" fill="red" p-id="17589"></path>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
bricks/imgs/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

1
bricks/imgs/app.svg Normal file
View File

@ -0,0 +1 @@
<svg t="1749272572588" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2369" width="100%" height="100%"><path d="M61.577 621.3V500.492c0-11.07 9.09-20.123 20.229-20.123h213.477l-92.945 161.063H81.805c-11.138 0-20.228-9.023-20.228-20.132z m152.068 247.375l-68.127 46.157c-9.167 6.24-15.65 2.279-14.379-8.715l9.09-78.98c1.266-10.993 10.187-15.497 19.832-9.99l52.725 30.12c9.631 5.527 10.027 15.206 0.86 21.408z m16.36-44.513l-52.724-30.12c-9.64-5.526-13.037-17.872-7.43-27.474L413.996 343.36c5.535-9.62 18.026-12.994 27.657-7.419l52.725 30.06c9.64 5.575 12.963 17.931 7.428 27.513l-244.14 423.247c-5.529 9.602-18.025 12.888-27.66 7.4z m185.816-182.73L508.76 480.37h53.517l75.475 161.062H415.82zM718.528 689.5c-21.107-10.53-126.229-252.003-153.16-315.007-26.962-63.002-108.376-230.71-82.044-243.751 18.74-9.361 85.994 122.701 136.41 201.972 50.349 79.29 155.634 283.715 168.588 306.997 12.886 23.338-12.404 42.794-26.469 48.609-14.075 5.837-22.228 11.633-43.325 1.18z m69.079 110.995l-31.762-49.962c-6.57-10.376-3.159-23.205 7.496-28.69l30.274-15.497c10.676-5.428 24.035-1.043 29.715 9.835l25.058 47.972c5.699 10.856 1.815 24.787-8.463 30.91l-21.648 12.888c-10.277 6.222-24.1 2.84-30.67-7.456z m116.896 131.029c-6.636-21.156-57.303-22.567-79.985-54.445-22.76-31.763-3.95-48.125 3.95-55.68 92.004-51.586 76.035 110.125 76.035 110.125zM951.847 621.3c0 11.11-9.09 20.132-20.229 20.132H824.76c-1.178-6.2-3.092-12.422-6.318-18.239-2.783-4.965-9.815-18.314-19.61-36.958-14.142-26.893-34.458-65.36-56.202-105.865h188.98c11.138 0 20.228 9.052 20.228 20.123V621.3h0.01z" fill="${color} p-id="2370"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

1
bricks/imgs/app_add.svg Normal file
View 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

BIN
bricks/imgs/app_delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1 @@
<svg t="1749634034299" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5162" width="100%" height="100%"><path d="M721.92 303.104a48.493714 48.493714 0 0 0-68.461714 0l-141.897143 141.897143L375.222857 308.736a46.957714 46.957714 0 1 0-66.56 66.56l136.338286 136.192-141.897143 141.897143a48.347429 48.347429 0 0 0 68.388571 68.388571l141.897143-141.897143 137.069715 136.996572a46.957714 46.957714 0 1 0 66.413714-66.413714L580.022857 513.462857l141.897143-141.897143a48.493714 48.493714 0 0 0 0-68.461714M512 1024A512 512 0 1 1 512 0a512 512 0 0 1 0 1024" fill="#FF3F3B" p-id="5163"></path></svg>

After

Width:  |  Height:  |  Size: 642 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1 @@
<svg t="1749634403553" class="icon" viewBox="0 0 1029 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11427" width="100%" height="100%"><path d="M514.547264 5.094527C233.329353 5.094527 5.094527 233.329353 5.094527 514.547264s228.234826 509.452736 509.452737 509.452736 509.452736-228.234826 509.452736-509.452736S795.765174 5.094527 514.547264 5.094527z m62.662686 731.064677H332.163184c-21.397015 0-38.718408-17.321393-38.718408-38.718408V452.39403c0-34.642786 41.775124-51.454726 65.719403-27.510448l245.046766 245.046766c24.453731 24.453731 7.132338 66.228856-27.000995 66.228856z m158.439801-158.949254c0 34.642786-41.775124 51.454726-65.719403 27.510448L424.883582 359.673632c-24.453731-24.453731-7.132338-65.719403 27.510448-65.719403h245.046766c21.397015 0 38.718408 17.321393 38.718408 38.718408l-0.509453 244.537313z" fill="#61C554" p-id="11428"></path></svg>

After

Width:  |  Height:  |  Size: 883 B

BIN
bricks/imgs/app_minimax.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1 @@
<svg t="1749634221894" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7125" width="100%" height="100%"><path d="M512 32c265.088 0 480 214.912 480 480 0 265.088-214.912 480-480 480-265.088 0-480-214.912-480-480C32 246.912 246.912 32 512 32z m224 448H288a32 32 0 0 0 0 64h448a32 32 0 0 0 0-64z" fill="#F4BF4F" p-id="7126"></path></svg>

After

Width:  |  Height:  |  Size: 379 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
bricks/imgs/bc_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
bricks/imgs/bc_empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
bricks/imgs/bc_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
bricks/imgs/bl_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
bricks/imgs/bl_empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
bricks/imgs/bl_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
bricks/imgs/br_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
bricks/imgs/br_empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
bricks/imgs/br_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
bricks/imgs/camera.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
bricks/imgs/cancel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

1
bricks/imgs/cancel.svg Normal file
View 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

BIN
bricks/imgs/cc_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
bricks/imgs/cc_empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
bricks/imgs/cc_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -0,0 +1 @@
<svg t="1749276805348" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6191" width="100%" height="100%"><path d="M921.6 0H477.866667c-58.026667 0-102.4 44.373333-102.4 102.4v51.2c0 3.413333 3.413333 10.24 6.826666 13.653333 3.413333 3.413333 6.826667 3.413333 13.653334 3.413334h13.653333c126.293333 0 160.426667 71.68 167.253333 92.16 0 3.413333 3.413333 3.413333 3.413334 6.826666 23.893333 23.893333 34.133333 58.026667 34.133333 105.813334v17.066666c0 10.24 6.826667 17.066667 17.066667 17.066667h13.653333l-13.653333 71.68v13.653333c0 13.653333-3.413333 34.133333-10.24 58.026667-3.413333 6.826667 0 17.066667 6.826666 20.48 3.413333 0 6.826667 3.413333 6.826667 3.413333 3.413333 0 10.24-3.413333 13.653333-6.826666l143.36-157.013334H921.6c58.026667 0 102.4-44.373333 102.4-102.4V102.4c0-58.026667-44.373333-102.4-102.4-102.4z" fill="green" p-id="6192"></path><path d="M798.72 921.6c-10.24-40.96-37.546667-71.68-78.506667-85.333333L570.026667 785.066667c-37.546667-13.653333-54.613333-75.093333-58.026667-95.573334 27.306667-23.893333 51.2-61.44 51.2-92.16 0-13.653333 3.413333-17.066667 3.413333-17.066666 6.826667 0 10.24-6.826667 10.24-10.24 3.413333-3.413333 17.066667-47.786667 17.066667-75.093334v-3.413333c-3.413333-6.826667-6.826667-17.066667-17.066667-23.893333V375.466667c0-54.613333-17.066667-78.506667-34.133333-92.16 0-23.893333-27.306667-78.506667-133.12-78.506667-105.813333 0-170.666667 98.986667-170.666667 170.666667v92.16c-10.24 6.826667-13.653333 17.066667-17.066666 23.893333v3.413333c0 27.306667 17.066667 68.266667 17.066666 75.093334 3.413333 3.413333 3.413333 6.826667 10.24 10.24 3.413333 0 6.826667 6.826667 6.826667 17.066666 0 30.72 23.893333 68.266667 51.2 92.16-3.413333 23.893333-20.48 81.92-54.613333 95.573334L102.4 836.266667c-37.546667 13.653333-68.266667 44.373333-78.506667 85.333333L0 1003.52c0 3.413333 0 10.24 3.413333 13.653333 3.413333 3.413333 6.826667 6.826667 13.653334 6.826667h785.066666c6.826667 0 10.24-3.413333 13.653334-6.826667 3.413333-3.413333 3.413333-10.24 3.413333-13.653333l-20.48-81.92z" fill="${color}" p-id="6193"></path></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View 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="${color}"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View 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

BIN
bricks/imgs/cl_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
bricks/imgs/cl_empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
bricks/imgs/cl_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

1
bricks/imgs/clear.svg Normal file
View 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

View File

@ -0,0 +1 @@
<svg t="1751017528469" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5616" width="100%" height="100%"><path d="M153.6 307.2h250.88l-51.2-76.8H153.6V307.2z m368.64 0H870.4c56.32 0 102.4 46.08 102.4 102.4v435.2c0 56.32-46.08 102.4-102.4 102.4H153.6c-56.32 0-102.4-46.08-102.4-102.4v-614.4c0-56.32 46.08-102.4 102.4-102.4h199.68c35.84 0 66.56 15.36 87.04 46.08L522.24 307.2zM153.6 409.6v435.2h716.8V409.6H153.6z" fill="${color}" p-id="5617"></path></svg>

After

Width:  |  Height:  |  Size: 498 B

View 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="100%" height="100%"><path d="M512 128l512 383.168L512 896 0 512l512-384z" p-id="13860" fill="${color}"></path></svg>

After

Width:  |  Height:  |  Size: 246 B

BIN
bricks/imgs/conform.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

1
bricks/imgs/conform.svg Normal file
View File

@ -0,0 +1 @@
<svg t="1748860419789" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="93428" width="100%" height="100%"><path d="M512 1024c-282.304 0-512-229.696-512-512s229.696-512 512-512 512 229.696 512 512S794.304 1024 512 1024zM512 48.768C256.576 48.768 48.768 256.576 48.768 512S256.576 975.168 512 975.168 975.168 767.424 975.168 512 767.424 48.768 512 48.768z" fill="${color}" p-id="93429"></path><path d="M425.728 750.784 206.528 531.648 251.776 486.336 425.728 660.288 772.224 313.792 817.472 359.04Z" fill="#3BDCBC" p-id="93430"></path></svg>

After

Width:  |  Height:  |  Size: 583 B

BIN
bricks/imgs/cr_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Some files were not shown because too many files have changed in this diff Show More