bricks/bricks/input.js
2026-03-05 15:44:18 +08:00

1233 lines
28 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var bricks = window.bricks || {};
bricks.UiType =class extends bricks.Layout {
constructor(opts){
super(opts);
this.name = this.opts.name;
this.required = opts.required || false;
this.ctype = 'text';
this.value = opts.value || opts.defaultvalue||'';
}
getValue(){
var o = {}
o[this.name] = this.resultValue();
var d = this.getUserData();
if (d){
o = bricks.extend(o, d);
}
return o;
}
set_formdata(formdata){
formdata.append(this.name, this.resultValue());
}
resultValue(){
return this.value;
}
focus(){
this.dom_element.focus();
}
reset(){
var v = this.opts.value||this.opts.defaultvalue|| '';
this.setValue(v);
}
setValue(v){
if (! v)
v = '';
this.vlaue = v;
this.dom_element.value = v;
}
set_disabled(f){
this.dom_element.disabled = f;
}
set_readonly(f){
this.dom_element.readOnly = f;
}
set_required(f){
this.dom_element.required = f;
this.required = f;
}
}
bricks.UiHide = class extends bricks.UiType {
constructor(opts){
super(opts);
this.uitype = 'hide';
this.set_style('display', 'none');
}
}
bricks.UiStr =class extends bricks.UiType {
/*
{
name:
value:
defaultValue:
align:"left", "center", "right"
length:
minlength:
tip:
width:
readonly:
required:
}
*/
constructor(opts){
super(opts);
this.uitype='str';
this.rate = this.opts.rate || 1;
this.dynsize = this.opts.dynsize || true;
this.cfontsize = this.opts.cfontsize || 1;
if (opts.readonly) {
this.set_readonly("Y");
} else {
this.set_readonly(false);
}
if (opts.width){
this.dom_element.style.width = opts.width;
}
this.charsize_sizing();
}
create(){
var el = this._create('input');
this.dom_element = el;
this.pattern = '.*';
el.autocomplete = 'off';
el.type = 'text';
el.id = this.name = el.name = this.opts.name;
if (this.opts.required)
el.required = true;
if (this.opts.css){
el.classList.add(this.opts.css);
this.actived_css = this.opts.css + '-actived';
} else {
el.classList.add('input');
this.actived_css = 'input_actived';
}
el.style.textAlign = this.opts.align || 'left';
if (this.opts.hasOwnProperty('length'))
el.maxlength = this.opts.length;
if (this.opts.hasOwnProperty('minlength'))
el.minlength = this.opts.minlength;
if (this.opts.hasOwnProperty('value'))
this.setValue(this.opts.value);
if (this.opts.defaultVlaue)
el.defaultValue = this.opts.defaultValue;
this.reset()
if (this.opts.placeholder)
el.placeholder = bricks.app.i18n._(this.opts.placeholder);
el.addEventListener('focus', this.onfocus.bind(this));
el.addEventListener('onkeydown', this.onkeydown.bind(this));
el.addEventListener('blur', this.onblur.bind(this));
el.addEventListener('input', this.set_value_from_input.bind(this))
}
onblur(event){
this.dom_element.classList.remove(this.actived_css);
this.value = this.dom_element.value;
this.set_value_from_input(event);
}
onfocus(event){
this.dom_element.classList.add(this.actived_css);
}
onkeydown(event){
if(event.key == 'Enter'){
var v = this.getValue();
this.dispatch('blur', v)
}
}
check_pattern(value){
var r = new RegExp(this.pattern);
var v = value.match(r);
if (! v || v[0] == ''){
return null;
}
return v[0];
}
set_value_from_input(event){
var oldv = this.value;
var changed = false;
var e = event.target;
var v = e.value;
if (e.value!='' && e.type != 'file'){
v = this.check_pattern(e.value);
}
if (v == null){
e.value = this.value;
return
}
this.value = v;
var o = this.getValue();
this.dispatch('changed', o);
}
resultValue(){
this.value = this.dom_element.value;
return this.value;
}
setValue(v){
if (! v)
v = '';
this.value = v;
this.dom_element.value = '' + this.value;
}
}
bricks.UiSearch = class extends bricks.HBox {
/*
search_url:
valueField
textField
select_event
popup_options
value,
text
*/
constructor(opts){
super(opts);
this.uitype = 'search';
var inputdesc = {
name:this.name,
value:this.text,
readonly:true
}
this.str_in = new bricks.UiStr(inputdesc);
this.search_icon = new bricks.Svg({
url:bricks_resource('imgs/search.svg'),
rate:1.5
});
this.str_in.set_css('filler');
this.search_icon.set_css('clickable');
this.search_icon.bind('click', this.open_search_window.bind(this));
this.add_widget(this.str_in);
this.add_widget(this.search_icon);
}
async open_search_window(event){
var desc = {
"widgettype":"urlwidget",
"options":{
"url":this.search_url
}
}
var w = await bricks.widgetBuild(desc, this);
var tabular = null;
for (var i=0;i<w.children.length;i++){
if (w.children[i] instanceof bricks.Tabular){
tabular = w.children[i];
}
}
if (!tabular){
console.log('tubular not found is w');
return;
}
var win = bricks.default_popupwindow(this.popup_options||{});
win.add_widget(w);
win.open();
tabular.bind(this.search_event, this.set_data.bind(this));
tabular.bind(this.search_event, win.dismiss.bind(win));
}
set_data(event){
var d = event.params;
this.value = d[this.valueField];
this.str_in.setValue(d[this.textField])
}
getValue(){
var o = {}
o[this.name] = this.resultValue();
var d = this.getUserData();
if (d){
o = bricks.extend(o, d);
}
return o;
}
set_formdata(formdata){
formdata.append(this.name, this.resultValue());
}
resultValue(){
return this.value;
}
focus(){
this.str_in.dom_element.focus();
}
reset(){
var v = this.opts.value||this.opts.defaultvalue|| '';
this.setValue(v);
this.str_in.setValue(this.opts.text||'');
}
setValue(v, t){
if (! v)
v = '';
this.vlaue = v;
this.str_in.setValue(t);
}
set_disabled(f){
this.dom_element.disabled = f;
}
set_readonly(f){
this.dom_element.readOnly = f;
}
set_required(f){
this.dom_element.required = f;
this.required = f;
}
}
bricks.UiPassword =class extends bricks.UiStr {
/*
{
name:
value:
defaultValue:
align:"left", "center", "right"
length:
minlength:
tip:
readonly:
required:
}
*/
constructor(opts){
opts.dynsize = opts.dynsize || true;
super(opts);
this.uitype='password';
this.dom_element.type = 'password';
}
}
bricks.UiInt =class extends bricks.UiStr {
/*
{
length:
}
*/
constructor(options){
super(options);
this.uitype='int';
this.dom_element.style.textAlign = 'right';
this.dom_element.type = 'number';
this.pattern = '\\d*';
}
resultValue(){
return parseInt(this.value);
}
setValue(v){
if (! v)
v = '';
this.value = '' + v;
this.dom_element.value = '' + v;
}
}
bricks.UiFloat =class extends bricks.UiInt {
/*
{
dec_len:
}
*/
constructor(options){
super(options);
this.uitype='float';
this.pattern = '\\d*\\.?\\d+';
var dec_len = this.opts.dec_len || 2;
var step = 1;
for (var i=0; i<dec_len; i++)
step = step / 10;
this.dom_element.step = step;
}
resultValue(){
super.resultValue();
return parseFloat(this.value);
}
setValue(v){
if (! v)
v = '';
this.value = '' + v;
this.dom_element.value = '' + v;
}
}
bricks.UiTel =class extends bricks.UiStr {
/*
{
pattern:
}
*/
constructor(opts){
super(opts);
this.uitype='tel';
this.dom_element.type = 'tel';
if (this.opts.pattern)
this.dom_element.pattern = this.opts.pattern;
this.pattern = '[+]?\\d+';
}
}
bricks.UiEmail =class extends bricks.UiStr {
/*
{
}
*/
constructor(opts){
super(opts);
this.uitype='email';
this.dom_element.type = 'email';
if (this.opts.pattern)
this.dom_element.pattern = this.opts.pattern;
if (this.opts.pattern)
this.dom_element.pattern = this.opts.pattern;
}
}
bricks.UiFile = class extends bricks.VBox {
/*
accept:
multiple:
*/
constructor(opts){
opts.width = opts.width || '100%';
super(opts);
this.set_css('droparea');
this.bind('dragover', (event) => {
event.preventDefault();
});
["dragenter", "dragover", "dragleave", "drop"].forEach(eventName => {
this.bind(eventName, (e) => e.preventDefault(), false);
});
this.bind('dragenter', () => {
this.set_css('hover');
});
this.bind('dragleave', () => {
this.set_css('hover', true);
});
this.bind('drop', this.dropHandle.bind(this));
this.input = document.createElement('input');
this.input.type = 'file';
if (opts.accept) this.input.accept = opts.accept;
if (opts.multiple) this.input.multiple = true;
this.input.addEventListener('change', this.handleFileSelect.bind(this));
this.add_widget(new bricks.Text({text:'drop in or click to choose file'}));
this.dom_element.appendChild(this.input);
}
reset(){
var v = this.opts.value || this.opts.defaultvalue||'';
this.value = '';
this.input.value = '';
}
handleFileSelect(event){
var files = [];
Array.from(event.target.files).forEach(f => {
if (! this.accept || f.type.startsWith(this.accept)){
files.push(f);
}
});
if (files.length == 0) return;
if (this.opts.multiple){
this.value = files;
} else {
this.value = files[0];
}
console.log('"changed" fired', this.value);
this.dispatch('changed', this.getValue());
}
set_input_file(files){
const dt = new DataTransfer();
if (this.opts.multiple){
this.value = [];
files.forEach(f => {
dt.items.add(f);
this.value.push(f);
});
this.input.files = dt.files;
} else {
var f = files[0]
this.value = f;
dt.items.add(f);
this.input.files = dt.files;
}
}
dropHandle(event){
event.preventDefault();
var files = [];
for (const f of event.dataTransfer.files) {
if (! this.opts.accept || f.type.startsWith(this.opts.accept)){
files.push(f);
}
};
if (files.length == 0) return;
if (this.opts.multiple){
this.value = files;
this.set_input_file(files);
} else {
this.value = files[0];
this.set_input_file([this.value]);
}
this.dispatch('changed', this.getValue());
console.log('"changed" fired', this.getValue());
}
set_formdata(fd){
fd.append(this.name, this.resultValue());
}
resultValue(){
if (this.value){
return this.value;
}
if (this.input.files.length)
return this.input.files[0];
return null;
}
getValue(){
var ret = {};
ret[this.name] = this.resultValue();
return ret;
}
}
bricks.UiAudio =class extends bricks.UiFile {
constructor(opts){
opts.name = opts.name || 'audio_file';
opts.width = opts.width || '100%';
opts.accept = 'audio/';
super(opts);
this.uitype='audio';
this.camera_w = new bricks.Svg({
url:bricks_resource('imgs/mic.svg'),
tip:'use mic to record audio',
rate:2});
this.add_widget(this.camera_w);
this.camera_w.bind('click', this.open_recorder.bind(this));
this.preview = new bricks.VBox({width: '100%'});
this.add_widget(this.preview);
this.bind('changed', this.show_audio.bind(this));
}
open_recorder(event){
event.stopPropagation();
var recorder = new bricks.SysAudioRecorder({
"archor":"cc",
"auto_open":true,
"cheight":3,
"cwidth":20
});
recorder.bring_to_top();
recorder.bind('record_end', this.accept_audio.bind(this, recorder));
}
accept_audio(recorder, event){
recorder.dismiss();
this.value = event.params.file
this.set_input_file([this.value]);
console.log('record finished, value=', this.value);
this.dispatch('changed', this.getValue());
}
show_audio(event){
var params = this.value;
if (params instanceof File){
params = [ params ];
}
if (typeof params == 'string'){
params = [ params ];
}
this.preview.clear_widgets();
params.forEach( f => {
this._show_audio(f);
});
}
_show_audio(file) {
if (typeof file == 'string'){
var vw = new bricks.AudioPlayer({
url:file,
audoplay: true,
width:'100%'
});
this.preview.add_widget(vw);
return;
}
const reader = new FileReader();
reader.onload = (e) => {
var imgw = new bricks.AudioPlayer({
url:e.target.result,
autoplay: true,
width:'100%'
});
console.log('show audio', e.target.result);
this.preview.add_widget(imgw);
};
reader.readAsDataURL(file);
}
}
bricks.UiVideo =class extends bricks.UiFile {
constructor(opts){
opts.name = opts.name || 'video_file';
opts.width = opts.width || '100%';
opts.accept = 'video/';
super(opts);
this.uitype='video';
this.camera_w = new bricks.Svg({
url:bricks_resource('imgs/video-recorder.svg'),
tip:'use cemera to record video',
rate:2});
this.set_css('droparea');
this.add_widget(this.camera_w);
this.camera_w.bind('click', this.open_recorder.bind(this));
this.preview = new bricks.VBox({width: '100%'});
this.add_widget(this.preview);
this.bind('changed', this.show_video.bind(this));
}
open_recorder(event){
event.stopPropagation();
var recorder = new bricks.SysVideoRecorder({
"archor":"cc",
"auto_open":true,
"height":"90%",
"width":"90%"
});
recorder.bring_to_top();
recorder.bind('record_end', this.accept_video.bind(this, recorder));
}
accept_video(recorder, event){
recorder.dismiss();
this.value = event.params.file
this.set_input_file([this.value]);
console.log('record finished, value=', this.value);
this.dispatch('changed', this.getValue());
}
show_video(event){
var params = this.value;
console.log('params=', params);
if (params instanceof File){
params = [ params ];
}
if (typeof params == 'string'){
params = [ params ];
}
this.preview.clear_widgets();
params.forEach( f => {
this._show_video(f);
});
}
_show_video(file) {
if (typeof file == 'string'){
var vw = new bricks.VideoPlayer({
url:file,
audoplay: true,
width:'100%'
});
this.preview.add_widget(vw);
return;
}
var url = URL.createObjectURL(file);
var imgw = new bricks.VideoPlayer({
url:url,
autoplay: true,
width:'100%'
});
console.log('show video', url);
this.preview.add_widget(imgw);
}
}
bricks.UiImage =class extends bricks.UiFile {
constructor(opts){
opts.name = opts.name || 'image';
opts.width = opts.width || '100%';
opts.accept = 'image/';
super(opts);
this.uitype='image';
this.camera_w = new bricks.Svg({
url:bricks_resource('imgs/camera.svg'),
tip:'use cemera to take a picture',
rate:2});
this.set_css('droparea');
this.add_widget(this.camera_w);
this.camera_w.bind('click', this.take_photo.bind(this));
this.preview = new bricks.VBox({width: '100%'});
this.add_widget(this.preview);
this.bind('changed', this.show_image.bind(this));
}
take_photo(event){
event.stopPropagation();
var camera = new bricks.SysCamera({
"archor":"cc",
"auto_open":true,
"height":"90%",
"width":"90%"
});
camera.bring_to_top();
camera.bind('shot', this.accept_photo.bind(this, camera));
}
accept_photo(camera, event){
camera.dismiss();
this.value = event.params.file;
this.set_input_file([this.value]);
var data = {};
data[this.name] = this.value;
this.dispatch('changed', data);
}
show_image(event){
var params = event.params[this.name];
if (params instanceof File){
params = [ params ];
}
if (typeof params == 'string'){
params = [ params ];
}
this.preview.clear_widgets();
params.forEach( f => {
this._show_image(f);
});
}
_show_image(file) {
if (typeof file == 'string'){
var imgw = new bricks.Image({
url:file,
width:'100%'
});
this.preview.add_widget(imgw);
}
const reader = new FileReader();
reader.onload = (e) => {
var imgw = new bricks.Image({
url:e.target.result,
width:'100%'
});
this.preview.add_widget(imgw);
};
reader.readAsDataURL(file);
}
}
bricks.UiCheck =class extends bricks.UiType {
constructor(opts){
super(opts);
this.uitype = 'check';
bricks.extend(bricks.UiCheck.prototype, bricks.Layout.prototype);
this.add_widget = bricks.Layout.prototype.add_widget.bind(this);
this.dom_element.style.width = 'auto';
this.dom_element.style.height = 'auto';
var state = 'unchecked';
if (opts.value){
state = 'checked';
}
this.ms_icon = new bricks.MultipleStateIcon({
state:state,
urls:{
checked:bricks_resource('imgs/checkbox-checked.svg'),
unchecked:bricks_resource('imgs/checkbox-unchecked.svg')
}
});
this.add_widget(this.ms_icon)
this.ms_icon.bind('state_changed', this.set_value_from_input.bind(this));
}
set_value_from_input(e){
var v;
if (this.ms_icon.state=='checked')
v = true;
else
v = false;
this.value = v;
var o = {};
o[this.name] = this.value;
var d = this.getUserData();
if (d){
o = bricks.extend(o, d);
}
this.dispatch('changed', o);
}
setValue(v){
this.value = v;
if (v)
this.ms_icon.set_state('checked');
else
this.ms_icon.set_state('unchecked');
}
resultValue(){
return this.value;
}
}
bricks.UiCheckBox =class extends bricks.UiType {
/*
{
name:
label:
value:
textField:'gg',
valueField:'hh',
otherField:'b',
data:[
{
'gg':
'hh':
'b':
}
]
or:
dataurl:
params:{},
method:
}
*/
constructor(opts){
super(opts);
this.uitype='checkbox';
this.valueField = opts.valueField || 'value';
this.textField = opts.textField || 'text';
this.value = this.opts.value || this.opts.defaultValue||[];
if (! Array.isArray(this.value)){
this.value = [ this.value ];
}
this.el_legend = this._create('legend');
var label = this.opts.label||this.opts.name;
this.el_legend.innerText = bricks.app.i18n._(label);
if (this.opts.dataurl){
schedule_once(this.load_data_onfly.bind(this), 0.01);
} else {
this.data = opts.data;
this.build_checkboxs();
}
this.sizable_elements = [];
this.sizable_elements.push(this.el_legend);
this.charsize_sizing();
}
create(){
this.dom_element = this._create('fieldset');
}
build_checkboxs(){
var data = this.data;
this.input_boxs = [];
if (this.multicheck){
if (typeof this.value != typeof []){
this.value = [this.value];
}
}
for (var i=0; i<data.length;i++){
var hbox = new bricks.HBox({height:"auto",width:"100%"});
var opts = {}
var value = data[i][this.valueField];
opts.value = false;
if (this.multicheck){
if (this.value.indexOf(value) >= 0){
opts.value = true;
}
}
else {
if (this.value == value){
opts.value = true
}
}
opts.name = value;
var check = new bricks.UiCheck(opts);
var otext = data[i][this.textField];
var txt = new bricks.Text({
otext:otext,
align:'left',
i18n:true});
txt.ht_left();
check.bind('changed', this.set_value_from_input.bind(this));
hbox.add_widget(check);
hbox.add_widget(txt);
this.add_widget(hbox);
this.input_boxs.push(check);
}
}
async load_data_onfly(){
var jc = new bricks.HttpJson();
var data = await jc.httpcall(this.opts.dataurl, {
"method":this.opts.method||'GET',
"params":this.opts.params});
this.data = data;
this.build_checkboxs();
}
set_value_from_input(event){
event.stopPropagation();
var e = event.target.bricks_widget;
if (this.multicheck){
if (e.value){
this.value.push(e.name);
} else {
this.value.remove(e.name)
}
} else {
for (var i=0;i<this.input_boxs.length;i++){
var e1 = this.input_boxs[i];
if (e1 != e){
e1.setValue(false);
}
}
this.value = e.name;
console.log('this is singlecheck ....', this.value);
}
var o = {};
o[this.name] = this.value;
this.dispatch('changed', o);
}
resultValue(){
return this.value;
}
setValue(v){
var thisvalue = this.value;
if (Array.isArray(v)){
thisvalue = v;
} else {
thisvalue = [v];
}
for (var i=0; i<this.input_boxs.length; i++){
if (thisvalue.includes(this.data[i][this.valueField])){
this.input_boxs[i].setValue(true);
} else {
this.input_boxs[i].setValue(false);
}
}
}
}
bricks.UiDate =class extends bricks.UiStr {
/*
{
max_date:
min_date:
*/
constructor(options){
super(options);
this.uitype='date';
this.opts_setup();
}
opts_setup(){
var e = this.dom_element;
e.type = 'date';
if (this.opts.max_date){
e.max = this.opts.max_date;
}
if (this.opts.min_date){
e.min = this.opts.min_date;
}
}
resultValue(){
if (this.value == ''){
return null;
}
return this.value;
}
}
bricks.UiText =class extends bricks.UiType {
/*
{
name:
value:
defaultValue:
tip:
readonly:
required:
}
*/
constructor(opts){
opts.dynsize = opts.dynsize || true;
opts.cfontsize = opts.cfontsize || 1;
if (opts.css){
opts.css += ' inputbox auto-textarea';
} else {
opts.css = 'inputbox auto-textarea';
}
super(opts);
this.uitype='text';
this.build();
this.charsize_sizing();
this.bind('input', this.handleInput.bind(this));
this.bind('keydown', this.key_handle.bind(this));
}
handleInput() {
// 1. 记录原始滚动位置(防止光标跳动)
var el = this.dom_element;
const scrollTop = el.scrollTop;
// 2. 核心:先设为固定高度而非 auto
// 避免某些浏览器(如 Safari在 auto 切换时丢失滚动焦点
el.style.height = '0px';
// 3. 获取实时计算样式
const style = window.getComputedStyle(el);
const maxHeight = parseInt(style.maxHeight) || Infinity;
const minHeight = parseInt(style.minHeight) || 40;
// 4. 计算目标高度
// scrollHeight 在所有现代浏览器中都包含 padding
const targetHeight = el.scrollHeight;
if (targetHeight >= maxHeight) {
// 达到或超过最大高度
el.style.height = maxHeight + 'px';
el.style.overflowY = 'auto';
} else {
// 低于最大高度
el.style.height = Math.max(targetHeight, minHeight) + 'px';
el.style.overflowY = 'hidden';
}
// 5. 恢复滚动(解决 Chrome/Safari 偶尔的置顶 Bug
el.scrollTop = scrollTop;
}
create(){
this.dom_element = this._create('textarea');
}
build(){
var e = this.dom_element;
e.id = e.name = this.opts.name;
this.reset();
this.bind('input', this.set_value_from_input.bind(this))
}
set_value_from_input(event){
this.value = this.dom_element.value;
}
resultValue(){
var e = this.dom_element;
this.value = e.value;
return this.value;
}
setValue(v){
if (! v) v = '';
this.value = v;
this.dom_element.value = v;
debug('UiText: v=', v);
this.handleInput();
}
reset(){
var v = this.opts.value || this.opts.defaultvalue||'';
this.setValue(v);
}
key_handle(e){
switch(e.key){
case 'Tab':
e.preventDefault(); // 阻止默认Tab行为
var erase = false
if (e.shiftKey) erase = true;
this.handle_tab_indent(erase);
break;
case 'Enter':
e.preventDefault(); // 阻止默认行为
this.handle_enter();
break;
case 'ArrowUp':
case 'ArrowDown':
default:
break;
}
}
set_editor_focus(editor, pos){
editor.selectionStart = editor.selectionEnd = pos;
editor.focus();
}
handle_enter(){
var editor = this.dom_element;
const cursorPos = editor.selectionStart;
const value = editor.value;
const before = value.substring(0, cursorPos);
const after = value.substring(cursorPos);
editor.value = before + '\n' + after;
editor.selectionStart = editor.selectionEnd = cursorPos + 1;
editor.focus();
schedule_once(this.set_editor_focus.bind(this, editor, cursorPos+1), 0.5);
}
handle_tab_indent(erase){
/* erase == true : delete tabspace
else
add tabspace
*/
var editor = this.dom_element;
var indent_cnt;
const cursorPos = editor.selectionStart;
const value = editor.value;
// 获取光标所在行的开始位置
const beforeCursor = value.substring(0, cursorPos);
const lastLineStart = beforeCursor.lastIndexOf("\n") + 1; // 上一行的结束位置
const currentLineStart = lastLineStart; // 当前行的开始位置
const cur_col = cursorPos - currentLineStart;
var pos;
if (!erase){
indent_cnt = 4 - cur_col % 4;
if (indent_cnt == 0) indent_cnt = 4;
// 根据光标前的空格数动态插入合适数量的空格
const before = value.substring(0, cursorPos);
const after = value.substring(cursorPos);
const indentation = ' '.repeat(indent_cnt); // 生成合适数量的空格
editor.value = before + indentation + after;
// 更新光标位置(将光标移到插入的缩进后面)
pos = cursorPos + indent_cnt;
editor.selectionStart = editor.selectionEnd = cursorPos + indent_cnt;
} else {
indent_cnt = cur_col % 4;
if (indent_cnt == 0) indent_cnt = 4;
const before = value.substring(0, cursorPos - indent_cnt);
const after = value.substring(cursorPos);
editor.value = before + after;
pos = cursorPos - indent_cnt;
editor.selectionStart = editor.selectionEnd = cursorPos - indent_cnt;
}
editor.focus();
schedule_once(this.set_editor_focus.bind(this, editor, pos), 0.5);
}
}
bricks.UiCode =class extends bricks.UiType {
/*
{
name:
value:
valueField:
nullable:
textField:
defaultValue:
readonly:
required:
data:
dataurl:
params:
method:
}
*/
constructor(opts){
opts.cfontsize = opts.cfontsize||1;
opts.dynsize = opts.dynsize || true;
super(opts);
this.uitype='code';
this.data = this.opts.data;
this.build();
}
create(){
this.dom_element = this._create('select');
}
build(){
this.dom_element.id = this.opts.name;
this.dom_element.name = this.opts.name;
if (this.opts.dataurl){
schedule_once(this.get_data.bind(this), 0.01);
return;
}
this.build_options(this.opts.data);
}
async loadData(params){
var _params = bricks.extend({}, this.opts.params);
bricks.extend(_params, params);
await this.load_data(_params);
}
async get_data(event){
var params = this.opts.params;
if(event){
bricks.extend(params, event.params);
}
await this.load_data(params);
}
async load_data(params){
var jc = new bricks.HttpJson();
var d = await jc.httpcall(this.opts.dataurl,
{
method:this.opts.method || 'GET',
params : params
});
this.data = d;
this.build_options(d);
}
build_options(data){
var e = this.dom_element;
while(e.firstChild){
e.removeChild(e.firstChild);
}
var v = this.opts.value || this.opts.defaultvalue || null;
if (!v && ! this.opts.nullable && data.length > 0){
v = data[0][this.opts.valueField]
}
if (this.opts.nullable){
var tmp = {};
tmp[this.opts.valueField] = null;
tmp[this.opts.textField] = '';
data.unshift(tmp);
}
this.value = v;
e.value = v;
this.option_widgets = {};
for (var i=0; i<data.length; i++){
var o = document.createElement('option');
o.value = data[i][this.opts.valueField||'value'];
var txt = bricks.app.i18n._(data[i][this.opts.textField||'text']);
if (!txt) txt = data[i][this.opts.valueField||'value'];
o.innerText = txt;
this.option_widgets[o.value] = o;
if (o.value == v){
o.selected = true;
}
e.appendChild(o);
this.sizable_elements.push(o);
}
this.bind('input', this.set_value_from_input.bind(this))
this.charsize_sizing();
}
set_value_from_input(event){
this.value = this.dom_element.value;
this.dispatch('changed', this.getValue());
}
resultValue(){
return this.value;
}
setValue(v){
this.value = v;
for (var i=0; i<this.option_widgets.length; i++){
if (this.value == this.option_widgets[i].value){
this.option_widgets[i].checked = true
} else {
this.option_widgets[i].checked = true
}
}
}
reset(){
var v = this.opts.value||this.opts.defaultvalue||'';
this.setValue(v);
}
}
bricks._Input = class {
constructor(){
this.uitypes = [];
}
register(name, uitype,Klass){
if (! Klass){
bricks.debug('Klass not defined', name);
return;
}
bricks.Factory.register(name, Klass);
this.uitypes[uitype] = Klass;
}
factory(options){
var klass = this.uitypes[options.uitype];
if (klass){
return new klass(options);
}
bricks.debug('create input for:', options.uitype, 'failed', this.uitypes);
return null;
}
}
var Input = new bricks._Input();
Input.register('UiAudio', 'audiorecorder', bricks.UiAudio);
Input.register('UiStr', 'str', bricks.UiStr);
Input.register('UiHide', 'hide', bricks.UiHide);
Input.register('UiTel', 'tel', bricks.UiTel);
Input.register('UiDate', 'date', bricks.UiDate);
Input.register('UiInt', 'int', bricks.UiInt);
Input.register('UiFloat', 'float', bricks.UiFloat);
Input.register('UiCheck', 'check', bricks.UiCheck);
Input.register('UiCheckBox', 'checkbox', bricks.UiCheckBox);
Input.register('UiEmail', 'email', bricks.UiEmail);
Input.register('UiFile', 'file', bricks.UiFile);
Input.register('UiImage', 'image', bricks.UiImage);
Input.register('UiCode', 'code', bricks.UiCode);
Input.register('UiText', 'text', bricks.UiText);
Input.register('UiPassword', 'password', bricks.UiPassword);
Input.register('UiAudio', 'audio', bricks.UiAudio);
Input.register('UiVideo', 'video', bricks.UiVideo);
Input.register('UiAudio', 'audiotext', bricks.UiAudio);
Input.register('UiSearch', 'search', bricks.UiSearch);