Merge pull request #5733 from vvlladd28/bugs/json-form/full-screen

[3.3.3] UI: Fixed incorrect work buttons in fullscreen mode at json-form
This commit is contained in:
Igor Kulikov 2021-12-16 17:18:48 +02:00 committed by GitHub
commit 2caa534802
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 62 deletions

View File

@ -15,8 +15,9 @@
limitations under the License. limitations under the License.
--> -->
<div class="tb-json-form" style="background: #fff;" tb-fullscreen [fullscreenElement]="targetFullscreenElement" <div class="tb-json-form" style="background: #fff;" tb-fullscreen [fullscreenElement]="reactFullscreen"
[fullscreen]="isFullscreen" [fullscreen]="isFullscreen"
(fullscreenChanged)="onFullscreenChanged($event)"> (fullscreenChanged)="onFullscreenChanged($event)">
<div #reactRoot></div> <div #reactRoot></div>
<div class="tb-json-form" #reactFullscreen></div>
</div> </div>

View File

@ -73,6 +73,9 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
@ViewChild('reactRoot', {static: true}) @ViewChild('reactRoot', {static: true})
reactRootElmRef: ElementRef<HTMLElement>; reactRootElmRef: ElementRef<HTMLElement>;
@ViewChild('reactFullscreen', {static: true})
reactFullscreenElmRef: ElementRef<HTMLElement>;
private readonlyValue: boolean; private readonlyValue: boolean;
get readonly(): boolean { get readonly(): boolean {
return this.readonlyValue; return this.readonlyValue;
@ -106,8 +109,7 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
isModelValid = true; isModelValid = true;
isFullscreen = false; isFullscreen = false;
targetFullscreenElement: HTMLElement; fullscreenFinishFn: (el: Element) => void;
fullscreenFinishFn: () => void;
private propagateChange = null; private propagateChange = null;
private propagateChangePending = false; private propagateChangePending = false;
@ -233,8 +235,7 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
}); });
} }
private onToggleFullscreen(element: HTMLElement, fullscreenFinishFn?: () => void) { private onToggleFullscreen(fullscreenFinishFn?: (el: Element) => void) {
this.targetFullscreenElement = element;
this.isFullscreen = !this.isFullscreen; this.isFullscreen = !this.isFullscreen;
this.fullscreenFinishFn = fullscreenFinishFn; this.fullscreenFinishFn = fullscreenFinishFn;
this.cd.markForCheck(); this.cd.markForCheck();
@ -244,7 +245,7 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
this.formProps.isFullscreen = fullscreen; this.formProps.isFullscreen = fullscreen;
this.renderReactSchemaForm(false); this.renderReactSchemaForm(false);
if (this.fullscreenFinishFn) { if (this.fullscreenFinishFn) {
this.fullscreenFinishFn(); this.fullscreenFinishFn(this.reactFullscreenElmRef.nativeElement);
this.fullscreenFinishFn = null; this.fullscreenFinishFn = null;
} }
} }

View File

@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import * as React from 'react'; import * as React from 'react';
import * as ReactDOM from 'react-dom';
import ThingsboardBaseComponent from './json-form-base-component'; import ThingsboardBaseComponent from './json-form-base-component';
import reactCSS from 'reactcss'; import reactCSS from 'reactcss';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
@ -42,6 +43,7 @@ interface ThingsboardAceEditorProps extends JsonFormFieldProps {
interface ThingsboardAceEditorState extends JsonFormFieldState { interface ThingsboardAceEditorState extends JsonFormFieldState {
isFull: boolean; isFull: boolean;
fullscreenContainerElement: Element;
helpVisible: boolean; helpVisible: boolean;
helpReady: boolean; helpReady: boolean;
focused: boolean; focused: boolean;
@ -49,7 +51,6 @@ interface ThingsboardAceEditorState extends JsonFormFieldState {
class ThingsboardAceEditor extends React.Component<ThingsboardAceEditorProps, ThingsboardAceEditorState> { class ThingsboardAceEditor extends React.Component<ThingsboardAceEditorProps, ThingsboardAceEditorState> {
hostElement: HTMLElement;
private aceEditor: IEditorProps; private aceEditor: IEditorProps;
constructor(props) { constructor(props) {
@ -64,6 +65,7 @@ class ThingsboardAceEditor extends React.Component<ThingsboardAceEditorProps, Th
const value = props.value ? props.value + '' : ''; const value = props.value ? props.value + '' : '';
this.state = { this.state = {
isFull: false, isFull: false,
fullscreenContainerElement: null,
helpVisible: false, helpVisible: false,
helpReady: true, helpReady: true,
value, value,
@ -131,12 +133,8 @@ class ThingsboardAceEditor extends React.Component<ThingsboardAceEditorProps, Th
} }
onToggleFull() { onToggleFull() {
this.setState({ isFull: !this.state.isFull }); this.props.onToggleFullscreen((el) => {
this.props.onToggleFullscreen(this.hostElement, () => { this.setState({ isFull: !this.state.isFull, fullscreenContainerElement: el });
if (this.aceEditor) {
this.aceEditor.resize();
this.aceEditor.renderer.updateFull();
}
}); });
} }
@ -177,56 +175,61 @@ class ThingsboardAceEditor extends React.Component<ThingsboardAceEditorProps, Th
if (this.state.isFull) { if (this.state.isFull) {
containerClass += ' fullscreen-form-field'; containerClass += ' fullscreen-form-field';
} }
return ( const formDom = (
<div> <div className={containerClass}>
<div className='tb-json-form' ref={c => (this.hostElement = c)}> <label className={labelClass}>{this.props.form.title}</label>
<div className={containerClass}> <div className='json-form-ace-editor'>
<label className={labelClass}>{this.props.form.title}</label> <div className='title-panel'>
<div className='json-form-ace-editor'> <label>{this.props.mode}</label>
<div className='title-panel'> { this.props.onTidy ? <Button style={ styles.tidyButtonStyle }
<label>{this.props.mode}</label> className='tidy-button' onClick={this.onTidy}>Tidy</Button> : null }
{ this.props.onTidy ? <Button style={ styles.tidyButtonStyle } { this.props.form.helpId ? <div style={ {position: 'relative', display: 'inline-block', marginLeft: '5px'} }>
className='tidy-button' onClick={this.onTidy}>Tidy</Button> : null } <IconButton color='primary'
{ this.props.form.helpId ? <div style={ {position: 'relative', display: 'inline-block', marginLeft: '5px'} }> className='help-button' onClick={this.onHelp}>
<IconButton color='primary' {this.state.helpVisible ? <Help /> : <HelpOutline /> }
className='help-button' onClick={this.onHelp}> </IconButton>
{this.state.helpVisible ? <Help /> : <HelpOutline /> } { this.state.helpVisible && !this.state.helpReady ?
</IconButton> <div className='tb-absolute-fill help-button-loading'>
{ this.state.helpVisible && !this.state.helpReady ? <CircularProgress size={18} thickness={4}/>
<div className='tb-absolute-fill help-button-loading'> </div> : null }</div> : null }
<CircularProgress size={18} thickness={4}/> <Button style={ styles.tidyButtonStyle }
</div> : null }</div> : null } className='tidy-button' onClick={this.onToggleFull}>
<Button style={ styles.tidyButtonStyle } {this.state.isFull ?
className='tidy-button' onClick={this.onToggleFull}> 'Exit fullscreen' : 'Fullscreen'}
{this.state.isFull ? </Button>
'Exit fullscreen' : 'Fullscreen'}
</Button>
</div>
<React.Suspense fallback={<div>Loading...</div>}>
<ReactAce mode={this.props.mode}
theme={'textmate'}
height={this.state.isFull ? '100%' : '150px'}
width={this.state.isFull ? '100%' : '300px'}
onChange={this.onValueChanged}
onFocus={this.onFocus}
onBlur={this.onBlur}
onLoad={this.onLoad}
name={this.props.form.title}
value={this.state.value}
readOnly={this.props.form.readonly}
editorProps={{$blockScrolling: Infinity}}
enableBasicAutocompletion={true}
enableSnippets={true}
enableLiveAutocompletion={true}
style={style}/>
</React.Suspense>
</div>
<div className='json-form-error'
style={{opacity: this.props.valid ? '0' : '1'}}>{this.props.error}</div>
</div> </div>
<React.Suspense fallback={<div>Loading...</div>}>
<ReactAce mode={this.props.mode}
theme={'textmate'}
height={this.state.isFull ? '100%' : '150px'}
width={this.state.isFull ? '100%' : '300px'}
onChange={this.onValueChanged}
onFocus={this.onFocus}
onBlur={this.onBlur}
onLoad={this.onLoad}
name={this.props.form.title}
value={this.state.value}
readOnly={this.props.form.readonly}
editorProps={{$blockScrolling: Infinity}}
enableBasicAutocompletion={true}
enableSnippets={true}
enableLiveAutocompletion={true}
style={style}/>
</React.Suspense>
</div> </div>
<div className='json-form-error'
style={{opacity: this.props.valid ? '0' : '1'}}>{this.props.error}</div>
</div> </div>
); );
if (this.state.isFull) {
return ReactDOM.createPortal(formDom, this.state.fullscreenContainerElement);
} else {
return (
<div>
{formDom}
</div>
);
}
} }
} }

View File

@ -106,8 +106,8 @@ class ThingsboardSchemaForm extends React.Component<JsonFormProps, any> {
this.props.onIconClick(key, val, iconSelectedFn); this.props.onIconClick(key, val, iconSelectedFn);
} }
onToggleFullscreen(element: HTMLElement, fullscreenFinishFn?: () => void) { onToggleFullscreen(fullscreenFinishFn?: (el: Element) => void) {
this.props.onToggleFullscreen(element, fullscreenFinishFn); this.props.onToggleFullscreen(fullscreenFinishFn);
} }
onHelpClick(event: MouseEvent, helpId: string, helpVisibleFn: (visible: boolean) => void, helpReadyFn: (ready: boolean) => void) { onHelpClick(event: MouseEvent, helpId: string, helpVisibleFn: (visible: boolean) => void, helpReadyFn: (ready: boolean) => void) {

View File

@ -48,7 +48,7 @@ export type OnColorClickFn = (key: (string | number)[], val: tinycolor.ColorForm
colorSelectedFn: (color: tinycolor.ColorFormats.RGBA) => void) => void; colorSelectedFn: (color: tinycolor.ColorFormats.RGBA) => void) => void;
export type OnIconClickFn = (key: (string | number)[], val: string, export type OnIconClickFn = (key: (string | number)[], val: string,
iconSelectedFn: (icon: string) => void) => void; iconSelectedFn: (icon: string) => void) => void;
export type onToggleFullscreenFn = (element: HTMLElement, fullscreenFinishFn?: () => void) => void; export type onToggleFullscreenFn = (fullscreenFinishFn?: (el: Element) => void) => void;
export type onHelpClickFn = (event: MouseEvent, helpId: string, helpVisibleFn: (visible: boolean) => void, export type onHelpClickFn = (event: MouseEvent, helpId: string, helpVisibleFn: (visible: boolean) => void,
helpReadyFn: (ready: boolean) => void) => void; helpReadyFn: (ready: boolean) => void) => void;