UNPKG

fastlion-amis

Version:

一种MIS页面生成工具

176 lines (152 loc) 4.02 kB
/** * @file 扩展 codemirror */ import type CodeMirror from 'codemirror'; import { eachTree } from '../../utils/helper'; import type { FormulaEditorProps, VariableItem } from './Editor'; export function editorFactory( dom: HTMLElement, cm: typeof CodeMirror, props: any ) { registerLaunguageMode(cm); return cm(dom, { value: props.value || '', autofocus: true, mode: props.evalMode ? 'text/formula' : 'text/formula-template' }); } export class FormulaPlugin { constructor( readonly editor: CodeMirror.Editor, readonly cm: typeof CodeMirror, readonly getProps: () => FormulaEditorProps ) { // editor.on('change', this.autoMarkText); this.autoMarkText(); } autoMarkText() { const { functions, variables, value } = this.getProps(); if (value) { // todo functions 也需要自动替换 this.autoMark(variables); } } insertContent(value: any, type: 'variable' | 'func') { const from = this.editor.getCursor(); if (type === 'variable') { this.editor.replaceSelection(value.key); var to = this.editor.getCursor(); this.markText(from, to, value.name, 'cm-field'); } else if (type === 'func') { // todo 支持 snippet,目前是不支持的 this.editor.replaceSelection(`${value}()`); var to = this.editor.getCursor(); this.markText( from, { line: to.line, ch: to.ch - 2 }, value, 'cm-func' ); this.editor.setCursor({ line: to.line, ch: to.ch - 1 }); } else if (typeof value === 'string') { this.editor.replaceSelection(value); } this.editor.focus(); } markText( from: CodeMirror.Position, to: CodeMirror.Position, label: string, className = 'cm-func' ) { const text = document.createElement('span'); text.className = className; text.innerText = label; this.editor.markText(from, to, { atomic: true, replacedWith: text }); } autoMark(variables: Array<VariableItem>) { if (!Array.isArray(variables) || !variables.length) { return; } const varMap: { [propname: string]: string; } = {}; eachTree( variables, item => item.value && (varMap[item.value] = item.label) ); const vars = Object.keys(varMap).sort((a, b) => b.length - a.length); const editor = this.editor; const lines = editor.lineCount(); for (let line = 0; line < lines; line++) { const content = editor.getLine(line); // 标记方法调用 content.replace(/([A-Z]+)\s*\(/g, (_, func, pos) => { this.markText( { line: line, ch: pos }, { line: line, ch: pos + func.length }, func, 'cm-func' ); return _; }); // 标记变量 vars.forEach(v => { let from = 0; let idx = -1; while (~(idx = content.indexOf(v, from))) { this.markText( { line: line, ch: idx }, { line: line, ch: idx + v.length }, varMap[v], 'cm-field' ); from = idx + v.length; } }); } } dispose() { } validate() { } } let modeRegisted = false; function registerLaunguageMode(cm: typeof CodeMirror) { if (modeRegisted) { return; } modeRegisted = true; // 对应 evalMode cm.defineMode('formula', (config: any, parserConfig: any) => { var formula = cm.getMode(config, 'javascript'); if (!parserConfig || !parserConfig.base) return formula; return cm.multiplexingMode(cm.getMode(config, parserConfig.base), { open: '${', close: '}', mode: formula }); }); cm.defineMIME('text/formula', { name: 'formula' }); cm.defineMIME('text/formula-template', { name: 'formula', base: 'htmlmixed' }); }