From 01e2b53a3f9a35dd41f6357d9fb0f2a0a41b8e9b Mon Sep 17 00:00:00 2001 From: Florian Rival Date: Sat, 10 Mar 2018 22:10:39 +0100 Subject: [PATCH] Improve GenericExpressionField performance --- .../GenericExpressionField/index.js | 55 ++++++++++--------- newIDE/app/src/UI/SemiControlledTextField.js | 21 ++++++- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/newIDE/app/src/EventsSheet/InstructionEditor/ParameterFields/GenericExpressionField/index.js b/newIDE/app/src/EventsSheet/InstructionEditor/ParameterFields/GenericExpressionField/index.js index 5a8d00463d..b8ffc085f2 100644 --- a/newIDE/app/src/EventsSheet/InstructionEditor/ParameterFields/GenericExpressionField/index.js +++ b/newIDE/app/src/EventsSheet/InstructionEditor/ParameterFields/GenericExpressionField/index.js @@ -1,12 +1,14 @@ -// @flow weak +// @flow import React, { Component } from 'react'; import ReactDOM from 'react-dom'; -import TextField from 'material-ui/TextField'; import Popover, { PopoverAnimationVertical } from 'material-ui/Popover'; import Functions from 'material-ui/svg-icons/editor/functions'; import RaisedButton from 'material-ui/RaisedButton'; +import SemiControlledTextField from '../../../../UI/SemiControlledTextField'; import ExpressionSelector from '../../InstructionOrExpressionSelector/ExpressionSelector'; -import ExpressionParametersEditorDialog from './ExpressionParametersEditorDialog'; +import ExpressionParametersEditorDialog, { + type ParameterValues, +} from './ExpressionParametersEditorDialog'; import { formatExpressionCall } from './FormatExpressionCall'; import { type InstructionOrExpressionInformation } from '../../InstructionOrExpressionSelector/InstructionOrExpressionInformation.flow.js'; const gd = global.gd; @@ -44,8 +46,8 @@ type State = {| |}; export default class ExpressionField extends Component<*, State> { - _field = null; - _fieldElement = null; + _field: ?any = null; + _fieldElement: ?any = null; _inputElement = null; state = { @@ -58,7 +60,7 @@ export default class ExpressionField extends Component<*, State> { componentDidMount() { if (this._field) { this._fieldElement = ReactDOM.findDOMNode(this._field); - this._inputElement = this._field.getInputNode(); + this._inputElement = this._field ? this._field.getInputNode() : null; } } @@ -72,34 +74,32 @@ export default class ExpressionField extends Component<*, State> { }); }; - _handleFocus = event => { + _handleFocus = (event: any) => { // This prevents ghost click. event.preventDefault(); }; - _handleBlur = () => { - this._doValidation(); - this.setState({ - popoverOpen: false, - }); - }; - _handleRequestClose = () => { this.setState({ popoverOpen: false, }); }; - _handleChange = (e, text) => { - if (this.props.onChange) this.props.onChange(text); + _handleChange = (value: string) => { + if (this.props.onChange) this.props.onChange(value); + + this._doValidation(value); + this.setState({ + popoverOpen: false, + }); }; - _handleMenuMouseDown = event => { + _handleMenuMouseDown = (event: any) => { // Keep the TextField focused event.preventDefault(); }; - _handleExpressionChosen = expressionInfo => { + _handleExpressionChosen = (expressionInfo: InstructionOrExpressionInformation) => { this.setState({ popoverOpen: false, parametersDialogOpen: true, @@ -107,7 +107,10 @@ export default class ExpressionField extends Component<*, State> { }); }; - insertExpression = (expressionInfo, parameterValues) => { + insertExpression = ( + expressionInfo: InstructionOrExpressionInformation, + parameterValues: ParameterValues + ) => { if (!this._inputElement) return; const cursorPosition = this._inputElement.selectionStart; @@ -133,14 +136,16 @@ export default class ExpressionField extends Component<*, State> { }, 5); }; - _getError = () => { + _getError = (value?: string) => { const { project, layout, expressionType } = this.props; const callbacks = new gd.CallbacksForExpressionCorrectnessTesting( project, layout ); - const parser = new gd.ExpressionParser(this.props.value); + const parser = new gd.ExpressionParser( + value === undefined ? this.props.value : value + ); const parseFunction = expressionType === 'string' @@ -161,8 +166,8 @@ export default class ExpressionField extends Component<*, State> { return isValid ? null : error; }; - _doValidation = () => { - this.setState({ errorText: this._getError() }); + _doValidation = (value?: string) => { + this.setState({ errorText: this._getError(value) }); }; render() { @@ -185,14 +190,14 @@ export default class ExpressionField extends Component<*, State> { return (
- (this._field = field)} onFocus={this._handleFocus} - onBlur={this._handleBlur} errorText={this.state.errorText} fullWidth /> diff --git a/newIDE/app/src/UI/SemiControlledTextField.js b/newIDE/app/src/UI/SemiControlledTextField.js index bc54386891..5efea3436d 100644 --- a/newIDE/app/src/UI/SemiControlledTextField.js +++ b/newIDE/app/src/UI/SemiControlledTextField.js @@ -6,6 +6,8 @@ type State = { focused: boolean, text: ?string, commitOnBlur?: boolean, + onFocus?: Function, + onBlur?: Function, }; /** @@ -20,18 +22,31 @@ export default class SemiControlledTextField extends React.Component<*, State> { text: null, }; + _field: ?any = null; + + focus() { + if (this._field) this._field.focus(); + } + + getInputNode() { + if (this._field) return this._field.getInputNode(); + } + render() { - const { value, onChange, commitOnBlur, ...otherProps } = this.props; + const { value, onChange, commitOnBlur, onFocus, onBlur, ...otherProps } = this.props; return ( this._field = field} value={this.state.focused ? this.state.text : value} - onFocus={() => { + onFocus={(event) => { this.setState({ focused: true, text: this.props.value, }); + + if (onFocus) onFocus(event); }} onChange={(event, newValue) => { this.setState({ @@ -46,6 +61,8 @@ export default class SemiControlledTextField extends React.Component<*, State> { focused: false, text: null, }); + + if (onBlur) onBlur(event); }} /> );