Upstream sync

This commit is contained in:
Senad Uka
2018-05-29 17:02:50 +02:00
parent 3969863cbf
commit 8e52651172
24 changed files with 657 additions and 252 deletions

View File

@@ -1,68 +1,68 @@
import React, { Component } from 'react';
import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton';
import Dialog from './draggable-dialog';
import './draggable-dialog/css/index.css';
const defaultDialogHeight = 100; //px
const dialogHeightPerLine = 25; //px
export class ValidationErrorsInfoDialog extends React.Component {
constructor(props) {
super(props)
this.props = props;
this.state = {
state = {
open: this.props.open,
title: "Errors",
}
componentWillReceiveProps(newProps){
this.setState({open: newProps.open});
}
handleOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
this.props.onDismiss();
};
render() {
const actions = [
<FlatButton
label="Dismiss"
primary={true}
onClick={this.handleClose}
/>,
];
return (
<div className="container">
{
this.state.open &&
<Dialog
title={this.props.title ? this.props.title : 'Error'}
isDraggable={this.props.draggable ? this.props.draggable : false}
buttons={actions}
hasCloseIcon={false}
modal={this.props.modal ? this.props.modal : false}
height={defaultDialogHeight + this.props.errorMessages.length * dialogHeightPerLine}
>
{this.props.errorMessages.map(errorMessage=>{
const oneValidationMessage = (<span><a>{errorMessage.message}</a><br /></span>);
const oneValidationMessageWithTab = (<span><li style={{marginLeft:2 + "em"}}>{errorMessage.message}</li></span>);
if (errorMessage.field_name === "password-tab"){
return oneValidationMessageWithTab;
} else{
return oneValidationMessage;
}
})}
</Dialog>
}
</div>
);
}
}
componentWillReceiveProps(newProps) {
let title = this.state.title;
if (newProps.errorTitle) {
title = newProps.errorTitle;
}
this.setState({ open: newProps.open, title: title });
}
handleOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
this.props.onDismiss();
};
render() {
const actions = [
<FlatButton
label="Dismiss"
primary={true}
keyboardFocused={true}
onClick={this.handleClose}
/>,
];
return (
<div>
<Dialog
title={this.state.title}
actions={actions}
modal={this.props.modal ? this.props.modal : false}
open={this.state.open}
onRequestClose={this.handleClose}
overlayStyle={{ backgroundColor: 'transparent' }}
>
{this.props.errorMessages.map(errorMessage => {
return (
<div>
<a>{errorMessage.message}</a>
<br />
</div>
);
})}
</Dialog>
</div>
);
}
}
module.exports = ValidationErrorsInfoDialog;
module.exports = ValidationErrorsInfoDialog;

View File

@@ -0,0 +1,18 @@
import React from "react";
import PropTypes from "prop-types";
class DialogBody extends React.Component {
render() {
return (
<div className="ui-dialog-content" style={{ "overflowY": "auto" }}>
{this.props.children}
</div>
);
}
}
DialogBody.propTypes = {
children: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
};
export default DialogBody;

View File

@@ -0,0 +1,43 @@
import React from "react";
import PropTypes from "prop-types";
import cs from "classnames";
const DialogFooter = (props) => {
const buttons = props.buttons;
if (!buttons || buttons.length == 0) {
return false;
}
const dialogButtons = buttons.map(function (button, index) {
if (React.isValidElement(button)) {
return button;
}
const { text, onClick, className } = button;
return (
<button
key={`button-${index}`}
type="button"
className={cs("button", className)}
onClick={onClick}>
{text}
</button>
);
}, this);
return (
<div className="ui-dialog-buttonpane">
<div className="ui-dialog-buttonset">
{dialogButtons}
</div>
</div>
);
};
DialogFooter.propTypes = {
buttons: PropTypes.array,
onClose: PropTypes.func.isRequired
};
export default DialogFooter;

View File

@@ -0,0 +1,65 @@
import React from "react";
import PropTypes from "prop-types";
const DialogTitle = ({ title, hasCloseIcon, onClose, allowMinimize, isMinimized, onMinimize, allowMaximize, isMaximized, onMaximize, onRestore }) => {
let closeIcon;
if (hasCloseIcon !== false) {
closeIcon = (
<i className="icon icon-close" onClick={onClose}></i>
);
}
let minimizeIcon;
if (allowMinimize) {
if (isMinimized) {
minimizeIcon = (
<i className="icon icon-restore" onClick={onRestore}></i>
);
} else {
minimizeIcon = (
<i className="icon icon-minimize" onClick={onMinimize}></i>
);
}
}
let maximizeIcon;
if (allowMaximize) {
if (isMaximized) {
maximizeIcon = (
<i className="icon icon-restore" onClick={onRestore}></i>
);
} else {
maximizeIcon = (
<i className="icon icon-maximize" onClick={onMaximize}></i>
);
}
}
return (
<header className="ui-dialog-titlebar">
<div className="title">
{title}
</div>
<div className="action-items">
{minimizeIcon}
{maximizeIcon}
{closeIcon}
</div>
</header>
);
};
DialogTitle.propTypes = {
hasCloseIcon: PropTypes.bool,
allowMinimize: PropTypes.bool,
allowMaximize: PropTypes.bool,
isMinimized: PropTypes.bool,
isMaximized: PropTypes.bool,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
onClose: PropTypes.func.isRequired,
onMinimize: PropTypes.func,
onMaximize: PropTypes.func,
onRestore: PropTypes.func
};
export default DialogTitle;

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

View File

@@ -0,0 +1,167 @@
body {
width: 100%;
min-height: 700px;
}
a {
cursor: pointer;
text-decoration: underline;
}
.ui-dialog-overlay {
background: #aaaaaa;
opacity: .3;
filter: Alpha(Opacity=30);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
}
.ui-dialog {
position: fixed;
top: 50%;
left: 50%;
outline: 0 none;
padding: 0 !important;;
z-index: 101;
background-color: white;
border: 1px solid #f6f6f6;
}
.ui-dialog.maximized{
position: fixed;
top: 0;
left: 0;
width: 100% !important;
height: 100% !important;
}
.ui-dialog.minimized{
position: fixed;
bottom: 0;
right: 0;
}
.ui-dialog .ui-dialog-titlebar {
position: relative;
font-size: 1em;
border-radius: 3px;
padding: 0.5em;
height: 35px;
/*border-bottom: 1px solid #f6f6f6;*/
}
.ui-dialog.react-draggable .ui-dialog-titlebar{
cursor: move;
}
.ui-dialog.react-draggable .ui-dialog-content{
cursor: move;
}
.ui-dialog.react-draggable .ui-dialog-buttonpane {
cursor: move;
}
.ui-dialog .ui-dialog-titlebar .action-items {
float: right;
position: relative;
}
.ui-dialog .ui-dialog-titlebar .title {
float: left;
margin-right: .5em;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
font-size: 1.3125em;
font-weight: 500;
line-height: 0.2em;
padding : 24px 0px 0px 19px;
}
.icon {
width: 24px;
height: 24px;
display: block;
float: left;
margin: 5px;
cursor: pointer;
background-size: cover;
}
.icon.icon-close {
width: 20px;
height: 20px;
background-image: url("./img/close.png");
}
.icon.icon-minimize {
background-image: url("./img/minimize.png");
}
.icon.icon-maximize {
background-image: url("./img/maximize.png");
}
.icon.icon-restore {
background-image: url("./img/restore.png");
}
.ui-dialog .ui-dialog-content {
background: none repeat scroll 0 0 transparent;
border: 0 none;
overflow: auto;
position: relative;
font-size: 1rem;
font-weight: 400;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
line-height: 1.5em;
color:rgba(0, 0, 0, 0.54);
padding : 24px 24px 24px 24px;
}
.ui-dialog .ui-dialog-buttonpane {
position: absolute;
width: 100%;
bottom: 0;
text-align: right;
border-width: 1px 0 0 0;
/*border-top: 1px solid #f6f6f6;*/
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{
padding: 0.5em;
}
.ui-dialog .ui-dialog-buttonpane button {
margin: 0 .5em 0 .5em;
cursor: pointer;
background-color: #f6f6f6;
padding: 0.5em 1em;
outline: none;
border: 1px solid #CCCCCC;
border-radius: 3px;
}
.ui-dialog .ui-dialog-buttonpane button:hover{
background-color: #CCCCCC;
border: 1px solid #BBBBBB;
}
.ui-dialog .react-resizable-handle {
position: absolute;
width: 20px;
height: 20px;
bottom: 0;
right: 0;
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+');
background-position: bottom right;
padding: 0 3px 3px 0;
background-repeat: no-repeat;
background-origin: content-box;
box-sizing: border-box;
cursor: se-resize;
}

View File

@@ -0,0 +1,171 @@
import React from "react";
import PropTypes from "prop-types";
import cs from "classnames";
import Draggable from "react-draggable";
import { Resizable } from "react-resizable";
import DialogTitle from "./DialogTitle";
import DialogBody from "./DialogBody";
import DialogFooter from "./DialogFooter";
import EventStack from "active-event-stack";
class Dialog extends React.Component {
constructor(props) {
super(props);
this.state = {
height: props.height,
width: props.width,
isMinimized: false,
isMaximized: false
};
}
componentWillMount() {
/**
* This is done in the componentWillMount instead of the componentDidMount
* because this way, a modal that is a child of another will have register
* for events after its parent
*/
this.eventToken = EventStack.addListenable([
["keydown", this.handleGlobalKeydown]
]);
}
componentWillUnmount = () => {
EventStack.removeListenable(this.eventToken);
}
handleGlobalKeydown = (e) => {
if (this.props.closeOnEscape && e.keyCode == 27) {
e.stopPropagation();
this.onClose();
}
return false;
}
onClose = () => {
if (this.props.onClose) {
this.props.onClose();
}
}
onMinimize = () => {
this.setState({ isMinimized: true, isMaximized: false });
}
onMaximize = () => {
this.setState({ isMinimized: false, isMaximized: true });
}
onRestore = () => {
this.setState({ isMinimized: false, isMaximized: false });
}
onResize = (event, { element, size }) => {
this.setState({ width: size.width, height: size.height });
}
getDialogTitle = () => {
return (
<DialogTitle
title={this.props.title}
hasCloseIcon={this.props.hasCloseIcon}
allowMinimize={this.props.allowMinimize}
allowMaximize={this.props.allowMaximize}
isMinimized={this.state.isMinimized}
isMaximized={this.state.isMaximized}
onMinimize={this.onMinimize}
onMaximize={this.onMaximize}
onRestore={this.onRestore}
onClose={this.onClose}
/>
);
}
render() {
const { height, width, isMinimized, isMaximized } = this.state;
const { modal, isDraggable, isResizable, buttons, children, position } = this.props;
const { x = -width / 2, y = -height / 2 } = position;
let dialog = (
<div style={{ height: height, width, transform: `translate(${x}px, ${y}px)` }} className={cs("ui-dialog", { "minimized": isMinimized, "maximized": isMaximized })}>
{this.getDialogTitle()}
{
!isMinimized && <DialogBody>{children}</DialogBody>
}
{
!isMinimized && <DialogFooter buttons={buttons} onClose={this.onClose}></DialogFooter>
}
</div>
);
if (!isMinimized && !isMaximized && isResizable) {
dialog = (
<Resizable className="box" height={height} width={width} onResize={this.onResize}>
{dialog}
</Resizable>
);
}
if (!isMinimized && !isMaximized && isDraggable !== false) {
dialog = (
<Draggable handle=".ui-dialog" bounds="body" defaultPosition={{ x, y }}>
{dialog}
</Draggable>
);
}
return (
<div
className={cs("ui-dialog-container", { "": modal })}>
{dialog}
{modal && <div className="ui-dialog-overlay"></div>}
</div>
);
}
}
Dialog.propTypes = {
height: PropTypes.number,
width: PropTypes.number,
modal: PropTypes.bool,
position: PropTypes.shape({
x: PropTypes.number,
y: PropTypes.number
}),
hasCloseIcon: PropTypes.bool,
allowMinimize: PropTypes.bool,
allowMaximize: PropTypes.bool,
isResizable: PropTypes.bool,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
closeOnEscape: PropTypes.bool,
onClose: PropTypes.func,
children: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.element]).isRequired,
buttons: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string,
onClick: PropTypes.func
})),
PropTypes.arrayOf(PropTypes.element)
])
};
Dialog.defaultProps = {
height: 200,
width: 600,
modal: false,
closeOnEscape: true,
isDraggable: false,
isResizable: false,
title: '',
hasCloseIcon: true,
allowMinimize: false,
allowMaximize: false,
onClose: null,
buttons: null,
position: { x: -250, y: -150 }
};
export default Dialog;