@lcap/asl
Version:
NetEase Application Specific Language
218 lines (204 loc) • 7.11 kB
text/typescript
import { action, circular, excludedInJSON, immutable } from '../decorators';
import { config, history, utils, LEVEL_ENUM, Vertex, PackageJSON, App, Page, DataNode, View, Element, Directive, ExpressionNode, Logic, genFinalCode, ActionOptions, ACTION_MODE } from '..';
import { elementService, attributeService, eventService, directiveService } from '../../service/page';
import { LogicItem, evaluate } from '../logic/LogicItem';
import { traverse } from '../utils';
function generateBody(body: Attr) {
if (body.expression) {
traverse((current) => {
delete current.node.editable;
delete current.node.index;
delete current.node.memberIdentifierSchema;
}, { node: body.expression as any }, { mode: 'anyObject' });
}
}
/**
* 前端组件属性
* 纯组件属性,不包含事件、指令等
* @examples
* - 纯字符串:color="primary"
* - 静态表达式::min="23"
* - 静态表达式::data="[{ text: '选项1', value: '选项1' }, { text: '选项2', value: '选项2' }]"
* - 动态表达式::expr="$utils.LowerCase(a + b)"
*/
export class Attr extends Vertex {
/**
* 概念类型
*/
()
public readonly level: LEVEL_ENUM = LEVEL_ENUM.attr;
/**
* 属性类型
*/
()
public readonly type: 'string' | 'static' | 'dynamic' = 'string';
/**
* 属性 Id
*/
()
public readonly id: string;
/**
* 属性名
*/
()
public readonly name: string;
/**
* 属性原始值
* 用户输入框中填入的值,同样也是 HTML 中 "" 中间的字符串
* 和 ASTElement 中的有区别
*/
()
public readonly value: string;
/**
* model 是否开启
*/
()
public readonly model?: boolean = false;
/**
* sync 是否开启
*/
()
public readonly sync?: boolean = false;
/**
* 关联的动态表达式
*/
()
public readonly expression?: ExpressionNode;
/**
* 所属元素 Id
*/
()
public readonly elementId: string;
/**
* 所属元素
*/
()
()
public readonly element: Element;
/**
* @param source 需要合并的部分参数
*/
constructor(source?: Partial<Attr>) {
super();
source && this.assign(source);
}
/**
* 转换成 Vue 的模板格式
*/
toVue(placeholder?: any, finalCode?: boolean) {
let value = this.value;
if (this.expression && this.type === 'dynamic') {
value = evaluate(this.expression, finalCode);
value && (value = genFinalCode(value, finalCode));
}
if (value !== undefined && value !== null && typeof value === 'string') {
value = value.replace(/"/g, '\'');
}
if (this.type === 'string') {
return value !== undefined && value !== null ? `${this.name}="${value}"` : '';
} else {
return value !== undefined && value !== null && value !== '' ? `:${this.name}${this.sync ? '.sync' : ''}="${value}"` : '';
}
}
/**
* 从后端 JSON 生成规范的 Attr 对象
*/
public static from(source: any, element: Element) {
const attr = new Attr(source);
attr.assign({ element });
return attr;
}
/**
* 添加组件属性
*/
('添加组件属性')
async create(none?: void, actionOptions?: ActionOptions) {
if (actionOptions?.actionMode === ACTION_MODE.local) {
this.element?.view?.emit('local-change');
return this;
}
config.defaultApp?.emit('saving');
if (actionOptions?.actionMode !== ACTION_MODE.undoRedo) {
const body = this.toJSON();
generateBody(body);
utils.logger.debug('添加组件属性', body);
const result: Attr = await attributeService.create({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'Attr.create',
operationDesc: actionOptions?.actionDesc || `添加组件"${this.element.tag}"属性"${this.name}"`,
},
body,
});
this.assign({ id: result });
}
this.element?.view?.emit('change');
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
return this;
}
/**
* 删除组件属性
*/
('删除组件属性')
async delete(none?: void, actionOptions?: ActionOptions) {
if (actionOptions?.actionMode === ACTION_MODE.local) {
const index = this.element.attrList.indexOf(this);
~index && this.element.attrList.splice(index, 1);
this.element?.view?.emit('local-change');
return this;
}
config.defaultApp?.emit('saving');
if (actionOptions?.actionMode !== ACTION_MODE.undoRedo) {
if (this.id) {
try {
await attributeService.delete({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'Attr.delete',
operationDesc: actionOptions?.actionDesc || `删除组件"${this.element.tag}"属性"${this.name}"`,
},
query: {
id: this.id,
},
});
} catch (err) {
await config.defaultApp?.history.load();
throw err;
}
}
}
const index = this.element.attrList.indexOf(this);
~index && this.element.attrList.splice(index, 1);
this.destroy();
this.element?.view?.emit('change');
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
}
/**
* 修改组件属性
*/
('修改组件属性')
async update(data?: Attr, actionOptions?: ActionOptions) {
config.defaultApp?.emit('saving');
data && this.assign(data);
if (actionOptions?.actionMode !== ACTION_MODE.undoRedo) {
const body = this.toJSON();
generateBody(body);
utils.logger.debug('修改组件属性', body);
await attributeService.update({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'Attr.update',
operationDesc: actionOptions?.actionDesc || `修改组件"${this.element.tag}"属性"${this.name}"`,
},
body,
});
}
this.element?.view?.emit('change');
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
return this;
}
}
export default Attr;