From d03844c706544d8199d3197c078ca89b7e83dae7 Mon Sep 17 00:00:00 2001 From: "zude.hzd" Date: Sun, 19 Apr 2020 22:13:58 +0800 Subject: [PATCH] add source-editor pannel --- packages/demo/build.plugin.js | 12 + packages/demo/package.json | 2 + packages/demo/skeleton.config.js | 10 +- packages/demo/src/editor/config/components.js | 6 +- packages/demo/src/editor/config/skeleton.js | 28 +- packages/plugin-source-editor/CHANGELOG.md | 20 ++ packages/plugin-source-editor/README.md | 1 + packages/plugin-source-editor/build.json | 9 + packages/plugin-source-editor/package.json | 41 +++ packages/plugin-source-editor/src/index.scss | 23 ++ packages/plugin-source-editor/src/index.tsx | 246 ++++++++++++++++++ .../plugin-source-editor/src/transform.ts | 98 +++++++ packages/plugin-source-editor/tsconfig.json | 9 + 13 files changed, 497 insertions(+), 8 deletions(-) create mode 100644 packages/plugin-source-editor/CHANGELOG.md create mode 100644 packages/plugin-source-editor/README.md create mode 100644 packages/plugin-source-editor/build.json create mode 100644 packages/plugin-source-editor/package.json create mode 100644 packages/plugin-source-editor/src/index.scss create mode 100644 packages/plugin-source-editor/src/index.tsx create mode 100644 packages/plugin-source-editor/src/transform.ts create mode 100644 packages/plugin-source-editor/tsconfig.json diff --git a/packages/demo/build.plugin.js b/packages/demo/build.plugin.js index 0fbf67f53..50ac34ddd 100644 --- a/packages/demo/build.plugin.js +++ b/packages/demo/build.plugin.js @@ -1,4 +1,6 @@ const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); +const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); + module.exports = ({ onGetWebpackConfig }) => { onGetWebpackConfig((config) => { @@ -7,6 +9,16 @@ module.exports = ({ onGetWebpackConfig }) => { .use(TsconfigPathsPlugin, [{ configFile: "./tsconfig.json" }]); + + + config + // 定义插件名称 + .plugin('MonacoWebpackPlugin') + // 第一项为具体插件,第二项为插件参数 + .use(new MonacoWebpackPlugin({ + languages:["javascript","css","json"] + }), []); + config.plugins.delete('hot'); config.devServer.hot(false); }); diff --git a/packages/demo/package.json b/packages/demo/package.json index bd8af2d92..bdd8a4759 100644 --- a/packages/demo/package.json +++ b/packages/demo/package.json @@ -18,6 +18,7 @@ "@ali/lowcode-plugin-event-bind-dialog": "^0.8.0", "@ali/lowcode-plugin-outline-pane": "^0.8.7", "@ali/lowcode-plugin-sample-logo": "^0.8.0", + "@ali/lowcode-plugin-source-editor":"^0.8.2", "@ali/lowcode-plugin-sample-preview": "^0.8.6", "@ali/lowcode-plugin-settings-pane": "^0.8.8", "@ali/lowcode-plugin-undo-redo": "^0.8.0", @@ -41,6 +42,7 @@ "build-plugin-fusion": "^0.1.0", "build-plugin-moment-locales": "^0.1.0", "build-plugin-react-app": "^1.1.2", + "monaco-editor-webpack-plugin":"^1.9.0", "tsconfig-paths-webpack-plugin": "^3.2.0" } } diff --git a/packages/demo/skeleton.config.js b/packages/demo/skeleton.config.js index 4dd4cc1c0..b649fd023 100644 --- a/packages/demo/skeleton.config.js +++ b/packages/demo/skeleton.config.js @@ -83,17 +83,18 @@ module.exports = { pluginProps: { } }, + { - pluginKey: 'outlinePane', + pluginKey: 'soueceEditor', type: 'PanelIcon', props: { align: 'top', icon: 'shuxingkongjian', - title: '大纲树' + title: '源码面板' }, config: { - package: '@ali/lowcode-plugin-outline-pane', - version: '^0.8.0' + package: '@ali/lowcode-plugin-source-editor', + version: '^0.8.2' }, pluginProps: {} }, @@ -137,6 +138,7 @@ module.exports = { version: '^0.8.0' } } + ] }, hooks: [], diff --git a/packages/demo/src/editor/config/components.js b/packages/demo/src/editor/config/components.js index 9648a7faf..348e048b7 100644 --- a/packages/demo/src/editor/config/components.js +++ b/packages/demo/src/editor/config/components.js @@ -8,6 +8,7 @@ import zhEn from '@ali/lowcode-plugin-zh-en'; import settingsPane from '@ali/lowcode-plugin-settings-pane'; import designer from '@ali/lowcode-plugin-designer'; import eventBindDialog from '@ali/lowcode-plugin-event-bind-dialog'; +import sourceEditor from '@ali/lowcode-plugin-source-editor' export default { LowcodeSkeleton, logo, @@ -18,5 +19,6 @@ export default { zhEn, settingsPane, designer, - eventBindDialog -}; \ No newline at end of file + eventBindDialog, + sourceEditor +}; diff --git a/packages/demo/src/editor/config/skeleton.js b/packages/demo/src/editor/config/skeleton.js index 4a8e417cc..65d182436 100644 --- a/packages/demo/src/editor/config/skeleton.js +++ b/packages/demo/src/editor/config/skeleton.js @@ -90,7 +90,30 @@ export default { "version": "^0.8.0" }, "pluginProps": {} - }, { + }, + + { + "pluginKey": "sourceEditor", + "type": "PanelIcon", + "props": { + "align": "top", + "icon": "zujianku", + "title": "组件库", + "panelProps":{ + "floatable": true, + "defaultWidth":500 + + }, + + }, + "config": { + "package": "@ali/lowcode-plugin-source-editor", + "version": "^0.8.0" + }, + "pluginProps": {} + }, + + { "pluginKey": "zhEn", "type": "Custom", "props": { @@ -124,7 +147,8 @@ export default { "package": "@ali/lowcode-plugin-event-bind-dialog", "version": "^0.8.0" } - }] + }, + ] }, "hooks": [], "shortCuts": [], diff --git a/packages/plugin-source-editor/CHANGELOG.md b/packages/plugin-source-editor/CHANGELOG.md new file mode 100644 index 000000000..7c5e8d83c --- /dev/null +++ b/packages/plugin-source-editor/CHANGELOG.md @@ -0,0 +1,20 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + + +## [0.8.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-plugin-variable-bind-dialog@0.8.1...@ali/lowcode-plugin-variable-bind-dialog@0.8.2) (2020-03-30) + + + + +**Note:** Version bump only for package @ali/lowcode-plugin-source-editor + + +## 0.8.1 (2020-03-30) + + + + +**Note:** Version bump only for package @ali/lowcode-plugin-source-editor diff --git a/packages/plugin-source-editor/README.md b/packages/plugin-source-editor/README.md new file mode 100644 index 000000000..8a6fb13f0 --- /dev/null +++ b/packages/plugin-source-editor/README.md @@ -0,0 +1 @@ +## todo diff --git a/packages/plugin-source-editor/build.json b/packages/plugin-source-editor/build.json new file mode 100644 index 000000000..e791d5b6b --- /dev/null +++ b/packages/plugin-source-editor/build.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "build-plugin-component", + "build-plugin-fusion", + ["build-plugin-moment-locales", { + "locales": ["zh-cn"] + }] + ] +} diff --git a/packages/plugin-source-editor/package.json b/packages/plugin-source-editor/package.json new file mode 100644 index 000000000..19c1c9178 --- /dev/null +++ b/packages/plugin-source-editor/package.json @@ -0,0 +1,41 @@ +{ + "name": "@ali/lowcode-plugin-source-editor", + "version": "0.8.2", + "description": "alibaba lowcode editor source-editor plugin", + "files": [ + "es", + "lib" + ], + "main": "lib/index.js", + "module": "es/index.js", + "scripts": { + "build": "build-scripts build --skip-demo", + "test": "ava", + "test:snapshot": "ava --update-snapshots" + }, + "keywords": [ + "lowcode", + "editor" + ], + "author": "zude.hzd", + "dependencies": { + "@ali/lowcode-editor-core": "^0.8.0", + "@alifd/next": "^1.19.16", + "react": "^16.8.1", + "react-dom": "^16.8.1", + "prettier":"^1.18.2", + "js-beautify": "^1.10.1", + "react-monaco-editor": "^0.36.0" + }, + "devDependencies": { + "@alib/build-scripts": "^0.1.3", + "@types/react": "^16.9.13", + "@types/react-dom": "^16.9.4", + "build-plugin-component": "^0.2.7-1", + "build-plugin-fusion": "^0.1.0", + "build-plugin-moment-locales": "^0.1.0" + }, + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + } +} diff --git a/packages/plugin-source-editor/src/index.scss b/packages/plugin-source-editor/src/index.scss new file mode 100644 index 000000000..02b902227 --- /dev/null +++ b/packages/plugin-source-editor/src/index.scss @@ -0,0 +1,23 @@ +.source-editor-container{ + height: 100%; + + + .next-tabs { + -webkit-box-sizing: border-box; + box-sizing: border-box; + width: 100%; + height: 100%; + } + + .next-tabs-content{ + height: 100%; + } + + .next-tabs-tabpane.active { + visibility: visible; + opacity: 1; + height: 100%; + } + +} + diff --git a/packages/plugin-source-editor/src/index.tsx b/packages/plugin-source-editor/src/index.tsx new file mode 100644 index 000000000..f1dba0d4e --- /dev/null +++ b/packages/plugin-source-editor/src/index.tsx @@ -0,0 +1,246 @@ +import { Component, isValidElement, ReactElement, ReactNode } from 'react'; +import { Tab, Search, Input, Button } from '@alifd/next'; +import Editor from '@ali/lowcode-editor-core'; +import { js_beautify, css_beautify } from 'js-beautify'; +import MonacoEditor from 'react-monaco-editor'; + +// import lolizer from './sorceEditorPlugin', + +import { Designer } from '@ali/lowcode-designer'; +const TAB_KEY = { + JS_TAB: 'js_tab', + CSS_TAB: 'css_tab', +}; + +import './index.scss'; +import transfrom from './transform'; + +const defaultEditorOption = { + width: '100%', + height: '96%', + options: { + readOnly: false, + automaticLayout: true, + folding: true, //默认开启折叠代码功能 + lineNumbers: 'on', + wordWrap: 'off', + formatOnPaste: true, + fontSize: 12, + tabSize: 2, + scrollBeyondLastLine: false, + fixedOverflowWidgets: false, + snippetSuggestions: 'top', + minimap: { + enabled: false, + }, + scrollbar: { + vertical: 'auto', + horizontal: 'auto', + }, + } +}; + +export default class SourceEditor extends Component<{ + editor: Editor; +}> { + private monocoEditer:Object; + private editorCmd:Object; + + state = { + isShow: false, + tabKey: TAB_KEY.JS_TAB + } + + componentWillMount() { + const { editor } = this.props; + editor.on('leftPanel.show', (key: String) => { + if (key === 'sourceEditor' && !this.monocoEditer) { + this.setState({ + isShow: true, + }); + } + }); + + // 添加函数 + editor.on('sourceEditor.addFunction',(params:Object)=>{ + this.callEditorEvent('sourceEditor.addFunction',params); + }) + + editor.once('designer.mount', (designer: Designer) => { + // let schema = designer.project.getSchema(); + // mock data + let schema = { + componentTree: [ + { + state: { + // 初始state: 选填 对象类型/变量表达式 + btnText: 'submit', // 默认数据值: 选填 变量表达式 + }, + css: 'body {font-size: 12px;} .botton{widht:100px;color:#ff00ff}', //css样式描述: 选填 + lifeCycles: { + //生命周期: 选填 对象类型 + didMount: { + type: 'JSExpression', + value: "function() {\n \t\tconsole.log('did mount');\n\t}", + }, + willUnmount: { + type: 'JSExpression', + value: "function() {\n \t\tconsole.log('will umount');\n\t}", + }, + }, + methods: { + //自定义方法对象: 选填 对象类型 + testFunc: { + //自定义方法: 选填 函数类型 + type: 'JSExpression', + value: "function() {\n \t\tconsole.log('testFunc');\n \t}", + }, + }, + }, + ], + }; + + this.initCode(schema); + }); + + + setTimeout (()=>{ + editor.emit('sourceEditor.addFunction',{ + functionName:'testgaga' + }) + },3000) + + } + + callEditorEvent = (eventName,params) => { + if (!this.monocoEditer){ + this.editorCmd = { + eventName, + params + }; + return; + } + + if (eventName === 'sourceEditor.addFunction'){ + this.addFunction(params); + } + + } + + initCode = (schema) => { + let jsCode = js_beautify(transfrom.schema2Code(schema),{ indent_size: 2, indent_empty_lines: true }); + let css; + + if (schema.componentTree[0].css) { + css = css_beautify(schema.componentTree[0].css,{ indent_size: 2 }); + } + + this.setState({ + jsCode, + css, + selectTab: TAB_KEY.JS_TAB, + }); + + }; + + addFunction (params){ + const count = this.monocoEditer.getModel().getLineCount() || 0; + const range = new monaco.Range(count, 1, count, 1); + const functionCode = transfrom.getNewFunctionCode(params.functionName); + this.monocoEditer.executeEdits('log-source', [{ identifier: 'event_id', range:range , text: functionCode, forceMoveMarkers:true }]); + + this.updateCode(this.monocoEditer.getModel().getValue()) + } + + editorDidMount = (editor, monaco) => { + console.log('editorDidMount', editor); + this.monocoEditer = editor; + + if (this.editorCmd){ + this.callEditorEvent(this.editorCmd.eventName,this.editorCmd.params); + } + + // var commandId = editor.addCommand( + // 0, + // function() { + // // services available in `ctx` + // alert('my command is executing!'); + // }, + // '', + // ); + + // monaco.languages.registerCodeLensProvider('javascript', { + // provideCodeLenses: function(model, token) { + // return { + // lenses: [ + // { + // range: { + // startLineNumber: 1, + // startColumn: 1, + // endLineNumber: 1, + // endColumn: 1, + // }, + // id: 'First Line', + // command: { + // id: commandId, + // title: 'First Line', + // }, + // }, + // ], + // }; + // }, + // resolveCodeLens: function(model, codeLens, token) { + // return codeLens; + // }, + // }); + }; + + onTabChange = (key) => { + this.setState({ + selectTab: key, + }); + }; + + updateCode = (newCode) => { + const { selectTab } = this.state; + if (selectTab === TAB_KEY.JS_TAB) { + this.setState({ + jsCode: newCode, + }); + } else { + this.setState({ + css: newCode, + }); + } + + transfrom.code2Schema(newCode); + } + + render() { + const { isShow, selectTab, jsCode, css } = this.state; + const tabs = [ + { tab: 'index.js', key: TAB_KEY.JS_TAB }, + { tab: 'style.css', key: TAB_KEY.CSS_TAB }, + ]; + + return ( +
+ + {tabs.map((item) => ( + + {isShow && ( + this.updateCode(newCode)} + editorDidMount={this.editorDidMount} + /> + )} + + ))} + +
+ ); + } +} diff --git a/packages/plugin-source-editor/src/transform.ts b/packages/plugin-source-editor/src/transform.ts new file mode 100644 index 000000000..35a87934a --- /dev/null +++ b/packages/plugin-source-editor/src/transform.ts @@ -0,0 +1,98 @@ +import walkSourcePlugin from './sorceEditorPlugin'; + +const transfrom = { + schema2Code(schema: Object) { + let componentSchema = schema.componentTree[0]; + let code = +`export default class { + ${initStateCode(componentSchema)} + ${initLifeCycleCode(componentSchema)} + ${initMethodsCode(componentSchema)} +}`; + console.log(code); + return code; + }, + + code2Schema(code: String) { + + let newCode = code.replace(/export default class/,'class A'); + + let A,a; + try { + A = eval('('+newCode + ')'); + a = new A(); + }catch(e){ + return '' + } + + + let functionNameList = Object.getOwnPropertyNames(a.__proto__); + + let functionMap = {}; + + functionNameList.map((functionName)=>{ + if (functionName != 'constructor'){ + let functionCode = a[functionName].toString().replace(new RegExp(functionName),'function'); + functionMap[functionName] = functionCode; + } + }) + + console.log(JSON.stringify(a.state)); + + console.log(functionMap); + + }, + + getNewFunctionCode(functionName:String){ + return `\n\t${functionName}(){\n\t}\n` + } +}; + + +function initStateCode(componentSchema:Object) { + if (componentSchema.state){ + return `state = ${JSON.stringify(componentSchema.state)}` + } + + return ''; +} + +function initLifeCycleCode(componentSchema: Object) { + if (componentSchema.lifeCycles) { + let lifeCycles = componentSchema.lifeCycles; + let codeList = []; + + for (let key in lifeCycles) { + codeList.push(createFunctionCode(key, lifeCycles[key])); + } + + return codeList.join(''); + } else { + return ''; + } +} + +function initMethodsCode(componentSchema: Object) { + if (componentSchema.methods) { + let methods = componentSchema.methods; + let codeList = []; + + for (let key in methods) { + codeList.push(createFunctionCode(key, methods[key])); + } + + return codeList.join(''); + } else { + return ''; + } +} + +function createFunctionCode(functionName: String, functionNode: Object) { + if (functionNode.type === 'JSExpression') { + let functionCode = functionNode.value; + functionCode = functionCode.replace(/function/, functionName); + return functionCode; + } +} + +export default transfrom; diff --git a/packages/plugin-source-editor/tsconfig.json b/packages/plugin-source-editor/tsconfig.json new file mode 100644 index 000000000..c37b76ecc --- /dev/null +++ b/packages/plugin-source-editor/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": [ + "./src/" + ] +}