Merge branch 'fix/ducheng0907-bugs' into 'release/1.0.0'

fix: source-editor bug & exp-setter bug



See merge request !972619
This commit is contained in:
荣彬 2020-09-11 15:21:56 +08:00
commit 653dc7f9c8
5 changed files with 102 additions and 66 deletions

View File

@ -21,10 +21,11 @@ const helpMap = {
'utils': '应用工具对象', 'utils': '应用工具对象',
'dataSourceMap': '容器数据源Map', 'dataSourceMap': '容器数据源Map',
'field': '表单Field对象' 'field': '表单Field对象'
} };
export default class ExpressionView extends PureComponent { export default class ExpressionView extends PureComponent {
static displayName = 'Expression'; static displayName = 'Expression';
static propTypes = { static propTypes = {
context: PropTypes.object, context: PropTypes.object,
dataSource: PropTypes.array, dataSource: PropTypes.array,
@ -32,8 +33,9 @@ export default class ExpressionView extends PureComponent {
messages: PropTypes.object, messages: PropTypes.object,
onChange: PropTypes.func, onChange: PropTypes.func,
placeholder: PropTypes.string, placeholder: PropTypes.string,
value: PropTypes.string value: PropTypes.string,
}; };
static defaultProps = { static defaultProps = {
context: {}, context: {},
dataSource: [], dataSource: [],
@ -41,12 +43,17 @@ export default class ExpressionView extends PureComponent {
messages: zhCN, messages: zhCN,
onChange: () => {}, onChange: () => {},
placeholder: '', placeholder: '',
value: '' value: '',
}; };
expression: React.RefObject<unknown>; expression: React.RefObject<unknown>;
i18n: any; i18n: any;
t: void; t: void;
$input: any; $input: any;
listenerFun: ((event: any) => void) | undefined; listenerFun: ((event: any) => void) | undefined;
static getInitValue(val: { value: any; match: (arg0: RegExp) => any; }) { static getInitValue(val: { value: any; match: (arg0: RegExp) => any; }) {
@ -54,12 +61,13 @@ export default class ExpressionView extends PureComponent {
if (typeof val === 'object') { if (typeof val === 'object') {
return val.value; return val.value;
} else if (typeof val === 'string') { } else if (typeof val === 'string') {
let arr = val.match(/^\{\{(.*?)\}\}$/); const arr = val.match(/^\{\{(.*?)\}\}$/);
if (arr) return arr[1]; if (arr) return arr[1];
} }
} }
return val; return val;
} }
constructor(props: Readonly<{}>) { constructor(props: Readonly<{}>) {
super(props); super(props);
this.expression = React.createRef(); this.expression = React.createRef();
@ -67,33 +75,35 @@ export default class ExpressionView extends PureComponent {
this.state = { this.state = {
value: ExpressionView.getInitValue(props.value), value: ExpressionView.getInitValue(props.value),
context: props.context || {}, context: props.context || {},
dataSource: props.dataSource || [] dataSource: props.dataSource || [],
}; };
} }
static getDerivedStateFromProps(props: { value: any; }, state: { preValue: any; }) { static getDerivedStateFromProps(props: { value: any; }, state: { preValue: any; }) {
let curValue = ExpressionView.getInitValue(props.value); const curValue = ExpressionView.getInitValue(props.value);
if (curValue !== state.preValue) { if (curValue !== state.preValue) {
return { return {
preValue: curValue, preValue: curValue,
value: curValue value: curValue,
}; };
} }
return null; return null;
} }
onChange(value: string, actionType: string) { onChange(value: string, actionType: string) {
let realInputValue = value; let realInputValue = value;
let realDataSource = null; const realDataSource = null;
let nextCursorIndex: number; let nextCursorIndex: number;
// 更新值 // 更新值
if (actionType === 'itemClick' || actionType === 'enter') { if (actionType === 'itemClick' || actionType === 'enter') {
let curValue = this.state.value; const curValue = this.state.value;
if (curValue) { if (curValue) {
realInputValue = curValue + realInputValue; realInputValue = curValue + realInputValue;
} }
} }
// 更新数据源 // 更新数据源
let newState = { const newState = {
value: realInputValue value: realInputValue,
}; };
if (realDataSource !== null) newState.dataSource = realDataSource; if (realDataSource !== null) newState.dataSource = realDataSource;
this.setState(newState, () => { this.setState(newState, () => {
@ -106,7 +116,7 @@ export default class ExpressionView extends PureComponent {
// realInputValue = realInputValue ? `{{${realInputValue}}}` : undefined; // realInputValue = realInputValue ? `{{${realInputValue}}}` : undefined;
onChange && onChange({ onChange && onChange({
type: 'JSExpression', type: 'JSExpression',
value: realInputValue value: realInputValue,
}); });
}, 300); }, 300);
} }
@ -116,23 +126,33 @@ export default class ExpressionView extends PureComponent {
* @param {String} * @param {String}
* @return {Array} * @return {Array}
*/ */
getDataSource(tempStr: string): Array<any> { getDataSource(tempStr: string): any[] {
if (/[^\w\.]$/.test(tempStr)) { const {editor} = this.props.field;
return []; const schema = editor.get('designer').project.getSchema();
} else if (tempStr === null || tempStr === '') { const stateMap = schema.componentsTree[0].state;
return this.getContextKeys([]); let dataSource = [];
} else if (/\w\.$/.test(tempStr)) {
let currentField = this.getCurrentFiled(tempStr); for (let key in stateMap){
if (!currentField) return null; dataSource.push(`this.state.${key}`);
let tempKeys = this.getObjectKeys(currentField.str);
tempKeys = this.getContextKeys(tempKeys);
if (!tempKeys) return null;
return tempKeys;
} else if (/\.$/.test(tempStr)) {
return [];
} else {
return null;
} }
// if (/[^\w\.]$/.test(tempStr)) {
// return [];
// } else if (tempStr === null || tempStr === '') {
// return this.getContextKeys([]);
// } else if (/\w\.$/.test(tempStr)) {
// const currentField = this.getCurrentFiled(tempStr);
// if (!currentField) return null;
// let tempKeys = this.getObjectKeys(currentField.str);
// tempKeys = this.getContextKeys(tempKeys);
// if (!tempKeys) return null;
// return tempKeys;
// } else if (/\.$/.test(tempStr)) {
// return [];
// } else {
// return null;
// }
return dataSource;
} }
/** /**
@ -143,10 +163,10 @@ export default class ExpressionView extends PureComponent {
getCurrentFiled(str: string | any[]) { getCurrentFiled(str: string | any[]) {
str += 'x'; // .后面加一个x字符便于acorn解析 str += 'x'; // .后面加一个x字符便于acorn解析
try { try {
let astTree = acorn.parse(str); const astTree = acorn.parse(str);
let right = astTree.body[0].expression.right || astTree.body[0].expression; const right = astTree.body[0].expression.right || astTree.body[0].expression;
if (right.type === 'MemberExpression') { if (right.type === 'MemberExpression') {
let { start, end } = right; const { start, end } = right;
str = str.slice(start, end); str = str.slice(start, end);
return { str, start, end }; return { str, start, end };
} }
@ -161,7 +181,7 @@ export default class ExpressionView extends PureComponent {
* @return {Array} * @return {Array}
*/ */
getContextKeys(keys: []) { getContextKeys(keys: []) {
const editor = this.props.field.editor; const { editor } = this.props.field;
console.log(editor); console.log(editor);
const limitKeys = ['schema', 'utils', 'constants']; const limitKeys = ['schema', 'utils', 'constants'];
if (keys.length === 0) return limitKeys; if (keys.length === 0) return limitKeys;
@ -176,7 +196,7 @@ export default class ExpressionView extends PureComponent {
if (keyValue[item]) { if (keyValue[item]) {
keyValue = keyValue[item]; keyValue = keyValue[item];
} }
}) });
if (assert) return []; if (assert) return [];
result = Object.keys(keyValue); result = Object.keys(keyValue);
return result; return result;
@ -185,7 +205,7 @@ export default class ExpressionView extends PureComponent {
/* 过滤key */ /* 过滤key */
filterKey(obj: any, name: string) { filterKey(obj: any, name: string) {
let filterKeys = [ const filterKeys = [
'reloadDataSource', 'reloadDataSource',
'REACT_HOT_LOADER_RENDERED_GENERATION', 'REACT_HOT_LOADER_RENDERED_GENERATION',
'refs', 'refs',
@ -194,10 +214,10 @@ export default class ExpressionView extends PureComponent {
'isReactComponent', 'isReactComponent',
'forceUpdate', 'forceUpdate',
'setState', 'setState',
'isPureReactComponent' 'isPureReactComponent',
]; ];
let result = []; const result = [];
for (let key in obj) { for (const key in obj) {
if (key.indexOf('_') !== 0 && filterKeys.indexOf(key) === -1) { if (key.indexOf('_') !== 0 && filterKeys.indexOf(key) === -1) {
result.push(`${name}.${key}`); result.push(`${name}.${key}`);
} }
@ -213,8 +233,8 @@ export default class ExpressionView extends PureComponent {
*/ */
filterOption(inputValue: string, item: { value: string | any[]; }) { filterOption(inputValue: string, item: { value: string | any[]; }) {
const cursorIndex = this.getInputCursorPosition(); const cursorIndex = this.getInputCursorPosition();
let preStr = inputValue.substr(0, cursorIndex); const preStr = inputValue.substr(0, cursorIndex);
let lastKey: string[] = preStr.split('.').slice(-1); const lastKey: string[] = preStr.split('.').slice(-1);
if (!lastKey) return true; if (!lastKey) return true;
if (item.value.indexOf(lastKey) > -1) return true; if (item.value.indexOf(lastKey) > -1) return true;
return false; return false;
@ -228,11 +248,11 @@ export default class ExpressionView extends PureComponent {
const { value, dataSource } = this.state; const { value, dataSource } = this.state;
const { placeholder } = this.props; const { placeholder } = this.props;
const isValObject = !!(value == '[object Object]'); const isValObject = !!(value == '[object Object]');
let title = isValObject const title = isValObject
? this.i18n('valueIllegal') ? this.i18n('valueIllegal')
: (value || placeholder || this.i18n('jsExpression')).toString(); : (value || placeholder || this.i18n('jsExpression')).toString();
const cursorIndex = this.getInputCursorPosition(); const cursorIndex = this.getInputCursorPosition();
let childNode = cursorIndex ? ( const childNode = cursorIndex ? (
<div className="cursor-blink"> <div className="cursor-blink">
{title.substr(0, cursorIndex)} {title.substr(0, cursorIndex)}
<b>|</b> <b>|</b>
@ -264,7 +284,7 @@ export default class ExpressionView extends PureComponent {
innerAfter={<span style={{ color: '#999', marginRight: 4 }}>{'}}'}</span>} innerAfter={<span style={{ color: '#999', marginRight: 4 }}>{'}}'}</span>}
popupClassName="expression-setter-item-inner" popupClassName="expression-setter-item-inner"
itemRender={({ value }) => { itemRender={({ value }) => {
console.log(value); console.log('111:'+value);
return ( return (
<Option key={value} text={value} value={value}> <Option key={value} text={value} value={value}>
<div className="code-input-value">{value}</div> <div className="code-input-value">{value}</div>
@ -289,12 +309,12 @@ export default class ExpressionView extends PureComponent {
this.$input = this.findInputElement(); this.$input = this.findInputElement();
if (this.$input) { if (this.$input) {
this.listenerFun = event => { this.listenerFun = event => {
let isMoveKey = !!(event.type == 'keyup' && ~[37, 38, 39, 91].indexOf(event.keyCode)); const isMoveKey = !!(event.type == 'keyup' && ~[37, 38, 39, 91].indexOf(event.keyCode));
let isMouseup = event.type == 'mouseup'; const isMouseup = event.type == 'mouseup';
if (isMoveKey || isMouseup) { if (isMoveKey || isMouseup) {
let dataSource = this.getDataSource(this.state.value) || []; const dataSource = this.getDataSource(this.state.value) || [];
this.setState({ this.setState({
dataSource dataSource,
}); });
} }
}; };
@ -302,18 +322,21 @@ export default class ExpressionView extends PureComponent {
this.$input.addEventListener('mouseup', this.listenerFun, false); this.$input.addEventListener('mouseup', this.listenerFun, false);
} }
} }
componentWillUnmount() { componentWillUnmount() {
if (this.listenerFun && this.$input) { if (this.listenerFun && this.$input) {
this.$input.removeEventListener('keyup', this.listenerFun, false); this.$input.removeEventListener('keyup', this.listenerFun, false);
this.$input.removeEventListener('mouseup', this.listenerFun, false); this.$input.removeEventListener('mouseup', this.listenerFun, false);
} }
} }
/** /**
* Input输入框DOM节点 * Input输入框DOM节点
*/ */
findInputElement() { findInputElement() {
return this.expression.current.children[0].getElementsByTagName('input')[0]; return this.expression.current.children[0].getElementsByTagName('input')[0];
} }
/** /**
* *
* *
@ -322,6 +345,7 @@ export default class ExpressionView extends PureComponent {
if (!this.$input) return; if (!this.$input) return;
return this.$input.selectionStart; return this.$input.selectionStart;
} }
/* /*
* keys * keys
*/ */
@ -330,6 +354,7 @@ export default class ExpressionView extends PureComponent {
if (str) keys = str.split('.'); if (str) keys = str.split('.');
return keys.slice(0, keys.length - 1); return keys.slice(0, keys.length - 1);
} }
/* /*
* input组件光标位置在闭合} * input组件光标位置在闭合}
*/ */

View File

@ -1,6 +1,6 @@
{ {
"name": "@ali/lowcode-plugin-source-editor", "name": "@ali/lowcode-plugin-source-editor",
"version": "1.0.8-0", "version": "1.0.8-beta-1",
"description": "alibaba lowcode editor source-editor plugin", "description": "alibaba lowcode editor source-editor plugin",
"files": [ "files": [
"es", "es",

View File

@ -13,6 +13,12 @@
height: 100%; height: 100%;
} }
.button-container{
position: absolute;
top: 0px;
right: 10px;
}
.editor-context-container{ .editor-context-container{
height: 100%; height: 100%;
width: 100%; width: 100%;

View File

@ -1,5 +1,5 @@
import { Component, isValidElement, ReactElement, ReactNode } from 'react'; import { Component, isValidElement, ReactElement, ReactNode } from 'react';
import { Tab, Search, Input, Button } from '@alifd/next'; import { Tab, Search, Input, Button,Message } from '@alifd/next';
import { Editor } from '@ali/lowcode-editor-core'; import { Editor } from '@ali/lowcode-editor-core';
import { js_beautify, css_beautify } from 'js-beautify'; import { js_beautify, css_beautify } from 'js-beautify';
import MonacoEditor from 'react-monaco-editor'; import MonacoEditor from 'react-monaco-editor';
@ -15,7 +15,7 @@ import transfrom from './transform';
const defaultEditorOption = { const defaultEditorOption = {
width: '100%', width: '100%',
height: '100%', height: '95%',
options: { options: {
readOnly: false, readOnly: false,
automaticLayout: true, automaticLayout: true,
@ -56,11 +56,13 @@ export default class SourceEditor extends Component<{
state = { state = {
isFullScreen:false, isFullScreen:false,
tabKey: TAB_KEY.JS_TAB, tabKey: TAB_KEY.JS_TAB,
isShowSaveBtn:true
}; };
componentWillMount() { componentWillMount() {
const { editor } = this.props; const { editor } = this.props;
// 添加函数 // 添加函数
editor.on('sourceEditor.addFunction', (params: FunctionEventParam) => { editor.on('sourceEditor.addFunction', (params: FunctionEventParam) => {
this.callEditorEvent('sourceEditor.addFunction', params); this.callEditorEvent('sourceEditor.addFunction', params);
@ -71,9 +73,6 @@ export default class SourceEditor extends Component<{
this.callEditorEvent('sourceEditor.focusByFunction', params); this.callEditorEvent('sourceEditor.focusByFunction', params);
}); });
// 插件面板关闭事件,监听规则同上 // 插件面板关闭事件,监听规则同上
editor.on('skeleton.panel-dock.unactive',(pluginName,dock)=>{ editor.on('skeleton.panel-dock.unactive',(pluginName,dock)=>{
if (pluginName == 'sourceEditor'){ if (pluginName == 'sourceEditor'){
@ -269,21 +268,22 @@ export default class SourceEditor extends Component<{
}; };
saveSchema = () => { saveSchema = (successFlag) => {
const {jsCode} = this.state; const {jsCode} = this.state;
const {editor} = this.props; const {editor} = this.props;
let functionMap = transfrom.code2Schema(jsCode); let functionMap = transfrom.code2Schema(jsCode);
let schema = editor.get('designer').project.getSchema(); let schema = editor.get('designer').project.getSchema();
let oldSchemaStr = JSON.stringify(schema); //let oldSchemaStr = JSON.stringify(schema);
let newSchema = transfrom.setFunction2Schema(functionMap, schema); let newSchema = transfrom.setFunction2Schema(functionMap, schema);
if (newSchema!='' && JSON.stringify(newSchema) != oldSchemaStr){ if (newSchema!=''){
editor.get('designer').project.setSchema(newSchema); editor.get('designer').project.setSchema(newSchema);
successFlag && Message.success('保存成功')
} }
} }
render() { render() {
const { selectTab, jsCode, css } = this.state; const { selectTab, jsCode, css ,isShowSaveBtn} = this.state;
const tabs = [ const tabs = [
{ tab: 'index.js', key: TAB_KEY.JS_TAB }, { tab: 'index.js', key: TAB_KEY.JS_TAB },
{ tab: 'style.css', key: TAB_KEY.CSS_TAB }, { tab: 'style.css', key: TAB_KEY.CSS_TAB },
@ -291,12 +291,13 @@ export default class SourceEditor extends Component<{
return ( return (
<div className="source-editor-container"> <div className="source-editor-container">
<Tab size="small" shape="wrapped" onChange={this.onTabChange} activeKey={selectTab}> <Tab size="small" shape="wrapped" onChange={this.onTabChange} activeKey={selectTab}>
{tabs.map((item) => ( {tabs.map((item) => (
<Tab.Item key={item.key} title={item.tab} /> <Tab.Item key={item.key} title={item.tab} />
))} ))}
</Tab> </Tab>
{ isShowSaveBtn && <div className="button-container"><Button type="primary" onClick={()=>this.saveSchema(successFlag)}></Button></div>}
<div style={{ height: '100%' }} className="editor-context-container"> <div style={{ height: '100%' }} className="editor-context-container">
<div id="jsEditorDom" className="editor-context" ref={this.editorJsRef}> <div id="jsEditorDom" className="editor-context" ref={this.editorJsRef}>

View File

@ -55,6 +55,10 @@ const transfrom = {
setFunction2Schema(functionMap,schema){ setFunction2Schema(functionMap,schema){
let pageNode = schema.componentsTree[0]; let pageNode = schema.componentsTree[0];
// 先清除原有的schema的值
delete pageNode.state;
pageNode.lifeCycles = {};
pageNode.methods = {};
if (!pageNode) return ''; if (!pageNode) return '';
for (let key in functionMap){ for (let key in functionMap){
if (key == 'state'){ if (key == 'state'){