UNPKG

tfp

Version:

A Web UI framework for TaskBuilder

633 lines (576 loc) 19.1 kB
const _parent = Symbol("parent"); /** * TaskUI组件基类 */ export class Component { constructor(__tfp, typeName, dataModel, parent) { if(!__tfp) { throw new Error("请提供tfp对象!"); return; } if(!typeName) { console.log(dataModel); throw new Error("请提供组件类型!"); return; } this._tfp = __tfp; this.level = 0; //组件相对页面组件的层次 this.index = 0; //组件在父组件中的索引,主要用来排序 //目前如果某个兄弟组件删除了,不会重置所有剩余的兄弟组件的索引 //如果没有提供数据模型,则进行模型初始化 if(!dataModel) { let metadata = this._tfp.type(typeName); if(!metadata) { throw new Error("请提供正确的组件类型!"); return; } this.dataModel = { type: typeName }; this.dataModel.id = this.dataModel.type.substr(0, 1).toLowerCase() +this.dataModel.type.substr(1)+this._tfp.getNewCptIndex(this.dataModel.type); let attrs = this.attrTypes; //设置组件默认属性 for(let i=0; i<attrs.length; i++) { let attr = attrs[i]; if(attr.default || attr.default==0 || attr.default==false) { if(attr.type.toLowerCase()=="string") { this.dataModel[attr.name] = attr.default.replace("{id}", this.id); } else { this.dataModel[attr.name] = attr.default; } } } //设置可视组件数据模型的默认样式 if(metadata.defaultStyles) { this.dataModel.styles = {}; for (let style in metadata.defaultStyles) { this.dataModel.styles[style] = metadata.defaultStyles[style]; } } } else { //否则用传入的数据模型 this.dataModel = dataModel; if(!this.dataModel.type) this.dataModel.type = typeName; } //设置组件数据模型的默认ID if(!this.dataModel.id) { this.dataModel.id = this.dataModel.type.substr(0, 1).toLowerCase() +this.dataModel.type.substr(1)+this._tfp.getNewCptIndex(this.dataModel.type); } this._tfp.components[this.dataModel.id] = this; if(this._tfp.isRuntime) window[this.dataModel.id] = this; //设置组件的父组件 if(parent) { this[_parent] = parent; this.level = parent.level+1; if(!this._tfp.isLoadingPage) { if(!parent.dataModel.components) parent.dataModel.components = []; let cptExists = false; for(var i=0;i<parent.dataModel.components.length;i++) { let cdmTmp = parent.dataModel.components[i]; if(cdmTmp.id == this.dataModel.id) { cptExists = true; continue; } if(cdmTmp.index>=this.index) this.index = cdmTmp.index + 1; } if(!cptExists) parent.dataModel.components.push(this.dataModel); } } else { //TODO 如果创建组件时没有提供父组件,则表示是临时组件,后续可以设置父组件 } } //组件ID,每个组件的ID是唯一的,不能重复 get id() { return this.dataModel.id } set id(value) { if(!value) return; let oldId = this.dataModel.id; if(oldId==value) return; for(let cptId in this._tfp.components) { if(cptId==value) { throw new Error("ID为的"+value+"组件已存在!"); return; } } this.dataModel.id = value; delete this._tfp.components[oldId]; this._tfp.components[this.dataModel.id] = this; if(this._tfp.isRuntime) { delete window[oldId]; window[this.dataModel.id] = this; } if($("#"+oldId).length>0) { $("#"+oldId).attr("id", this.dataModel.id); } } //组件类型,组件一旦创建,不允许再修改类型 get type() { return this.dataModel.type } set type(value) {} //组件类型元数据,组件一旦创建,不允许再修改 get metadata() { return this._tfp.type(this.dataModel.type) } set metadata(value) {} //父组件 get parent() { return this[_parent] } set parent(value) { //如果没有设置父组件 if(!this[_parent]) { this[_parent] = value; if(!this[_parent].dataModel.components) this[_parent].dataModel.components = []; this[_parent].dataModel.components.push(this.dataModel); } else { if(this[_parent].id!=value.id) { //如果已经设置了父组件,但新设置的父组件和原来的父组件不一样 this[_parent].dataModel.components.remove(this.dataModel); this[_parent] = value; if(!this[_parent].dataModel.components) this[_parent].dataModel.components = []; this[_parent].dataModel.components.push(this.dataModel); } else { //如果父组件没有变化,则不需要执行后续操作 return; } } //设置当前组件的层级和索引 this.level = this[_parent].level+1; for(var i=0;i<this[_parent].dataModel.components.length;i++) { let cdmTmp = this[_parent].dataModel.components[i]; if(cdmTmp.index>=this.index) this.index = cdmTmp.index + 1; } } get attrTypes() { let attrs = []; let metadata = this._tfp.type(this.type); if(metadata.attrs) { for(let i=0; i<metadata.attrs.length; i++) { let attr = metadata.attrs[i]; if(attr.type=="group" || attr.items) { for(let j=0;j<attr.items.length;j++) { attrs.push(attr.items[j]); } } else { attrs.push(attr); } } } return attrs; } set attrTypes(value) {} attr(attrName, attrValue) { if(arguments.length==0) return; //获取样式值 if(arguments.length==1) { return this[attrName]; } this[attrName] = attrValue; } /** * 获得属性定义信息 * @param {[type]} attrName [description] * @return {[type]} [description] */ getAttrTypeInfo(attrName) { if(!this.metadata) { throw new Error("没有找到组件类型定义信息,请先引用类型信息!"); return; } if(!this.metadata.attrs) { //throw new Error("没有找到组件的属性定义信息!"); return null; } for(var i=0;i<this.metadata.attrs.length;i++) { let attrInfo = this.metadata.attrs[i]; if(attrInfo.type=="group" || attrInfo.items) { for(var j=0;j<attrInfo.items.length;j++) { if(attrInfo.items[j].name==attrName) { return attrInfo.items[j]; } } } else { if(this.metadata.attrs[i].name==attrName) { return this.metadata.attrs[i]; } } } return null; } /** * 检查属性选项是否是组件类型定义中设置的选项 * @param {[type]} attrName [description] * @param {[type]} attrVal [description] * @return {[type]} [description] */ checkAttrOption(attrName, attrVal) { let attr = this.getAttrTypeInfo(attrName); if(!attr) return false; let options = attr.options; if(!options) return false; for(var i=0;i<options.length;i++) { if(options[i].value==attrVal) return true; } return false; } /** * 执行事件处理函数 * @param {[type]} eventName [description] * @return {[type]} [description] */ exeEventHandler(eventName) { //设计时不执行任何事件处理函数 if(this._tfp.isDesigning) return; let ret; if (this[eventName] && typeof this[eventName] == "function") { ret = this[eventName](arguments); } else if (this.dataModel[eventName]) { let funcStr = this.dataModel[eventName]; if(funcStr.indexOf("(")>0) { let funcName = funcStr.substr(0, funcStr.indexOf("(")); if(typeof(window[funcName])=="function") { let args = []; if(arguments.length>1) { for(var i=1;i<arguments.length;i++) { args.push(arguments[i]); } } let func = window[funcName]; ret = func.apply(window, args); } else { ret = eval(funcStr); } } else { ret = eval(funcStr); } } if(ret) return ret; } } export class InvisibleComponent extends Component{ constructor(__tfp, typeName, dataModel, parent) { super(__tfp, typeName, dataModel, parent); } get isInvisible() { return true } set isInvisible(value) {} render() { //如果是不可视组件,只有在设计时需要渲染 if(this._tfp.isDesigning) { window.parent.uiDesigner.addInvisibleComponent(this); this._tfp.initCptDesignSetting(this); } } } export class VisibleComponent extends Component{ constructor(__tfp, typeName, dataModel, parent) { super(__tfp, typeName, dataModel, parent); this._jqObj = null; this.el = null; this.isRendered = false; } get isInvisible() { return false } set isInvisible(value) {} get isContainer() { return false } set isContainer(value) {} get styles() { return this.dataModel.styles; } set styles(value) {} get style() { return this.dataModel.style; } set style(value) { if(!value) value = ""; this.dataModel.style = value; if(this._jqObj) { let style = value.trim(); if(style!="" && !style.endsWith(";")) style += ";"; if(this.dataModel.styles) { for(let styleTmp in this.dataModel.styles) { style += styleTmp +": "+this.dataModel.styles[styleTmp]+";"; } } //要保留设计时的外边框 let outline = this._jqObj.css("outline"); this._jqObj.attr("style", style); this._jqObj.css("outline", outline); } } get class() { return this.dataModel.class; } set class(value) { if(!value) value = ""; this.dataModel.class = value; if(this._jqObj) { this._jqObj.attr("class", value); } } get indent() { var _indent = ""; for(var i=0;i<this.level;i++) { _indent += "\t"; } return _indent; } set indent(value) {} css(styleName, styleValue) { if(arguments.length==0) return; //获取样式值 if(arguments.length==1) { if(!this.dataModel.styles) return null; return this.dataModel.styles[styleName]; } if(this._jqObj) this._jqObj.css(styleName, styleValue); if(!this.dataModel.styles) this.dataModel.styles = {}; if(styleValue=="" || styleValue==null) { delete this.dataModel.styles[styleName]; } else { this.dataModel.styles[styleName] = styleValue; } } val(value) { if(arguments.length==0) return this.value; this.value = value; } show() { if(this._jqObj) this._jqObj.show(); } hide() { if(this._jqObj) this._jqObj.hide(); } toggle() { if(this._jqObj) this._jqObj.toggle(); } focus() { if(this._jqObj) this._jqObj.focus(); } getHtmlIndent() { if(this.indent) return this.indent; let indent = ""; for(let i=0;i<this.level;i++) { indent += "\t"; } return indent; } render() { if((!this.parent || !this.parent.containerEl) && this.type!="Page") return; let Render = this._tfp.renders[this.type]; let render = new Render(this._tfp, this.dataModel, this.level); if(this.type=="Page") { if(this.dataModel.pageElId && this._tfp.isRuntime) { this._jqObj = $("#"+this.dataModel.pageElId); } else { this._jqObj = $("body"); } this._jqObj.append(render.getHtml()); this._tfp.curPage = this; } else { $(this.parent.containerEl).append(render.getHtml()); this._jqObj = $("#"+this.id); } if(this._jqObj.length>0) this.el = this._jqObj.get(0); if(!this.isRendered && this._tfp.isDesigning) { this._tfp.initCptDesignSetting(this); } if (typeof window != "undefined" && !this._tfp.isDesigning) { window[this.id] = this; } if(this.dataModel.components) { for(var i=0;i<this.dataModel.components.length;i++) { let cdmChild = this.dataModel.components[i]; let cptChild = this._tfp.render(cdmChild, this); } } if(this["initDesigning"]) this.initDesigning(); this.isRendered = true; } clear() { if(this.dataModel.components) { for(var i=0;i<this.dataModel.components.length;i++) { let childCdm = this.dataModel.components[i]; let child = this._tfp.get(childCdm.id); child.clear(); if(child._jqObj) child._jqObj.remove(); delete this._tfp.components[child.id]; } //this.dataModel.components = []; } } } //容器组件 export class ContainerComponent extends VisibleComponent{ constructor(__tfp, typeName, dataModel, parent) { super(__tfp, typeName, dataModel, parent); if(!this.dataModel.components) this.dataModel.components = []; } get isContainer() { return true } set isContainer(value) {} get containerEl() { return this.el } set containerEl(value) { this.el = value; } get components() { return this.dataModel.components } set components(value) {} /** * 添加子组件 * @param {[type]} cptChild [description] */ addChild(cptChild) { cptChild.parent = this; } /** * 移除子组件 * @param {[type]} cptId [description] * @return {[type]} [description] */ removeChild(cptId) { for(var i=0;i<this.dataModel.components.length;i++) { let childCdm = this.dataModel.components[i]; if(childCdm.id==cptId) { let child = this._tfp.components[childCdm.id]; child.clear(); if(child._jqObj) child._jqObj.remove(); if(this._tfp.isRuntime) { delete this._tfp.components[child.id]; delete window[child.id]; } child = null; childCdm = null; return; } } } /** * 清空子组件 * @return {[type]} [description] */ clearChildren() { for(var i=0;i<this.dataModel.components.length;i++) { let childCdm = this.dataModel.components[i]; let child = this._tfp.components[childCdm.id]; child.clear(); if(child._jqObj) child._jqObj.remove(); delete this._tfp.components[child.id]; if(this._tfp.isRuntime) delete window[child.id]; child = null; childCdm = null; } this.dataModel.components = []; } } //表单输入项组件 export class FormInput extends VisibleComponent{ constructor(__tfp, typeName, dataModel, parent) { super(__tfp, typeName, dataModel, parent); } get isFormInput() { return true } //组件备注 get comment() { return this.dataModel.comment } set comment(value) {this.dataModel.comment = value} //数据绑定格式 get dataBindingFormat() { return this.dataModel.dataBindingFormat } set dataBindingFormat(value) {this.dataModel.dataBindingFormat = value} //是否必填 get required() { return this.dataModel.required } set required(value) {this.dataModel.required = value ? true : false} //是否只读 get readonly() { return this.dataModel.readonly } set readonly(value) { this.dataModel.readonly = value ? true : false; if(!this.dataModel.readonly) delete this.dataModel.readonly; if(this._jqObj && this._jqObj.length>0 && !this._tfp.isDesigning) { let el = this._jqObj.get(0); if(el.tagName=="INPUT" || el.tagName=="SELECT" || el.tagName=="TEXTAREA") { el.readOnly = this.dataModel.readonly; } else if(el.tagName=="DIV") { this._jqObj.find("input").each(function(){ $(this).get(0).readOnly = this.dataModel.readonly; }); } } } //是否禁用 get disabled() { return this.dataModel.disabled } set disabled(value) { this.dataModel.disabled = value ? true : false; if(!this.dataModel.disabled) delete this.dataModel.disabled; if(this._jqObj && this._jqObj.length>0 && !this._tfp.isDesigning) { let el = this._jqObj.get(0); if(el.tagName=="INPUT" || el.tagName=="SELECT" || el.tagName=="TEXTAREA") { el.disabled = this.dataModel.disabled; } else if(el.tagName=="DIV") { this._jqObj.find("input").each(function(){ $(this).get(0).disabled = this.dataModel.disabled; }); } } } //自动计算表达式 get formula() { return this.dataModel.formula } set formula(value) { if(isNull(value)) { delete this.dataModel["formula"]; return; } this.dataModel.formula = value; } /** * 当值发生变化时 * @return {[type]} [description] */ valueOnChange() { this._tfp.iptValueOnChange(this); } /** * 执行计算表达式 * @return {[type]} [description] */ exeFormula() { if(!this.dataModel.formula) return; let val = this.dataModel.formula; let ipts = this.dataModel.formula.match(/\$\{[\w]+\}/g); for(let i=0;i<ipts.length;i++) { let iptId = ipts[i].substr(2, ipts[i].length-3); let ipt = this._tfp.components[iptId]; if(!ipt) continue; let iptVal = ipt.value; if(ipt.type=="Text" && isNull(iptVal)) { //如果是单行输入框,且数据类型不是文本,则值为空时,将值设置为0,以便计算 //不判断类型了,用户经常不设置类型 //if(ipt.dataType=="int" || ipt.dataType=="float" || ipt.dataType=="money") { iptVal = "0"; //} } else if(ipt.type=="DataSet") { iptVal = ipt.id; } val = val.replaceAll("\$\{"+iptId+"\}", iptVal); } try { this.value = eval(val); } catch(err) { console.error("执行计算表达式出错:"+err.message); } } /** * 设置输入项的选项 * @param {[type]} value [description] */ setOptions(value) { if(!value) return; let options = []; if(typeof(value)=="string") { let arr = value.split(","); for(var i=0;i<arr.length;i++) { let str = arr[i]; if(str.trim()!="") { options.push({ value: str, text: str }); } } } else if(Array.isArray(value)) { for(var i=0;i<value.length;i++) { let val = value[i]; if(Object.prototype.toString.call(val) === '[object Object]') { options.push(val); } else { options.push({ value: val, text: val }); } } } this.dataModel.options = options; } }