'use strict'; import React, { Component } from 'react'; import { translate } from 'react-i18next'; import PropTypes from 'prop-types'; import { withErrorHandling, withAsyncErrorHandler } from './error-handling'; @translate() @withErrorHandling class DismissibleAlert extends Component { static propTypes = { severity: PropTypes.string.isRequired, onCloseAsync: PropTypes.func } @withAsyncErrorHandler onClose() { if (this.props.onCloseAsync) { this.props.onCloseAsync(); } } render() { const t = this.props.t; return (
{this.props.children}
) } } class Icon extends Component { static propTypes = { icon: PropTypes.string.isRequired, family: PropTypes.string, title: PropTypes.string, className: PropTypes.string } static defaultProps = { family: 'glyphicon' } render() { const props = this.props; return ; } } @withErrorHandling class Button extends Component { static propTypes = { onClickAsync: PropTypes.func, label: PropTypes.string, icon: PropTypes.string, className: PropTypes.string, type: PropTypes.string } @withAsyncErrorHandler async onClick(evt) { if (this.props.onClickAsync) { evt.preventDefault(); await this.props.onClickAsync(evt); } } render() { const props = this.props; let className = 'btn'; if (props.className) { className = className + ' ' + props.className; } let type = props.type || 'button'; let icon; if (props.icon) { icon = } let iconSpacer; if (props.icon && props.label) { iconSpacer = ' '; } return ( ); } } class DropdownMenu extends Component { static propTypes = { label: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), noCaret: PropTypes.bool, className: PropTypes.string } render() { const props = this.props; let className = 'btn dropdown-toggle'; if (props.className) { className = className + ' ' + props.className; } let label; if (this.props.noCaret) { label = props.label; } else { label = {props.label}{' '}; } return (
); } } class DropdownMenuItem extends Component { static propTypes = { label: PropTypes.string, icon: PropTypes.string, className: PropTypes.string } render() { const props = this.props; let className = 'dropdown'; if (props.className) { className = className + ' ' + props.className; } return (
  • {props.icon ? : }
  • ); } } @withErrorHandling class ActionLink extends Component { static propTypes = { onClickAsync: PropTypes.func, className: PropTypes.string } @withAsyncErrorHandler async onClick(evt) { if (this.props.onClickAsync) { evt.preventDefault(); evt.stopPropagation(); await this.props.onClickAsync(evt); } } render() { const props = this.props; return ( {props.children} ); } } @translate() @withErrorHandling class ModalDialog extends Component { constructor(props) { super(props); const t = props.t; this.state = { buttons: this.props.buttons || [ { label: t('Close'), className: 'btn-default', onClickAsync: null } ] }; } static propTypes = { title: PropTypes.string, onCloseAsync: PropTypes.func, onButtonClickAsync: PropTypes.func, buttons: PropTypes.array, hidden: PropTypes.bool } /* this.props.hidden - this is the desired state of the modal this.hidden - this is the actual state of the modal - this is because there is no public API on Bootstrap modal to know whether the modal is shown or not */ componentDidMount() { const jqModal = jQuery(this.domModal); jqModal.on('shown.bs.modal', () => jqModal.focus()); jqModal.on('hide.bs.modal', ::this.onHide); this.hidden = this.props.hidden; jqModal.modal({ show: !this.props.hidden }); } componentDidUpdate() { if (this.props.hidden != this.hidden) { const jqModal = jQuery(this.domModal); this.hidden = this.props.hidden; jqModal.modal(this.props.hidden ? 'hide' : 'show'); } } componentWillUnmount() { // We discard the modal in a hard way (without hiding it). Thus we have to take care of the backgrop too. jQuery('.modal-backdrop').remove(); } onHide(evt) { // Hide event is emited is both when hidden through user action or through API. We have to let the API // calls through, otherwise the modal would never hide. The user actions, which change the desired state, // are capture, converted to onClose callback and prevented. It's up to the parent to decide whether to // hide the modal or not. if (!this.props.hidden) { this.onClose(); evt.preventDefault(); } } @withAsyncErrorHandler async onClose() { if (this.props.onCloseAsync) { await this.props.onCloseAsync(); } } async onButtonClick(idx) { const buttonSpec = this.state.buttons[idx]; if (buttonSpec.onClickAsync) { await buttonSpec.onClickAsync(idx); } } render() { const props = this.props; const t = props.t; const buttons = []; for (let idx = 0; idx < this.state.buttons.length; idx++) { const buttonSpec = this.state.buttons[idx]; const button =

    {this.props.title}

    {this.props.children}
    {buttons}
    ); } } export { Button, DropdownMenu, DropdownMenuItem, ActionLink, DismissibleAlert, ModalDialog, Icon };