<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import EventListener from 'react-event-listener';
import keycode from 'keycode';
import transitions from '../styles/transitions';
import Overlay from '../internal/Overlay';
import RenderToLayer from '../internal/RenderToLayer';
import Paper from '../Paper';

import ReactTransitionGroup from 'react-transition-group/TransitionGroup';

class TransitionItem extends Component {
  static propTypes = {
    id: PropTypes.string,
    children: PropTypes.node,
    style: PropTypes.object,
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  state = {
    style: {},
  };

  componentWillMount() {
    const uniqueId = `${this.constructor.name}-${Math.floor(Math.random() * 0xFFFF)}`;
    this.uniqueIdTransactionItem = uniqueId.replace(/[^A-Za-z0-9-]/gi, '');
  }

  componentWillUnmount() {
    clearTimeout(this.enterTimeout);
    clearTimeout(this.leaveTimeout);
  }

  componentWillEnter(callback) {
    this.componentWillAppear(callback);
  }

  componentWillAppear(callback) {
    const spacing = this.context.muiTheme.baseTheme.spacing;

    this.setState({
      style: {
        opacity: 1,
        transform: `translate(0, ${spacing.desktopKeylineIncrement}px)`,
      },
    });

    this.enterTimeout = setTimeout(callback, 450); // matches transition duration
  }

  componentWillLeave(callback) {
    this.setState({
      style: {
        opacity: 0,
        transform: 'translate(0, 0)',
      },
    });

    this.leaveTimeout = setTimeout(callback, 450); // matches transition duration
  }

  render() {
    const {
      id,
      style,
      children,
      ...other
    } = this.props;

    const {prepareStyles} = this.context.muiTheme;
    const baseIdItem = id || this.uniqueIdTransactionItem;

    return (

        {children}

    );
  }
}

function getStyles(props, context) {
  const {
    autoScrollBodyContent,
    open,
  } = props;

  const {
    baseTheme: {
      spacing,
      palette,
    },
    dialog,
    zIndex,
  } = context.muiTheme;

  const gutter = spacing.desktopGutter;
  const borderScroll = `1px solid ${palette.borderColor}`;

  return {
    root: {
      position: 'fixed',
      boxSizing: 'border-box',
      WebkitTapHighlightColor: 'rgba(0,0,0,0)', // Remove mobile color flashing (deprecated)
      zIndex: zIndex.dialog,
      top: 0,
      left: open ? 0 : -10000,
      width: '100%',
      height: '100%',
      transition: open ?
        transitions.easeOut('0ms', 'left', '0ms') :
        transitions.easeOut('0ms', 'left', '450ms'),
    },
    content: {
      boxSizing: 'border-box',
      WebkitTapHighlightColor: 'rgba(0,0,0,0)', // Remove mobile color flashing (deprecated)
      transition: transitions.easeOut(),
      position: 'relative',
      width: '75%',
      maxWidth: spacing.desktopKeylineIncrement * 12,
      margin: '0 auto',
      zIndex: zIndex.dialog,
    },
    actionsContainer: {
      boxSizing: 'border-box',
      WebkitTapHighlightColor: 'rgba(0,0,0,0)', // Remove mobile color flashing (deprecated)
      padding: 8,
      width: '100%',
      textAlign: 'right',
      marginTop: autoScrollBodyContent ? -1 : 0,
      borderTop: autoScrollBodyContent ? borderScroll : 'none',
    },
    overlay: {
      zIndex: zIndex.dialogOverlay,
    },
    title: {
      margin: 0,
      padding: `${gutter}px ${gutter}px 20px ${gutter}px`,
      color: palette.textColor,
      fontSize: dialog.titleFontSize,
      lineHeight: '32px',
      fontWeight: 400,
      marginBottom: autoScrollBodyContent ? -1 : 0,
      borderBottom: autoScrollBodyContent ? borderScroll : 'none',
    },
    body: {
      fontSize: dialog.bodyFontSize,
      color: dialog.bodyColor,
      padding: `${props.title ? 0 : gutter}px ${gutter}px ${gutter}px`,
      boxSizing: 'border-box',
      overflowY: autoScrollBodyContent ? 'auto' : 'hidden',
      borderTop: autoScrollBodyContent ? borderScroll : 'none',
      borderBottom: autoScrollBodyContent ? borderScroll : 'none',
    },
  };
}

class DialogInline extends Component {
  static propTypes = {
    id: PropTypes.string,
    actions: PropTypes.node,
    actionsContainerClassName: PropTypes.string,
    actionsContainerStyle: PropTypes.object,
    autoDetectWindowHeight: PropTypes.bool,
    autoScrollBodyContent: PropTypes.bool,
    bodyClassName: PropTypes.string,
    bodyStyle: PropTypes.object,
    children: PropTypes.node,
    className: PropTypes.string,
    contentClassName: PropTypes.string,
    contentStyle: PropTypes.object,
    modal: PropTypes.bool,
    onRequestClose: PropTypes.func,
    open: PropTypes.bool.isRequired,
    overlayClassName: PropTypes.string,
    overlayStyle: PropTypes.object,
    paperClassName: PropTypes.string,
    paperProps: PropTypes.object,
    repositionOnUpdate: PropTypes.bool,
    style: PropTypes.object,
    title: PropTypes.node,
    titleClassName: PropTypes.string,
    titleStyle: PropTypes.object,
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  componentWillMount() {
    const uniqueId = `${this.constructor.name}-${this.makeRandomNumber()}`;
    this.uniqueId = uniqueId.replace(/[^A-Za-z0-9-]/gi, '');
  }

  componentDidMount() {
    this.positionDialog();
  }

  componentDidUpdate() {
    this.positionDialog();
  }

  componentWillUpdate(nextProps) {
    if (nextProps.open) {
      this.originalFocus = document.activeElement;
    } else if (this.originalFocus) {
      this.originalFocus.focus();
      this.originalFocus = null;
    }
  }

  makeRandomNumber(){
    return Math.floor(Math.random() * 0xFFFF);
  }

  positionDialog() {
    const {
      actions,
      autoDetectWindowHeight,
      autoScrollBodyContent,
      bodyStyle,
      open,
      repositionOnUpdate,
      title,
    } = this.props;

    if (!open) {
      return;
    }

    const clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
    const container = ReactDOM.findDOMNode(this);
    const dialogWindow = ReactDOM.findDOMNode(this.refs.dialogWindow);
    const dialogContent = ReactDOM.findDOMNode(this.refs.dialogContent);
    const minPaddingTop = 16;

    // Reset the height in case the window was resized.
    dialogWindow.style.height = '';
    dialogContent.style.height = '';

    const dialogWindowHeight = dialogWindow.offsetHeight;
    let paddingTop = ((clientHeight - dialogWindowHeight) / 2) - 64;
    if (paddingTop < minPaddingTop) paddingTop = minPaddingTop;

    // Vertically center the dialog window, but make sure it doesn't
    // transition to that position.
    if (repositionOnUpdate || !container.style.paddingTop) {
      container.style.paddingTop = `${paddingTop}px`;
    }

    // Force a height if the dialog is taller than clientHeight
    if (autoDetectWindowHeight || autoScrollBodyContent) {
      const styles = getStyles(this.props, this.context);
      styles.body = Object.assign(styles.body, bodyStyle);
      let maxDialogContentHeight = clientHeight - 2 * 64;

      if (title) maxDialogContentHeight -= dialogContent.previousSibling.offsetHeight;

      if (React.Children.count(actions)) {
        maxDialogContentHeight -= dialogContent.nextSibling.offsetHeight;
      }

      dialogContent.style.maxHeight = `${maxDialogContentHeight}px`;
      if (maxDialogContentHeight > dialogWindowHeight) {
        dialogContent.style.borderBottom = 'none';
        dialogContent.style.borderTop = 'none';
      }
    }
  }

  requestClose(buttonClicked) {
    if (!buttonClicked && this.props.modal) {
      return;
    }

    if (this.props.onRequestClose) {
      this.props.onRequestClose(!!buttonClicked);
      const ActiveElement = window.prevActiveElement;
      ActiveElement.focus();
    }
  }

  handleTouchTapOverlay = () => {
    this.requestClose(false);
  };

  handleKeyUp = (event) => {
    switch (keycode(event)) {
      case 'esc':
        this.requestClose(false);
        break;
      case 'tab':
        if (!this.refs.dialogContainer.contains(document.activeElement)) {
          const actionWrap = this.refs.dialogActions.children[0],
          button = actionWrap.querySelector('button');

          (button || actionWrap).focus();
          event.preventDefault();
        }
        break;
    }
  };

  handleResize = () => {
    this.positionDialog();
  };

  render() {
    window.prevActiveElement = document.activeElement;

    const {
      id,
      actions,
      actionsContainerClassName,
      actionsContainerStyle,
      bodyClassName,
      bodyStyle,
      children,
      className,
      contentClassName,
      contentStyle,
      overlayClassName,
      overlayStyle,
      open,
      paperClassName,
      paperProps,
      style,
      titleClassName,
      titleStyle,
      title,
      style,
      modal,
    } = this.props;

    const baseId = id || this.uniqueId;
    const actionsContainerId = baseId + '-actionsContainer';
    const titleId = baseId + "-title";

    const {prepareStyles} = this.context.muiTheme;
    const styles = getStyles(this.props, this.context);

    styles.root = Object.assign(styles.root, style);
    styles.content = Object.assign(styles.content, contentStyle);
    styles.body = Object.assign(styles.body, bodyStyle);
    styles.actionsContainer = Object.assign(styles.actionsContainer, actionsContainerStyle);
    styles.overlay = Object.assign(styles.overlay, overlayStyle);
    styles.title = Object.assign(styles.title, titleStyle);

    const actionsContainer = React.Children.count(actions) > 0 && (

        {React.Children.map(actions, (action) => {
          const childKey = this.makeRandomNumber();
          return React.cloneElement(action, {
            ref: `action-${childKey}`
          });
        })}

    );

    let titleElement = title;
    if (React.isValidElement(title)) {
      titleElement = React.cloneElement(title, {
        className: title.props.className || titleClassName,
        style: prepareStyles(Object.assign(styles.title, title.props.style)),
        id: this.contentTitleId
      });
    } else if (typeof title === 'string') {
      titleElement = (

          {title}

      );
    }

    const ariaHidden = this.props.modal ? true : null;
    const ariaLabelledBy = (typeof title === 'string') ? titleId : null;
    const dialogGroupID = baseId + '-dialogGroup';
    const transitionGroupId = baseId + '-transitionGroup';
    const transitionItemId = baseId + '-transitionItem';
    const overlayId = baseId + '-overlay';
    const dialogContentId = baseId + '-dialogContent';

    return (

        {open &&
          <EventListener
            target="window"
            onKeyDown={this.handleKeyDown}
            onKeyUp={this.handleKeyUp}
            onResize={this.handleResize}
          />
        }
        <ReactTransitionGroup
          role="dialog"
          aria-live="assertive"
          aria-labelledby={ariaLabelledBy}
          aria-describedby={baseId}
          component="div"
          ref="dialogWindow"
          transitionAppear={true}
          transitionAppearTimeout={450}
          transitionEnter={true}
          transitionEnterTimeout={450}
          id={transitionGroupId}
        >
          {open &&
            <TransitionItem
              id={transitionItemId}
              aria-hidden={ariaHidden}
              className={contentClassName}
              style={styles.content}
            >
              <Paper className={paperClassName} zDepth={4} {...paperProps}>
                {titleElement}

                  {children}

                {actionsContainer}
              </Paper>
            </TransitionItem>
          }
        </ReactTransitionGroup>
        <Overlay
          show={open}
          className={overlayClassName}
          style={styles.overlay}
          onTouchTap={this.handleTouchTapOverlay}
        />

    );
  }
}

class Dialog extends Component {
  static propTypes = {
    /**
     * Action buttons to display below the Dialog content (`children`).
     * This property accepts either a React element, or an array of React elements.
     */
    actions: PropTypes.node,
    /**
     * The `className` to add to the actions container's root element.
     */
    actionsContainerClassName: PropTypes.string,
    /**
     * Overrides the inline-styles of the actions container's root element.
     */
    actionsContainerStyle: PropTypes.object,
    /**
     * If set to true, the height of the `Dialog` will be auto detected. A max height
     * will be enforced so that the content does not extend beyond the viewport.
     */
    autoDetectWindowHeight: PropTypes.bool,
    /**
     * If set to true, the body content of the `Dialog` will be scrollable.
     */
    autoScrollBodyContent: PropTypes.bool,
    /**
     * The `className` to add to the content's root element under the title.
     */
    bodyClassName: PropTypes.string,
    /**
     * Overrides the inline-styles of the content's root element under the title.
     */
    bodyStyle: PropTypes.object,
    /**
     * The contents of the `Dialog`.
     */
    children: PropTypes.node,
    /**
     * @ignore
     */
    className: PropTypes.string,
    /**
     * The `className` to add to the content container.
     */
    contentClassName: PropTypes.string,
    /**
     * Overrides the inline-styles of the content container.
     */
    contentStyle: PropTypes.object,
    /**
     * The id value used for the component.
     * This will be used as a base for all child components also.
     * If not provided the class name along with appropriate properties and a random number will be used.
     */
    id: PropTypes.string,
    /**
     * Force the user to use one of the actions in the `Dialog`.
     * Clicking outside the `Dialog` will not trigger the `onRequestClose`.
     */
    modal: PropTypes.bool,
    /**
     * Fired when the `Dialog` is requested to be closed by a click outside the `Dialog` or on the buttons.
     *
     * @param {bool} buttonClicked Determines whether a button click triggered this request.
     */
    onRequestClose: PropTypes.func,
    /**
     * Controls whether the Dialog is opened or not.
     */
    open: PropTypes.bool.isRequired,
    /**
     * The `className` to add to the `Overlay` component that is rendered behind the `Dialog`.
     */
    overlayClassName: PropTypes.string,
    /**
     * Overrides the inline-styles of the `Overlay` component that is rendered behind the `Dialog`.
     */
    overlayStyle: PropTypes.object,
    /**
     * The CSS class name of the `Paper` element.
     */
    paperClassName: PropTypes.string,
    /**
     * Properties applied to the `Paper` element.
     */
    paperProps: PropTypes.object,
    /**
     * Determines whether the `Dialog` should be repositioned when it's contents are updated.
     */
    repositionOnUpdate: PropTypes.bool,
    /**
     * Override the inline-styles of the root element.
     */
    style: PropTypes.object,
    /**
     * The title to display on the `Dialog`. Could be number, string, element or an array containing these types.
     */
    title: PropTypes.node,
    /**
     * The `className` to add to the title's root container element.
     */
    titleClassName: PropTypes.string,
    /**
     * Overrides the inline-styles of the title's root container element.
     */
    titleStyle: PropTypes.object,
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  static defaultProps = {
    autoDetectWindowHeight: true,
    autoScrollBodyContent: false,
    modal: false,
    repositionOnUpdate: true,
  };

  renderLayer = () => {
    return (
      <DialogInline {...this.props} />
    );
  };

  componentWillUpdate(nextProps) {
    if (nextProps.open) {
      this.originalFocus = document.activeElement;
    } else {
      setTimeout(() => {
        if (this.originalFocus) {
          this.originalFocus.focus();
          this.originalFocus = null;
        }
      }, 1);
    }
  }

  render() {
    return (
      <RenderToLayer render={this.renderLayer} open={true} useLayerForClickAway={false} />
    );
  }
}

export default Dialog;
<commit_msg>issue caused when doing a merge on dialog #36 removed the extra declaration of "style"<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import EventListener from 'react-event-listener';
import keycode from 'keycode';
import transitions from '../styles/transitions';
import Overlay from '../internal/Overlay';
import RenderToLayer from '../internal/RenderToLayer';
import Paper from '../Paper';

import ReactTransitionGroup from 'react-transition-group/TransitionGroup';

class TransitionItem extends Component {
  static propTypes = {
    id: PropTypes.string,
    children: PropTypes.node,
    style: PropTypes.object,
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  state = {
    style: {},
  };

  componentWillMount() {
    const uniqueId = `${this.constructor.name}-${Math.floor(Math.random() * 0xFFFF)}`;
    this.uniqueIdTransactionItem = uniqueId.replace(/[^A-Za-z0-9-]/gi, '');
  }

  componentWillUnmount() {
    clearTimeout(this.enterTimeout);
    clearTimeout(this.leaveTimeout);
  }

  componentWillEnter(callback) {
    this.componentWillAppear(callback);
  }

  componentWillAppear(callback) {
    const spacing = this.context.muiTheme.baseTheme.spacing;

    this.setState({
      style: {
        opacity: 1,
        transform: `translate(0, ${spacing.desktopKeylineIncrement}px)`,
      },
    });

    this.enterTimeout = setTimeout(callback, 450); // matches transition duration
  }

  componentWillLeave(callback) {
    this.setState({
      style: {
        opacity: 0,
        transform: 'translate(0, 0)',
      },
    });

    this.leaveTimeout = setTimeout(callback, 450); // matches transition duration
  }

  render() {
    const {
      id,
      style,
      children,
      ...other
    } = this.props;

    const {prepareStyles} = this.context.muiTheme;
    const baseIdItem = id || this.uniqueIdTransactionItem;

    return (

        {children}

    );
  }
}

function getStyles(props, context) {
  const {
    autoScrollBodyContent,
    open,
  } = props;

  const {
    baseTheme: {
      spacing,
      palette,
    },
    dialog,
    zIndex,
  } = context.muiTheme;

  const gutter = spacing.desktopGutter;
  const borderScroll = `1px solid ${palette.borderColor}`;

  return {
    root: {
      position: 'fixed',
      boxSizing: 'border-box',
      WebkitTapHighlightColor: 'rgba(0,0,0,0)', // Remove mobile color flashing (deprecated)
      zIndex: zIndex.dialog,
      top: 0,
      left: open ? 0 : -10000,
      width: '100%',
      height: '100%',
      transition: open ?
        transitions.easeOut('0ms', 'left', '0ms') :
        transitions.easeOut('0ms', 'left', '450ms'),
    },
    content: {
      boxSizing: 'border-box',
      WebkitTapHighlightColor: 'rgba(0,0,0,0)', // Remove mobile color flashing (deprecated)
      transition: transitions.easeOut(),
      position: 'relative',
      width: '75%',
      maxWidth: spacing.desktopKeylineIncrement * 12,
      margin: '0 auto',
      zIndex: zIndex.dialog,
    },
    actionsContainer: {
      boxSizing: 'border-box',
      WebkitTapHighlightColor: 'rgba(0,0,0,0)', // Remove mobile color flashing (deprecated)
      padding: 8,
      width: '100%',
      textAlign: 'right',
      marginTop: autoScrollBodyContent ? -1 : 0,
      borderTop: autoScrollBodyContent ? borderScroll : 'none',
    },
    overlay: {
      zIndex: zIndex.dialogOverlay,
    },
    title: {
      margin: 0,
      padding: `${gutter}px ${gutter}px 20px ${gutter}px`,
      color: palette.textColor,
      fontSize: dialog.titleFontSize,
      lineHeight: '32px',
      fontWeight: 400,
      marginBottom: autoScrollBodyContent ? -1 : 0,
      borderBottom: autoScrollBodyContent ? borderScroll : 'none',
    },
    body: {
      fontSize: dialog.bodyFontSize,
      color: dialog.bodyColor,
      padding: `${props.title ? 0 : gutter}px ${gutter}px ${gutter}px`,
      boxSizing: 'border-box',
      overflowY: autoScrollBodyContent ? 'auto' : 'hidden',
      borderTop: autoScrollBodyContent ? borderScroll : 'none',
      borderBottom: autoScrollBodyContent ? borderScroll : 'none',
    },
  };
}

class DialogInline extends Component {
  static propTypes = {
    id: PropTypes.string,
    actions: PropTypes.node,
    actionsContainerClassName: PropTypes.string,
    actionsContainerStyle: PropTypes.object,
    autoDetectWindowHeight: PropTypes.bool,
    autoScrollBodyContent: PropTypes.bool,
    bodyClassName: PropTypes.string,
    bodyStyle: PropTypes.object,
    children: PropTypes.node,
    className: PropTypes.string,
    contentClassName: PropTypes.string,
    contentStyle: PropTypes.object,
    modal: PropTypes.bool,
    onRequestClose: PropTypes.func,
    open: PropTypes.bool.isRequired,
    overlayClassName: PropTypes.string,
    overlayStyle: PropTypes.object,
    paperClassName: PropTypes.string,
    paperProps: PropTypes.object,
    repositionOnUpdate: PropTypes.bool,
    style: PropTypes.object,
    title: PropTypes.node,
    titleClassName: PropTypes.string,
    titleStyle: PropTypes.object,
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  componentWillMount() {
    const uniqueId = `${this.constructor.name}-${this.makeRandomNumber()}`;
    this.uniqueId = uniqueId.replace(/[^A-Za-z0-9-]/gi, '');
  }

  componentDidMount() {
    this.positionDialog();
  }

  componentDidUpdate() {
    this.positionDialog();
  }

  componentWillUpdate(nextProps) {
    if (nextProps.open) {
      this.originalFocus = document.activeElement;
    } else if (this.originalFocus) {
      this.originalFocus.focus();
      this.originalFocus = null;
    }
  }

  makeRandomNumber(){
    return Math.floor(Math.random() * 0xFFFF);
  }

  positionDialog() {
    const {
      actions,
      autoDetectWindowHeight,
      autoScrollBodyContent,
      bodyStyle,
      open,
      repositionOnUpdate,
      title,
    } = this.props;

    if (!open) {
      return;
    }

    const clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
    const container = ReactDOM.findDOMNode(this);
    const dialogWindow = ReactDOM.findDOMNode(this.refs.dialogWindow);
    const dialogContent = ReactDOM.findDOMNode(this.refs.dialogContent);
    const minPaddingTop = 16;

    // Reset the height in case the window was resized.
    dialogWindow.style.height = '';
    dialogContent.style.height = '';

    const dialogWindowHeight = dialogWindow.offsetHeight;
    let paddingTop = ((clientHeight - dialogWindowHeight) / 2) - 64;
    if (paddingTop < minPaddingTop) paddingTop = minPaddingTop;

    // Vertically center the dialog window, but make sure it doesn't
    // transition to that position.
    if (repositionOnUpdate || !container.style.paddingTop) {
      container.style.paddingTop = `${paddingTop}px`;
    }

    // Force a height if the dialog is taller than clientHeight
    if (autoDetectWindowHeight || autoScrollBodyContent) {
      const styles = getStyles(this.props, this.context);
      styles.body = Object.assign(styles.body, bodyStyle);
      let maxDialogContentHeight = clientHeight - 2 * 64;

      if (title) maxDialogContentHeight -= dialogContent.previousSibling.offsetHeight;

      if (React.Children.count(actions)) {
        maxDialogContentHeight -= dialogContent.nextSibling.offsetHeight;
      }

      dialogContent.style.maxHeight = `${maxDialogContentHeight}px`;
      if (maxDialogContentHeight > dialogWindowHeight) {
        dialogContent.style.borderBottom = 'none';
        dialogContent.style.borderTop = 'none';
      }
    }
  }

  requestClose(buttonClicked) {
    if (!buttonClicked && this.props.modal) {
      return;
    }

    if (this.props.onRequestClose) {
      this.props.onRequestClose(!!buttonClicked);
      const ActiveElement = window.prevActiveElement;
      ActiveElement.focus();
    }
  }

  handleTouchTapOverlay = () => {
    this.requestClose(false);
  };

  handleKeyUp = (event) => {
    switch (keycode(event)) {
      case 'esc':
        this.requestClose(false);
        break;
      case 'tab':
        if (!this.refs.dialogContainer.contains(document.activeElement)) {
          const actionWrap = this.refs.dialogActions.children[0],
          button = actionWrap.querySelector('button');

          (button || actionWrap).focus();
          event.preventDefault();
        }
        break;
    }
  };

  handleResize = () => {
    this.positionDialog();
  };

  render() {
    window.prevActiveElement = document.activeElement;

    const {
      id,
      actions,
      actionsContainerClassName,
      actionsContainerStyle,
      bodyClassName,
      bodyStyle,
      children,
      className,
      contentClassName,
      contentStyle,
      overlayClassName,
      overlayStyle,
      open,
      paperClassName,
      paperProps,
      titleClassName,
      titleStyle,
      title,
      style,
      modal,
    } = this.props;

    const baseId = id || this.uniqueId;
    const actionsContainerId = baseId + '-actionsContainer';
    const titleId = baseId + "-title";

    const {prepareStyles} = this.context.muiTheme;
    const styles = getStyles(this.props, this.context);

    styles.root = Object.assign(styles.root, style);
    styles.content = Object.assign(styles.content, contentStyle);
    styles.body = Object.assign(styles.body, bodyStyle);
    styles.actionsContainer = Object.assign(styles.actionsContainer, actionsContainerStyle);
    styles.overlay = Object.assign(styles.overlay, overlayStyle);
    styles.title = Object.assign(styles.title, titleStyle);

    const actionsContainer = React.Children.count(actions) > 0 && (

        {React.Children.map(actions, (action) => {
          const childKey = this.makeRandomNumber();
          return React.cloneElement(action, {
            ref: `action-${childKey}`
          });
        })}

    );

    let titleElement = title;
    if (React.isValidElement(title)) {
      titleElement = React.cloneElement(title, {
        className: title.props.className || titleClassName,
        style: prepareStyles(Object.assign(styles.title, title.props.style)),
        id: this.contentTitleId
      });
    } else if (typeof title === 'string') {
      titleElement = (

          {title}

      );
    }

    const ariaHidden = this.props.modal ? true : null;
    const ariaLabelledBy = (typeof title === 'string') ? titleId : null;
    const dialogGroupID = baseId + '-dialogGroup';
    const transitionGroupId = baseId + '-transitionGroup';
    const transitionItemId = baseId + '-transitionItem';
    const overlayId = baseId + '-overlay';
    const dialogContentId = baseId + '-dialogContent';

    return (

        {open &&
          <EventListener
            target="window"
            onKeyDown={this.handleKeyDown}
            onKeyUp={this.handleKeyUp}
            onResize={this.handleResize}
          />
        }
        <ReactTransitionGroup
          role="dialog"
          aria-live="assertive"
          aria-labelledby={ariaLabelledBy}
          aria-describedby={baseId}
          component="div"
          ref="dialogWindow"
          transitionAppear={true}
          transitionAppearTimeout={450}
          transitionEnter={true}
          transitionEnterTimeout={450}
          id={transitionGroupId}
        >
          {open &&
            <TransitionItem
              id={transitionItemId}
              aria-hidden={ariaHidden}
              className={contentClassName}
              style={styles.content}
            >
              <Paper className={paperClassName} zDepth={4} {...paperProps}>
                {titleElement}

                  {children}

                {actionsContainer}
              </Paper>
            </TransitionItem>
          }
        </ReactTransitionGroup>
        <Overlay
          show={open}
          className={overlayClassName}
          style={styles.overlay}
          onTouchTap={this.handleTouchTapOverlay}
        />

    );
  }
}

class Dialog extends Component {
  static propTypes = {
    /**
     * Action buttons to display below the Dialog content (`children`).
     * This property accepts either a React element, or an array of React elements.
     */
    actions: PropTypes.node,
    /**
     * The `className` to add to the actions container's root element.
     */
    actionsContainerClassName: PropTypes.string,
    /**
     * Overrides the inline-styles of the actions container's root element.
     */
    actionsContainerStyle: PropTypes.object,
    /**
     * If set to true, the height of the `Dialog` will be auto detected. A max height
     * will be enforced so that the content does not extend beyond the viewport.
     */
    autoDetectWindowHeight: PropTypes.bool,
    /**
     * If set to true, the body content of the `Dialog` will be scrollable.
     */
    autoScrollBodyContent: PropTypes.bool,
    /**
     * The `className` to add to the content's root element under the title.
     */
    bodyClassName: PropTypes.string,
    /**
     * Overrides the inline-styles of the content's root element under the title.
     */
    bodyStyle: PropTypes.object,
    /**
     * The contents of the `Dialog`.
     */
    children: PropTypes.node,
    /**
     * @ignore
     */
    className: PropTypes.string,
    /**
     * The `className` to add to the content container.
     */
    contentClassName: PropTypes.string,
    /**
     * Overrides the inline-styles of the content container.
     */
    contentStyle: PropTypes.object,
    /**
     * The id value used for the component.
     * This will be used as a base for all child components also.
     * If not provided the class name along with appropriate properties and a random number will be used.
     */
    id: PropTypes.string,
    /**
     * Force the user to use one of the actions in the `Dialog`.
     * Clicking outside the `Dialog` will not trigger the `onRequestClose`.
     */
    modal: PropTypes.bool,
    /**
     * Fired when the `Dialog` is requested to be closed by a click outside the `Dialog` or on the buttons.
     *
     * @param {bool} buttonClicked Determines whether a button click triggered this request.
     */
    onRequestClose: PropTypes.func,
    /**
     * Controls whether the Dialog is opened or not.
     */
    open: PropTypes.bool.isRequired,
    /**
     * The `className` to add to the `Overlay` component that is rendered behind the `Dialog`.
     */
    overlayClassName: PropTypes.string,
    /**
     * Overrides the inline-styles of the `Overlay` component that is rendered behind the `Dialog`.
     */
    overlayStyle: PropTypes.object,
    /**
     * The CSS class name of the `Paper` element.
     */
    paperClassName: PropTypes.string,
    /**
     * Properties applied to the `Paper` element.
     */
    paperProps: PropTypes.object,
    /**
     * Determines whether the `Dialog` should be repositioned when it's contents are updated.
     */
    repositionOnUpdate: PropTypes.bool,
    /**
     * Override the inline-styles of the root element.
     */
    style: PropTypes.object,
    /**
     * The title to display on the `Dialog`. Could be number, string, element or an array containing these types.
     */
    title: PropTypes.node,
    /**
     * The `className` to add to the title's root container element.
     */
    titleClassName: PropTypes.string,
    /**
     * Overrides the inline-styles of the title's root container element.
     */
    titleStyle: PropTypes.object,
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  static defaultProps = {
    autoDetectWindowHeight: true,
    autoScrollBodyContent: false,
    modal: false,
    repositionOnUpdate: true,
  };

  renderLayer = () => {
    return (
      <DialogInline {...this.props} />
    );
  };

  componentWillUpdate(nextProps) {
    if (nextProps.open) {
      this.originalFocus = document.activeElement;
    } else {
      setTimeout(() => {
        if (this.originalFocus) {
          this.originalFocus.focus();
          this.originalFocus = null;
        }
      }, 1);
    }
  }

  render() {
    return (
      <RenderToLayer render={this.renderLayer} open={true} useLayerForClickAway={false} />
    );
  }
}

export default Dialog;
<|endoftext|>


<commit_before>var assert = require('assert');
var mocha  = require('mocha');

var fakedomamd = require('../fakedom-amd');

describe('fakedom-amd', function() {

    var dom;

    describe('Constructor', function() {
        var err;
        var window;

        var html = '
test
';
        var options = { };

        context('when given HTML, require options and a callback', function() {
            beforeEach(function(done) {
                dom = new fakedomamd(html, options, function(e, w) {
                    err = e;
                    window = w;
                    done();
                });
            });

            it('should load the given HTML', function() {
                assert.ok(window.document.innerHTML.indexOf('
test
') !== -1);
            });

            it('should initialise require.js', function() {
                assert.ok(window.require);
            });

            it('should pass the given options to require.js');

            it('should not pass an error to the callback', function() {
                assert.ok(!err);
            });
        });

        context('when given html and a callback', function() {
            beforeEach(function(done) {
                dom = new fakedomamd(html, function(e, w) {
                    err = e;
                    window = w;
                    done();
                });
            });

            it('should load the given HTML', function() {
                assert.ok(window.document.innerHTML.indexOf('
test
') !== -1);
            });

            it('should initialise require.js', function() {
                assert.ok(window.require);
            });

            it('should not pass an error to the callback', function() {
                assert.ok(!err);
            });
        });

        context('when given options and a callback', function() {
            beforeEach(function(done) {
                dom = new fakedomamd({ baseUrl: 'test' }, function(e, w) {
                    err = e;
                    window = w;
                    done();
                });
            });

            it('should load default HTML', function() {
                assert.ok(window.document.innerHTML.indexOf('
test
') === -1);
            });

            it('should initialise require.js', function() {
                assert.ok(window.require);
            });

            it('should not pass an error to the callback', function() {
                assert.ok(!err);
            });
        });

        context('when given a callback', function() {
            beforeEach(function(done) {
                dom = new fakedomamd(function(e, w) {
                    err = e;
                    window = w;
                    done();
                });
            });

            it('should load default HTML', function() {
                assert.ok(window.document.innerHTML.indexOf('
test
') === -1);
            });

            it('should initialise require.js', function() {
                assert.ok(window.require);
            });

            it('should not pass an error to the callback', function() {
                assert.ok(!err);
            });
        });
    });

    describe('amdrequire()', function() {
        var err;
        var window;
        var module;

        var html = '
test
';
        var options = { };

        context('when it has been constructed', function() {
            beforeEach(function(done) {
                dom = new fakedomamd({ baseUrl: 'test' }, function(e, w) {
                    window = w;
                    done();
                });
            });

            context('and amdrequire() is given a module name and callback', function() {
                beforeEach(function(done) {
                    dom.amdrequire('fixture/standalone', function(e, m) {
                        err = e;
                        module = m;
                        done();
                    });
                });

                it('should not pass an error to the callback', function() {
                    assert.ok(!err);
                });

                it('should pass the module to the callback', function() {
                    assert.ok(module);
                    assert.equal(module.foo(), 'standalone-foo');
                });

                context('and amdrequire() is run again with the same module name', function() {
                    beforeEach(function(done) {
                        dom.amdrequire('fixture/standalone', function(e, m) {
                            err = e;
                            module = m;
                            done();
                        });
                    });

                    it('should not pass an error to the callback', function() {
                        assert.ok(!err);
                    });

                    it('should pass the module to the callback', function() {
                        assert.ok(module);
                        assert.equal(module.foo(), 'standalone-foo');
                    });
                });
            });

            context('and amdrequire() loads a module that has a dependency', function() {
                beforeEach(function(done) {
                    dom.amdrequire('fixture/dependency-a', function(e, m) {
                        err = e;
                        module = m;
                        done();
                    });
                });

                it('should not pass an error to the callback', function() {
                    assert.ok(!err);
                });

                it('should pass the module to the callback with depdency fulfilled', function() {
                    assert.ok(module);
                    assert.equal(module.foo(), 'foo');
                    assert.equal(module.bar(), 'bar');
                });
            });

            context('and amdrequire() loads a module that it cannot find', function() {
                beforeEach(function(done) {
                    dom.amdrequire('fixture/does-not-exist', function(e, m) {
                        err = e;
                        module = m;
                        done();
                    });
                });

                it('should pass an error to the callback', function() {
                    assert.ok(err);
                });

                it('should not have loaded the module', function() {
                    assert.ok(!module);
                });
            });
        });
    });

    describe('DOM manipulation', function() {
        var window;
        var module;

        context('with an AMD module loaded that reaches into the DOM', function() {
            beforeEach(function(done) {
                var dom = new fakedomamd({ baseUrl: 'test' }, function(e, w) {
                    err = e;
                    window = w;
                    loadModule()
                });

                function loadModule() {
                    dom.amdrequire('fixture/dom-manipulator', function(e, m) {
                        err = e;
                        module = m;
                        done();
                    });
                }
            });

            context('when the module tries to add a class to the DOM body element', function() {
                beforeEach(function() {
                    module.addClassToBody('foo');
                });

                it('should have added the class', function() {
                    var actual = window.document.body.getAttribute('class');
                    assert.ok(actual.indexOf('foo') !== -1);
                });
            });
        });
    });

    describe('stub()', function() {
        var window;
        var module;

        context('when it has been constructed', function() {
            beforeEach(function(done) {
                dom = new fakedomamd({ baseUrl: 'test' }, function(e, w) {
                    window = w;
                    done();
                });
            });

            context('and an existing module is stubbed', function() {
                beforeEach(function() {
                    var stub = {
                        bar: function() {
                            return 'stub'
                        }
                    }
                    dom.stub('fixture/dependency-b', stub);
                });

                context('and amdrequire() loads a module that has the stub dependency', function() {
                    beforeEach(function(done) {
                        dom.amdrequire('fixture/dependency-a', function(e, m) {
                            err = e;
                            module = m;
                            done();
                        });
                    });

                    it('should use the stub instead of the real dependency', function() {
                        assert.equal(module.foo(), 'foo');
                        assert.equal(module.bar(), 'stub');
                    });
                });
            });
        });
    });

});
<commit_msg>Implement test for require.js options being passed through<commit_after>var assert = require('assert');
var mocha  = require('mocha');

var fakedomamd = require('../fakedom-amd');

describe('fakedom-amd', function() {

    var dom;

    describe('Constructor', function() {
        var err;
        var window;

        var requireJsLoaded = false;

        var html = '
test
';
        var options = {
            callback: function() { requireJsLoaded = true; }
        };

        context('when given HTML, require options and a callback', function() {
            beforeEach(function(done) {
                dom = new fakedomamd(html, options, function(e, w) {
                    err = e;
                    window = w;
                    done();
                });
            });

            it('should load the given HTML', function() {
                assert.ok(window.document.innerHTML.indexOf('
test
') !== -1);
            });

            it('should initialise require.js', function() {
                assert.ok(window.require);
            });

            it('should pass the given options to require.js', function() {
                assert.ok(requireJsLoaded);
            });

            it('should not pass an error to the callback', function() {
                assert.ok(!err);
            });
        });

        context('when given html and a callback', function() {
            beforeEach(function(done) {
                dom = new fakedomamd(html, function(e, w) {
                    err = e;
                    window = w;
                    done();
                });
            });

            it('should load the given HTML', function() {
                assert.ok(window.document.innerHTML.indexOf('
test
') !== -1);
            });

            it('should initialise require.js', function() {
                assert.ok(window.require);
            });

            it('should not pass an error to the callback', function() {
                assert.ok(!err);
            });
        });

        context('when given options and a callback', function() {
            beforeEach(function(done) {
                dom = new fakedomamd({ baseUrl: 'test' }, function(e, w) {
                    err = e;
                    window = w;
                    done();
                });
            });

            it('should load default HTML', function() {
                assert.ok(window.document.innerHTML.indexOf('
test
') === -1);
            });

            it('should initialise require.js', function() {
                assert.ok(window.require);
            });

            it('should not pass an error to the callback', function() {
                assert.ok(!err);
            });
        });

        context('when given a callback', function() {
            beforeEach(function(done) {
                dom = new fakedomamd(function(e, w) {
                    err = e;
                    window = w;
                    done();
                });
            });

            it('should load default HTML', function() {
                assert.ok(window.document.innerHTML.indexOf('
test
') === -1);
            });

            it('should initialise require.js', function() {
                assert.ok(window.require);
            });

            it('should not pass an error to the callback', function() {
                assert.ok(!err);
            });
        });
    });

    describe('amdrequire()', function() {
        var err;
        var window;
        var module;

        var html = '
test
';
        var options = { };

        context('when it has been constructed', function() {
            beforeEach(function(done) {
                dom = new fakedomamd({ baseUrl: 'test' }, function(e, w) {
                    window = w;
                    done();
                });
            });

            context('and amdrequire() is given a module name and callback', function() {
                beforeEach(function(done) {
                    dom.amdrequire('fixture/standalone', function(e, m) {
                        err = e;
                        module = m;
                        done();
                    });
                });

                it('should not pass an error to the callback', function() {
                    assert.ok(!err);
                });

                it('should pass the module to the callback', function() {
                    assert.ok(module);
                    assert.equal(module.foo(), 'standalone-foo');
                });

                context('and amdrequire() is run again with the same module name', function() {
                    beforeEach(function(done) {
                        dom.amdrequire('fixture/standalone', function(e, m) {
                            err = e;
                            module = m;
                            done();
                        });
                    });

                    it('should not pass an error to the callback', function() {
                        assert.ok(!err);
                    });

                    it('should pass the module to the callback', function() {
                        assert.ok(module);
                        assert.equal(module.foo(), 'standalone-foo');
                    });
                });
            });

            context('and amdrequire() loads a module that has a dependency', function() {
                beforeEach(function(done) {
                    dom.amdrequire('fixture/dependency-a', function(e, m) {
                        err = e;
                        module = m;
                        done();
                    });
                });

                it('should not pass an error to the callback', function() {
                    assert.ok(!err);
                });

                it('should pass the module to the callback with depdency fulfilled', function() {
                    assert.ok(module);
                    assert.equal(module.foo(), 'foo');
                    assert.equal(module.bar(), 'bar');
                });
            });

            context('and amdrequire() loads a module that it cannot find', function() {
                beforeEach(function(done) {
                    dom.amdrequire('fixture/does-not-exist', function(e, m) {
                        err = e;
                        module = m;
                        done();
                    });
                });

                it('should pass an error to the callback', function() {
                    assert.ok(err);
                });

                it('should not have loaded the module', function() {
                    assert.ok(!module);
                });
            });
        });
    });

    describe('DOM manipulation', function() {
        var window;
        var module;

        context('with an AMD module loaded that reaches into the DOM', function() {
            beforeEach(function(done) {
                var dom = new fakedomamd({ baseUrl: 'test' }, function(e, w) {
                    err = e;
                    window = w;
                    loadModule()
                });

                function loadModule() {
                    dom.amdrequire('fixture/dom-manipulator', function(e, m) {
                        err = e;
                        module = m;
                        done();
                    });
                }
            });

            context('when the module tries to add a class to the DOM body element', function() {
                beforeEach(function() {
                    module.addClassToBody('foo');
                });

                it('should have added the class', function() {
                    var actual = window.document.body.getAttribute('class');
                    assert.ok(actual.indexOf('foo') !== -1);
                });
            });
        });
    });

    describe('stub()', function() {
        var window;
        var module;

        context('when it has been constructed', function() {
            beforeEach(function(done) {
                dom = new fakedomamd({ baseUrl: 'test' }, function(e, w) {
                    window = w;
                    done();
                });
            });

            context('and an existing module is stubbed', function() {
                beforeEach(function() {
                    var stub = {
                        bar: function() {
                            return 'stub'
                        }
                    }
                    dom.stub('fixture/dependency-b', stub);
                });

                context('and amdrequire() loads a module that has the stub dependency', function() {
                    beforeEach(function(done) {
                        dom.amdrequire('fixture/dependency-a', function(e, m) {
                            err = e;
                            module = m;
                            done();
                        });
                    });

                    it('should use the stub instead of the real dependency', function() {
                        assert.equal(module.foo(), 'foo');
                        assert.equal(module.bar(), 'stub');
                    });
                });
            });
        });
    });

});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  name: 'Protobuf',
  package: 'foam.grammars',

  properties: [
    {
      name: 'grammar',
      factory: function() {
        return  SkipGrammar.create({
          __proto__: grammar,

          START: sym('proto'),

          d: range('0', '9'),

          w: alt(sym('d'), range('a', 'z'), range('A', 'Z'), "_"),

          a: alt(range('a', 'z'), range('A', 'Z')),

          proto: repeat(alt(
            sym('message'),
            sym('extend'),
            sym('enum'),
            sym('import'),
            sym('package'),
            sym('option'),
            sym('syntax'), ';')),

          syntax: seq("syntax", "=", sym('strLit'), ";"),

          import: seq("import", sym('strLit'), ";"),

          package: seq("package", sym('ident'), repeat(seq(".", sym("ident"))), ";"),

          option: seq("option", sym('optionBody'), ";"),

          optionBody: seq(sym('ident'), repeat(seq(".", sym('ident'))), "=", sym('constant')),

          message: seq("message", sym('ident'), sym('messageBody')),

          extend: seq("extend", sym('userType'), sym('messageBody')),

          enum: seq("enum", sym('ident'), sym("openBrace"), repeat(alt(sym('option'), sym('enumField'), ";")), sym("closeBrace")),

          enumField: seq(sym('ident'), "=", sym('sintLit'), ";"),

          service: seq("service", sym('ident'), sym("openBrace"), repeat(seq(sym('option'), sym('rpc')), ";"), sym("closeBrace")),

          rpc: seq("rpc", sym('ident'), "(", sym('userType'), ")", "returns", "(", sym('userType'), ")", ";"),

          openBrace: literal("{"),
          closeBrace: literal("}"),

          messageBody: seq(
            sym('openBrace'),
            repeat(
              alt(sym('field'), sym('enum'), sym('message'), sym('extend'), sym('extensions'), sym('group'), sym('option'), ';')
            ),
            sym('closeBrace')),

          group: seq(sym('modifier'), "group", sym('camelIdent'), "=", sym('intLit'), sym('messageBody')),

          // tag number must be 2^28-1 or lower
          field: seq(
            sym('modifier'),
            sym('type'),
            sym('ident'),
            "=",
            sym('intLit'),
            optional(seq("[", sym('fieldOption'), repeat(",", sym('fieldOption') ), "]")),
            ";"),

          fieldOption: alt(sym('optionBody'), seq("default", "=", sym('constant'))),

          extensions: seq("extensions", sym('intLit'), "to", alt(sym('intLit'), "max"), ";"),

          modifier: alt("required", "optional", "repeated"),

          type: alt(
            "double", "float", "int32", "int64", "uint32", "uint64",
            "sint32", "sint64", "fixed32", "fixed64", "sfixed32",
            "sfixed64", "bool", "string", "bytes", sym('userType')),

          // leading dot for identifiers means they're fully qualified
          userType: noskip(plus(seq(optional("."), sym('ident')))),

          constant: alt(sym('ident'), sym('sintLit'), sym('floatLit'), sym('strLit'), sym('boolLit')),

          ident: seq(sym('a'), repeat(sym('w'))),

          // according to parser.cc, group names must start with a capital letter as a
          // hack for backwards-compatibility
          camelIdent: seq(range('A', 'Z'), repeat(sym('w'))),

          intLit: alt(sym('decInt'), sym('hexInt'), sym('octInt')),

          sintLit: alt(
            seq(optional(alt('+', '-')), sym('decInt')),
            sym('intLit')),

          decInt: plus(sym('d')),

          hexInt: seq('/0', alt('x', 'X'), plus(alt(range('A','F'), range('a', 'f'), range('0', '9')))),

          octInt: seq('/0', plus(range('0', '7'))),

          floatLit:
          seq(
            seq(
              sym('decInt'),
              optional('.', sym('decInt'))),
            optional(
              seq(
                alt('E', 'e'),
                optional(alt('+', '-')),
                sym('decInt')))),

          boolLit: alt("true", "false"),

          strLit: noskip(seq(sym('quote'), repeat(alt(sym('hexEscape'), sym('octEscape'), sym('charEscape'), sym('quoteEscape'), not(sym('quote'), anyChar))) ,sym('quote'))),

          quote: alt('"', "'"),

          hexEscape: seq('\\', alt('x', 'X'), repeat(alt(range('A','F'), range('a', 'f'), range('0', '9'), undefined, 1,2))),

          octEscape: seq('\\0', repeat(range('0', '7'), undefined, 1, 3)),

          charEscape: seq('\\', alt('a', 'b', 'f', 'n', 'r', 't', 'v','?')),

          quoteEscape: seq('\\"'),
        }, alt(repeat0(alt(' ', '\t', '\n', '\r')), // Skip whitespace and C++ style comments.
               seq('//', repeat0(notChar('\n')))));

      }
    },
    {
      name: 'parser',
      factory: function() {
        var X = this.X;
        return this.grammar.addActions({
          package: function(a) {
            this.currentPackage = a[1];
            if ( a[2] && a[2].length ) {
              this.currentPackage += a[2].map(function(a) { return a.join(''); }).join('')
            }
          },

          quoteEscape: function(a) {
            return ['"'];
          },

          enumField: function(a) {
            return [a[0], a[2]];
          },

          enum: function(a) {
            var constants = {};
            var name = a[1];
            var values = a[3];
            for ( var i = 0 ; i < values.length ; i++ ) {
              var value = values[i];
              constants[value[0]] = value[1][1];
            }
            var m = Model.create({
              name: name,
              package: this.currentPackage,
              constants: constants
            });
            return m;
          },

          userType: function(a) {
            return a[0].join('');
          },

          field: function(a) {
            if (a[0] === 'repeated') {
              return ArrayProperty.create({
                subType: a[1],
                name: a[2],
                prototag: a[4]
              });
            } else {
              var prop = Property.create({
                type: a[1],
                name: a[2],
                prototag: a[4],
                required: a[0] === 'required'
              });
              // TODO: Hack for enums unti they're modelled.
              var subtype = (this.ctx || GLOBAL)[prop.type];
              if ( subtype && subtype.type === 'Enum' ) {
                prop.outProtobuf = function(obj, out) {
                  if ( this.f(obj) === "" ) return;
                  outProtobufPrimitive('int32', this.prototag, this.f(obj), out);
                };
              }
              return prop;
            }
          },

          message: function(a) {
            var properties = [];
            var models = [];
            for (var i = 0; i < a[2].length; i++) {
              if ( ! a[2][i] ) continue;

              if ( Property.isInstance(a[2][i]) ) {
                properties.push(a[2][i]);
              } else if ( Model.isInstance(a[2][i]) ) {
                models.push(a[2][i]);
              }
            }
            var args = {
              name: a[1],
              properties: properties,
              models: models
            };
            if ( this.currentPackage ) args.package = this.currentPackage;
            var model = Model.create(args);
            return model;
          },

          messageBody: function(a) { return a[1]; },

          ident: function(a) { return a[0] + a[1].join(''); },

          decInt: function(a) { return parseInt(a.join('')); }
        });
      }
    }
  ]
});
<commit_msg>Protobufs: Parser now handles services and RPCs, and works as a CLI tool<commit_after>/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  name: 'Protobuf',
  package: 'foam.grammars',
  requires: [
    'node.dao.JSModelFileDAO',
  ],

  properties: [
    {
      model_: 'foam.node.NodeRequireProperty',
      name: 'fs',
    },
    {
      name: 'inputFile',
    },
    {
      name: 'outputDir',
    },
    {
      name: 'grammar',
      factory: function() {
        return  SkipGrammar.create({
          __proto__: grammar,

          START: sym('proto'),

          d: range('0', '9'),

          w: alt(sym('d'), range('a', 'z'), range('A', 'Z'), "_"),

          a: alt(range('a', 'z'), range('A', 'Z')),

          proto: repeat(alt(
            sym('message'),
            sym('extend'),
            sym('enum'),
            sym('import'),
            sym('package'),
            sym('service'),
            sym('option'),
            sym('syntax'), ';')),

          syntax: seq("syntax", "=", sym('strLit'), ";"),

          import: seq("import", sym('strLit'), ";"),

          package: seq("package", sym('ident'), repeat(seq(".", sym("ident"))), ";"),

          option: seq("option", sym('optionBody'), ";"),

          optionBody: seq(
            alt(
              seq1(1, '(', plus(sym('ident'), '.'), ')'),
              sym('ident')),
            repeat(seq(".", sym('ident'))),
            "=", sym('constant')),

          message: seq("message", sym('ident'), sym('messageBody')),

          extend: seq("extend", sym('userType'), sym('messageBody')),

          enum: seq("enum", sym('ident'), sym("openBrace"), repeat(alt(sym('option'), sym('enumField'), ";")), sym("closeBrace")),

          enumField: seq(sym('ident'), "=", sym('sintLit'), ";"),

          service: seq("service", sym('ident'), sym("openBrace"), repeat(alt(sym('option'), sym('rpc'))), sym("closeBrace")),

          rpc: seq("rpc", sym('ident'), "(", sym('userType'), ")", "returns", "(", sym('userType'), ")", optional(seq1(1, '{', repeat(sym('option')), '}')), ';'),

          openBrace: literal("{"),
          closeBrace: literal("}"),

          messageBody: seq(
            sym('openBrace'),
            repeat(
              alt(sym('field'), sym('enum'), sym('message'), sym('extend'), sym('extensions'), sym('group'), sym('option'), ';')
            ),
            sym('closeBrace')),

          group: seq(sym('modifier'), "group", sym('camelIdent'), "=", sym('intLit'), sym('messageBody')),

          // tag number must be 2^28-1 or lower
          field: seq(
            sym('modifier'),
            sym('type'),
            sym('ident'),
            "=",
            sym('intLit'),
            optional(seq("[", sym('fieldOption'), repeat(",", sym('fieldOption') ), "]")),
            ";"),

          fieldOption: alt(sym('optionBody'), seq("default", "=", sym('constant'))),

          extensions: seq("extensions", sym('intLit'), "to", alt(sym('intLit'), "max"), ";"),

          modifier: alt("required", "optional", "repeated"),

          type: alt(
            "double", "float", "int32", "int64", "uint32", "uint64",
            "sint32", "sint64", "fixed32", "fixed64", "sfixed32",
            "sfixed64", "bool", "string", "bytes", sym('userType')),

          // leading dot for identifiers means they're fully qualified
          userType: noskip(plus(seq(optional("."), sym('ident')))),

          constant: alt(sym('ident'), sym('floatLit'), sym('sintLit'), sym('strLit'), sym('boolLit')),

          ident: seq(sym('a'), repeat(sym('w'))),

          // according to parser.cc, group names must start with a capital letter as a
          // hack for backwards-compatibility
          camelIdent: seq(range('A', 'Z'), repeat(sym('w'))),

          intLit: alt(sym('decInt'), sym('hexInt'), sym('octInt')),

          sintLit: alt(
            seq(alt('+', '-'), sym('decInt')),
            sym('intLit')),

          decInt: plus(sym('d')),

          hexInt: seq('/0', alt('x', 'X'), plus(alt(range('A','F'), range('a', 'f'), range('0', '9')))),

          octInt: seq('/0', plus(range('0', '7'))),

          floatLit: alt(
            seq('.', sym('decInt'), optional(sym('exponent'))),
            seq(sym('decInt'), sym('exponent')),
            seq(sym('decInt'), '.', optional(sym('decInt')), optional(sym('exponent')))),

          exponent: seq(alt('E', 'e'), optional(alt('+', '-')), sym('decInt')),

          boolLit: alt("true", "false"),

          strLit: noskip(seq(sym('quote'), repeat(alt(sym('hexEscape'), sym('octEscape'), sym('charEscape'), sym('quoteEscape'), not(sym('quote'), anyChar))) ,sym('quote'))),

          quote: alt('"', "'"),

          hexEscape: seq('\\', alt('x', 'X'), repeat(alt(range('A','F'), range('a', 'f'), range('0', '9'), undefined, 1,2))),

          octEscape: seq('\\0', repeat(range('0', '7'), undefined, 1, 3)),

          charEscape: seq('\\', alt('a', 'b', 'f', 'n', 'r', 't', 'v','?')),

          quoteEscape: seq('\\"'),
        }, alt(repeat0(alt(' ', '\t', '\n', '\r')), // Skip whitespace and C++ style comments.
               seq('//', repeat0(notChar('\n')))));

      }
    },
    {
      name: 'parser',
      factory: function() {
        var X = this.X;
        return this.grammar.addActions({
          package: function(a) {
            this.currentPackage = a[1];
            if ( a[2] && a[2].length ) {
              this.currentPackage += a[2].map(function(a) { return a.join(''); }).join('')
            }
          },

          quoteEscape: function(a) {
            return ['"'];
          },

          enumField: function(a) {
            return [a[0], a[2]];
          },

          enum: function(a) {
            var constants = {};
            var name = a[1];
            var values = a[3];
            for ( var i = 0 ; i < values.length ; i++ ) {
              var value = values[i];
              constants[value[0]] = value[1][1];
            }
            var m = Model.create({
              name: name,
              package: this.currentPackage,
              constants: constants
            });
            return m;
          },

          userType: function(a) {
            return a[0].join('');
          },

          field: function(a) {
            if (a[0] === 'repeated') {
              return ArrayProperty.create({
                subType: a[1],
                name: a[2],
                prototag: a[4]
              });
            } else {
              var prop = Property.create({
                type: a[1],
                name: a[2],
                prototag: a[4],
                required: a[0] === 'required'
              });
              // TODO: Hack for enums unti they're modelled.
              var subtype = (this.ctx || GLOBAL)[prop.type];
              if ( subtype && subtype.type === 'Enum' ) {
                prop.outProtobuf = function(obj, out) {
                  if ( this.f(obj) === "" ) return;
                  outProtobufPrimitive('int32', this.prototag, this.f(obj), out);
                };
              }
              return prop;
            }
          },

          message: function(a) {
            var properties = [];
            var models = [];
            for (var i = 0; i < a[2].length; i++) {
              if ( ! a[2][i] ) continue;

              if ( Property.isInstance(a[2][i]) ) {
                properties.push(a[2][i]);
              } else if ( Model.isInstance(a[2][i]) ) {
                models.push(a[2][i]);
              }
            }
            var args = {
              name: a[1],
              properties: properties,
              models: models
            };
            if ( this.currentPackage ) args.package = this.currentPackage;
            var model = Model.create(args);
            return model;
          },

          messageBody: function(a) { return a[1]; },

          ident: function(a) { return a[0] + a[1].join(''); },

          decInt: function(a) { return parseInt(a.join('')); }
        });
      }
    }
  ],

  methods: [
    function execute() {
      if (!this.inputFile || !this.outputDir) {
        console.error('inputFile and outputDir arguments are required.');
        process.exit(1);
      }
      var buffer = this.fs.readFileSync(this.inputFile);
      var output = this.parser.parseString(buffer.toString());
      var dao = this.JSModelFileDAO.create({
        prefix: this.outputDir
      });
      for (var i = 0; i < output.length; i++) {
        if (Model.isInstance(output[i])) {
          dao.put(output[i]);
        }
      }
    },
  ]
});
<|endoftext|>


<commit_before>/*jslint*/

(function(){

	function teardown() {
		$('#testElement').remove();
	}

	function setup() {
		$('body').append('

');
	}

	module("Capture", {teardown: teardown, setup: setup });

		test("Namespace setup", function() {
			ok(typeof jQuery !== "undefined",'jQuery namespace initialised');
			ok(typeof $.fn.capture !== "undefined",'Capture plugin exists');
		});

		test("Basic binding to elements", function() {
			var viewController = { init:function(){} };
			var boundViewController = $('#testElement').capture(viewController);

			strictEqual(viewController, boundViewController, 'The boundViewController is not a new instance of viewController');
		});

		test("Methods in the prototype are not called by capture", function() {
			function ViewController() {
				// Empty
			}
			ViewController.prototype = {
				init : function() {
					ok(false,'Init in prototype will never execute');
				},
				onclick : {
					'#testElement' : function(e) {}
				}
			};

			var viewController = new ViewController();
			var boundViewController = $('#testElement').capture(viewController);

			ok(typeof $('#testElement').data('events') === "undefined", 'valid onclick in the prototype will not bind');
		});

	module("Initialisation", {teardown: teardown, setup: setup });

		test("Extra arguments are sent to init function", function() {

			var options = {};
			var anotherValue = 'bar';
			var viewController = {
				init: function(firstArg, secondArg){
					equal(options, firstArg, 'Options object is passed to init');
					equal(anotherValue, secondArg, 'anotherValue is pass to init');
				}
			};

			$('#testElement').capture(viewController, options, anotherValue);

			expect(2);
		});

		test("Object oriented style calling works", function() {

			var options = {};
			var anotherValue = 'bar';
			var viewController = {
				init: function(firstArg, secondArg){
					equal(options, firstArg, 'Options object is passed to init');
					equal(anotherValue, secondArg, 'anotherValue is pass to init');
				}
			};

			Capture('#testElement', viewController, options, anotherValue);

			expect(2);
		});

}());<commit_msg>Tests to ensure exceptions are generated when called differently.<commit_after>/*jslint*/

(function(){

    function teardown() {
        $('#testElement').remove();
    }

    function setup() {
        $('body').append('

');
    }

    module("Capture", {teardown: teardown, setup: setup });

        test("Namespace setup", function() {
            ok(typeof jQuery !== "undefined",'jQuery namespace initialised');
            ok(typeof $.fn.capture !== "undefined",'Capture plugin exists');
        });

        test("Basic binding to elements", function() {
            var viewController = { init:function(){} };
            var boundViewController = $('#testElement').capture(viewController);

            strictEqual(viewController, boundViewController, 'The boundViewController is not a new instance of viewController');
        });

        test("Methods in the prototype are not called by capture", function() {
            function ViewController() {
                // Empty
            }
            ViewController.prototype = {
                init : function() {
                    ok(false,'Init in prototype will never execute');
                },
                onclick : {
                    '#testElement' : function(e) {}
                }
            };

            var viewController = new ViewController();
            var boundViewController = $('#testElement').capture(viewController);

            ok(typeof $('#testElement').data('events') === "undefined", 'valid onclick in the prototype will not bind');
        });

    module("Initialisation", {teardown: teardown, setup: setup });

        test("Extra arguments are sent to init function", function() {

            var options = {};
            var anotherValue = 'bar';
            var viewController = {
                init: function(firstArg, secondArg){
                    equal(options, firstArg, 'Options object is passed to init');
                    equal(anotherValue, secondArg, 'anotherValue is pass to init');
                }
            };

            $('#testElement').capture(viewController, options, anotherValue);

            expect(2);
        });

        test("Object oriented style calling works", function() {

            var options = {};
            var anotherValue = 'bar';
            var viewController = {
                init: function(firstArg, secondArg){
                    equal(options, firstArg, 'Options object is passed to init');
                    equal(anotherValue, secondArg, 'anotherValue is pass to init');
                }
            };

            Capture('#testElement', viewController, options, anotherValue);

            expect(2);
        });

        test("Calling 'Capture' generates exception on lack of element", function() {

            try {
                Capture('#fakeElement', {});
                fail('Exception not created');
            } catch (e) {
                ok('Exception created when when element doesn\'t exist');
            }

        });

        test("Calling '$().capture' doesnt generate exception on lack of element", function() {
            // Because the jQuery way is to fail silently
            try {
                Capture('#fakeElement', {});
                ok('No exception created when element doesn\'t exist');
            } catch (e) {
                fail('Exception created when element doesn\'t exist');
            }

        });

}());<|endoftext|>


<commit_before>import React from 'react';
import sinon from 'sinon';
import ColourHelper from "helper/colourHelper";

describe("Tests for helper/colourHelper.js", () => {

    describe("and validates colours as true for", () => {

        it("rgb", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "rgb" })).to.equal(true);

        });

        it("hex", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "hex" })).to.equal(true);

        });

        it("hue", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "hue" })).to.equal(true);

        });

        it("saturation", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "saturation" })).to.equal(true);

        });

        it("lightness", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "lightness" })).to.equal(true);

        });

        it("alpha", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "alpha" })).to.equal(true);

        });

    });

    describe("and validates colours as false for", () => {

        it("default", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "default" })).to.equal(false);

        });

        it("incorrect hex length", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b32565b3256', type: "default" })).to.equal(false);

        });

        it("non match against rgb pattern", () => {

            expect(ColourHelper.validateColours({ rgb: '333,666,999', hex: '5b3256', type: "default" })).to.equal(false);

        });

    });

    describe("and handles button functions when clicked, for", () => {

        it("randomise", () => {

            let spy = sinon.spy();
            spy(ColourHelper.randomise());

            sinon.assert.calledWith(spy, sinon.match.has("rgb", sinon.match.string)
                .and(sinon.match.has("hex", sinon.match.string))
                .and(sinon.match.has("hue", sinon.match.number))
                .and(sinon.match.has("rgbOpacity", sinon.match.number))
                .and(sinon.match.has("hexOpacity", sinon.match.number))
                .and(sinon.match.has("saturation", sinon.match.number))
                .and(sinon.match.has("lightness", sinon.match.number))
                .and(sinon.match.has("alpha", sinon.match.number))
                .and(sinon.match.has("theme", sinon.match.string))
                .and(sinon.match.has("bgColour", sinon.match.string))
            );

        });

        it("lighten", () => {

            let spy = sinon.spy();
            spy(ColourHelper.lighten("5b3256"));

            sinon.assert.calledWith(spy, sinon.match.has("rgb", "124,68,117")
                .and(sinon.match.has("hex", "7c4475"))
                .and(sinon.match.has("hue", 307))
                .and(sinon.match.has("rgbOpacity", sinon.match.number))
                .and(sinon.match.has("hexOpacity", sinon.match.number))
                .and(sinon.match.has("saturation", 29))
                .and(sinon.match.has("lightness", 38))
                .and(sinon.match.has("alpha", sinon.match.number))
                .and(sinon.match.has("theme", "light"))
                .and(sinon.match.has("bgColour", "124,68,117,1.0"))
            );

        });

        it("darken", () => {

            let spy = sinon.spy();
            spy(ColourHelper.darken("5b3256"));

            sinon.assert.calledWith(spy, sinon.match.has("rgb", "58,32,55")
                .and(sinon.match.has("hex", "3a2037"))
                .and(sinon.match.has("hue", 307))
                .and(sinon.match.has("rgbOpacity", sinon.match.number))
                .and(sinon.match.has("hexOpacity", sinon.match.number))
                .and(sinon.match.has("saturation", 29))
                .and(sinon.match.has("lightness", 18))
                .and(sinon.match.has("alpha", sinon.match.number))
                .and(sinon.match.has("theme", "light"))
                .and(sinon.match.has("bgColour", "58,32,55,1.0"))
            );

        });

    });

});
<commit_msg>:construction: Added tests around colour trimming strings - identified a number of bugs<commit_after>import React from 'react';
import sinon from 'sinon';
import ColourHelper from "helper/colourHelper";

describe("Tests for helper/colourHelper.js", () => {

    describe("and validates colours as true for", () => {

        it("rgb", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "rgb" })).to.equal(true);

        });

        it("hex", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "hex" })).to.equal(true);

        });

        it("hue", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "hue" })).to.equal(true);

        });

        it("saturation", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "saturation" })).to.equal(true);

        });

        it("lightness", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "lightness" })).to.equal(true);

        });

        it("alpha", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "alpha" })).to.equal(true);

        });

    });

    describe("and validates colours as false for", () => {

        it("default", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b3256', type: "default" })).to.equal(false);

        });

        it("incorrect hex length", () => {

            expect(ColourHelper.validateColours({ rgb: '91,50,86', hex: '5b32565b3256', type: "default" })).to.equal(false);

        });

        it("non match against rgb pattern", () => {

            expect(ColourHelper.validateColours({ rgb: '333,666,999', hex: '5b3256', type: "default" })).to.equal(false);

        });

    });

    describe("and handles button functions when clicked, for", () => {

        let spy;

        beforeEach(() => {

            spy = sinon.spy();

        });

        afterEach(() => {

            spy.reset();

        });

        it("randomise", () => {

            spy(ColourHelper.randomise());

            sinon.assert.calledWith(spy, sinon.match.has("rgb", sinon.match.string)
                .and(sinon.match.has("hex", sinon.match.string))
                .and(sinon.match.has("hue", sinon.match.number))
                .and(sinon.match.has("rgbOpacity", sinon.match.number))
                .and(sinon.match.has("hexOpacity", sinon.match.number))
                .and(sinon.match.has("saturation", sinon.match.number))
                .and(sinon.match.has("lightness", sinon.match.number))
                .and(sinon.match.has("alpha", sinon.match.number))
                .and(sinon.match.has("theme", sinon.match.string))
                .and(sinon.match.has("bgColour", sinon.match.string))
            );

        });

        it("lighten", () => {

            spy(ColourHelper.lighten("5b3256"));

            sinon.assert.calledWith(spy, sinon.match.has("rgb", "124,68,117")
                .and(sinon.match.has("hex", "7c4475"))
                .and(sinon.match.has("hue", 307))
                .and(sinon.match.has("rgbOpacity", sinon.match.number))
                .and(sinon.match.has("hexOpacity", sinon.match.number))
                .and(sinon.match.has("saturation", 29))
                .and(sinon.match.has("lightness", 38))
                .and(sinon.match.has("alpha", sinon.match.number))
                .and(sinon.match.has("theme", "light"))
                .and(sinon.match.has("bgColour", "124,68,117,1.0"))
            );

        });

        it("darken", () => {

            spy(ColourHelper.darken("5b3256"));

            sinon.assert.calledWith(spy, sinon.match.has("rgb", "58,32,55")
                .and(sinon.match.has("hex", "3a2037"))
                .and(sinon.match.has("hue", 307))
                .and(sinon.match.has("rgbOpacity", sinon.match.number))
                .and(sinon.match.has("hexOpacity", sinon.match.number))
                .and(sinon.match.has("saturation", 29))
                .and(sinon.match.has("lightness", 18))
                .and(sinon.match.has("alpha", sinon.match.number))
                .and(sinon.match.has("theme", "light"))
                .and(sinon.match.has("bgColour", "58,32,55,1.0"))
            );

        });

    });

    describe("and trims correctly, for", () => {

        it("rgb", () => {

            expect(ColourHelper.trimRgb("123 123 123")).to.equal("123,123,123");

            // bug identified here
            // This is a bug where 3 characters allows the fullstop and 2 characters doesn't
            expect(ColourHelper.trimRgb("123.")).to.equal("123,.");

            expect(ColourHelper.trimRgb("rgb(123,123,123)")).to.equal("123,123,123");

            // bug identified here
            // not excluding all unwanted characters
            // expect(ColourHelper.trimRgb("rgba(123,123,123)")).to.equal("123,123,123");

            expect(ColourHelper.trimRgb(",")).to.equal("");

            // bug identified here
            // shouldn't allow initial fullstop
            // expect(ColourHelper.trimRgb(".")).to.equal("");

            expect(ColourHelper.trimRgb("123,123,123,0.9,")).to.equal("123,123,123,0.9");

            expect(ColourHelper.trimRgb("123,123,123,1.")).to.equal("123,123,123,1");

            expect(ColourHelper.trimRgb("123,123,123,,")).to.equal("123,123,123,");

            // bug identified here
            // shouldn't allow initial space or replace space with comma
            // expect(ColourHelper.trimRgb(" ")).to.equal(",");

            expect(ColourHelper.trimRgb("1231")).to.equal("123,1");

            expect(ColourHelper.trimRgb("123,1231")).to.equal("123,123,1");

            expect(ColourHelper.trimRgb("123,123,1230")).to.equal("123,123,123,0");

            expect(ColourHelper.trimRgb("256")).to.equal("25");

            expect(ColourHelper.trimRgb("255,256")).to.equal("255,25");

            expect(ColourHelper.trimRgb("255,255,256")).to.equal("255,255,25");

            // bug identified here
            // zeros shouldn't be allowed in first 3 sections
            // expect(ColourHelper.trimRgb("255,255,0")).to.equal("255,255,0");

        });

        it("hex", () => {

            expect(ColourHelper.trimHex("5b3256")).to.equal("5b3256");

            expect(ColourHelper.trimHex("#5b3256")).to.equal("5b3256");

            expect(ColourHelper.trimHex("5b3256cc")).to.equal("5b3256cc");

            expect(ColourHelper.trimHex("5b3256cc0")).to.equal("5b3256cc");

            expect(ColourHelper.trimHex("ghijklmnopqrstuvwxyz")).to.equal("");

        });

    });

});
<|endoftext|>