/* * << * Davinci * == * Copyright (C) 2016 - 2017 EDP * == * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * >> */ import React from 'react' import { uuid } from 'utils/util' import { IViewVariable } from '../types' import { Resizable, ResizeCallbackData } from 'libs/react-resizable' import { ISqlEditorProps } from './SqlEditorByAce' import { IViewVariableListProps } from './ViewVariableList' import { IVariableModalProps } from './VariableModal' import { ISqlPreviewProps } from './SqlPreview' import Styles from '../View.less' type TEditorSubComponents = 'SourceTable' | 'SqlEditor' | 'ViewVariableList' | 'VariableModal' | 'SqlPreview' | 'EditorBottom' interface IEditorContainerProps { visible: boolean variable: IViewVariable[] children?: React.ReactNode onVariableChange: (variable: IViewVariable[]) => void } interface IEditorContainerStates { editorHeight: number siderWidth: number previewHeight: number variableModalVisible: boolean editingVariable: IViewVariable } export class EditorContainer extends React.Component { private editor = React.createRef() public static SiderMinWidth = 250 public static EditorMinHeight = 100 public static DefaultPreviewHeight = 300 public state: Readonly = { editorHeight: 0, siderWidth: EditorContainer.SiderMinWidth, previewHeight: EditorContainer.DefaultPreviewHeight, variableModalVisible: false, editingVariable: null } public componentDidMount () { window.addEventListener('resize', this.setEditorHeight, false) // @FIX for this init height, 64px is the height of the hidden navigator in Main.tsx const editorHeight = this.editor.current.clientHeight this.setState({ editorHeight }) } public componentWillUnmount () { window.removeEventListener('resize', this.setEditorHeight, false) } public setEditorHeight = () => { const editorHeight = this.editor.current.clientHeight const { previewHeight, editorHeight: oldEditorHeight } = this.state const newPreviewHeight = Math.min(Math.floor(previewHeight * (editorHeight / oldEditorHeight)), editorHeight) this.setState({ editorHeight, previewHeight: newPreviewHeight }) } private siderResize = (_: any, { size }: ResizeCallbackData) => { const { width } = size this.setState({ siderWidth: width }) } private previewResize = (_: any, { size }: ResizeCallbackData) => { const { height } = size this.setState(({ editorHeight }) => ({ previewHeight: editorHeight - height })) } private addVariable = () => { this.setState({ editingVariable: null, variableModalVisible: true }) } private saveVariable = (updatedVariable: IViewVariable) => { const { variable, onVariableChange } = this.props const updatedViewVariables = [...variable] if (!updatedVariable.key) { updatedVariable.key = uuid(5) updatedViewVariables.push(updatedVariable) } else { const idx = variable.findIndex((v) => v.key === updatedVariable.key) updatedViewVariables[idx] = updatedVariable } onVariableChange(updatedViewVariables) this.setState({ variableModalVisible: false }) } private deleteVariable = (key: string) => { const { variable, onVariableChange } = this.props const updatedViewVariables = variable.filter((v) => v.key !== key) onVariableChange(updatedViewVariables) } private editVariable = (variable: IViewVariable) => { this.setState({ editingVariable: variable, variableModalVisible: true }) } private variableNameValidate = (key: string, name: string, callback: (msg?: string) => void) => { const { variable } = this.props const existed = variable.findIndex((v) => ((!key || v.key !== key) && v.name === name)) >= 0 if (existed) { callback('名称不能重复') return } callback() } private closeVariableModal = () => { this.setState({ variableModalVisible: false }) } private getChildren = (props: IEditorContainerProps, state: IEditorContainerStates) => { const obj = {} React.Children.forEach(props.children, (child: React.ReactElement) => { const name = child.key as TEditorSubComponents if (name === 'ViewVariableList') { obj[name] = React.cloneElement(child, { className: Styles.viewVariable, onAdd: this.addVariable, onDelete: this.deleteVariable, onEdit: this.editVariable }) } else if (name === 'VariableModal') { const { variableModalVisible, editingVariable } = this.state obj[name] = React.cloneElement(child, { visible: variableModalVisible, variable: editingVariable, nameValidator: this.variableNameValidate, onCancel: this.closeVariableModal, onSave: this.saveVariable }) } else if (name === 'SqlPreview') { const { previewHeight } = state obj[name] = React.cloneElement(child, { height: previewHeight }) } else if (name === 'SqlEditor') { const { previewHeight } = state obj[name] = React.cloneElement(child, { sizeChanged: previewHeight }) } else { obj[name] = child } }) return obj as Record> } public render () { const { visible } = this.props const { editorHeight, siderWidth, previewHeight } = this.state const style = visible ? {} : { display: 'none' } const { SourceTable, SqlEditor, SqlPreview, EditorBottom, ViewVariableList, VariableModal } = this.getChildren(this.props, this.state) return ( <>
{SourceTable}
{SqlEditor} {ViewVariableList}
{SqlPreview}
{EditorBottom}
{VariableModal} ) } } export default EditorContainer