123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- /*
- * <<
- * 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<IEditorContainerProps, IEditorContainerStates> {
- private editor = React.createRef<HTMLDivElement>()
- public static SiderMinWidth = 250
- public static EditorMinHeight = 100
- public static DefaultPreviewHeight = 300
- public state: Readonly<IEditorContainerStates> = {
- 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<any>) => {
- const name = child.key as TEditorSubComponents
- if (name === 'ViewVariableList') {
- obj[name] = React.cloneElement<IViewVariableListProps>(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<IVariableModalProps>(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<ISqlPreviewProps>(child, { height: previewHeight })
- } else if (name === 'SqlEditor') {
- const { previewHeight } = state
- obj[name] = React.cloneElement<ISqlEditorProps>(child, { sizeChanged: previewHeight })
- } else {
- obj[name] = child
- }
- })
- return obj as Record<TEditorSubComponents, React.ReactElement<any>>
- }
- 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 (
- <>
- <div className={Styles.containerVertical} style={style}>
- <div className={Styles.sider} style={{ width: siderWidth }}>
- <Resizable
- axis="x"
- width={siderWidth}
- height={0}
- minConstraints={[EditorContainer.SiderMinWidth, 0]}
- maxConstraints={[EditorContainer.SiderMinWidth * 2, 0]}
- onResize={this.siderResize}
- >
- <div>{SourceTable}</div>
- </Resizable>
- </div>
- <div className={Styles.containerHorizontal}>
- <div className={Styles.containerHorizontal} ref={this.editor}>
- <div className={Styles.right} style={{ height: editorHeight - previewHeight }}>
- <Resizable
- axis="y"
- width={0}
- height={editorHeight - previewHeight}
- minConstraints={[0, EditorContainer.EditorMinHeight]}
- maxConstraints={[0, editorHeight]}
- onResize={this.previewResize}
- >
- <div className={Styles.containerVertical}>
- {SqlEditor}
- {ViewVariableList}
- </div>
- </Resizable>
- </div>
- <div className={Styles.preview} style={{ height: previewHeight }}>
- {SqlPreview}
- </div>
- </div>
- {EditorBottom}
- </div>
- </div>
- {VariableModal}
- </>
- )
- }
- }
- export default EditorContainer
|