tfp
Version:
A Web UI framework for TaskBuilder
296 lines (269 loc) • 11.6 kB
JavaScript
export default class TFPComponentRender {
constructor(__tfp, _dataModel, _level) {
if(!__tfp) {
throw new Error("请提供tfp对象!");
return;
}
if(!_dataModel) {
throw new Error("请提供组件数据模型!");
return;
}
this._tfp = __tfp;
this.dataModel = _dataModel;
this.metadata = this._tfp.type(this.dataModel.type);
this.level = 0; //组件相对页面组件的层次
if(_level) this.level = _level;
}
get cpt() {
return this._tfp.components[this.dataModel.id];
}
get isContainer() {
return this._tfp.components[this.dataModel.id].isContainer;
}
getHtmlIndent() {
return this.cpt.getHtmlIndent();
}
getAttrHtml(retainStyleAttr) {
let attrHtml = "";
let attrs = this.metadata.attrs;
let arrAttr = [];
for(let i=0;i<attrs.length;i++) {
let attrInfo = attrs[i];
if(attrInfo.type=="group") {
for(let j=0;j<attrInfo.items.length;j++) {
arrAttr.push(attrInfo.items[j]);
}
} else {
arrAttr.push(attrInfo);
}
}
for(let i=0;i<arrAttr.length;i++) {
let attrInfo = arrAttr[i];
if ((attrInfo.isHtmlAttr || attrInfo.attrName) && attrInfo.name in this.dataModel) {
let attrVal = this.dataModel[attrInfo.name];
if (!attrVal || attrVal == 0 || attrVal == false || attrVal == "false") continue;
//如果是特殊属性,则调用自定义方法获得属性html
if (attrInfo.special && this.getCustomAttrHtml) {
attrHtml += this.getCustomAttrHtml(attrInfo.name);
continue;
}
if (typeof (attrVal) == "string"
&& ((attrVal.indexOf("{") >= 0 && attrVal.indexOf("}") > 0)
|| (attrVal.indexOf("#[") >= 0 && attrVal.indexOf("]") > 0))) {
//如果不是设计时,并且不是组件值属性,则不渲染,但不包括在数据表格行里动态生成的组件
if (!(this._tfp.isDesigning && attrInfo.name == "value") && !retainStyleAttr) continue;
}
//设计时组件不能禁用,否则无法点击获得焦点
if (this._tfp.isDesigning && attrInfo.name == "disabled") continue;
if (attrInfo.name == "disabled" || attrInfo.name == "readonly") {
attrHtml += " " + attrInfo.name;
if (attrVal == false || attrVal == "false") attrHtml += "=\"false\"";
}
else {
var vvv = this.dataModel[attrInfo.name];
//HTML标签的属性名必须小写
if (attrInfo.attrName)
attrHtml += " " + attrInfo.attrName.toLowerCase() + "=\"" + vvv + "\"";
else
attrHtml += " " + attrInfo.name.toLowerCase() + "=\"" + vvv + "\"";
}
}
}
//事件
if(!this._tfp.isDesigning && this.metadata.events) {
for(var i=0;i<this.metadata.events.length;i++) {
let eventInfo = this.metadata.events[i];
//如果不是HTML事件,则忽略
if(eventInfo.isNotHtmlEvent) continue;
//input type=text 的onchange事件在代码里修改值不会触发,需要在各个组件里处理
//页面加载事件不能直接写在body标签的属性里,因为需要等tfp组件解析完毕
if(eventInfo.name.toLowerCase()=="onchange" ||
(this.cpt.type=="Page" && eventInfo.name.toLowerCase()=="onload")) continue;
for(let propName in this.dataModel) {
//事件名称忽略大小写
if(eventInfo.name.toLowerCase()==propName.toLowerCase()) {
let eventFunc = this.dataModel[propName];
//如果事件处理函数内有数据绑定表达式,则不渲染,但不包括在数据表格行里动态生成的组件
if (!retainStyleAttr && ((eventFunc.indexOf("{") >= 0 && eventFunc.indexOf("}") > 0)
|| (eventFunc.indexOf("#[") >= 0 && eventFunc.indexOf("]") > 0))) continue;
if (eventInfo.eventArgs != "")
if (eventFunc.indexOf("(") < 0 || eventFunc.indexOf(")") < 0) eventFunc += "()";
attrHtml += " " + eventInfo.name.toLowerCase() + "=\"" + eventFunc + "\"";
break;
}
}
}
}
return attrHtml;
}
/**
* 获得组件的样式HTML
* @param {Boolean} isGetHead [description]
* @param {[type]} retainStyleAttr 是否在组件的HTML标签的属性中保留CSS样式代码,
* 例如移动端数据表格组件的数据行里的子组件,因为是动态生成的,没有唯一的id
* @return {[type]} [description]
*/
getStyleHtml(isGetHead, retainStyleAttr) {
let styleHtml = "";
if(this.dataModel.styles) {
for(let styleName in this.dataModel.styles) {
styleHtml += " "+styleName+":"+this.dataModel.styles[styleName]+";";
}
}
if (this.dataModel.style
&& !((this.dataModel.style.indexOf("{") >= 0 && this.dataModel.style.indexOf("}") > 0)
|| (this.dataModel.style.indexOf("#[") >= 0 && this.dataModel.style.indexOf("]") > 0))) {
styleHtml += this.dataModel.style;
}
if(this.getCustomStyleHtml) styleHtml += this.getCustomStyleHtml();
if(this._tfp.isDesigning) {
styleHtml += "user-select:none;";
//设计时,如果容器组件没有设置边框,则为其添加一个轮廓线,以便查看
//不能直接设置border样式,因为会造成面板组件的内容宽度和高度与实际不一致
//导致设计时可能会出现滚动条,而实际运行时没有
if((this.isContainer || this.dataModel.components)
&& styleHtml.indexOf("border:")<0
&& styleHtml.indexOf("border-width:")<0)
styleHtml += "outline:#cccccc dashed 1px;";
}
//如果是在后台编译时获得样式信息,则将组件样式抽取到页面头部style标签中,以便统一查看
if(isGetHead) {
//
} else if(this._tfp.isDesigning || retainStyleAttr) {
styleHtml = " style=\""+styleHtml+" \"";
} else {
styleHtml = "";
}
return styleHtml;
}
getComponentsHtml(getComponentsHtml, indent, retainStyleAttr) {
let html = "";
if(!indent) indent = "";
for(var i=0;i<this.dataModel.components.length;i++) {
let cdm = this.dataModel.components[i];
let Render = this._tfp.renders[cdm.type];
if(!Render) continue;
let render = new Render(this._tfp, cdm, this.level+1);
html += render.getHtml(getComponentsHtml, indent, retainStyleAttr);
}
return html;
}
getHtml(tagName, getComponentsHtml, parentIndent, retainStyleAttr) {
if(!tagName) return "";
let indent = this.getHtmlIndent();
//有些容器组件由多级html元素构成,他们子组件的代码缩进
//需要根据父组件的容器元素的代码缩进进行相应的增加
if(parentIndent) {
indent = parentIndent+"\t";
this.indent = indent;
}
let cptHtml = indent+"<"+tagName+" id=\""+this.dataModel.id + "\" class=\"";
if (this._tfp.curPage.dataModel.client != "mini") {
cptHtml += "tfp-" + this.dataModel.type.toLowerCase().replace("_", "-");
if (this.getSpecialClass) cptHtml += this.getSpecialClass();
}
else {
cptHtml += "w-" + this.dataModel.id + " wx-" + this.dataModel.type.toLowerCase().replace("_", "-");
}
if (this.dataModel.class
&& !((this.dataModel.class.indexOf("{") >= 0 && this.dataModel.class.indexOf("}") > 0)
|| (this.dataModel.class.indexOf("#[") >= 0 && this.dataModel.class.indexOf("]") > 0))) {
cptHtml += " " + this.dataModel.class;
}
cptHtml += "\"";
cptHtml += this.getAttrHtml(retainStyleAttr)+this.getStyleHtml(false, retainStyleAttr);
if(this.getBodyHtml) {
cptHtml += ">";
cptHtml += this.getBodyHtml(getComponentsHtml, retainStyleAttr);
cptHtml += "</"+tagName+">\r\n";
} else if(this.isContainer || this.dataModel.components) {
cptHtml += ">\r\n";
if(getComponentsHtml && this.dataModel.components) {
cptHtml += this.getComponentsHtml(getComponentsHtml, indent, retainStyleAttr);
}
cptHtml += indent+"</"+tagName+">\r\n";
} else {
cptHtml += "/>\r\n";
}
return cptHtml;
}
getComponentsWX(getComponentsHtml, indent, retainStyleAttr, otherOptions) {
let wx = {
"wxjson": "",
"wxjs": "",
"wxml": "",
"wxss": ""
}
if (!indent) indent = "";
if (this.dataModel.components) {
for (var i = 0; i < this.dataModel.components.length; i++) {
let cdm = this.dataModel.components[i];
let Render = this._tfp.renders[cdm.type];
if (!Render) continue;
let render = new Render(this._tfp, cdm, this.level + 1);
var wx0 = render.getWX(getComponentsHtml, indent, retainStyleAttr, otherOptions);
wx.wxjson += wx0.wxjson;
wx.wxjs += wx0.wxjs;
wx.wxml += wx0.wxml;
wx.wxss += wx0.wxss;
}
}
return wx;
}
getWX(tagName, getComponentsHtml, parentIndent, retainStyleAttr, otherOptions) {
if (!tagName) return "";
let indent = this.getHtmlIndent();
//有些容器组件由多级html元素构成,他们子组件的代码缩进
//需要根据父组件的容器元素的代码缩进进行相应的增加
if (parentIndent) {
indent = parentIndent + "\t";
this.indent = indent;
}
var cpt_wx = {
"wxjson": "",
"wxjs": "",
"wxml": "",
"wxss": ""
}
cpt_wx.wxml += indent + "<" + tagName + "";
if (otherOptions && otherOptions.gridContainer)
cpt_wx.wxml += " id=\"" + this.dataModel.id + "_{{index}}\"";
else
cpt_wx.wxml += " id=\"" + this.dataModel.id + "\"";
cpt_wx.wxml += " class=\"";
cpt_wx.wxml += "w-" + this.dataModel.id + " ";
if (this._tfp.curPage.dataModel.client != "mini") {
cpt_wx.wxml += "tfp-" + this.dataModel.type.toLowerCase().replace("_", "-");
if (this.getSpecialClass) cpt_wx.wxml += this.getSpecialClass();
}
else {
cpt_wx.wxml += "wx-" + this.dataModel.type.toLowerCase().replace("_", "-");
}
if (this.dataModel.class
&& !((this.dataModel.class.indexOf("{") >= 0 && this.dataModel.class.indexOf("}") > 0)
|| (this.dataModel.class.indexOf("#[") >= 0 && this.dataModel.class.indexOf("]") > 0))) {
cpt_wx.wxml += " " + this.dataModel.class;
}
cpt_wx.wxml += "\"";
cpt_wx.wxml += this.getAttrHtml(retainStyleAttr, otherOptions) + this.getStyleHtml(false, retainStyleAttr, otherOptions);
if (this.getBodyWX) {
cpt_wx.wxml += ">";
var body_wx = this.getBodyWX(getComponentsHtml, retainStyleAttr, otherOptions);
cpt_wx.wxml += body_wx.wxml;
cpt_wx.wxml += "</" + tagName + ">\r\n";
cpt_wx.wxjs += body_wx.wxjs;
} else if (this.isContainer || this.dataModel.components) {
cpt_wx.wxml += ">\r\n";
if (getComponentsHtml && this.dataModel.components) {
var coms_wx = this.getComponentsWX(getComponentsHtml, indent, retainStyleAttr, otherOptions);
cpt_wx.wxml += coms_wx.wxml;
cpt_wx.wxjs += coms_wx.wxjs;
}
cpt_wx.wxml += indent;
cpt_wx.wxml += "</" + tagName + ">\r\n";
} else {
cpt_wx.wxml += "/>\r\n";
}
return cpt_wx;
}
}