1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/web/ synced 2025-03-09 00:00:01 +01:00

fix problem with widget context menu and remove code redundancy #229

This commit is contained in:
Sonja Happ 2021-05-27 15:20:50 +02:00
parent cff28715a1
commit d334fac2c3
5 changed files with 277 additions and 303 deletions

View file

@ -37,7 +37,7 @@ import AppDispatcher from '../common/app-dispatcher';
import ScenarioStore from '../scenario/scenario-store';
import 'react-contexify/dist/ReactContexify.min.css';
import WidgetContainer from '../widget/widget-container';
import EditableWidgetContainer from '../widget/editable-widget-container';
import Widget from "../widget/widget";
class Dashboard extends Component {
@ -505,8 +505,8 @@ class Dashboard extends Component {
const grid = this.state.dashboard.grid;
const boxClasses = classNames('section', 'box', { 'fullscreen-padding': this.props.isFullscreen });
let draggable = this.state.editing;
let dropZoneHeight = this.state.dashboard.height;
return (<div className={boxClasses} >
<div className='section-header box-header'>
<div className="section-title">
@ -528,119 +528,111 @@ class Dashboard extends Component {
</h2>
</div>
<DashboardButtonGroup
locked={this.state.locked}
editing={this.state.editing}
onEdit={this.startEditing.bind(this)}
fullscreen={this.props.isFullscreen}
paused={this.state.paused}
onSave={this.saveEditing.bind(this)}
onCancel={this.cancelEditing.bind(this)}
onFullscreen={this.props.toggleFullscreen}
onPause={this.pauseData.bind(this)}
onUnpause={this.unpauseData.bind(this)}
onEditFiles={this.startEditFiles.bind(this)}
onEditOutputSignals={this.editOutputSignals.bind(this)}
onEditInputSignals={this.editInputSignals.bind(this)}
/>
</div>
<div className="box box-content" onContextMenu={(e) => e.preventDefault()}>
{this.state.editing &&
<WidgetToolbox grid={grid} onGridChange={this.setGrid.bind(this)} dashboard={this.state.dashboard} onDashboardSizeChange={this.setDashboardSize.bind(this)} widgets={this.state.widgets} />
}
{!draggable ? (
<WidgetArea widgets={this.state.widgets} dropZoneHeight={dropZoneHeight} editing={this.state.editing} grid={grid} onWidgetAdded={this.handleDrop.bind(this)}>
{this.state.widgets != null && Object.keys(this.state.widgets).map(widgetKey => (
<WidgetContainer widget={this.state.widgets[widgetKey]} key={widgetKey}>
<WidgetContextMenu
key={widgetKey}
index={parseInt(widgetKey, 10)}
widget={this.state.widgets[widgetKey]}
onEdit={this.editWidget.bind(this)}
onDuplicate={this.duplicateWidget.bind(this)}
onDelete={this.deleteWidget.bind(this)}
onChange={this.widgetChange.bind(this)}
onWidgetChange={this.widgetChange.bind(this)}
editing={this.state.editing}
grid={grid}
paused={this.state.paused}
/>
</WidgetContainer>
))}
</WidgetArea>
) : (
<WidgetArea widgets={this.state.widgets} editing={this.state.editing} dropZoneHeight={dropZoneHeight} grid={grid} onWidgetAdded={this.handleDrop.bind(this)}>
{this.state.widgets != null && Object.keys(this.state.widgets).map(widgetKey => (
<EditableWidgetContainer
widget={this.state.widgets[widgetKey]}
key={widgetKey}
grid={grid}
index={parseInt(widgetKey, 10)}
onWidgetChange={this.widgetChange.bind(this)}>
<WidgetContextMenu
key={widgetKey}
index={parseInt(widgetKey, 10)}
widget={this.state.widgets[widgetKey]}
onEdit={this.editWidget.bind(this)}
onDuplicate={this.duplicateWidget.bind(this)}
onDelete={this.deleteWidget.bind(this)}
onChange={this.widgetChange.bind(this)}
onWidgetChange={this.widgetChange.bind(this)}
editing={this.state.editing}
paused={this.state.paused}
/>
</EditableWidgetContainer>
))}
</WidgetArea>
)}
<EditWidget
sessionToken={this.state.sessionToken}
show={this.state.editModal}
onClose={this.closeEdit.bind(this)}
widget={this.state.modalData}
signals={this.state.signals}
files={this.state.files}
ics={this.state.ics}
/>
<EditFilesDialog
sessionToken={this.state.sessionToken}
show={this.state.filesEditModal}
onClose={this.closeEditFiles.bind(this)}
signals={this.state.signals}
files={this.state.files}
scenarioID={this.state.dashboard.scenarioID}
locked={this.state.locked}
/>
<EditSignalMappingDialog
show={this.state.editOutputSignalsModal}
onCloseEdit={(direction) => this.closeEditSignalsModal(direction)}
direction="Output"
signals={this.state.signals}
configID={null}
configs={this.state.configs}
sessionToken={this.state.sessionToken}
/>
<EditSignalMappingDialog
show={this.state.editInputSignalsModal}
onCloseEdit={(direction) => this.closeEditSignalsModal(direction)}
direction="Input"
signals={this.state.signals}
configID={null}
configs={this.state.configs}
sessionToken={this.state.sessionToken}
/>
</div>
<DashboardButtonGroup
locked={this.state.locked}
editing={this.state.editing}
onEdit={this.startEditing.bind(this)}
fullscreen={this.props.isFullscreen}
paused={this.state.paused}
onSave={this.saveEditing.bind(this)}
onCancel={this.cancelEditing.bind(this)}
onFullscreen={this.props.toggleFullscreen}
onPause={this.pauseData.bind(this)}
onUnpause={this.unpauseData.bind(this)}
onEditFiles={this.startEditFiles.bind(this)}
onEditOutputSignals={this.editOutputSignals.bind(this)}
onEditInputSignals={this.editInputSignals.bind(this)}
/>
</div>
);
<div className="box box-content" onContextMenu={(e) => e.preventDefault()}>
{this.state.editing &&
<WidgetToolbox
grid={grid}
onGridChange={this.setGrid.bind(this)}
dashboard={this.state.dashboard}
onDashboardSizeChange={this.setDashboardSize.bind(this)}
widgets={this.state.widgets} />
}
<WidgetArea
widgets={this.state.widgets}
editing={this.state.editing}
dropZoneHeight={dropZoneHeight}
grid={grid}
onWidgetAdded={this.handleDrop.bind(this)}
>
{this.state.widgets != null && Object.keys(this.state.widgets).map(widgetKey => (
<div >
<WidgetContainer
widget={this.state.widgets[widgetKey]}
key={widgetKey}
index={parseInt(widgetKey, 10)}
grid={grid}
onWidgetChange={this.widgetChange.bind(this)}
editing={this.state.editing}
paused={this.state.paused}
onEdit={this.editWidget.bind(this)}
onDuplicate={this.duplicateWidget.bind(this)}
onDelete={this.deleteWidget.bind(this)}
onChange={this.widgetChange.bind(this)}
>
<Widget
key={widgetKey}
data={this.state.widgets[widgetKey]}
onWidgetChange={this.widgetChange.bind(this)}
editing={this.state.editing}
index={parseInt(widgetKey, 10)}
paused={this.state.paused}
/>
</WidgetContainer>
</div>
))}
</WidgetArea>
<EditWidget
sessionToken={this.state.sessionToken}
show={this.state.editModal}
onClose={this.closeEdit.bind(this)}
widget={this.state.modalData}
signals={this.state.signals}
files={this.state.files}
ics={this.state.ics}
/>
<EditFilesDialog
sessionToken={this.state.sessionToken}
show={this.state.filesEditModal}
onClose={this.closeEditFiles.bind(this)}
signals={this.state.signals}
files={this.state.files}
scenarioID={this.state.dashboard.scenarioID}
locked={this.state.locked}
/>
<EditSignalMappingDialog
show={this.state.editOutputSignalsModal}
onCloseEdit={(direction) => this.closeEditSignalsModal(direction)}
direction="Output"
signals={this.state.signals}
configID={null}
configs={this.state.configs}
sessionToken={this.state.sessionToken}
/>
<EditSignalMappingDialog
show={this.state.editInputSignalsModal}
onCloseEdit={(direction) => this.closeEditSignalsModal(direction)}
direction="Input"
signals={this.state.signals}
configID={null}
configs={this.state.configs}
sessionToken={this.state.sessionToken}
/>
</div>
</div>);
}
}

View file

@ -45,10 +45,18 @@ class WidgetArea extends React.Component {
render() {
return <Dropzone height={this.props.dropZoneHeight} onDrop={this.handleDrop} editing={this.props.editing} widgets={this.props.widgets}>
return <Dropzone
height={this.props.dropZoneHeight}
onDrop={this.handleDrop}
editing={this.props.editing}
widgets={this.props.widgets}
>
{this.props.children}
<Grid size={this.props.grid} disabled={this.props.grid === 1 || this.props.editing !== true} />
<Grid
size={this.props.grid}
disabled={this.props.grid === 1 || this.props.editing !== true}
/>
</Dropzone>;
}
}

View file

@ -1,142 +0,0 @@
/**
* This file is part of VILLASweb.
*
* VILLASweb is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VILLASweb is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Rnd } from 'react-rnd';
class EditableWidgetContainer extends React.Component {
constructor(props) {
super(props);
this.rnd = null;
}
snapToGrid(value) {
if (this.props.grid === 1) {
return value;
}
return Math.round(value / this.props.grid) * this.props.grid;
}
borderWasClicked = event => {
if (event.button !== 2) {
return;
}
};
dragStop = (event, data) => {
const widget = this.props.widget;
widget.x = this.snapToGrid(data.x);
widget.y = this.snapToGrid(data.y);
if (widget.x !== data.x || widget.y !== data.y) {
this.rnd.updatePosition({ x: widget.x, y: widget.y });
}
if (this.props.onWidgetChange != null) {
this.props.onWidgetChange(widget, this.props.index);
}
};
resizeStop = (event, direction, ref, delta, position) => {
const widget = this.props.widget;
// resize depends on direction
if (direction === 'left' || direction === 'topLeft' || direction === 'bottomLeft') {
widget.x -= delta.width;
}
if (direction === 'top' || direction === 'topLeft' || direction === 'topRight') {
widget.y -= delta.height;
}
widget.width += delta.width;
widget.height += delta.height;
if (this.props.onWidgetChange != null) {
this.props.onWidgetChange(widget, this.props.index);
}
/* hand over new dimensions to child element so that the rotation is displayed correctly
* already before the dashboard changes are saved
if (this.props.widget.type === 'Line') {
this.refs.child0.illustrateDuringEdit(widget.width, widget.height);
}*/
};
render() {
const widget = this.props.widget;
let resizingRestricted = false;
if (widget.customProperties.resizeRightLeftLock || widget.customProperties.resizeTopBottomLock) {
resizingRestricted = true;
}
const resizing = {
bottom: !(widget.customProperties.resizeTopBottomLock || widget.isLocked),
bottomLeft: !(resizingRestricted || widget.isLocked),
bottomRight: !(resizingRestricted || widget.isLocked),
left: !(widget.customProperties.resizeRightLeftLock || widget.isLocked),
right: !(widget.customProperties.resizeRightLeftLock || widget.isLocked),
top: !(widget.customProperties.resizeTopBottomLock || widget.isLocked),
topLeft: !(resizingRestricted || widget.isLocked),
topRight: !(resizingRestricted || widget.isLocked)
};
const gridArray = [this.props.grid, this.props.grid];
const widgetClasses = classNames({
'editing-widget': true,
'locked': widget.isLocked
});
return <Rnd
ref={c => { this.rnd = c; }}
default={{ x: Number(widget.x), y: Number(widget.y), width: widget.width, height: widget.height }}
minWidth={widget.minWidth}
minHeight={widget.minHeight}
maxWidth={widget.customProperties.maxWidth || '100%'}
lockAspectRatio={Boolean(widget.customProperties.lockAspect)}
bounds={'parent'}
className={widgetClasses}
onResizeStart={this.borderWasClicked}
onResizeStop={this.resizeStop}
onDragStop={this.dragStop}
dragGrid={gridArray}
resizeGrid={gridArray}
zindex={widget.z}
enableResizing={resizing}
disableDragging={widget.isLocked}
>
{this.props.children}
</Rnd>;
}
}
EditableWidgetContainer.propTypes = {
widget: PropTypes.object.isRequired,
index: PropTypes.number.isRequired,
grid: PropTypes.number,
onWidgetChange: PropTypes.func
};
export default EditableWidgetContainer

View file

@ -17,28 +17,172 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Rnd } from 'react-rnd';
import WidgetContextMenu from '../widget/widget-context-menu';
import {contextMenu} from "react-contexify";
class WidgetContainer extends React.Component {
constructor(props) {
super(props);
this.rnd = null;
}
snapToGrid(value) {
if (this.props.grid === 1) {
return value;
}
return Math.round(value / this.props.grid) * this.props.grid;
}
borderWasClicked = event => {
if (event.button !== 2) {
return;
}
};
dragStop = (event, data) => {
const widget = this.props.widget;
widget.x = this.snapToGrid(data.x);
widget.y = this.snapToGrid(data.y);
if (widget.x !== data.x || widget.y !== data.y) {
this.rnd.updatePosition({ x: widget.x, y: widget.y });
}
if (this.props.onWidgetChange != null) {
this.props.onWidgetChange(widget, this.props.index);
}
};
resizeStop = (event, direction, ref, delta, position) => {
const widget = this.props.widget;
// resize depends on direction
if (direction === 'left' || direction === 'topLeft' || direction === 'bottomLeft') {
widget.x -= delta.width;
}
if (direction === 'top' || direction === 'topLeft' || direction === 'topRight') {
widget.y -= delta.height;
}
widget.width += delta.width;
widget.height += delta.height;
if (this.props.onWidgetChange != null) {
this.props.onWidgetChange(widget, this.props.index);
}
/* hand over new dimensions to child element so that the rotation is displayed correctly
* already before the dashboard changes are saved
if (this.props.widget.type === 'Line') {
this.refs.child0.illustrateDuringEdit(widget.width, widget.height);
}*/
};
showMenu(e, index, editing) {
e.preventDefault();
contextMenu.show({
event: e,
id: 'widgetMenu' + index,
})
}
render() {
const containerStyle = {
width: Number(this.props.widget.width),
height: Number(this.props.widget.height),
left: Number(this.props.widget.x),
top: Number(this.props.widget.y),
zIndex: Number(this.props.widget.z),
position: 'absolute'
const widget = this.props.widget;
let contextMenu = (<WidgetContextMenu
key={this.props.key}
index={this.props.index}
widget={this.props.widget}
onEdit={this.props.onEdit}
onDuplicate={this.props.onDuplicate}
onDelete={this.props.onDelete}
onChange={this.props.onChange}
onWidgetChange={this.props.onWidgetChange}
editing={this.props.editing}
paused={this.props.paused}
/>)
if ( !this.props.editing ){
const containerStyle = {
width: Number(widget.width),
height: Number(widget.height),
left: Number(widget.x),
top: Number(widget.y),
zIndex: Number(widget.z),
position: 'absolute'
};
return <div className='widget' style={containerStyle} onContextMenu={(e) => this.showMenu(e, this.props.index, this.props.editing)}>
{this.props.children}
{contextMenu}
</div>;
}
let resizingRestricted = false;
if (widget.customProperties.resizeRightLeftLock || widget.customProperties.resizeTopBottomLock) {
resizingRestricted = true;
}
const resizing = {
bottom: !(widget.customProperties.resizeTopBottomLock || widget.isLocked),
bottomLeft: !(resizingRestricted || widget.isLocked),
bottomRight: !(resizingRestricted || widget.isLocked),
left: !(widget.customProperties.resizeRightLeftLock || widget.isLocked),
right: !(widget.customProperties.resizeRightLeftLock || widget.isLocked),
top: !(widget.customProperties.resizeTopBottomLock || widget.isLocked),
topLeft: !(resizingRestricted || widget.isLocked),
topRight: !(resizingRestricted || widget.isLocked)
};
return <div className='widget' style={containerStyle}>
{this.props.children}
</div>;
const gridArray = [this.props.grid, this.props.grid];
const widgetClasses = classNames({
'editing-widget': true,
'locked': widget.isLocked
});
return ( <div className='widget' onContextMenu={(e) => this.showMenu(e, this.props.index, this.props.editing)}>
<Rnd
ref={c => { this.rnd = c; }}
size={{width: Number(widget.width), height: Number(widget.height)}}
position={{x: Number(widget.x), y: Number(widget.y),}}
minWidth={widget.minWidth}
minHeight={widget.minHeight}
maxWidth={widget.customProperties.maxWidth || '100%'}
lockAspectRatio={Boolean(widget.customProperties.lockAspect)}
bounds={'parent'}
className={widgetClasses}
onResizeStart={this.borderWasClicked}
onResizeStop={this.resizeStop}
onDragStop={this.dragStop}
dragGrid={gridArray}
resizeGrid={gridArray}
zindex={widget.z}
enableResizing={resizing}
disableDragging={widget.isLocked}
>
{this.props.children}
</Rnd>
{contextMenu}
</div>);
}
}
WidgetContainer.propTypes = {
widget: PropTypes.object.isRequired,
children: PropTypes.node, //TODO is .node correct here? Was .children before leading to compile error
index: PropTypes.number.isRequired,
grid: PropTypes.number,
onWidgetChange: PropTypes.func,
children: PropTypes.node,
editing: PropTypes.bool.isRequired,
};
export default WidgetContainer

View file

@ -17,10 +17,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Menu, Item, Separator, contextMenu } from 'react-contexify';
import Widget from './widget';
import { Menu, Item, Separator } from 'react-contexify';
import "react-contexify/dist/ReactContexify.css";
class WidgetContextMenu extends React.Component {
editWidget = event => {
if (this.props.onEdit != null) {
this.props.onEdit(this.props.widget, this.props.index);
@ -93,26 +94,6 @@ class WidgetContextMenu extends React.Component {
}
};
showMenu = e => {
let index = this.props.index
if (this.props.editing){
contextMenu.show({
event: e,
id: 'widgetMenu' + index,
position: {
x: 'inherit',
y: 'inherit',
}
})
}
else {
contextMenu.show({
event: e,
id: 'widgetMenu' + index,
})
}
}
render() {
const isLocked = this.props.widget.locked;
@ -122,16 +103,7 @@ class WidgetContextMenu extends React.Component {
};
return (
<div style={dim} onContextMenu={this.showMenu}>
<Widget
data={this.props.widget}
onWidgetChange={this.props.onWidgetChange}
editing={this.props.editing}
index={this.props.index}
paused={this.props.paused}
/>
<div >
<Menu id={'widgetMenu' + this.props.index}>
<Item disabled={isLocked} onClick={this.editWidget}>Edit</Item>
<Item disabled={isLocked} onClick={this.duplicateWidget}>Duplicate</Item>
@ -158,8 +130,8 @@ WidgetContextMenu.propTypes = {
index: PropTypes.number.isRequired,
widget: PropTypes.object.isRequired,
onEdit: PropTypes.func.isRequired,
onDelete: PropTypes.func,
onChange: PropTypes.func
onDelete: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired
};
export default WidgetContextMenu