<commit_before>import GeminiScrollbar from 'react-gemini-scrollbar';
/* eslint-disable no-unused-vars */
import React, {PropTypes} from 'react';
/* eslint-enable no-unused-vars */
/**
 * Lifecycle of a Modal:
 * initial page load -> empty ReactCSSTransitionGroup
 * interaction changes open to true -> render modal content without scrollbars
 * get height of content -> rerender modal content and cap the height
 */
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';

import BindMixin from '../Mixin/BindMixin';
import KeyDownMixin from '../Mixin/KeyDownMixin';
import * as DOMUtil from '../Util/DOMUtil';
import Util from '../Util/Util';

const DEFAULT_HEIGHT = {
  height: 'auto',
  contentHeight: 'auto',
  innerContentHeight: null
};

class ModalContents extends Util.mixin(BindMixin, KeyDownMixin) {
  get methodsToBind() {
    return [
      'handleWindowResize',
      'handleBackdropClick',
      'closeModal'
    ];
  }

  get keysToBind() {
    return {
      esc: this.closeModal
    };
  }

  componentWillReceiveProps(nextProps) {
    super.componentWillReceiveProps(...arguments);

    if (this.props.open !== nextProps.open) {
      document.body.classList.toggle('no-overflow');
    }
  }

  componentDidUpdate(prevProps) {
    super.componentDidUpdate(...arguments);

    if (this.props.open) {
      this.checkHeight();
    } else if (!this.props.open && prevProps.open) {
      this.resetHeight();
      this.rerendered = false;
    }
  }

  componentWillMount() {
    super.componentWillMount(...arguments);

    this.resetHeight();
    if (this.props.open) {
      document.body.classList.add('no-overflow');
    }
    window.addEventListener('resize', this.handleWindowResize);
  }

  componentWillUnmount() {
    super.componentWillUnmount(...arguments);

    this.resetHeight();
    document.body.classList.remove('no-overflow');
    window.removeEventListener('resize', this.handleWindowResize);
  }

  handleBackdropClick() {
    if (this.props.closeByBackdropClick) {
      this.closeModal();
    }
  }

  handleWindowResize() {
    // Render the modal again if the window resizes because the height
    // of the viewport may change and we need to adapt to that.
    if (this.props.open) {
      this.forceUpdate();
    }
  }

  resetHeight() {
    this.heightInfo = Util.clone(DEFAULT_HEIGHT);
  }

  checkContentHeightChange(prevHeightInfo, heightInfo) {
    let {contentHeight, height, maxHeight, innerContentHeight} = heightInfo;
    let prevInnerContentHeight = prevHeightInfo.innerContentHeight;
    let prevHeight = prevHeightInfo.height;
    let prevContentHeight = prevHeightInfo.contentHeight;
    let prevMaxHeight = prevHeightInfo.maxHeight;

    // Default update height to whether there is some change in height
    let update = prevHeight !== height || prevContentHeight !== contentHeight;

    if (prevInnerContentHeight != null) {
      // Make sure to update heightInfo with new height difference
      let difference = innerContentHeight - prevInnerContentHeight;
      if (difference !== 0 && height + difference < maxHeight) {
        // Changes this.heightInfo as this is a reference
        heightInfo.height += difference;
        heightInfo.contentHeight += difference;
        update = true;
      }

      // Make sure to update heightInfo with new max height difference
      let maxHeightDifference = maxHeight - prevMaxHeight;
      if (maxHeightDifference > 0 &&
        (heightInfo.contentHeight + difference < innerContentHeight)) {
        // Changes this.heightInfo as this is a reference
        heightInfo.height += maxHeightDifference;
        heightInfo.contentHeight += maxHeightDifference;
        update = true;
      }

    }

    if (update) {
      this.forceUpdate();
    }
  }

  checkHeight() {
    let prevHeightInfo = this.heightInfo;

    // Calculate height and call a render on first render cycle
    this.heightInfo = this.calculateModalHeight();
    this.checkContentHeightChange(prevHeightInfo, this.heightInfo);

    // This only occurs on first render
    if (!this.rerendered) {
      this.rerendered = true;
      this.forceUpdate();
    }
  }

  closeModal() {
    this.props.onClose();
  }

  getInnerContentHeight() {
    if (!this.refs.innerContent) {
      return null;
    }

    return DOMUtil.getComputedDimensions(this.refs.innerContent).height;
  }

  getInnerContainerHeightInfo() {
    let innerContainer = this.refs.innerContainer;
    let originalHeight = innerContainer.offsetHeight;
    let totalContentHeight = this.refs.modal.offsetHeight;

    // Height without padding, margin, border.
    let contentHeight = DOMUtil.getComputedDimensions(innerContainer).height;

    // Height of padding, margin, border.
    let outerHeight = originalHeight - contentHeight;

    let innerContentHeight = this.getInnerContentHeight();

    // Modal cannot be bigger than this height. Add 10 for the gemini
    // horizontal scrollbar.
    let maxHeight = Math.ceil(
      window.innerHeight * this.props.maxHeightPercentage
    ) + 10;

    // We minus the maxHeight with the outerHeight because it will
    // not show the content correctly due to 'box-sizing: border-box'.
    if (contentHeight > maxHeight) {
      contentHeight = maxHeight;
    }

    return {
      contentHeight,
      innerContentHeight,
      maxHeight,
      originalHeight,
      outerHeight,
      totalContentHeight
    };
  }

  calculateModalHeight() {
    let height = 0;
    let {
      contentHeight,
      innerContentHeight,
      maxHeight,
      originalHeight,
      outerHeight,
      totalContentHeight
    } = this.getInnerContainerHeightInfo();

    if (totalContentHeight > maxHeight) {
      height = maxHeight - (totalContentHeight - originalHeight);
      contentHeight = height - outerHeight;
    } else {
      height = originalHeight;
    }

    // Default to auto height because we don't want height to be 0. This may
    // happen when you close a modal and there is no content.
    if (height == null || height <= 0) {
      return Util.clone(DEFAULT_HEIGHT);
    }

    return {height, contentHeight, innerContentHeight, maxHeight};
  }

  getCloseButton() {
    let props = this.props;
    if (!props.showCloseButton) {
      return null;
    }

    return (

          Close

    );
  }

  getHeader() {
    let props = this.props;

    if (props.showHeader === false) {
      return null;
    }

    return (

            {props.titleText}

          {props.subHeader}

    );
  }

  getFooter() {
    let props = this.props;
    if (props.showFooter === false) {
      return null;
    }

    return (

          {props.footer}

    );
  }

  getModalContent(useScrollbar, contentHeight) {
    if (!useScrollbar) {
      return (

          {this.props.children}

      );
    }

    let geminiContainerStyle = {
      height: contentHeight
    };

    return (
      <GeminiScrollbar
        autoshow={true}
        className="container-scrollable"
        style={geminiContainerStyle}>

          {this.props.children}

      </GeminiScrollbar>
    );
  }

  getModal() {
    let props = this.props;
    if (!props.open) {
      return null;
    }

    let calculatedHeight = this.heightInfo;
    let contentHeight = calculatedHeight.contentHeight;

    let modalStyle = null;
    if (this.props.dynamicHeight) {
      modalStyle = {height: calculatedHeight.height};
    }

    let useScrollbar = false;
    if (this.props.useGemini && calculatedHeight.height !== 'auto') {
      useScrollbar = true;
    }

    return (

          {this.getCloseButton()}
          {this.getHeader()}

              {this.getModalContent(useScrollbar, contentHeight)}

          {this.getFooter()}

    );
  }

  getBackdrop() {
    let props = this.props;
    if (!props.open) {
      return null;
    }

    return (

    );
  }

  render() {
    let props = this.props;

    return (

        <ReactCSSTransitionGroup
          transitionAppear={true}
          transitionName={props.transitionNameBackdrop}
          transitionAppearTimeout={props.transitionAppearTimeoutBackdrop}
          transitionEnterTimeout={props.transitionEnterTimeoutBackdrop}
          transitionLeaveTimeout={props.transitionLeaveTimeoutBackdrop}
          component="div">
          {this.getBackdrop()}
        </ReactCSSTransitionGroup>
        <ReactCSSTransitionGroup
          transitionAppear={true}
          transitionName={props.transitionNameModal}
          transitionAppearTimeout={props.transitionAppearTimeoutModal}
          transitionEnterTimeout={props.transitionEnterTimeoutModal}
          transitionLeaveTimeout={props.transitionLeaveTimeoutModal}
          component="div">
          {this.getModal()}
        </ReactCSSTransitionGroup>

    );
  }
}

ModalContents.defaultProps = {
  closeByBackdropClick: true,
  dynamicHeight: true,
  footer: null,
  maxHeightPercentage: 0.6,
  onClose: () => {},
  open: false,
  showCloseButton: false,
  showHeader: false,
  showFooter: false,
  subHeader: null,
  titleText: '',
  transitionNameBackdrop: 'modal-backdrop',
  transitionAppearTimeoutBackdrop: 500,
  transitionEnterTimeoutBackdrop: 500,
  transitionLeaveTimeoutBackdrop: 500,
  transitionNameModal: 'modal',
  transitionAppearTimeoutModal: 500,
  transitionEnterTimeoutModal: 500,
  transitionLeaveTimeoutModal: 500,
  useGemini: true,

  // Default classes.
  backdropClass: 'modal-backdrop',
  bodyClass: 'modal-content',
  closeButtonClass: 'modal-close',
  closeIconClass: 'modal-close-icon icon icon-mini icon-mini-white icon-close',
  closeTitleClass: 'modal-close-title',
  containerClass: 'modal-container',
  footerClass: 'modal-footer',
  footerContainerClass: 'container',
  headerClass: 'modal-header',
  headerContainerClass: 'container',
  modalClass: 'modal modal-large',
  scrollContainerClass: 'modal-content-inner',
  titleClass: 'modal-header-title text-align-center flush-top flush-bottom'
};

ModalContents.propTypes = {
  children: PropTypes.node,
  // Allow closing of modal when click happens outside modal. Defaults to true.
  closeByBackdropClick: PropTypes.bool,
  // Allow resize of modal to fit screen. Defaults to true.
  dynamicHeight: PropTypes.bool,
  // Optional footer
  footer: PropTypes.object,
  // Maximum percent of the viewport the modal can be. Defaults to 0.5.
  maxHeightPercentage: PropTypes.number,
  // Optional callback function exected when modal is closed.
  onClose: PropTypes.func,
  // True if modal is open, false otherwise.
  open: PropTypes.bool,
  // Set true to show explicit close button. Defaults to false.
  showCloseButton: PropTypes.bool,
  // Set true to show header. Defaults to false.
  showHeader: PropTypes.bool,
  // Set true to show footer. Defaults to false.
  showFooter: PropTypes.bool,
  // Optional subheader.
  subHeader: PropTypes.node,
  // Optional title.
  titleText: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.node
  ]),
  // Optional enter and leave transition name for backdrop
  transitionNameBackdrop: PropTypes.string,
  // Optional enter and leave transition name for modal
  // Transition lengths, must be non-zero
  transitionAppearTimeoutBackdrop: PropTypes.number,
  transitionEnterTimeoutBackdrop: PropTypes.number,
  transitionLeaveTimeoutBackdrop: PropTypes.number,
  transitionNameModal: PropTypes.string,
  // Transition lengths, must be non-zero
  transitionAppearTimeoutModal: PropTypes.number,
  transitionEnterTimeoutModal: PropTypes.number,
  transitionLeaveTimeoutModal: PropTypes.number,
  // Option to use Gemini scrollbar. Defaults to true.
  useGemini: PropTypes.bool,

  // Classes
  backdropClass: PropTypes.string,
  bodyClass: PropTypes.string,
  closeButtonClass: PropTypes.string,
  closeIconClass: PropTypes.string,
  closeTitleClass: PropTypes.string,
  containerClass: PropTypes.string,
  footerClass: PropTypes.string,
  footerContainerClass: PropTypes.string,
  headerClass: PropTypes.string,
  headerContainerClass: PropTypes.string,
  innerBodyClass: PropTypes.string,
  modalClass: PropTypes.string,
  modalWrapperClass: PropTypes.string,
  scrollContainerClass: PropTypes.string,
  titleClass: PropTypes.string
};

module.exports = ModalContents;
<commit_msg>Allow modal is enable and disable its transitions<commit_after>import GeminiScrollbar from 'react-gemini-scrollbar';
/* eslint-disable no-unused-vars */
import React, {PropTypes} from 'react';
/* eslint-enable no-unused-vars */
/**
 * Lifecycle of a Modal:
 * initial page load -> empty ReactCSSTransitionGroup
 * interaction changes open to true -> render modal content without scrollbars
 * get height of content -> rerender modal content and cap the height
 */
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';

import BindMixin from '../Mixin/BindMixin';
import KeyDownMixin from '../Mixin/KeyDownMixin';
import * as DOMUtil from '../Util/DOMUtil';
import Util from '../Util/Util';

const DEFAULT_HEIGHT = {
  height: 'auto',
  contentHeight: 'auto',
  innerContentHeight: null
};

class ModalContents extends Util.mixin(BindMixin, KeyDownMixin) {
  get methodsToBind() {
    return [
      'handleWindowResize',
      'handleBackdropClick',
      'closeModal'
    ];
  }

  get keysToBind() {
    return {
      esc: this.closeModal
    };
  }

  componentWillReceiveProps(nextProps) {
    super.componentWillReceiveProps(...arguments);

    if (this.props.open !== nextProps.open) {
      document.body.classList.toggle('no-overflow');
    }
  }

  componentDidUpdate(prevProps) {
    super.componentDidUpdate(...arguments);

    if (this.props.open) {
      this.checkHeight();
    } else if (!this.props.open && prevProps.open) {
      this.resetHeight();
      this.rerendered = false;
    }
  }

  componentWillMount() {
    super.componentWillMount(...arguments);

    this.resetHeight();
    if (this.props.open) {
      document.body.classList.add('no-overflow');
    }
    window.addEventListener('resize', this.handleWindowResize);
  }

  componentWillUnmount() {
    super.componentWillUnmount(...arguments);

    this.resetHeight();
    document.body.classList.remove('no-overflow');
    window.removeEventListener('resize', this.handleWindowResize);
  }

  handleBackdropClick() {
    if (this.props.closeByBackdropClick) {
      this.closeModal();
    }
  }

  handleWindowResize() {
    // Render the modal again if the window resizes because the height
    // of the viewport may change and we need to adapt to that.
    if (this.props.open) {
      this.forceUpdate();
    }
  }

  resetHeight() {
    this.heightInfo = Util.clone(DEFAULT_HEIGHT);
  }

  checkContentHeightChange(prevHeightInfo, heightInfo) {
    let {contentHeight, height, maxHeight, innerContentHeight} = heightInfo;
    let prevInnerContentHeight = prevHeightInfo.innerContentHeight;
    let prevHeight = prevHeightInfo.height;
    let prevContentHeight = prevHeightInfo.contentHeight;
    let prevMaxHeight = prevHeightInfo.maxHeight;

    // Default update height to whether there is some change in height
    let update = prevHeight !== height || prevContentHeight !== contentHeight;

    if (prevInnerContentHeight != null) {
      // Make sure to update heightInfo with new height difference
      let difference = innerContentHeight - prevInnerContentHeight;
      if (difference !== 0 && height + difference < maxHeight) {
        // Changes this.heightInfo as this is a reference
        heightInfo.height += difference;
        heightInfo.contentHeight += difference;
        update = true;
      }

      // Make sure to update heightInfo with new max height difference
      let maxHeightDifference = maxHeight - prevMaxHeight;
      if (maxHeightDifference > 0 &&
        (heightInfo.contentHeight + difference < innerContentHeight)) {
        // Changes this.heightInfo as this is a reference
        heightInfo.height += maxHeightDifference;
        heightInfo.contentHeight += maxHeightDifference;
        update = true;
      }

    }

    if (update) {
      this.forceUpdate();
    }
  }

  checkHeight() {
    let prevHeightInfo = this.heightInfo;

    // Calculate height and call a render on first render cycle
    this.heightInfo = this.calculateModalHeight();
    this.checkContentHeightChange(prevHeightInfo, this.heightInfo);

    // This only occurs on first render
    if (!this.rerendered) {
      this.rerendered = true;
      this.forceUpdate();
    }
  }

  closeModal() {
    this.props.onClose();
  }

  getInnerContentHeight() {
    if (!this.refs.innerContent) {
      return null;
    }

    return DOMUtil.getComputedDimensions(this.refs.innerContent).height;
  }

  getInnerContainerHeightInfo() {
    let innerContainer = this.refs.innerContainer;
    let originalHeight = innerContainer.offsetHeight;
    let totalContentHeight = this.refs.modal.offsetHeight;

    // Height without padding, margin, border.
    let contentHeight = DOMUtil.getComputedDimensions(innerContainer).height;

    // Height of padding, margin, border.
    let outerHeight = originalHeight - contentHeight;

    let innerContentHeight = this.getInnerContentHeight();

    // Modal cannot be bigger than this height. Add 10 for the gemini
    // horizontal scrollbar.
    let maxHeight = Math.ceil(
      window.innerHeight * this.props.maxHeightPercentage
    ) + 10;

    // We minus the maxHeight with the outerHeight because it will
    // not show the content correctly due to 'box-sizing: border-box'.
    if (contentHeight > maxHeight) {
      contentHeight = maxHeight;
    }

    return {
      contentHeight,
      innerContentHeight,
      maxHeight,
      originalHeight,
      outerHeight,
      totalContentHeight
    };
  }

  calculateModalHeight() {
    let height = 0;
    let {
      contentHeight,
      innerContentHeight,
      maxHeight,
      originalHeight,
      outerHeight,
      totalContentHeight
    } = this.getInnerContainerHeightInfo();

    if (totalContentHeight > maxHeight) {
      height = maxHeight - (totalContentHeight - originalHeight);
      contentHeight = height - outerHeight;
    } else {
      height = originalHeight;
    }

    // Default to auto height because we don't want height to be 0. This may
    // happen when you close a modal and there is no content.
    if (height == null || height <= 0) {
      return Util.clone(DEFAULT_HEIGHT);
    }

    return {height, contentHeight, innerContentHeight, maxHeight};
  }

  getCloseButton() {
    let props = this.props;
    if (!props.showCloseButton) {
      return null;
    }

    return (

          Close

    );
  }

  getHeader() {
    let props = this.props;

    if (props.showHeader === false) {
      return null;
    }

    return (

            {props.titleText}

          {props.subHeader}

    );
  }

  getFooter() {
    let props = this.props;
    if (props.showFooter === false) {
      return null;
    }

    return (

          {props.footer}

    );
  }

  getModalContent(useScrollbar, contentHeight) {
    if (!useScrollbar) {
      return (

          {this.props.children}

      );
    }

    let geminiContainerStyle = {
      height: contentHeight
    };

    return (
      <GeminiScrollbar
        autoshow={true}
        className="container-scrollable"
        style={geminiContainerStyle}>

          {this.props.children}

      </GeminiScrollbar>
    );
  }

  getModal() {
    let props = this.props;
    if (!props.open) {
      return null;
    }

    let calculatedHeight = this.heightInfo;
    let contentHeight = calculatedHeight.contentHeight;

    let modalStyle = null;
    if (this.props.dynamicHeight) {
      modalStyle = {height: calculatedHeight.height};
    }

    let useScrollbar = false;
    if (this.props.useGemini && calculatedHeight.height !== 'auto') {
      useScrollbar = true;
    }

    return (

          {this.getCloseButton()}
          {this.getHeader()}

              {this.getModalContent(useScrollbar, contentHeight)}

          {this.getFooter()}

    );
  }

  getBackdrop() {
    let props = this.props;
    if (!props.open) {
      return null;
    }

    return (

    );
  }

  render() {
    let props = this.props;

    return (

        <ReactCSSTransitionGroup
          transitionAppear={true}
          transitionEnter={props.transitionsIn}
          transitionLeave={props.transitionsOut}
          transitionName={props.transitionNameBackdrop}
          transitionAppearTimeout={props.transitionAppearTimeoutBackdrop}
          transitionEnterTimeout={props.transitionEnterTimeoutBackdrop}
          transitionLeaveTimeout={props.transitionLeaveTimeoutBackdrop}
          component="div">
          {this.getBackdrop()}
        </ReactCSSTransitionGroup>
        <ReactCSSTransitionGroup
          transitionAppear={true}
          transitionEnter={props.transitionsIn}
          transitionLeave={props.transitionsOut}
          transitionName={props.transitionNameModal}
          transitionAppearTimeout={props.transitionAppearTimeoutModal}
          transitionEnterTimeout={props.transitionEnterTimeoutModal}
          transitionLeaveTimeout={props.transitionLeaveTimeoutModal}
          component="div">
          {this.getModal()}
        </ReactCSSTransitionGroup>

    );
  }
}

ModalContents.defaultProps = {
  closeByBackdropClick: true,
  dynamicHeight: true,
  footer: null,
  maxHeightPercentage: 0.6,
  onClose: () => {},
  open: false,
  showCloseButton: false,
  showHeader: false,
  showFooter: false,
  subHeader: null,
  titleText: '',
  transitionNameBackdrop: 'modal-backdrop',
  transitionAppearTimeoutBackdrop: 500,
  transitionEnterTimeoutBackdrop: 500,
  transitionLeaveTimeoutBackdrop: 500,
  transitionNameModal: 'modal',
  transitionAppearTimeoutModal: 500,
  transitionEnterTimeoutModal: 500,
  transitionLeaveTimeoutModal: 500,
  transitionsIn: true,
  transitionsOut: true,
  useGemini: true,

  // Default classes.
  backdropClass: 'modal-backdrop',
  bodyClass: 'modal-content',
  closeButtonClass: 'modal-close',
  closeIconClass: 'modal-close-icon icon icon-mini icon-mini-white icon-close',
  closeTitleClass: 'modal-close-title',
  containerClass: 'modal-container',
  footerClass: 'modal-footer',
  footerContainerClass: 'container',
  headerClass: 'modal-header',
  headerContainerClass: 'container',
  modalClass: 'modal modal-large',
  scrollContainerClass: 'modal-content-inner',
  titleClass: 'modal-header-title text-align-center flush-top flush-bottom'
};

ModalContents.propTypes = {
  children: PropTypes.node,
  // Allow closing of modal when click happens outside modal. Defaults to true.
  closeByBackdropClick: PropTypes.bool,
  // Allow resize of modal to fit screen. Defaults to true.
  dynamicHeight: PropTypes.bool,
  // Optional footer
  footer: PropTypes.object,
  // Maximum percent of the viewport the modal can be. Defaults to 0.5.
  maxHeightPercentage: PropTypes.number,
  // Optional callback function exected when modal is closed.
  onClose: PropTypes.func,
  // True if modal is open, false otherwise.
  open: PropTypes.bool,
  // Set true to show explicit close button. Defaults to false.
  showCloseButton: PropTypes.bool,
  // Set true to show header. Defaults to false.
  showHeader: PropTypes.bool,
  // Set true to show footer. Defaults to false.
  showFooter: PropTypes.bool,
  // Optional subheader.
  subHeader: PropTypes.node,
  // Optional title.
  titleText: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.node
  ]),
  // Optional enter and leave transition name for backdrop
  transitionNameBackdrop: PropTypes.string,
  // Optional enter and leave transition name for modal
  // Transition lengths, must be non-zero
  transitionAppearTimeoutBackdrop: PropTypes.number,
  transitionEnterTimeoutBackdrop: PropTypes.number,
  transitionLeaveTimeoutBackdrop: PropTypes.number,
  transitionNameModal: PropTypes.string,
  // Transition lengths, must be non-zero
  transitionAppearTimeoutModal: PropTypes.number,
  transitionEnterTimeoutModal: PropTypes.number,
  transitionLeaveTimeoutModal: PropTypes.number,
  // Optionally disable transitions
  transitionsIn: PropTypes.bool,
  transitionsOut: PropTypes.bool,
  // Option to use Gemini scrollbar. Defaults to true.
  useGemini: PropTypes.bool,

  // Classes
  backdropClass: PropTypes.string,
  bodyClass: PropTypes.string,
  closeButtonClass: PropTypes.string,
  closeIconClass: PropTypes.string,
  closeTitleClass: PropTypes.string,
  containerClass: PropTypes.string,
  footerClass: PropTypes.string,
  footerContainerClass: PropTypes.string,
  headerClass: PropTypes.string,
  headerContainerClass: PropTypes.string,
  innerBodyClass: PropTypes.string,
  modalClass: PropTypes.string,
  modalWrapperClass: PropTypes.string,
  scrollContainerClass: PropTypes.string,
  titleClass: PropTypes.string
};

module.exports = ModalContents;
<|endoftext|>


<commit_before>var XiangqiViewer = {}
window.XiangqiViewer = XiangqiViewer;

XiangqiViewer.BoardRenderer = function(element, cellSize, strokeWidth) {
  var BOARD_WIDTH = 8;
  var BOARD_HEIGHT = 9;
  var BOARD_COLOR = 'rgb(6, 120, 155)';
  var MARGIN = cellSize * 0.70;
  var XSIZE = 2;
  var PIECE_SIZE = 0.85 * cellSize;

  var width = BOARD_WIDTH * cellSize + 2*MARGIN;
  var height = BOARD_HEIGHT * cellSize + 2*MARGIN;

  var leftBorder = MARGIN;
  var rightBorder = BOARD_WIDTH * cellSize + MARGIN;
  var topBorder = MARGIN;
  var botBorder = BOARD_HEIGHT * cellSize + MARGIN;
  var riverTop = Math.floor(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var riverBot = Math.ceil(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var dotDistance = 2 * strokeWidth;

  var root = SVG('xiangqi-example').width(width).height(height);

  this.draw = function(selector) {
    // horizontal
    drawHorizontalLines();
    drawVerticalLines(topBorder, riverTop);
    drawVerticalLines(riverBot, botBorder);
    drawBorder(leftBorder);
    drawBorder(rightBorder);
    drawX(topBorder);
    drawX(botBorder - XSIZE * cellSize);

    for (var i = 2; i < 10; i += 2) {
      drawDots(i, 3, false);
      drawDots(i, 6, false);
    }

    for (var i = 0; i < 8; i += 2) {
      drawDots(i, 3, true);
      drawDots(i, 6, true);
    }
  };

  var drawBoardLine = function(x1, y1, x2, y2) {
    root.line(x1, y1, x2, y2).stroke({
      color: BOARD_COLOR,
      width: strokeWidth
    });
  };

  var drawHorizontalLines = function() {
    for (var j = 0; j < BOARD_HEIGHT + 1; j++) {
      var height = MARGIN + j * cellSize;

      drawBoardLine(leftBorder, height, rightBorder, height);
    };
  }

  var drawVerticalLines = function(top, bottom) {
    for (var j = 1; j < BOARD_WIDTH; j++) {
      var offset = MARGIN + j * cellSize;

      drawBoardLine(offset, top, offset, bottom);
    };
  }

  var drawBorder = function(x) {
    drawBoardLine(x, topBorder - strokeWidth/2, x, botBorder + strokeWidth/2);
  };

  var drawX = function(top) {
    var leftEdge = leftBorder + 3 * cellSize;
    var rightEdge = leftBorder + (3 + XSIZE) * cellSize;
    var bot = top + XSIZE * cellSize;
    drawBoardLine(leftEdge, top, rightEdge, bot);
    drawBoardLine(leftEdge, bot, rightEdge, top);
  };

  // x and y are from 0 to (n - 1)
  var drawDots = function(x, y, isRight) {
    var directionMultipler = isRight ? -1 : 1;
    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize - dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});

    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize + dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});
  };

  this.putPiece = function(x, y, piece) {
    var renderedX = MARGIN + cellSize * x - (PIECE_SIZE / 2);
    var renderedY = MARGIN + cellSize * y - (PIECE_SIZE / 2);
    root.image(piece.spriteUrl())
      .move(renderedX, renderedY)
      .attr({
        width: PIECE_SIZE,
        height: PIECE_SIZE
      });
  }

  return this;
};

XiangqiViewer.Board = function(selector, cellSize, strokeWidth) {
  var renderer = new XiangqiViewer.BoardRenderer(selector, cellSize, strokeWidth);
  renderer.draw();

  var WIDTH = 9
  var HEIGHT = 10
  var matrix;

  var initialize = function() {
    matrix = []; // rank, file; x, y

    for(var i = 0; i < WIDTH; i++) {
      matrix[i] = [];
      for(var j = 0; j < HEIGHT; j++) {
        matrix[i][j] = null;
      }
    }
  };

  var get = function(file, rank) {
    return matrix[file][rank];
  };

  var place = function(x, y, piece) {
    if (x < 0 || y < 0 || x >= WIDTH || y >= HEIGHT) {
      throw "x, y coords are out of bounds";
    }

    matrix[x][y] = piece;
    renderer.putPiece(x, y, piece);
  };

  var searchForward = function(pieceCode) {
    for (var i = 0; i < WIDTH; i++) {
      for (var j = 0; j < HEIGHT; j++) {
        var piece = get(i, j);
        if (piece && piece.code == pieceCode) {
          return {piece: piece, position: {x: i, y: j}};
        }
      }
    }
  };

  var searchBackward = function(pieceCode) {
    for (var i = 0; i < WIDTH; i++) {
      for (var j = HEIGHT - 1; j >= 0; j--) {
        var piece = get(i, j);
        if (piece && piece.code == pieceCode) {
          return {piece: piece, position: {x: i, y: j}};
        }
      }
    }
  };

  var getPositionedPiece(instruction, red) {
    if (instruction[0] == 'f' && red) {
      return searchBackward(instruction[1]);
    } else if (instruction[0] == 'b' && red) {
      return searchForward(instruction[1]);
    } else if (instruction[0] == 'f' && !red) {
      return searchBackward(instruction[1]);
    } else if (instruction[0] == 'b' && !red) {
      return searchForward(instruction[1]);
    } else {
      var instructionPiece = instruction[0];
      var file = instruction[1];

      for (var i = 0; i < HEIGHT; i++) {
        var piece = get(file, i);
        if (piece && piece.code == instructionPiece) {
          return {piece: piece, position: {x: file, y: i}};
        }
      }

      throw "no piece on this file";
    }
  }

  this.runMove = function(instruction) {
    if (instruction.length != 4) {
      throw "illegal instruction format";
    }
    instruction = instruction.toLowerCase();

    var positionedPiece = getPositionedPiece(instruction);
    var move = positionedPiece.piece.getMove(positionedPiece.position, instruction);
    var from = move.from;
    var to = move.to;
  }

  this.defaultSetup = function() {
    place(0, 0, new XiangqiViewer.Chariot(false));
    place(1, 0, new XiangqiViewer.Horse(false));
    place(2, 0, new XiangqiViewer.Elephant(false));
    place(3, 0, new XiangqiViewer.Advisor(false));
    place(4, 0, new XiangqiViewer.General(false));
    place(5, 0, new XiangqiViewer.Advisor(false));
    place(6, 0, new XiangqiViewer.Elephant(false));
    place(7, 0, new XiangqiViewer.Horse(false));
    place(8, 0, new XiangqiViewer.Chariot(false));
    place(0, 3, new XiangqiViewer.Pawn(false));
    place(2, 3, new XiangqiViewer.Pawn(false));
    place(4, 3, new XiangqiViewer.Pawn(false));
    place(6, 3, new XiangqiViewer.Pawn(false));
    place(8, 3, new XiangqiViewer.Pawn(false));
    place(1, 2, new XiangqiViewer.Cannon(false));
    place(7, 2, new XiangqiViewer.Cannon(false));

    place(0, 9, new XiangqiViewer.Chariot(true));
    place(1, 9, new XiangqiViewer.Horse(true));
    place(2, 9, new XiangqiViewer.Elephant(true));
    place(3, 9, new XiangqiViewer.Advisor(true));
    place(4, 9, new XiangqiViewer.General(true));
    place(5, 9, new XiangqiViewer.Advisor(true));
    place(6, 9, new XiangqiViewer.Elephant(true));
    place(7, 9, new XiangqiViewer.Horse(true));
    place(8, 9, new XiangqiViewer.Chariot(true));
    place(0, 6, new XiangqiViewer.Pawn(true));
    place(2, 6, new XiangqiViewer.Pawn(true));
    place(4, 6, new XiangqiViewer.Pawn(true));
    place(6, 6, new XiangqiViewer.Pawn(true));
    place(8, 6, new XiangqiViewer.Pawn(true));
    place(1, 7, new XiangqiViewer.Cannon(true));
    place(7, 7, new XiangqiViewer.Cannon(true));
  };

  initialize();
}

XiangqiViewer.Chariot = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/chariot_red.svg";
    } else {
      return "images/chariot_black.svg";
    }
  };
};

XiangqiViewer.Horse = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/horse_red.svg";
    } else {
      return "images/horse_black.svg";
    }
  };
};

XiangqiViewer.Elephant = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/elephant_red.svg";
    } else {
      return "images/elephant_black.svg";
    }
  };
};

XiangqiViewer.Advisor = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/adviser_red.svg";
    } else {
      return "images/adviser_black.svg";
    }
  };
};

XiangqiViewer.General = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/general_red.svg";
    } else {
      return "images/general_black.svg";
    }
  };
};

XiangqiViewer.Pawn = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/pawn_red.svg";
    } else {
      return "images/pawn_black.svg";
    }
  };
};

XiangqiViewer.Cannon = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/cannon_red.svg";
    } else {
      return "images/cannon_black.svg";
    }
  };
};
<commit_msg>finish runMove<commit_after>var XiangqiViewer = {}
window.XiangqiViewer = XiangqiViewer;

XiangqiViewer.BoardRenderer = function(element, cellSize, strokeWidth) {
  var BOARD_WIDTH = 8;
  var BOARD_HEIGHT = 9;
  var BOARD_COLOR = 'rgb(6, 120, 155)';
  var MARGIN = cellSize * 0.70;
  var XSIZE = 2;
  var PIECE_SIZE = 0.85 * cellSize;

  var width = BOARD_WIDTH * cellSize + 2*MARGIN;
  var height = BOARD_HEIGHT * cellSize + 2*MARGIN;

  var leftBorder = MARGIN;
  var rightBorder = BOARD_WIDTH * cellSize + MARGIN;
  var topBorder = MARGIN;
  var botBorder = BOARD_HEIGHT * cellSize + MARGIN;
  var riverTop = Math.floor(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var riverBot = Math.ceil(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var dotDistance = 2 * strokeWidth;

  var root = SVG('xiangqi-example').width(width).height(height);

  this.draw = function(selector) {
    // horizontal
    drawHorizontalLines();
    drawVerticalLines(topBorder, riverTop);
    drawVerticalLines(riverBot, botBorder);
    drawBorder(leftBorder);
    drawBorder(rightBorder);
    drawX(topBorder);
    drawX(botBorder - XSIZE * cellSize);

    for (var i = 2; i < 10; i += 2) {
      drawDots(i, 3, false);
      drawDots(i, 6, false);
    }

    for (var i = 0; i < 8; i += 2) {
      drawDots(i, 3, true);
      drawDots(i, 6, true);
    }
  };

  var drawBoardLine = function(x1, y1, x2, y2) {
    root.line(x1, y1, x2, y2).stroke({
      color: BOARD_COLOR,
      width: strokeWidth
    });
  };

  var drawHorizontalLines = function() {
    for (var j = 0; j < BOARD_HEIGHT + 1; j++) {
      var height = MARGIN + j * cellSize;

      drawBoardLine(leftBorder, height, rightBorder, height);
    };
  }

  var drawVerticalLines = function(top, bottom) {
    for (var j = 1; j < BOARD_WIDTH; j++) {
      var offset = MARGIN + j * cellSize;

      drawBoardLine(offset, top, offset, bottom);
    };
  }

  var drawBorder = function(x) {
    drawBoardLine(x, topBorder - strokeWidth/2, x, botBorder + strokeWidth/2);
  };

  var drawX = function(top) {
    var leftEdge = leftBorder + 3 * cellSize;
    var rightEdge = leftBorder + (3 + XSIZE) * cellSize;
    var bot = top + XSIZE * cellSize;
    drawBoardLine(leftEdge, top, rightEdge, bot);
    drawBoardLine(leftEdge, bot, rightEdge, top);
  };

  // x and y are from 0 to (n - 1)
  var drawDots = function(x, y, isRight) {
    var directionMultipler = isRight ? -1 : 1;
    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize - dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});

    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize + dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});
  };

  this.putPiece = function(x, y, piece) {
    var renderedX = MARGIN + cellSize * x - (PIECE_SIZE / 2);
    var renderedY = MARGIN + cellSize * y - (PIECE_SIZE / 2);
    root.image(piece.spriteUrl())
      .move(renderedX, renderedY)
      .attr({
        width: PIECE_SIZE,
        height: PIECE_SIZE
      });
  }

  return this;
};

XiangqiViewer.Board = function(selector, cellSize, strokeWidth) {
  var renderer = new XiangqiViewer.BoardRenderer(selector, cellSize, strokeWidth);
  renderer.draw();

  var WIDTH = 9
  var HEIGHT = 10
  var matrix;

  var initialize = function() {
    matrix = []; // rank, file; x, y

    for(var i = 0; i < WIDTH; i++) {
      matrix[i] = [];
      for(var j = 0; j < HEIGHT; j++) {
        matrix[i][j] = null;
      }
    }
  };

  var get = function(file, rank) {
    return matrix[file][rank];
  };

  var place = function(x, y, piece) {
    if (x < 0 || y < 0 || x >= WIDTH || y >= HEIGHT) {
      throw "x, y coords are out of bounds";
    }

    matrix[x][y] = piece;
    renderer.putPiece(x, y, piece);
  };

  var searchForward = function(pieceCode) {
    for (var i = 0; i < WIDTH; i++) {
      for (var j = 0; j < HEIGHT; j++) {
        var piece = get(i, j);
        if (piece && piece.code == pieceCode) {
          return {piece: piece, position: {file: i, rank: j}};
        }
      }
    }
  };

  var searchBackward = function(pieceCode) {
    for (var i = 0; i < WIDTH; i++) {
      for (var j = HEIGHT - 1; j >= 0; j--) {
        var piece = get(i, j);
        if (piece && piece.code == pieceCode) {
          return {piece: piece, position: {file: i, rank: j}};
        }
      }
    }
  };

  var getPositionedPiece(instruction, red) {
    if (instruction[0] == 'f' && red) {
      return searchBackward(instruction[1]);
    } else if (instruction[0] == 'b' && red) {
      return searchForward(instruction[1]);
    } else if (instruction[0] == 'f' && !red) {
      return searchBackward(instruction[1]);
    } else if (instruction[0] == 'b' && !red) {
      return searchForward(instruction[1]);
    } else {
      var instructionPiece = instruction[0];
      var file = instruction[1];

      for (var i = 0; i < HEIGHT; i++) {
        var piece = get(file, i);
        if (piece && piece.code == instructionPiece) {
          return {piece: piece, position: {file: file, rank: i}};
        }
      }

      throw "no piece on this file";
    }
  }

  this.runMove = function(instruction) {
    if (instruction.length != 4) {
      throw "illegal instruction format";
    }
    instruction = instruction.toLowerCase();

    var positionedPiece = getPositionedPiece(instruction);
    var move = positionedPiece.piece.getMove(positionedPiece.position, instruction);

    var capturedPiece = get(move.from.file, move.from.rank);
    if (capturedPiece) {
      matrix[file][rank] = null;
    }

    history.push({from: move.from, to: move.to, capturedPiece: capturedPiece});
    positionedPiece.piece.render();
  }

  this.defaultSetup = function() {
    place(0, 0, new XiangqiViewer.Chariot(false));
    place(1, 0, new XiangqiViewer.Horse(false));
    place(2, 0, new XiangqiViewer.Elephant(false));
    place(3, 0, new XiangqiViewer.Advisor(false));
    place(4, 0, new XiangqiViewer.General(false));
    place(5, 0, new XiangqiViewer.Advisor(false));
    place(6, 0, new XiangqiViewer.Elephant(false));
    place(7, 0, new XiangqiViewer.Horse(false));
    place(8, 0, new XiangqiViewer.Chariot(false));
    place(0, 3, new XiangqiViewer.Pawn(false));
    place(2, 3, new XiangqiViewer.Pawn(false));
    place(4, 3, new XiangqiViewer.Pawn(false));
    place(6, 3, new XiangqiViewer.Pawn(false));
    place(8, 3, new XiangqiViewer.Pawn(false));
    place(1, 2, new XiangqiViewer.Cannon(false));
    place(7, 2, new XiangqiViewer.Cannon(false));

    place(0, 9, new XiangqiViewer.Chariot(true));
    place(1, 9, new XiangqiViewer.Horse(true));
    place(2, 9, new XiangqiViewer.Elephant(true));
    place(3, 9, new XiangqiViewer.Advisor(true));
    place(4, 9, new XiangqiViewer.General(true));
    place(5, 9, new XiangqiViewer.Advisor(true));
    place(6, 9, new XiangqiViewer.Elephant(true));
    place(7, 9, new XiangqiViewer.Horse(true));
    place(8, 9, new XiangqiViewer.Chariot(true));
    place(0, 6, new XiangqiViewer.Pawn(true));
    place(2, 6, new XiangqiViewer.Pawn(true));
    place(4, 6, new XiangqiViewer.Pawn(true));
    place(6, 6, new XiangqiViewer.Pawn(true));
    place(8, 6, new XiangqiViewer.Pawn(true));
    place(1, 7, new XiangqiViewer.Cannon(true));
    place(7, 7, new XiangqiViewer.Cannon(true));
  };

  initialize();
}

XiangqiViewer.Chariot = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/chariot_red.svg";
    } else {
      return "images/chariot_black.svg";
    }
  };
};

XiangqiViewer.Horse = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/horse_red.svg";
    } else {
      return "images/horse_black.svg";
    }
  };
};

XiangqiViewer.Elephant = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/elephant_red.svg";
    } else {
      return "images/elephant_black.svg";
    }
  };
};

XiangqiViewer.Advisor = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/adviser_red.svg";
    } else {
      return "images/adviser_black.svg";
    }
  };
};

XiangqiViewer.General = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/general_red.svg";
    } else {
      return "images/general_black.svg";
    }
  };
};

XiangqiViewer.Pawn = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/pawn_red.svg";
    } else {
      return "images/pawn_black.svg";
    }
  };
};

XiangqiViewer.Cannon = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/cannon_red.svg";
    } else {
      return "images/cannon_black.svg";
    }
  };
};
<|endoftext|>


<commit_before>// Copyright 2014 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.

module.exports = function(grunt) {
  // Load the grunt related dev deps listed in package.json.
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  // Load our custom tasks.
  grunt.loadTasks('./build/tasks/');

  var browsers = grunt.option('browsers');
  if (browsers) {
    browsers = browsers.split(/\s*,\s*/g);
  } else {
    browsers = ['PhantomJS'];
  }

  grunt.initConfig({
    clean: {
      all: ['tmp', 'dist']
    },

    'closure-compiler': {
      check: {
        cwd: 'lib/',
        js: ['**/*.js',
             '../third_party/closure-compiler/contrib/externs/jasmine.js',
             '../tmp/third_party/dcodeIO/fs.js',
             '../tmp/third_party/dcodeIO/buffer.js',
             '../tmp/third_party/dcodeIO/stream.js',
             '../tmp/third_party/dcodeIO/events.js'
            ],
        jsOutputFile: 'tmp/closure/out.js',
        options: require('./build/closure-options.json')
      }
    },

    git_deploy: {
      samples: {
        options: {
          url: 'git@github.com:chromium/axiom.git'
        },
        src: 'tmp'
      },
    },

    make_dir_module: {
      wash: {
        strip: 2,
        dest: 'lib/wash/exe_modules.js',
        cwd: 'lib',
        modules: ['wash/exe/*.js']
      }
    },

    make_main_module: {
      test: {
        require: '__axiomRequire__',
        dest: 'tmp/test/test_main.js',
        cwd: 'lib/',
        modules: ['**/*.test.js']
      }
    },

    closure_externs: {
      build: {
        expand: true,
        src: ['**/*.js'],
        dest: 'tmp/third_party/dcodeIO/',
        cwd: 'third_party/dcodeIO/',
      }
    },

    concat: {
      axiom_base: {
        src: ['loader/axiom_amd.js',
              'tmp/amd/lib/axiom/**/*.js',
              '!tmp/amd/lib/axiom/fs/node/*.js',
              '!tmp/amd/lib/axiom/**/*.test.js'],
        dest: 'dist/axiom_base/amd/lib/axiom_base.amd.concat.js'
      },
      wash: {
        src: ['tmp/amd/lib/wash/**/*.js',
              '!tmp/amd/lib/wash/**/*.test.js'],
        dest: 'dist/axiom_wash/amd/lib/wash.amd.concat.js'
      }
    },

    copy: {
      axiom_publish: {
        files: [
          // {expand: true,cwd: 'dist/axiom_base', src: ['*'], dest: 'dist/dist/axiom_base'},
          {expand: true, cwd: 'tmp/cjs/', src: ['lib/axiom/**'], dest: 'dist/axiom_base/cjs'},
          {expand: true, cwd: 'tmp/amd/', src: ['lib/axiom/**'], dest: 'dist/axiom_base/amd'},
          {expand: true, cwd: '', src: ['lib/axiom/**', '!package_dist.json'], dest: 'dist/axiom_base/es6'},
          {expand: true, cwd: 'lib/axiom/', src: ['package_dist.json'], dest: '',
              rename: function(dest, matchedSrcPath, options) {
                return 'dist/axiom_base/package.json';
              }
          },
        ]
      }, wash_publish: {
        files: [
          // {expand: true, cwd: 'dist/wash', src: ['*'], dest: 'dist/axiom_wash'},
          {expand: true, cwd: 'tmp/cjs/', src: ['lib/wash/**'], dest: 'dist/axiom_wash/cjs'},
          {expand: true, cwd: 'tmp/amd/', src: ['lib/wash/**'], dest: 'dist/axiom_wash/amd'},
          {expand: true, cwd: '', src: ['lib/wash/**', '!package_dist.json'], dest: 'dist/axiom_wash/es6'},
          {expand: true, cwd: 'lib/wash/', src: ['package_dist.json'], dest: '',
              rename: function(dest, matchedSrcPath, options) {
                return 'dist/axiom_wash/package.json';
              }
          }
        ]
      },
      samples_web_shell_files: {
        files: [{
          expand: true,
          cwd: 'dist/axiom_base/amd/lib/',
          src: ['*.js', '*.map'],
          dest: 'tmp/samples/web_shell/js/'
        },
        {
          expand: true,
          cwd: 'dist/axiom_wash/amd/lib/',
          src: ['*.js'],
          dest: 'tmp/samples/web_shell/js/'
        },
        {
          expand: true,
          cwd: 'node_modules/hterm/dist/amd/lib/',
          src: ['hterm.amd.js'],
          dest: 'tmp/samples/web_shell/js/'
        },
        {
          expand: true,
          cwd: 'samples/web_shell/boot/',
          src: ['**/*.js',
                '**/*.js.map'
          ],
          dest: 'tmp/samples/web_shell/js/boot'
        },
        {
          expand: true,
          cwd: 'samples/web_shell/css/',
          src: ['**/*.css'],
          dest: 'tmp/samples/web_shell/css'
        }]
      },
      samples_use_globals_files: {
        files: [{
          expand: true,
          cwd: 'tmp/dist/',
          src: ['**/*.js'],
          dest: 'tmp/samples/use_globals/js/'
        },
        {
          expand: true,
          cwd: 'samples/use_globals/css/',
          src: ['**/*.css'],
          dest: 'tmp/samples/use_globals/css'
        },
        {
          expand: true,
          cwd: 'samples/use_globals/',
          src: ['**/*.html'],
          dest: 'tmp/samples/use_globals/'
        }]
      }
    },

    make_html_index: {
      samples_web_shell: {
        dest: 'tmp/samples/web_shell/index.html',
        title: 'Console',
        cwd: 'tmp/samples/web_shell/',
        scriptrefs: [
          'js/axiom_base.amd.concat.js',
          'js/wash.amd.concat.js',
          'js/*.js',
          'js/shell/**/*.js',
          'js/boot/startup.js' // last entry since we are synchronous (for now)
        ],
        cssrefs: [
          'css/**/*.css'
        ]
      }
    },

    watch: {
      check: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js'],
        tasks: ['check']
      },
      test: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js', 'test/**/*.js'],
        tasks: ['transpile', 'make_main_module:test', 'karma:once']
      },
      check_test: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js', 'test/**/*.js'],
        tasks: ['check', 'transpile', 'make_main_module:test', 'karma:once']
      }
    },

    es6_transpile: {
      amd: {
        type: "amd",
        fileResolver: ['lib/'],
        files: [{
          expand: true,
          cwd: 'lib/',
          src: ['**/*.js'],
          dest: 'tmp/amd/lib/'
        }]
      },

      cjs: {
        type: "cjs",
        fileResolver: ['lib/'],
        files: [{
          expand: true,
          cwd: 'lib/',
          src: ['**/*.js'],
          dest: 'tmp/cjs/lib/'
        }]
      },
      samples_web_shell: {
        type: "amd",
        fileResolver: ['lib/',
                       'node_modules/hterm/dist/stub/',
                       'samples/web_shell/lib'],
        files: [{
          expand: true,
          cwd: 'samples/web_shell/lib/',
          src: ['**/*.js'],
          dest: 'tmp/samples/web_shell/js/'
        }]
      }
    },

    shell: {
        options: {
            stderr: true
        },
        target: {
            command: 'npm publish dist/axiom_base; npm publish dist/axiom_wash'
        }
    },

    karma: {
      options: {
        browsers: browsers,
        frameworks: ['jasmine'],
        files: [
          'node_modules/es6-collections/index.js',
          'node_modules/es6-promise/dist/es6-promise.js',
          'polyfill/promise.js',
          'polyfill/bind.js',
          'loader/axiom_amd.js',
          'tmp/amd/lib/**/*.js',
          'tmp/test/test_main.js',
        ]
      },
      once: {
        singleRun: true
      },
      server: {
        singleRun: false
      }
    },

    run_wash: {
      main: {}
    }
  });

  // Just transpile.
  grunt.registerTask('transpile', ['clean',
                                   'make_dir_module',
                                   'es6_transpile']);

  // Static check with closure compiler.
  grunt.registerTask('check', ['make_dir_module',
                               'closure_externs:build',
                               'closure-compiler:check']);
  grunt.registerTask('check-watch', ['watch:check']);

  grunt.registerTask('dist', ['transpile',
                              'concat:axiom_base',
                              'concat:wash']);

  // Transpile and test.
  grunt.registerTask('test', ['transpile',
                              'make_main_module:test',
                              'karma:once']);
  grunt.registerTask('test-watch', ['clean',
                                    'watch:test']);

  // Static check, transpile, test, repeat on changes.
  grunt.registerTask('check-test-watch', ['clean', 'watch:check_test']);

  // Build, then run wash from node.js
  grunt.registerTask('wash', ['clean', 'make_dir_module', 'es6_transpile:cjs',
                              'run_wash']);

  grunt.registerTask('default', ['check', 'test']);

  // Sample apps
  grunt.registerTask('samples_use_globals', ['copy:samples_use_globals_files']);

  grunt.registerTask('samples_web_shell', ['copy:samples_web_shell_files',
                                         'make_html_index:samples_web_shell']);

  grunt.registerTask('samples', ['dist',
                                 'samples_web_shell',
                                 'samples_use_globals']);

  grunt.registerTask('deploy_samples', ['samples', 'git_deploy:samples']);

  grunt.registerTask('npm-publish', ['copy:axiom_publish', 'copy:wash_publish',
                                     'shell']);
};
<commit_msg>Reformatted and now selectively copying only .js and .js.map files<commit_after>// Copyright 2014 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.

module.exports = function(grunt) {
  // Load the grunt related dev deps listed in package.json.
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  // Load our custom tasks.
  grunt.loadTasks('./build/tasks/');

  var browsers = grunt.option('browsers');
  if (browsers) {
    browsers = browsers.split(/\s*,\s*/g);
  } else {
    browsers = ['PhantomJS'];
  }

  grunt.initConfig({
    clean: {
      all: ['tmp', 'dist']
    },

    'closure-compiler': {
      check: {
        cwd: 'lib/',
        js: ['**/*.js',
             '../third_party/closure-compiler/contrib/externs/jasmine.js',
             '../tmp/third_party/dcodeIO/fs.js',
             '../tmp/third_party/dcodeIO/buffer.js',
             '../tmp/third_party/dcodeIO/stream.js',
             '../tmp/third_party/dcodeIO/events.js'
            ],
        jsOutputFile: 'tmp/closure/out.js',
        options: require('./build/closure-options.json')
      }
    },

    git_deploy: {
      samples: {
        options: {
          url: 'git@github.com:chromium/axiom.git'
        },
        src: 'tmp'
      },
    },

    make_dir_module: {
      wash: {
        strip: 2,
        dest: 'lib/wash/exe_modules.js',
        cwd: 'lib',
        modules: ['wash/exe/*.js']
      }
    },

    make_main_module: {
      test: {
        require: '__axiomRequire__',
        dest: 'tmp/test/test_main.js',
        cwd: 'lib/',
        modules: ['**/*.test.js']
      }
    },

    closure_externs: {
      build: {
        expand: true,
        src: ['**/*.js'],
        dest: 'tmp/third_party/dcodeIO/',
        cwd: 'third_party/dcodeIO/',
      }
    },

    concat: {
      axiom_base: {
        src: ['loader/axiom_amd.js',
              'tmp/amd/lib/axiom/**/*.js',
              '!tmp/amd/lib/axiom/fs/node/*.js',
              '!tmp/amd/lib/axiom/**/*.test.js'],
        dest: 'dist/axiom_base/amd/lib/axiom_base.amd.concat.js'
      },
      wash: {
        src: ['tmp/amd/lib/wash/**/*.js',
              '!tmp/amd/lib/wash/**/*.test.js'],
        dest: 'dist/axiom_wash/amd/lib/wash.amd.concat.js'
      }
    },

    copy: {
      axiom_publish: {
        files: [
          {expand: true, cwd: 'tmp/cjs/', src: ['lib/axiom/**/*.js',
              'lib/axiom/**/*.js.map'], dest: 'dist/axiom_base/cjs'},
          {expand: true, cwd: 'tmp/amd/', src: ['lib/axiom/**/*.js'],
              dest: 'dist/axiom_base/amd'},
          {expand: true, cwd: '', src: ['lib/axiom/**/*.js',
              '!package_dist.json'], dest: 'dist/axiom_base/es6'},
          {expand: true, cwd: 'lib/axiom/', src: ['package_dist.json'],
              dest: '', rename: function(dest, matchedSrcPath, options) {
                return 'dist/axiom_base/package.json';
              }
          }
        ]
      },
      wash_publish: {
        files: [
          {expand: true, cwd: 'tmp/cjs/', src: ['lib/wash/**/*.js',
              'lib/wash/**/*.js.map'], dest: 'dist/axiom_wash/cjs'},
          {expand: true, cwd: 'tmp/amd/', src: ['lib/wash/**/*.js'],
              dest: 'dist/axiom_wash/amd'},
          {expand: true, cwd: '', src: ['lib/wash/**/*.js',
              '!package_dist.json'], dest: 'dist/axiom_wash/es6'},
          {expand: true, cwd: 'lib/wash/', src: ['package_dist.json'],
              dest: '', rename: function(dest, matchedSrcPath, options) {
                return 'dist/axiom_wash/package.json';
              }
          }
        ]
      },
      samples_web_shell_files: {
        files: [{
          expand: true,
          cwd: 'dist/axiom_base/amd/lib/',
          src: ['*.js', '*.map'],
          dest: 'tmp/samples/web_shell/js/'
        },
        {
          expand: true,
          cwd: 'dist/axiom_wash/amd/lib/',
          src: ['*.js'],
          dest: 'tmp/samples/web_shell/js/'
        },
        {
          expand: true,
          cwd: 'node_modules/hterm/dist/amd/lib/',
          src: ['hterm.amd.js'],
          dest: 'tmp/samples/web_shell/js/'
        },
        {
          expand: true,
          cwd: 'samples/web_shell/boot/',
          src: ['**/*.js',
                '**/*.js.map'
          ],
          dest: 'tmp/samples/web_shell/js/boot'
        },
        {
          expand: true,
          cwd: 'samples/web_shell/css/',
          src: ['**/*.css'],
          dest: 'tmp/samples/web_shell/css'
        }]
      },
      samples_use_globals_files: {
        files: [{
          expand: true,
          cwd: 'tmp/dist/',
          src: ['**/*.js'],
          dest: 'tmp/samples/use_globals/js/'
        },
        {
          expand: true,
          cwd: 'samples/use_globals/css/',
          src: ['**/*.css'],
          dest: 'tmp/samples/use_globals/css'
        },
        {
          expand: true,
          cwd: 'samples/use_globals/',
          src: ['**/*.html'],
          dest: 'tmp/samples/use_globals/'
        }]
      }
    },

    make_html_index: {
      samples_web_shell: {
        dest: 'tmp/samples/web_shell/index.html',
        title: 'Console',
        cwd: 'tmp/samples/web_shell/',
        scriptrefs: [
          'js/axiom_base.amd.concat.js',
          'js/wash.amd.concat.js',
          'js/*.js',
          'js/shell/**/*.js',
          'js/boot/startup.js' // last entry since we are synchronous (for now)
        ],
        cssrefs: [
          'css/**/*.css'
        ]
      }
    },

    watch: {
      check: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js'],
        tasks: ['check']
      },
      test: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js', 'test/**/*.js'],
        tasks: ['transpile', 'make_main_module:test', 'karma:once']
      },
      check_test: {
        options: {
          atBegin: true
        },
        files: ['lib/**/*.js', 'test/**/*.js'],
        tasks: ['check', 'transpile', 'make_main_module:test', 'karma:once']
      }
    },

    es6_transpile: {
      amd: {
        type: "amd",
        fileResolver: ['lib/'],
        files: [{
          expand: true,
          cwd: 'lib/',
          src: ['**/*.js'],
          dest: 'tmp/amd/lib/'
        }]
      },

      cjs: {
        type: "cjs",
        fileResolver: ['lib/'],
        files: [{
          expand: true,
          cwd: 'lib/',
          src: ['**/*.js'],
          dest: 'tmp/cjs/lib/'
        }]
      },
      samples_web_shell: {
        type: "amd",
        fileResolver: ['lib/',
                       'node_modules/hterm/dist/stub/',
                       'samples/web_shell/lib'],
        files: [{
          expand: true,
          cwd: 'samples/web_shell/lib/',
          src: ['**/*.js'],
          dest: 'tmp/samples/web_shell/js/'
        }]
      }
    },

    shell: {
        options: {
            stderr: true
        },
        target: {
            command: 'npm publish dist/axiom_base; npm publish dist/axiom_wash'
        }
    },

    karma: {
      options: {
        browsers: browsers,
        frameworks: ['jasmine'],
        files: [
          'node_modules/es6-collections/index.js',
          'node_modules/es6-promise/dist/es6-promise.js',
          'polyfill/promise.js',
          'polyfill/bind.js',
          'loader/axiom_amd.js',
          'tmp/amd/lib/**/*.js',
          'tmp/test/test_main.js',
        ]
      },
      once: {
        singleRun: true
      },
      server: {
        singleRun: false
      }
    },

    run_wash: {
      main: {}
    }
  });

  // Just transpile.
  grunt.registerTask('transpile', ['clean',
                                   'make_dir_module',
                                   'es6_transpile']);

  // Static check with closure compiler.
  grunt.registerTask('check', ['make_dir_module',
                               'closure_externs:build',
                               'closure-compiler:check']);
  grunt.registerTask('check-watch', ['watch:check']);

  grunt.registerTask('dist', ['transpile',
                              'concat:axiom_base',
                              'concat:wash']);

  // Transpile and test.
  grunt.registerTask('test', ['transpile',
                              'make_main_module:test',
                              'karma:once']);
  grunt.registerTask('test-watch', ['clean',
                                    'watch:test']);

  // Static check, transpile, test, repeat on changes.
  grunt.registerTask('check-test-watch', ['clean', 'watch:check_test']);

  // Build, then run wash from node.js
  grunt.registerTask('wash', ['clean', 'make_dir_module', 'es6_transpile:cjs',
                              'run_wash']);

  grunt.registerTask('default', ['check', 'test']);

  // Sample apps
  grunt.registerTask('samples_use_globals', ['copy:samples_use_globals_files']);

  grunt.registerTask('samples_web_shell', ['copy:samples_web_shell_files',
                                         'make_html_index:samples_web_shell']);

  grunt.registerTask('samples', ['dist',
                                 'samples_web_shell',
                                 'samples_use_globals']);

  grunt.registerTask('deploy_samples', ['samples', 'git_deploy:samples']);

  grunt.registerTask('npm-publish', ['copy:axiom_publish', 'copy:wash_publish',
                     'shell']);
};
<|endoftext|>


<commit_before>var expect = require('chai').expect,
  launcher = require('./helpers/launcher.js'),
  config = require('../config'),
  CallFramesProvider = require('../lib/CallFramesProvider').CallFramesProvider;

describe('CallFramesProvider', function() {
  launcher.stopAllDebuggersAfterEachTest();

  it('gets stack trace', function(done) {
    launcher.runOnBreakInFunction(function(debuggerClient) {
      var provider = new CallFramesProvider(config, debuggerClient);
      provider.fetchCallFrames(function(error, callFrames) {
        if (error !== undefined && error !== null) {
          done(error);
          return;
        }

        // The order of script loading has changed in v0.11
        var scriptId = /^v0\.10\./.test(process.version) ? '28' : '32';

        expect(callFrames).to.have.length.least(2);

        function objectValueWithId(id, className) {
          return {
            type: 'object',
            objectId: id,
            className: className || 'Object',
            description: className || 'Object'
          };
        }

        assertFrame({
            callFrameId: '0',
            functionName: 'MyObj.myFunc',
            location: {scriptId: scriptId, lineNumber: 8, columnNumber: 4},
            scopeChain: [
              { object: objectValueWithId('scope:0:0'), type: 'local' },
              { object: objectValueWithId('scope:0:1'), type: 'closure' },
              { object: objectValueWithId('scope:0:2'), type: 'global' }
            ],
            'this': objectValueWithId('1')
          },
          callFrames[0],
          'frame[0]');

        assertFrame({
            callFrameId: '1',
            functionName: 'globalFunc',
            location: {scriptId: scriptId, lineNumber: 13, columnNumber: 6},
            scopeChain: [
              { object: objectValueWithId('scope:1:0'), type: 'local' },
              { object: objectValueWithId('scope:1:1'), type: 'closure' },
              { object: objectValueWithId('scope:1:2'), type: 'global' }
            ],
            'this': objectValueWithId('10', 'global')
          },
          callFrames[1],
          'frame[1]');

        done();
      });
    });
  });

  it('retrieves specified number of stack traces when configured', function(done) {
    launcher.runOnBreakInFunction(function(debuggerClient) {
      var provider = new CallFramesProvider({stackTraceLimit: 1}, debuggerClient);
      provider.fetchCallFrames(function(error, callFrames) {
        if (error !== undefined && error !== null) {
          done(error);
          return;
        }

        expect(callFrames).to.have.length(1);
        done();
      });
    });
  });
});

function assertFrame(expected, actual, frameName) {
  expect(actual.callFrameId, frameName + '.callFrameId')
    .to.equal(expected.callFrameId);
  expect(actual.functionName, frameName + '.functionName')
    .to.equal(expected.functionName);
  assertJSONEqual(expected.location, actual.location, frameName + '.location');
  assertScopeChain(expected.scopeChain, actual.scopeChain, frameName + '.scopeChain');
  assertJSONEqual(expected.this, actual.this, frameName + '.this');
}

function assertScopeChain(expected, actual, objectName) {
  var i;
  expect(actual.length, objectName + '.length').to.equal(expected.length);
  for (i = 0; i < expected.length; i++) {
    assertJSONEqual(expected[i], actual[i], objectName + '[' + i + ']');
  }
}

function assertJSONEqual(expected, actual, message) {
  var expectedString = expected ? JSON.stringify(expected) : expected;
  var actualString = actual ? JSON.stringify(actual) : actual;
  expect(actualString, message).to.equal(expectedString);
}

<commit_msg>Fix tests for NodeJS v0.11.13.<commit_after>var expect = require('chai').expect,
  launcher = require('./helpers/launcher.js'),
  config = require('../config'),
  CallFramesProvider = require('../lib/CallFramesProvider').CallFramesProvider;

describe('CallFramesProvider', function() {
  launcher.stopAllDebuggersAfterEachTest();

  it('gets stack trace', function(done) {
    launcher.runOnBreakInFunction(function(debuggerClient) {
      var provider = new CallFramesProvider(config, debuggerClient);
      provider.fetchCallFrames(function(error, callFrames) {
        if (error !== undefined && error !== null) {
          done(error);
          return;
        }

        // The order of script loading has changed in v0.11
        var scriptId = /^v0\.10\./.test(process.version) ? '28' : '36';

        expect(callFrames).to.have.length.least(2);

        function objectValueWithId(id, className) {
          return {
            type: 'object',
            objectId: id,
            className: className || 'Object',
            description: className || 'Object'
          };
        }

        assertFrame({
            callFrameId: '0',
            functionName: 'MyObj.myFunc',
            location: {scriptId: scriptId, lineNumber: 8, columnNumber: 4},
            scopeChain: [
              { object: objectValueWithId('scope:0:0'), type: 'local' },
              { object: objectValueWithId('scope:0:1'), type: 'closure' },
              { object: objectValueWithId('scope:0:2'), type: 'global' }
            ],
            'this': objectValueWithId('1')
          },
          callFrames[0],
          'frame[0]');

        assertFrame({
            callFrameId: '1',
            functionName: 'globalFunc',
            location: {scriptId: scriptId, lineNumber: 13, columnNumber: 6},
            scopeChain: [
              { object: objectValueWithId('scope:1:0'), type: 'local' },
              { object: objectValueWithId('scope:1:1'), type: 'closure' },
              { object: objectValueWithId('scope:1:2'), type: 'global' }
            ],
            'this': objectValueWithId('10', 'global')
          },
          callFrames[1],
          'frame[1]');

        done();
      });
    });
  });

  it('retrieves specified number of stack traces when configured', function(done) {
    launcher.runOnBreakInFunction(function(debuggerClient) {
      var provider = new CallFramesProvider({stackTraceLimit: 1}, debuggerClient);
      provider.fetchCallFrames(function(error, callFrames) {
        if (error !== undefined && error !== null) {
          done(error);
          return;
        }

        expect(callFrames).to.have.length(1);
        done();
      });
    });
  });
});

function assertFrame(expected, actual, frameName) {
  expect(actual.callFrameId, frameName + '.callFrameId')
    .to.equal(expected.callFrameId);
  expect(actual.functionName, frameName + '.functionName')
    .to.equal(expected.functionName);
  assertJSONEqual(expected.location, actual.location, frameName + '.location');
  assertScopeChain(expected.scopeChain, actual.scopeChain, frameName + '.scopeChain');
  assertJSONEqual(expected.this, actual.this, frameName + '.this');
}

function assertScopeChain(expected, actual, objectName) {
  var i;
  expect(actual.length, objectName + '.length').to.equal(expected.length);
  for (i = 0; i < expected.length; i++) {
    assertJSONEqual(expected[i], actual[i], objectName + '[' + i + ']');
  }
}

function assertJSONEqual(expected, actual, message) {
  var expectedString = expected ? JSON.stringify(expected) : expected;
  var actualString = actual ? JSON.stringify(actual) : actual;
  expect(actualString, message).to.equal(expectedString);
}

<|endoftext|>


<commit_before>module.exports = function(grunt) {
    // Project Configuration
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        watch: {
            jade: {
                files: ['app/views/**'],
                options: {
                    livereload: true,
                },
            },
            js: {
                files: ['public/js/**', 'app/**/*.js'],
                tasks: ['jshint'],
                options: {
                    livereload: true,
                },
            },
            html: {
                files: ['public/views/**'],
                options: {
                    livereload: true,
                },
            },
            css: {
                files: ['public/css/**'],
                options: {
                    livereload: true
                }
            }
        },
        jshint: {
            all: ['gruntfile.js', 'public/js/**/*.js', 'test/mocha/**/*.js', 'test/karma/**/*.js', 'app/**/*.js']
        },
        nodemon: {
            dev: {
                options: {
                    file: 'server.js',
                    args: [],
                    ignoredFiles: ['README.md', 'node_modules/**', '.DS_Store'],
                    watchedExtensions: ['js'],
                    watchedFolders: ['app', 'config'],
                    debug: true,
                    delayTime: 1,
                    env: {
                        PORT: 3000
                    },
                    cwd: __dirname
                }
            }
        },
        concurrent: {
            tasks: ['nodemon', 'watch'],
            options: {
                logConcurrentOutput: true
            }
        },
        mochaTest: {
            options: {
                reporter: 'spec'
            },
            src: ['test/mocha/**/*.js']
        },
        env: {
            test: {
                NODE_ENV: 'test'
            }
        },
        karma: {
            unit: {
                configFile: 'test/karma/karma.conf.js'
            }
        }
    });

    //Load NPM tasks
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-mocha-test');
    grunt.loadNpmTasks('grunt-karma');
    grunt.loadNpmTasks('grunt-nodemon');
    grunt.loadNpmTasks('grunt-concurrent');
    grunt.loadNpmTasks('grunt-env');

    //Making grunt default to force in order not to break the project.
    grunt.option('force', true);

    //Default task(s).
    grunt.registerTask('default', ['jshint', 'concurrent']);

    //Test task.
    grunt.registerTask('test', ['env:test', 'mochaTest', 'karma:unit']);
};<commit_msg>update gruntfile.js to let jshint adhere to .jshintrc<commit_after>module.exports = function(grunt) {
    // Project Configuration
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        watch: {
            jade: {
                files: ['app/views/**'],
                options: {
                    livereload: true,
                },
            },
            js: {
                files: ['public/js/**', 'app/**/*.js'],
                tasks: ['jshint'],
                options: {
                    livereload: true,
                },
            },
            html: {
                files: ['public/views/**'],
                options: {
                    livereload: true,
                },
            },
            css: {
                files: ['public/css/**'],
                options: {
                    livereload: true
                }
            }
        },
        jshint: {
            all: {
                src: ['gruntfile.js', 'public/js/**/*.js', 'test/mocha/**/*.js', 'test/karma/**/*.js', 'app/**/*.js'],
                options: {
                    jshintrc: true
                }
            }
        },
        nodemon: {
            dev: {
                options: {
                    file: 'server.js',
                    args: [],
                    ignoredFiles: ['README.md', 'node_modules/**', '.DS_Store'],
                    watchedExtensions: ['js'],
                    watchedFolders: ['app', 'config'],
                    debug: true,
                    delayTime: 1,
                    env: {
                        PORT: 3000
                    },
                    cwd: __dirname
                }
            }
        },
        concurrent: {
            tasks: ['nodemon', 'watch'],
            options: {
                logConcurrentOutput: true
            }
        },
        mochaTest: {
            options: {
                reporter: 'spec'
            },
            src: ['test/mocha/**/*.js']
        },
        env: {
            test: {
                NODE_ENV: 'test'
            }
        },
        karma: {
            unit: {
                configFile: 'test/karma/karma.conf.js'
            }
        }
    });

    //Load NPM tasks
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-mocha-test');
    grunt.loadNpmTasks('grunt-karma');
    grunt.loadNpmTasks('grunt-nodemon');
    grunt.loadNpmTasks('grunt-concurrent');
    grunt.loadNpmTasks('grunt-env');

    //Making grunt default to force in order not to break the project.
    grunt.option('force', true);

    //Default task(s).
    grunt.registerTask('default', ['jshint', 'concurrent']);

    //Test task.
    grunt.registerTask('test', ['env:test', 'mochaTest', 'karma:unit']);
};
<|endoftext|>


<commit_before>/* jshint node: true*/
'use strict';
module.exports = function(grunt) {
    var target = grunt.option('target') || 'http://localhost:5000',
        port = process.env.PORT || 5000;

    grunt.initConfig({
        'gh-pages': {
            origin: {
                options: {
                    base: 'public',
                    message: 'Deploy to GitHub Pages'
                },
                src: ['**/*']
            },
            upstream: {
                options: {
                    base: 'public',
                    message: 'Deploy to GitHub Pages',
                    repo: 'https://github.com/ScottLogic/StockFlux.git'
                },
                src: ['**/*']
            }
        },

        connect: {
            options: {
                port: port,
                // Change this to '0.0.0.0' to access the server from outside.
                hostname: '0.0.0.0',
                livereload: 35729
            },
            livereload: {
                options: {
                    open: false,
                    base: ['public']
                }
            }
        },

        openfin: {
            options: {
                configPath: target + '/app.json',
                config: {
                    create: false,
                    filePath: 'public/app.json',
                    options: {
                        startup_app: {
                            url: target + '/parent.html',
                            applicationIcon: target + '/favicon.ico'
                        },
                        shortcut: {
                            icon: target + '/favicon.ico'
                        }
                    }
                }
            },
            serve: {
                open: true
            },
            build: {
                open: false
            }
        },

        less: {
            development: {
                options: {
                    strictMath: true,
                    sourceMap: true,
                    outputSourceFiles: true,
                    sourceMapURL: 'style.css.map',
                    sourceMapFilename: 'public/assets/css/style.css.map'
                },
                files: {
                    'public/assets/css/style.css': 'src/assets/styles/style.less'
                }
            },
            production: {
                options: {
                    strictMath: true
                },
                files: {
                    'public/assets/css/style.css': 'src/assets/styles/style.less'
                }
            }
        },

        download: {
            openfinZip: {
                src: ['https://dl.openfin.co/services/download?fileName=StockFlux&config=http://scottlogic.github.io/StockFlux/app.json'],
                dest: './public/StockFlux.zip'
            }
        },

        eslint: {
            target: ['src/**/*.js']
        },

        clean: {
            dist: {
                src: ['public', 'node_modules/BitFlux/dist']
            }
        },

        copy: {
            modulescss: {
                expand: true,
                cwd: 'node_modules/',
                src: ['d3fc/dist/d3fc.min.css',
                    'malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.css'],
                dest: 'public/assets/css/',
                flatten: true
            },
            modulesjs: {
                expand: true,
                cwd: 'node_modules/',
                src: [
                    'jquery/dist/jquery.min.js',
                    'angular/angular.min.js',
                    'angular-resource/angular-resource.min.js',
                    'moment/min/moment.min.js',
                    'angular-animate/angular-animate.min.js',
                    'angular-storage/dist/angular-storage.min.js',
                    'd3fc/dist/d3fc.bundle.min.js',
                    'BitFlux/node_modules/bootstrap/js/dropdown.js',
                    'malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.js'
                ],
                dest: 'public/assets/js/',
                flatten: true
            },
            showcase: {
                expand: true,
                cwd: 'node_modules/BitFlux/dist/',
                src: ['**'],
                dest: 'public/',
                rename: function(dest, src) {
                    if (src.split('.').pop() === 'html') {
                        return dest + 'BitFlux.html';
                    }

                    return dest + src;
                }
            },
            html: {
                expand: true,
                cwd: 'src/',
                src: ['**/*.html'],
                dest: 'public'
            },
            json: {
                expand: true,
                cwd: 'src/',
                src: ['**/*.json'],
                dest: 'public'
            },
            icons: {
                expand: true,
                cwd: 'src/',
                src: ['**/*.svg', '**/*.ico'],
                dest: 'public'
            },
            fonts: {
                files: [{
                    expand: true,
                    cwd: 'node_modules/BitFlux/node_modules/bootstrap/dist/fonts/',
                    src: ['**'],
                    dest: 'public/assets/fonts'
                }]
            }
        },
        concat: {
            dist: {
                src: ['src/**/*.js', '!src/parent-controller.js',
                      '!src/parentApp.js', '!src/window-service.js'],
                dest: 'public/app.js'
            },
            parent: {
                src: ['src/parentApp.js', 'src/parent-controller.js', 'src/store-service.js',
                    'src/window-service.js', 'src/sidebars/favourites/geometry-service.js',
                    'src/config-service.js'],
                dest: 'public/app-parent.js'
            }
        },

        uglify: {
            dist: {
                files: {
                    'public/app.js': ['public/app.js']
                }
            }
        },
        babel: {
            options: {
                sourceMap: false
            },
            dist: {
                files: {
                    'public/app.js': 'public/app.js',
                    'public/app-parent.js': 'public/app-parent.js'
                }
            }
        },
        bump: {
            options: {
                files: ['package.json', 'src/main/version/version-controller.js'],
                commit: true,
                commitMessage: 'Release v%VERSION%',
                commitFiles: ['package.json', 'src/main/version/version-controller.js'],
                createTag: true,
                tagName: 'v%VERSION%',
                tagMessage: 'Version %VERSION%',
                push: false
            }
        },

        'string-replace': {
            inline: {
                files: {
                    'public/app.js': 'public/app.js',
                    'public/app-parent.js': 'public/app-parent.js'
                },
                options: {
                    replacements: [{
                        pattern: 'const allowContextMenu = true;',
                        replacement: 'const allowContextMenu = false;'
                    }]
                }
            }
        }
    });

    var isWin = (/^win/).test(process.platform);

    grunt.loadNpmTasks('grunt-contrib-connect');
    if (isWin) {
        grunt.loadNpmTasks('grunt-openfin');
    }
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-eslint');
    grunt.loadNpmTasks('grunt-http-download');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-gh-pages');
    grunt.loadNpmTasks('grunt-babel');
    grunt.loadNpmTasks('grunt-bump');
    grunt.loadNpmTasks('grunt-string-replace');

    grunt.registerTask('showcase', function() {
        var callback = this.async();
        grunt.util.spawn({
            grunt: true,
            args: ['build:module'],
            opts: {
                cwd: 'node_modules/BitFlux/'
            }
        }, function(error, result, code) {
            console.log(result.stdout);
            callback();
        });
    });

    grunt.registerTask('concatenate', ['eslint', 'clean', 'showcase', 'copy', 'concat'])
    grunt.registerTask('transpile', ['babel', 'less:development']);

    grunt.registerTask('build:dev', ['concatenate', 'transpile', 'connect:livereload']);
    grunt.registerTask('build:release', ['concatenate', 'string-replace', 'transpile', 'uglify', 'connect:livereload']);

    grunt.registerTask('serve', ['build:dev', 'openfin:serve']);
    grunt.registerTask('default', ['serve']);

    grunt.registerTask('createZip', ['build:release', 'download']);
    grunt.registerTask('deploy', ['createZip', 'gh-pages:origin']);
    grunt.registerTask('deploy:upstream', ['ci', 'gh-pages:upstream']);

    grunt.registerTask('release', ['bump:major']);

    grunt.registerTask('ci', ['build:release', 'download']);

};
<commit_msg>Change upstream repo to use git@github path<commit_after>/* jshint node: true*/
'use strict';
module.exports = function(grunt) {
    var target = grunt.option('target') || 'http://localhost:5000',
        port = process.env.PORT || 5000;

    grunt.initConfig({
        'gh-pages': {
            origin: {
                options: {
                    base: 'public',
                    message: 'Deploy to GitHub Pages'
                },
                src: ['**/*']
            },
            upstream: {
                options: {
                    base: 'public',
                    message: 'Deploy to GitHub Pages',
                    repo: 'git@github.com:ScottLogic/StockFlux.git'
                },
                src: ['**/*']
            }
        },

        connect: {
            options: {
                port: port,
                // Change this to '0.0.0.0' to access the server from outside.
                hostname: '0.0.0.0',
                livereload: 35729
            },
            livereload: {
                options: {
                    open: false,
                    base: ['public']
                }
            }
        },

        openfin: {
            options: {
                configPath: target + '/app.json',
                config: {
                    create: false,
                    filePath: 'public/app.json',
                    options: {
                        startup_app: {
                            url: target + '/parent.html',
                            applicationIcon: target + '/favicon.ico'
                        },
                        shortcut: {
                            icon: target + '/favicon.ico'
                        }
                    }
                }
            },
            serve: {
                open: true
            },
            build: {
                open: false
            }
        },

        less: {
            development: {
                options: {
                    strictMath: true,
                    sourceMap: true,
                    outputSourceFiles: true,
                    sourceMapURL: 'style.css.map',
                    sourceMapFilename: 'public/assets/css/style.css.map'
                },
                files: {
                    'public/assets/css/style.css': 'src/assets/styles/style.less'
                }
            },
            production: {
                options: {
                    strictMath: true
                },
                files: {
                    'public/assets/css/style.css': 'src/assets/styles/style.less'
                }
            }
        },

        download: {
            openfinZip: {
                src: ['https://dl.openfin.co/services/download?fileName=StockFlux&config=http://scottlogic.github.io/StockFlux/app.json'],
                dest: './public/StockFlux.zip'
            }
        },

        eslint: {
            target: ['src/**/*.js']
        },

        clean: {
            dist: {
                src: ['public', 'node_modules/BitFlux/dist']
            }
        },

        copy: {
            modulescss: {
                expand: true,
                cwd: 'node_modules/',
                src: ['d3fc/dist/d3fc.min.css',
                    'malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.css'],
                dest: 'public/assets/css/',
                flatten: true
            },
            modulesjs: {
                expand: true,
                cwd: 'node_modules/',
                src: [
                    'jquery/dist/jquery.min.js',
                    'angular/angular.min.js',
                    'angular-resource/angular-resource.min.js',
                    'moment/min/moment.min.js',
                    'angular-animate/angular-animate.min.js',
                    'angular-storage/dist/angular-storage.min.js',
                    'd3fc/dist/d3fc.bundle.min.js',
                    'BitFlux/node_modules/bootstrap/js/dropdown.js',
                    'malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.js'
                ],
                dest: 'public/assets/js/',
                flatten: true
            },
            showcase: {
                expand: true,
                cwd: 'node_modules/BitFlux/dist/',
                src: ['**'],
                dest: 'public/',
                rename: function(dest, src) {
                    if (src.split('.').pop() === 'html') {
                        return dest + 'BitFlux.html';
                    }

                    return dest + src;
                }
            },
            html: {
                expand: true,
                cwd: 'src/',
                src: ['**/*.html'],
                dest: 'public'
            },
            json: {
                expand: true,
                cwd: 'src/',
                src: ['**/*.json'],
                dest: 'public'
            },
            icons: {
                expand: true,
                cwd: 'src/',
                src: ['**/*.svg', '**/*.ico'],
                dest: 'public'
            },
            fonts: {
                files: [{
                    expand: true,
                    cwd: 'node_modules/BitFlux/node_modules/bootstrap/dist/fonts/',
                    src: ['**'],
                    dest: 'public/assets/fonts'
                }]
            }
        },
        concat: {
            dist: {
                src: ['src/**/*.js', '!src/parent-controller.js',
                      '!src/parentApp.js', '!src/window-service.js'],
                dest: 'public/app.js'
            },
            parent: {
                src: ['src/parentApp.js', 'src/parent-controller.js', 'src/store-service.js',
                    'src/window-service.js', 'src/sidebars/favourites/geometry-service.js',
                    'src/config-service.js'],
                dest: 'public/app-parent.js'
            }
        },

        uglify: {
            dist: {
                files: {
                    'public/app.js': ['public/app.js']
                }
            }
        },
        babel: {
            options: {
                sourceMap: false
            },
            dist: {
                files: {
                    'public/app.js': 'public/app.js',
                    'public/app-parent.js': 'public/app-parent.js'
                }
            }
        },
        bump: {
            options: {
                files: ['package.json', 'src/main/version/version-controller.js'],
                commit: true,
                commitMessage: 'Release v%VERSION%',
                commitFiles: ['package.json', 'src/main/version/version-controller.js'],
                createTag: true,
                tagName: 'v%VERSION%',
                tagMessage: 'Version %VERSION%',
                push: false
            }
        },

        'string-replace': {
            inline: {
                files: {
                    'public/app.js': 'public/app.js',
                    'public/app-parent.js': 'public/app-parent.js'
                },
                options: {
                    replacements: [{
                        pattern: 'const allowContextMenu = true;',
                        replacement: 'const allowContextMenu = false;'
                    }]
                }
            }
        }
    });

    var isWin = (/^win/).test(process.platform);

    grunt.loadNpmTasks('grunt-contrib-connect');
    if (isWin) {
        grunt.loadNpmTasks('grunt-openfin');
    }
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-eslint');
    grunt.loadNpmTasks('grunt-http-download');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-gh-pages');
    grunt.loadNpmTasks('grunt-babel');
    grunt.loadNpmTasks('grunt-bump');
    grunt.loadNpmTasks('grunt-string-replace');

    grunt.registerTask('showcase', function() {
        var callback = this.async();
        grunt.util.spawn({
            grunt: true,
            args: ['build:module'],
            opts: {
                cwd: 'node_modules/BitFlux/'
            }
        }, function(error, result, code) {
            console.log(result.stdout);
            callback();
        });
    });

    grunt.registerTask('concatenate', ['eslint', 'clean', 'showcase', 'copy', 'concat'])
    grunt.registerTask('transpile', ['babel', 'less:development']);

    grunt.registerTask('build:dev', ['concatenate', 'transpile', 'connect:livereload']);
    grunt.registerTask('build:release', ['concatenate', 'string-replace', 'transpile', 'uglify', 'connect:livereload']);

    grunt.registerTask('serve', ['build:dev', 'openfin:serve']);
    grunt.registerTask('default', ['serve']);

    grunt.registerTask('createZip', ['build:release', 'download']);
    grunt.registerTask('deploy', ['createZip', 'gh-pages:origin']);
    grunt.registerTask('deploy:upstream', ['ci', 'gh-pages:upstream']);

    grunt.registerTask('release', ['bump:major']);

    grunt.registerTask('ci', ['build:release', 'download']);

};
<|endoftext|>


<commit_before>module.exports = function (grunt) {

  // Load Grunt tasks declared in the package.json file
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  grunt.initConfig({

    clean : {
      dist: ['dist/*.js', 'examples/dist/*.js']
    },

    concat : {
      dist: {
        src: ['app/scripts/*.js', 'app/scripts/**/*.js'],
        dest: 'dist/ng-map.js'
      }
    },

    uglify: {
      files: {
        src: 'dist/*.js',  // source files mask
        dest: 'dist/',    // destination folder
        expand: true,    // allow dynamic building
        flatten: true,   // remove all unnecessary nesting
        ext: '.min.js'   // replace .js to .min.js
      }
    },

    connect: {
      all : {
        options: {
          port: 9000,
          middleware: function(connect, options) {
            return [
              require('connect-livereload')({
                src: "//rawgithub.com/allenhwkim/util/master/livereload.js"
              }),
              connect.static('examples'),
              connect.directory('examples')
            ];
          }
        }
      }
    },

    watch: {
      all: {
        files: ['app/**/*', 'examples/*'],
        options: {
          livereload: true  // starts livereload server at port 35729
        }
      }
    },

   bump: {
     options: {
       //files: ['package.json'],
       //updateConfigs: [],
       //commit: true,
       //commitMessage: 'Release v%VERSION%',
       //commitFiles: ['package.json'], // '-a' for all files
       //createTag: true,
       //tagName: 'v%VERSION%',
       //tagMessage: 'Version %VERSION%',
       //push: true,
       pushTo: '',
       //gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d' // options to use with '$ git describe'
     }
   },

  });

  grunt.registerTask('server', ['connect', 'watch']);
  grunt.registerTask('min', ['clean', 'concat', 'uglify']);

};
<commit_msg>updated gruntfile.js<commit_after>module.exports = function (grunt) {

  // Load Grunt tasks declared in the package.json file
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  grunt.initConfig({

    clean : {
      dist: ['dist/*.js', 'examples/dist/*.js']
    },

    concat : {
      dist: {
        src: ['app/scripts/*.js', 'app/scripts/**/*.js'],
        dest: 'dist/ng-map.js'
      }
    },

    uglify: {
      files: {
        src: 'dist/*.js',  // source files mask
        dest: 'dist/',    // destination folder
        expand: true,    // allow dynamic building
        flatten: true,   // remove all unnecessary nesting
        ext: '.min.js'   // replace .js to .min.js
      }
    },

    connect: {
      all : {
        options: {
          port: 9000,
          middleware: function(connect, options) {
            return [
              require('connect-livereload')({
                src: "//rawgithub.com/allenhwkim/util/master/livereload.js"
              }),
              connect.static('examples'),
              connect.directory('examples')
            ];
          }
        }
      }
    },

    watch: {
      all: {
        files: ['app/**/*', 'examples/*'],
        options: {
          livereload: true  // starts livereload server at port 35729
        }
      }
    },

   bump: {
     options: {
       pushTo: ''
     }
   },

  });

  grunt.registerTask('server', ['connect', 'watch']);
  grunt.registerTask('min', ['clean', 'concat', 'uglify']);

};
<|endoftext|>